-
Notifications
You must be signed in to change notification settings - Fork 44
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
C22 Phoenix -- Beenish Ali #25
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good overall! Please review my comments, and let me know if you have any questions.
throw "Complete test"; | ||
expectScores({ | ||
'': 0 | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing semicolon
});
let totalWeight=0; | ||
for (const weight of WEIGHTS) { | ||
totalWeight += weight; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👀 Avoid running code in global scope.
const letterFreq = {}; | ||
|
||
while( i < HAND_SIZE){ | ||
const randomLetter = weightedRandomLetter() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This calculation is an improvement over your Python version (which didn't reflect the weights in how the letters get picked). However, notice that weightedRandomLetter
does not adjust to the lower likelihood of picking a particular letter once it has been picked. In the extreme, once all the available copies of a letter have been picked, there should be a 0% chance of picking it going forward. This is not the same thing as excluding the letter if it gets picked again. Rather, its chance of it being picked would need to be distributed throughout the remaining tiles to match the expected behavior of picking tiles from a pile.
This (albeit minor, but still real) discrepency, along with the fact that we still do need to allocate additional memory to ensure that we don't use more copied of a letter than should be available, point towards an approach that truly builds the pile of tiles (a list with as many copies of a letter as there should be tiles) as the method that will most closely provide the probabilities we want, and does so in a predictable number of iterations.
Alternatively, we could decrement the weights of a tiles as they are picked, but this still would require iterating through the letters for each letter, resulting in O(m * n) where m is the size of the hand and n is the number of letters. By contrast, there is a pool-based approach that would be only O(m + n). Of course, for the size of the inputs, these aren't major considerations, but they're still worth considering.
let i=0; | ||
const letterFreq = {}; | ||
|
||
while( i < HAND_SIZE){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than tracking a separate variable i
which we must update independently, we could make this condition dependent on the actual result we're building.
while (drawnLetters.length < HAND_SIZE) {
Nit: Leave a space between the while
and its condition, and between the end of the condition and the block brace.
if (letterFreq[randomLetter] <= LETTER_POOL[randomLetter]){ | ||
drawnLetters.push(randomLetter); | ||
i++ | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While unlikely, we could end up picking the same letter over and over, to the point that this loop never completes. We would prefer an approach that will predictably pick a letter every iteration.
if (word.length >= MIN_LEN_FOR_BONUS){ | ||
score += BONUS_POINTS; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great job incorporating named constants instead of using magic numbers. This is much more self-documenting.
if (possibleWinners.length === 1) { | ||
; | ||
} else { | ||
winner = tieBreaker(possibleWinners); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Restructure this to avoid the empty block. Empty blocks are not a typical pattern we'll see in JS.
if (possibleWinners.length !== 1) {
winner = tieBreaker(possibleWinners);
}
|
||
const possibleWinners = []; | ||
|
||
for (const [word, score] of wordAndScores) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JS Maps do preserve the insertion order of keys. In practice, we don't see Maps used that often unless the keys need to be something that isn't a string. Since Maps require the use of the set
and get
methods, they're a frequent source of bugs (since developers prefer to use []
).
}; | ||
|
||
const getPossibleWinners = (words) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice helper to get a collection of all the highest score words.
I might restructure into separate steps that
- builds a Map of all the words to their scores (removing the need to run
scoreWord
multiple times for the same word) - Finds the max score
- builds a filtered list of the words that have the max score
We could return this as a two value list, the list of words tied, and the score they have. Something like
[tiedWordList, highestScore]
Elsewhere, I'd break any tie in the filtered word list, which doesn't depend on the score. Then we don't need to build the final return value until the very end of the function.
return possibleWinners; | ||
} | ||
|
||
const tieBreaker = possibleWinners => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Breaking the ties depends only on the words themselves. Consider restructuring this to receive only a list os words (no score info) and leaving it to the caller to build the necessary retrun value.
No description provided.