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

Allow customized ranking statistics and sorting #68

Merged
merged 5 commits into from
Oct 7, 2018

Conversation

0spooky2me
Copy link
Collaborator

Possible implementation of #15

Implemented dropdown menus for choosing a stat to sort by and compare against any other stat
Moved some calculations out of UI code and into API code
Slightly improved test code, but it can be removed

Copy link

@amrocha amrocha left a comment

Choose a reason for hiding this comment

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

I don't think this will break anything, left a bunch of comments regarding readability but up to you if you want to fix them

I didn't do a manual test or anything though

@@ -18,7 +18,13 @@ export default {
return standardizePlayerStatistics(format, Players.findOne(criteria));
},

getPlayers(format, sort) {
/**
Copy link

Choose a reason for hiding this comment

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

wow nice automated docs

return formatPlayer;
}

let gamesPlayed = player[format + "GamesPlayed"];
Copy link

Choose a reason for hiding this comment

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

This works but I bet you could really simplify it with a more suited data structure here. I'm not super familiar with the code base so I can't tell you the optimal solution, but off the top of my head I think that the following structure would lead to more readable and resilient code:

{
  japanese: {
    ...
  },
  hongKong: {
    ...
  ,
}

Resilient because string manipulation like this is prone to breaking during refactors, and since we're not using any typing here JS is gonna fail this silently and we might not notice.

Copy link

Choose a reason for hiding this comment

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

I do think this is better than before though

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I agree with this, I was thinking of making this change. Should I do that in this PR?

Copy link

Choose a reason for hiding this comment

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

follow-up PR is fine, this is pretty big already

<select name="sortStatistic" class="sortStatisticSelect">
<option disabled selected>Sort by: ELO</option>
<option value="elo">ELO</option>
{{ #each statistic in (getRankingStatistics format sortRankingExclusion) }}
Copy link

Choose a reason for hiding this comment

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

oh my god I hate that this line is even allowed to work

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Welcome to Meteor.js

<th class="players">Player</th>
<th class="sortStat">
<select name="sortStatistic" class="sortStatisticSelect">
<option disabled selected>Sort by: ELO</option>
Copy link

Choose a reason for hiding this comment

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

Why disabled? Why are there two ELO options actually?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I couldn't think of a good UX solution to indicate that the sortStatistic column is where sorting comes from. How do you indicate that changing this option will re-sort?

Copy link

Choose a reason for hiding this comment

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

oh huh, idk it seems pretty intuitive to me but if it's not obvious enough this is fine, maybe change the wording to Sort by ... or something

{value: "averageHandSize", format: "Avg Hand Size"},
{value: "averagePosition", format: "Avg Position"},
{value: "flyRate", format: "Bankrupt %"},
{value: "chomboTotal", format: "Chombos"}
Copy link

Choose a reason for hiding this comment

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

kinda confusing that statisticsList[0].format is the format for the stat, but format is the type of game

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That's fair.

{value: "riichiRate", format: "Riichi %"},
{value: "riichiWinRate", format: "Riichi Win %"}
];
statisticsList = statisticsList.concat(japaneseStatisticsList);
Copy link

Choose a reason for hiding this comment

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

Can simplify this as

statisticsList = [
  {value: "averageHandDora", format: "Avg Hand Dora"},
  {value: "riichiRate", format: "Riichi %"},
  {value: "riichiWinRate", format: "Riichi Win %"},
  ...statisticsList,
];

Copy link

Choose a reason for hiding this comment

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

Or even

statisticsList = format === Constants.GAME_TYPE.JAPANESE ? [
  {value: "averageHandDora", format: "Avg Hand Dora"},
  {value: "riichiRate", format: "Riichi %"},
  {value: "riichiWinRate", format: "Riichi Win %"},
  ...statisticsList,
] : statisticsList;

but maybe this is too clever

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Your Javascript powers are too strong for me

statisticsList = statisticsList.concat(japaneseStatisticsList);
}

for (let stat of exclusions) {
Copy link

Choose a reason for hiding this comment

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

are you one of those people that use for loops in js? I thought you were better than this

Copy link

Choose a reason for hiding this comment

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

Anyway this can be simplified to

statisticsList.filter((statistic) => !excusions.includes(statistic));

Combined with the previous simplification this function becomes something like

function getRankingStatistics(format, exclusions) {
  let standardStatisticsList = [
    {value: "elo", format: "ELO"},
    {value: "gamesPlayed", format: "Games"},
    {value: "handWinRate", format: "Hand Win %"},
    {value: "dealinRate", format: "Deal-in %"},
    {value: "averageHandSize", format: "Avg Hand Size"},
    {value: "averagePosition", format: "Avg Position"},
    {value: "flyRate", format: "Bankrupt %"},
    {value: "chomboTotal", format: "Chombos"}
  ];
  const japaneseStatisticsList = [
    {value: "averageHandDora", format: "Avg Hand Dora"},
    {value: "riichiRate", format: "Riichi %"},
    {value: "riichiWinRate", format: "Riichi Win %"}
  ];

  return [...standardStatisticsList, japaneseStatisticsList].filter(
    (statistic) => (
      !exclusions.find((exclusion) => exclusion.value === statistic.value) && 
      (japaneseStatisticsList.includes(statistic) && format === Constants.GAME_TYPE.JAPANESE)
    );
}

I think it reads easier, up to you though

did not test this code btw make sure I didn't fuck up somewhere if you use it

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I need time to process this comment. You're probably right though. I thought Javascript was all about that list comprehension though? Are for loops actually discouraged?

Copy link

Choose a reason for hiding this comment

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

Some people like for...each, but generally the React community tend to favor the functional approach with map etc. and I work with React everyday so I don't like for loops.

List comprehension might be a thing more recently, but generally the JIT compiler is so good now that performance is gonna be roughly the same no matter what you use

* Exclusion lists for statistics options. Allows for manual entries
* @returns a list of statistics to exclude
*/
sortRankingExclusion() {
Copy link

Choose a reason for hiding this comment

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

Are these the only places where exclusions can come from?

In that case I recommend having a list of possible statistics, and then picking items from it like so

const STATISTICS_LIST = [...];
additionalRankingExclusion() {
  return STATISTICS_LIST[2];
}

or something like this, it'll make the comparisons easier to read since you'll be able to just compare references to objects instead of the inner content of these objects. It's also more performant but that's whatever.

It's kind of a big change and this is fine though

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'm going to leave this for now.

* Event handler for modifying ranking sort statistic
* @param[in] event The event to handle
*/
'change select[name="sortStatistic"]'(event) {
Copy link

Choose a reason for hiding this comment

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

I have no idea what's going on here lmao

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Apparently this is the syntax
'change -> Detect a "change event"
select -> on an HTML select field
[name="sortStatistic"]' -> with the name "sortStatistic"
(event) -> capture the event

Copy link

Choose a reason for hiding this comment

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

I'm like, super confused how this is calling a function with a string name? Or I guess this is a function definition. JS is weird

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

JS is the worst

}
});

function getStatisticUnit(statistic) {
Copy link

Choose a reason for hiding this comment

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

can simplify this as

return ["handWinRate", "dealinRate", "flyRate", "riichiRate", "riichiWinRate"].includes(statistic) ? '%' : '';

@0spooky2me
Copy link
Collaborator Author

Addressed PR comments, please re-review @Mooters @amrocha

@0spooky 0spooky force-pushed the 15-allow-customized-sort-orders branch from 41a37dd to a321445 Compare October 5, 2018 19:28
@0spooky 0spooky force-pushed the 15-allow-customized-sort-orders branch from a321445 to 0b4cdf6 Compare October 5, 2018 19:31
Copy link

@amrocha amrocha left a comment

Choose a reason for hiding this comment

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

good stuff

@0spooky 0spooky temporarily deployed to mjc-league-app October 5, 2018 21:01 Inactive
@0spooky2me 0spooky2me merged commit 951ec1a into master Oct 7, 2018
@0spooky2me 0spooky2me deleted the 15-allow-customized-sort-orders branch October 7, 2018 07:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants