Skip to content
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
166 changes: 162 additions & 4 deletions src/adagrams.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,173 @@
const SIZE_OF_DRAW = 10;

Choose a reason for hiding this comment

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

I like having a value for this that we could change in just one place if we wanted to update it.

const LETTER_VALUES = {

Choose a reason for hiding this comment

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

Since LETTER_VALUES is only accessed by the scoreWord function, it would be reasonable to place the object inside the function rather than as a constant. There are tradeoffs, the structure would clutter the function some, but it keeps the data as close as possible to where it's being used, and would mean other functions couldn't access it to accidentally alter the contents.

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

const genPoolLetters = (poolRulesObj) => {

Choose a reason for hiding this comment

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

Nice helper to generate the letter distribution array to index into.

const myPool = [];
for (const letter in poolRulesObj) {
for (let i = 0; i < poolRulesObj[letter]; ++i) {
myPool.push(letter);
}
}
return myPool;
};

//Gets a random number excluding the maxNum
const getRandomNumber = (maxNum) => {
return Math.floor(Math.random() * maxNum);
};

export const drawLetters = () => {
// Implement this method for wave 1
const poolRules = {
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 draw = [];
const poolLetters = genPoolLetters(poolRules);

while (draw.length < SIZE_OF_DRAW) {
let randNum = getRandomNumber(poolLetters.length);
draw.push(poolLetters[randNum]);
poolLetters.splice(randNum, 1);
}
return draw;
Comment on lines +75 to +83

Choose a reason for hiding this comment

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

I love how nicely laid out this is and how easy it is to read with the helper functions.

};

const createLettersInHandDict = (lettersInHandArray) => {
const lettersDict = {};
for (let i = 0; i < lettersInHandArray.length; ++i) {
let char = lettersInHandArray[i];
if (lettersDict[char] === undefined) {
lettersDict[char] = 1;
} else {
lettersDict[char]++;
}
}
return lettersDict;
};

export const usesAvailableLetters = (input, lettersInHand) => {
// Implement this method for wave 2
if (!input || lettersInHand === []) {
return false;
}
const letterBank = createLettersInHandDict(lettersInHand);

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 =]

input = input.toUpperCase();
for (let i = 0; i < input.length; ++i) {
let letter = input[i];
if (letterBank[letter] == undefined) {
return false;
}
if (letterBank[letter] == 0) {

Choose a reason for hiding this comment

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

In javascript we should use === to make a strict comparison against value and type. This article gets into more of the distinctions between == and === which might be helpful: https://www.scaler.com/topics/javascript/difference-between-double-equals-and-triple-equals-in-javascript/

return false;
}
Comment on lines +107 to +112

Choose a reason for hiding this comment

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

If the line doesn't get too long, I suggest combining these into one if-statement so we can have one false return.

letterBank[letter]--;
}
return true;
};

export const scoreWord = (word) => {
// Implement this method for wave 3
if (!word) {
return 0;
}
let points = 0;
word = word.toUpperCase();
for (let i = 0; i < word.length; ++i) {

Choose a reason for hiding this comment

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

If we won't be reassigning the loop variable in the body of a loop, I recommend using const over let to declare the variable.

let letter = word[i];
if (LETTER_VALUES[letter] != undefined) {
// If its undefined means letter is a special character
points += LETTER_VALUES[letter];
}
}
Comment on lines +124 to +130

Choose a reason for hiding this comment

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

We could simplify this loop a little with a for...of loop:

for (const letter of word) {
    if (LETTER_VALUES[letter] != undefined) {
        // If its undefined means letter is a special character
        points += LETTER_VALUES[letter];
    }
}


if (word.length >= 7 && word.length <= SIZE_OF_DRAW) {
points += 8;
}
return points;
};

export const highestScoreFrom = (words) => {
// Implement this method for wave 4
if (!words) {
return {};
}

let maxScore = 0;
const wordScores = {}; //will store all the highscored words
words.forEach((word) => {
let score = scoreWord(word);
if (score > maxScore) {
maxScore = score;
wordScores[score] = new Array({ score, word });
} else if (score === maxScore) {
wordScores[score].push({ score, word });
}
});

const maxScoreWords = wordScores[maxScore];
let winWord = maxScoreWords[0];
if (maxScoreWords.length > 1) {
let minLen = winWord["word"].length;
for (let i = 0; i < maxScoreWords.length; ++i) {
let word = maxScoreWords[i]["word"];
if (word.length === SIZE_OF_DRAW) {
winWord = maxScoreWords[i];
break;
}
if (word.length < minLen) {
minLen = word.length;
winWord = maxScoreWords[i];
}
}
}

return winWord;
};
8 changes: 5 additions & 3 deletions test/adagrams.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,9 @@ describe("Adagrams", () => {
});

it("returns a score of 0 if given an empty input", () => {
throw "Complete test";
expectScores({
"": 0,
});
});

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

describe.skip("highestScoreFrom", () => {
describe("highestScoreFrom", () => {
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 +147,7 @@ describe("Adagrams", () => {
const words = ["XXX", "XXXX", "X", "XX"];
const correct = { word: "XXXX", score: scoreWord("XXXX") };

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

describe("in case of tied score", () => {
Expand Down
Loading