diff --git a/.gitignore b/.gitignore index f6851a87..b331e578 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ node_modules package.json.lock .DS_Store -coverage \ No newline at end of file +coverage +.vscode/ +.gitignore \ No newline at end of file diff --git a/src/adagrams.js b/src/adagrams.js index 7ec5afc7..b88c7b27 100644 --- a/src/adagrams.js +++ b/src/adagrams.js @@ -1,15 +1,71 @@ +import { Alphabet } from "./modules/Alphabet.js"; +import { Score } from "./modules/Score.js"; + export const drawLetters = () => { - // Implement this method for wave 1 + // initialize player hand + let hand = []; + // initialize alphabet + let alphabet = new Alphabet(); + // draw 10 letters + for (let i = 0; i < 10; ++i) { + // get array of letters (keys) from alphabet object + const keys = Object.keys(alphabet.letterCounts); + // randomly pick one letter (key) + const letter = keys[Math.floor(Math.random() * keys.length)]; + // add letter to hand + hand.push(letter); + // letter value in alphabet object + alphabet.decreaseLetterCount(letter); + } + return hand; }; export const usesAvailableLetters = (input, lettersInHand) => { - // Implement this method for wave 2 + // convert input string to array + const inputArr = [...input.toUpperCase()]; + // make mutable copy of letters in hand + let handArr = [...lettersInHand]; + for (let i = 0; i < inputArr.length; i++) { + // collect letter + const letter = inputArr[i]; + // check if input letter is in hand + if (handArr.includes(letter)) { + // collect index of letter + const index = handArr.indexOf(letter); + // remove letter from copy of letters in hand - prevent duplication + handArr.splice(index, 1); + } else { + return false; + } + } + return true; }; export const scoreWord = (word) => { - // Implement this method for wave 3 + // check for word input + if (typeof word === "undefined") { + return 0; + } else { + return new Score().calculateWordScore(word); + } }; export const highestScoreFrom = (words) => { - // Implement this method for wave 4 + // initialize winning word object + const winningWord = { word: "", score: 0 }; + for (let word of words) { + // collect word score + const score = scoreWord(word); + // pick word with highest score + if (score > winningWord.score) { + winningWord.word = word; + winningWord.score = score; + } else if (score === winningWord.score) { + // pick word by tie breaker criteria + winningWord.word = Score.breakTie(winningWord.word, word); + } else { + continue; + } + } + return winningWord; }; diff --git a/src/modules/Alphabet.js b/src/modules/Alphabet.js new file mode 100644 index 00000000..c9c13ece --- /dev/null +++ b/src/modules/Alphabet.js @@ -0,0 +1,47 @@ +export class Alphabet { + constructor() { + this.letterCounts = { + 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, + }; + } + + decreaseLetterCount(letter) { + /** + * Decreases letter count by 1 for a given letter and updates letter in letterCounts. + * When letter count is 0, removes letter from letterCounts. + * @param {[string]} letter [letter to decrease] + */ + // decrease letter count by 1 for given letter + this.letterCounts[letter] -= 1; + // check if value is now zero + if (this.letterCounts[letter] === 0) { + // remove key from alphabet obj + delete this.letterCounts[letter]; + } + } +} diff --git a/src/modules/Hand.js b/src/modules/Hand.js new file mode 100644 index 00000000..aba6f15f --- /dev/null +++ b/src/modules/Hand.js @@ -0,0 +1,16 @@ +import { Alphabet } from "./Alphabet"; + +export class Hand extends Alphabet { + constructor(num) { + super(); + this.hand = this.drawLettersInAlphabet(num); + } + drawLettersInAlphabet(num) { + for (let i = 0; i < num; ++i) { + const letters = Object.keys(this.letterCounts); + const randomLetter = letters[Math.floor(Math.random() * letters.length)]; + this.hand.push(randomLetter); + this.letterCounts.decreaseLetterCount(randomLetter); + } + } +} diff --git a/src/modules/Score.js b/src/modules/Score.js new file mode 100644 index 00000000..c9573987 --- /dev/null +++ b/src/modules/Score.js @@ -0,0 +1,67 @@ +export class Score { + constructor() { + this.scoreChart = { + 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, + }; + } + calculateWordScore(word) { + // initialize word score + let wordScore = 0; + // convert word string to array + const wordArr = [...word.toUpperCase()]; + // check each letter in word + wordArr.forEach((letter) => { + // look up letter score in scoreChart + const letterScore = this.scoreChart[letter]; + // add to word score + wordScore += letterScore; + }); + if (word.length >= 7) { + wordScore += 8; + } + return wordScore; + } + static breakTie(word1, word2) { + /** + * Chooses between two words of equal score with the following criteria + * in order of priority: + * (1) word of length 10 + * (2) smallest length word + * (3) word1 if lengths equal + */ + // pick smallest word length + if (word1.length === 10) { + return word1; + } else if (word2.length < word1.length || word2.length === 10) { + return word2; + } else { + // return first word + return word1; + } + } +} diff --git a/test/adagrams.test.js b/test/adagrams.test.js index 1a0dc94e..fc35fcf9 100644 --- a/test/adagrams.test.js +++ b/test/adagrams.test.js @@ -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", () => { @@ -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") }; @@ -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", () => {