Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Riichi point calculations #22

Closed
wants to merge 11 commits into from

Conversation

TwelveNights
Copy link
Member

Resolution for #16 and #8

Copy link
Contributor

@0spooky 0spooky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please split the constant definitions and the actual work in two seperate branches. Also do not adapt the code to your own style choices. All you are doing is making the code messier by having multiple styles existing at once in the same code base.

NORTH: "north",

MAHJONG_CLUB_LEAGUE: "Mahjong Club League",
MANGAN: 2000
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have good intentions here, but "MANGAN = 2000" is meaningless. You may as well have called the constant "Y2K" or "Andre minus 1000". At least call this something like MANGAN_BASE_POINTS or something.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure

else //if (round > 8)
return "西";;
break;
case Constants.GAME_TYPE.HONG_KONG:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not the style I use for switch/case. Case stays indented the same as switch.

Copy link
Member Author

@TwelveNights TwelveNights Oct 7, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll update my code to have the case be aligned with switch.

return "西";
else //if (round > 12)
return "北";
break;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you so keen on putting breaks in every case? I prefer to not include breaks in switch cases which are returned from. Looks cleaner and the break is never called anyway.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It wasn't me that had them to begin with lmao

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

o im dum

};
},

// Helper function to ensure all players are selected
allPlayersSelected() {
return (Session.get("current_east") != Constants.DEFAULT_EAST &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just the style I've been taught, but can formatting please be put in a seperate branch if you think it's important? Otherwise there's just a lot of clutter.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of this pull request seems unrelated to point calculation. Either rename the commit or change this to reflect what the commit is.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of the code changes I wanted to make in this ticket are relating to refactoring, hence the refactor name of the commit. Actually, no behaviour should be changed from this ticket.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you done extensive testing of point submission? This is the most critically important part of the submission form so every possible input must work exactly correct or the entire system is broken.

import { Constants } from './Constants';
import { NewGameUtils } from './NewGameUtils';

export var PointCalculationUtils = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're going to do this, make it generic (include HK calculation too it's much more simple anyway)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to do it later, since this ticket is already quite large.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm just worried about JPN and HKG code diverging too much when it should be converging.

@@ -601,7 +601,7 @@ function save_game_to_database(hands_array) {
};

// Initialise ELO calculator to update player ELO
var jpn_elo_calculator = new EloCalculator(2000, 5, [15000, 0, -5000, -10000], game, Constants.GAME_TYPE.JAPANESE);
var jpn_elo_calculator = new EloCalculator(2000, 5, [15000, 0, -5000, -10000], game, Constants.GAME_TYPE.JAPANESE);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this space

let winds = {};
winds[Constants.EAST] = winds[Constants.SOUTH] = winds[Constants.WEST] = winds[Constants.NORTH] = 0;

let basicPoints;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some funky indentation here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll fix that in my next commit.

let manganPayout = multiplier * Constants.MANGAN;

if (points < 5) {
if (fu == 20 || (points == 1 && fu == 25)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super funky indentation. Use tabs for indentation and spaces for alignment please.

}
else if (winnerWind == "south") {
}
} else if (winnerWind == Constants.SOUTH) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Force of habit, although keep in mind that all this change does is modify it so that the oneline if statement is encapsulated in curly braces instead of following in a logical line.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just an encompasing statement I happened to put on this line. I actually generally agree with wrapping single line conditional logic.

@0spooky
Copy link
Contributor

0spooky commented Oct 26, 2016

Some responses posted. Please refactor as well as there are now merge conflicts.

@TwelveNights TwelveNights force-pushed the refactor-point-calculations branch 2 times, most recently from 87844b5 to 093651b Compare November 21, 2016 06:28
winds[w] = (nonDealerPays * 3) + (currentBonus * 300) + (riichiSticks * 1000);
} else {
winds[w] = -(nonDealerPays + (currentBonus * 100));
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotta correct this as an aside, lol

Copy link
Contributor

@0spooky 0spooky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review to continue once these changes are made.

};

Constants.WINDS = [Constants.EAST, Constants.SOUTH, Constants.WEST, Constants.NORTH];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this defined outside the Constants object?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those values don't exist until the Constants object is defined. I added this line afterwards so I didn't have to be redundant.

