Skip to content

C22 Phenix Luqi Xie #33

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

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 115 additions & 4 deletions src/adagrams.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,126 @@
const LETTER_POOL = {
A: 9,
B: 2,
C: 2,
D: 4,
E: 12,
F: 2,
G: 3,
H: 2,
I: 9,
J: 1,
K: 1,
L: 4,
M: 2,
N: 6,
O: 8,
P: 2,
Q: 1,
R: 6,
S: 4,
T: 6,
U: 4,
V: 2,
W: 2,
X: 1,
Y: 2,
Z: 1,
};

const SCORE_CHART = {

Choose a reason for hiding this comment

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

The order of the letters aren't important to JS, but we can make it a little easier to double check that the scores are all present and accounted for if we wrote this in alphabetical order.

const SCORE_CHART = {
  A: 1,
  B: 3,
  C: 3,
  ...
};

A: 1,
E: 1,
I: 1,
O: 1,
U: 1,
L: 1,
N: 1,
R: 1,
S: 1,
T: 1,
D: 2,
G: 2,
B: 3,
C: 3,
M: 3,
P: 3,
F: 4,
H: 4,
V: 4,
W: 4,
Y: 4,
K: 5,
J: 8,
X: 8,
Q: 10,
Z: 10
};

export const drawLetters = () => {
// Implement this method for wave 1
const letterList = [];
for (const [letter, count] of Object.entries(LETTER_POOL)) {
for (let i = 0; i < count; i++) {
letterList.push(letter);
}
}
const drawLetters = [];
for (let i = 0; i < 10; i++) {
const letterIndex = Math.floor(Math.random() * letterList.length);
const lastPos = letterList.length - 1;
[letterList[letterIndex], letterList[lastPos]] = [letterList[lastPos], letterList[letterIndex]];
drawLetters.push(letterList.pop());
Comment on lines +70 to +71

Choose a reason for hiding this comment

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

Nice approach of swapping the picked letter to the end, which then allows us to pop in constant time. This makes the complexity dependent only upon the size of the hand.

}
return drawLetters;
};


export const usesAvailableLetters = (input, lettersInHand) => {
// Implement this method for wave 2
const letterFrequencyMap = {};
for (const letter of lettersInHand) {
if (letterFrequencyMap[letter]) {
letterFrequencyMap[letter] += 1;
} else {
letterFrequencyMap[letter] = 1;
}
}

for (const letter of input.toUpperCase()) {
if (!letterFrequencyMap[letter] || letterFrequencyMap[letter] === 0) {
return false;
} else {
letterFrequencyMap[letter] -= 1;

Choose a reason for hiding this comment

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

Even though JS doesn't use indentation to control the flow of logic, we should still make sure to follow good indentation practice to help with readability. So we'd want to indent this line.

}
}
Comment on lines +87 to +93

Choose a reason for hiding this comment

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

Nice use of a frequency map to check the validity of the owrd against th hand. We can build the map in a single iteration over the hand, then validate the word in a single iteration over the word, resulting in time complexity O(m + n), where m is the size of the hand and n is the size of the word.

return true;
};

export const scoreWord = (word) => {
// Implement this method for wave 3
let totalScore = 0;
for (const letter of word.toUpperCase()) {
totalScore += SCORE_CHART[letter];
}
Comment on lines +98 to +101

Choose a reason for hiding this comment

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

Great use of a score lookup table to keep this simple. We could also use Array.reduce to perform this summation.

  let totalScore = word.toUpperCase().split('').reduce((acc, letter) => acc + SCORE_CHART[letter], 0);

Personally, I find the loop approach you used more readable, but the reduce approach is also popular with JS programmers.

if (word.length >= 7 && word.length <= 10) {
totalScore += 8;
}
Comment on lines +102 to +104

Choose a reason for hiding this comment

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

Consider creating global constants to use instead of the magic numbers, to make this code more self-documenting.

const MIN_BONUS_LENGTH = 7;
const MAX_WORD_LENGTH = 10;
const LENGTH_BONUS = 8;

then

  if (word.length >= MIN_BONUS_LENGTH && word.length <= MAX_WORD_LENGTH) {
    totalScore += LENGTH_BONUS;
  }

return totalScore;
};

export const highestScoreFrom = (words) => {
// Implement this method for wave 4
let highestScore = 0;
let bestWord = "";

for (const word of words) {
const score = scoreWord(word);
if (score > highestScore) {
highestScore = score;
bestWord = word;
} else if (score === highestScore && bestWord.length !== 10) {

Choose a reason for hiding this comment

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

Each of the nested cases would only apply if the best word wasn't already of length 10, so moving that up to this condition helps simplify the nested conditions.

if (word.length === 10) {
bestWord = word;
} else if (word.length < bestWord.length) {
bestWord = word;
}
}
}
return { word: bestWord, score: highestScore };
};
10 changes: 7 additions & 3 deletions test/adagrams.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,10 @@ describe("Adagrams", () => {
});

it("returns a score of 0 if given an empty input", () => {
throw "Complete test";
// throw "Complete test";
expectScores({
"": 0,
});
Comment on lines +124 to +126

Choose a reason for hiding this comment

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

👍

});

it("adds an extra 8 points if word is 7 or more characters long", () => {
Expand All @@ -133,7 +136,7 @@ describe("Adagrams", () => {
});
});

describe.skip("highestScoreFrom", () => {
describe("highestScoreFrom", () => {

Choose a reason for hiding this comment

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

👍

it("returns a hash that contains the word and score of best word in an array", () => {
const words = ["X", "XX", "XXX", "XXXX"];
const correct = { word: "XXXX", score: scoreWord("XXXX") };
Expand All @@ -145,7 +148,8 @@ describe("Adagrams", () => {
const words = ["XXX", "XXXX", "X", "XX"];
const correct = { word: "XXXX", score: scoreWord("XXXX") };

throw "Complete test by adding an assertion";
// throw "Complete test by adding an assertion";
expect(highestScoreFrom(words)).toEqual(correct);

Choose a reason for hiding this comment

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

👍

});

describe("in case of tied score", () => {
Expand Down
2 changes: 1 addition & 1 deletion test/demo/model.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Model from 'demo/model';
import Adagrams from 'demo/adagrams';

describe.skip('Game Model', () => {
describe('Game Model', () => {
const config = {
players: [
'Player A',
Expand Down