Session.get("current_south") != Constants.DEFAULT_SOUTH &&
Session.get("current_west") != Constants.DEFAULT_WEST &&
Session.get("current_north") != Constants.DEFAULT_NORTH);
Session.get("current_south") != Constants.DEFAULT_SOUTH &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Align these blocks with spaces. For instance, this line should be two tabs followed by 8 spaces in order for the Session(...) code to align properly on all environments.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did not address.

@@ -129,13 +123,13 @@ export var NewGameUtils = {
let westRoundOver = Session.get("current_round") > 12;
// End condition where game has reached the end of south round with at least one player above minimum
let someoneAboveMinimum = Session.get("current_round") > 8 &&
this.someoneAboveMinimum(Constants.JPN_END_POINTS);
this.someoneAboveMinimum(Constants.JPN_END_POINTS);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above (RE: Spaces)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did not address.

Session.get("current_bonus") > 0 &&
this.getDirectionScore("north") >= Constants.JPN_END_POINTS &&
this.getFirstPlace() == "north";
Session.get("current_bonus") > 0 &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above (RE: Spaces)


export var PointCalculationUtils = {
jpn: {
dealin_delta,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps these should be renamed jpn_dealin_delta to more easily accomodate later addition of hkg

}
};

function dealin_delta(points, fu, winnerWind, loserWind, riichiSticks) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it hurt to put comments in your code additions? It makes it faster for others to review, and easier for others to maintain. I think we should probably start including function headers as well just to make things easier to understand.

} else { basicPoints = manganValue(points); }

let nonDealerPays = Math.ceil(basicPoints / 100 * (dealerWind == winnerWind ? 2 : 1)) * 100;
let dealerPays = Math.ceil(basicPoints / 100 * 2) * 100;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should declare used variables at the beginning of the function.

}
} else { basicPoints = manganValue(points) * multiplier };

let currentBonus = Number(Session.get("current_bonus")) * 300;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bonus amount should probably be defined in Constants.js

} else { basicPoints = manganValue(points) * multiplier };

let currentBonus = Number(Session.get("current_bonus")) * 300;
winds[winnerWind] = basicPoints + currentBonus + (riichiSticks * 1000);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So should riichi amount


function mistake_delta(loser) {
let winds = {};
winds[Constants.EAST] = winds[Constants.SOUTH] = winds[Constants.WEST] = winds[Constants.NORTH] = 4000;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mistake points should probably be defined in Constants.js

RIICHI_POINTS: 1000,

// Points paid for a mistake
MISTAKE_POINTS: 12000,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please specify this is the Japanese chombo amount. The Hong Kong amount is different.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might as well give the JPN_ prefix to bonus and Riichi too, since that is sort of the convention it seems.

Session.get("current_south") != Constants.DEFAULT_SOUTH &&
Session.get("current_west") != Constants.DEFAULT_WEST &&
Session.get("current_north") != Constants.DEFAULT_NORTH);
Session.get("current_south") != Constants.DEFAULT_SOUTH &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did not address.

@@ -129,13 +123,13 @@ export var NewGameUtils = {
let westRoundOver = Session.get("current_round") > 12;
// End condition where game has reached the end of south round with at least one player above minimum
let someoneAboveMinimum = Session.get("current_round") > 8 &&
this.someoneAboveMinimum(Constants.JPN_END_POINTS);
this.someoneAboveMinimum(Constants.JPN_END_POINTS);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did not address.

@@ -129,13 +123,12 @@ export var NewGameUtils = {
let westRoundOver = Session.get("current_round") > 12;
// End condition where game has reached the end of south round with at least one player above minimum
let someoneAboveMinimum = Session.get("current_round") > 8 &&
this.someoneAboveMinimum(Constants.JPN_END_POINTS);
this.someoneAboveMinimum(Constants.JPN_END_POINTS);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So close, but this doesn't actually line up with the above line.

this.getDirectionScore("north") >= Constants.JPN_END_POINTS &&
this.getFirstPlace() == "north";

Session.get("current_bonus") > 0 &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above.

basicPoints = Math.ceil((fu * Math.pow(2, 2 + points)) * multiplier / 100) * 100;
basicPoints = basicPoints < manganPayout ? basicPoints : manganPayout;
}
} else { basicPoints = manganValue(points) * multiplier };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you're going to do this, the semicolon should be at the end of the line, not the end of the block. I would still make this and the other one like it a seperate line.

*
* @return {Object} containing the point difference for each seat
*/
function jpn_dealin_delta(points, fu, winnerWind, loserWind, riichiSticks) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're adding function headers, make sure to add @param entries

export var PointCalculationUtils = {
jpn_dealin_delta,
jpn_selfdraw_delta,
jpn_mistake_delta
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, is it possible to keep the jpn object in PointCalculationUtils with members "dealin_delta = jpn_dealin_delta"? It seems you removed it this entry in favour of just the suffix.

northDelta += dealin_delta(points, fu, "north", winnerWind, loserWind) +
rewardRiichiSticks(riichiSum, "north", winnerWind);
allDelta = PointCalculationUtils.jpn_dealin_delta(points, fu, winnerWind, loserWind, riichiSum);
Session.set("free_riichi_sticks", 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. This is redundant as it exists in PointCalculationUtils (I would remove it from there personally)
  2. This is located in a different location than in self_draw. Should be consistent.


// Check to see if you have to count basic points
if (points < 5) {
if (points == 1 && (fu == 20 || fu == 25)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You also need to protect 2 point 25 selfdraw as that combination does not exist.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is prevented in NewGameUtils#noIllegalSelfDraw. This should be removed for issue #27.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So will this be removed or augmented with 2p25f? In between makes no sense

* Calculates the change in points as a result of a deal-in hand
* Uses the formula from https://en.wikipedia.org/wiki/Japanese_Mahjong_scoring_rules
*
* @param {number} points - the total number of han + dora
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think param variable types need to be capitalized.

@@ -1089,36 +1091,37 @@ function push_split_pao_hand(template) {
Session.set("north_riichi_sum", Number(Session.get("north_riichi_sum")) + 1);
}

var value = dealin_delta(points, fu, winnerWind, winnerWind);
var value = PointCalculationUtils.jpn.dealin_delta(points, fu, winnerWind, loserWind, 0)[loserWind];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this correct? I'm worried this might not be fully tested.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is wrong. I use the value of loserWind instead of winnerWind. Good catch.

As an aside, this one is weird where I have to pass 0 in the riichi value because of the unique splitting rules :/
The code previously would always return 0, too, because you compared winnerWind with winnerWind. The code for the original dealin_delta was:
if (playerWind != winnerWind && playerWind != loserWind) return 0;

Copy link
Contributor

@0spooky 0spooky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget to put in constants where we spoke about.


// Check to see if you have to count basic points
if (points < 5) {
if (points == 1 && (fu == 20 || fu == 25)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So will this be removed or augmented with 2p25f? In between makes no sense

@@ -43,7 +55,21 @@ export const Constants = {
SELF_DRAW: "selfdraw",
NO_WIN: "nowin",
RESTART: "restart",
MISTAKE: "fuckup"
MISTAKE: "fuckup",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might conflict now

@@ -790,7 +791,7 @@ function save_game_to_database(hands_array) {
if (Number(Session.get("west_score")) >= Number(Session.get("north_score"))) position--;
Players.update({_id: west_id}, {$inc: {japanesePositionSum: position}});

switch (position) {
switch (position) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's generally a lot of ruined indentation in this patch. Please fix. (Tabs for indentation, spaces for alignment)

@@ -1188,36 +1195,37 @@ function push_split_pao_hand(template) {
Session.set("north_riichi_sum", Number(Session.get("north_riichi_sum")) + 1);
}

var value = dealin_delta(points, fu, winnerWind, winnerWind);
var value = PointCalculationUtils.jpn.dealin_delta(points, fu, winnerWind, loserWind, 0)[winnerWind];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's worth creating another PointCalculationUtils function for Pao situations.

@0spooky
Copy link
Contributor

0spooky commented Oct 15, 2017

Can you rebase so I can review this again?

@0spooky2me
Copy link
Collaborator

Now a duplicate of #64

@0spooky2me 0spooky2me closed this Sep 26, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants