diff --git a/scrabble.js b/scrabble.js index e95f352..9320408 100644 --- a/scrabble.js +++ b/scrabble.js @@ -1,15 +1,154 @@ +const scoreTable = { + 'a': { 'points': 1, 'tiles': 9 }, + 'b': { 'points': 3, 'tiles': 2 }, + 'c': { 'points': 3, 'tiles': 2 }, + 'd': { 'points': 2, 'tiles': 4 }, + 'e': { 'points': 1, 'tiles': 12 }, + 'f': { 'points': 4, 'tiles': 2 }, + 'g': { 'points': 2, 'tiles': 3 }, + 'h': { 'points': 4, 'tiles': 2 }, + 'i': { 'points': 1, 'tiles': 9 }, + 'j': { 'points': 8, 'tiles': 1 }, + 'k': { 'points': 5, 'tiles': 1 }, + 'l': { 'points': 1, 'tiles': 4 }, + 'm': { 'points': 3, 'tiles': 2 }, + 'n': { 'points': 1, 'tiles': 6 }, + 'o': { 'points': 1, 'tiles': 8 }, + 'p': { 'points': 3, 'tiles': 2 }, + 'q': { 'points': 10, 'tiles': 1 }, + 'r': { 'points': 1, 'tiles': 6 }, + 's': { 'points': 1, 'tiles': 4 }, + 't': { 'points': 1, 'tiles': 6 }, + 'u': { 'points': 1, 'tiles': 4 }, + 'v': { 'points': 4, 'tiles': 2 }, + 'w': { 'points': 4, 'tiles': 2 }, + 'x': { 'points': 8, 'tiles': 1 }, + 'y': { 'points': 4, 'tiles': 2 }, + 'z': { 'points': 10, 'tiles': 1 }, + 'blank': { 'tiles': 2} +} + + +const findPoints = function findPoints(letter) { + let lowercase_letter = letter.toLowerCase(); + let points = scoreTable[lowercase_letter]['points']; + + return points; +} + +const checkWord = function permissableWord(word) { + let pattern = /[^a-zA-Z]/; + + if (word === '') { + throw "Word cannot be empty"; + } else if (pattern.test(word)) { + throw "Must be a real word"; + } else if (word.length > 7) { + throw "More than 7 letters not allowed"; + } +} + +const checkArrayOfWords = function checkArrayofWords(arrayOfWords) { + if (arrayOfWords.length === 0) { + throw "List of words cannot be empty"; + } +} + +// const highestScoreTieBreaker = function highestScoreTieBreaker(maxWord, word) { +// if (maxWord.length != 7 && word.length == 7) { +// maxWord = word +// } +// +// if (maxWord.length != 7 && word.length != 7 && maxWord.length > word.length) { +// maxWord = word; +// } +// } const Scrabble = { score(word) { + checkWord(word); + let score = 0; + if (word.length === 7) { + score += 50; + } + for (let i = 0; i < word.length; i++) { + let points = findPoints(word[i]); + score += points; + } + return score; }, + highestScoreFrom(arrayOfWords) { + checkArrayOfWords(arrayOfWords); + + let maxWord = null; + let maxPoints = null; + + arrayOfWords.forEach(function (word) { + let score = Scrabble.score(word); + + + if (maxPoints === score) { + + // highestScoreTieBreaker(maxWord, word); + + if (maxWord.length != 7 && word.length == 7) { + maxWord = word + } + if (maxWord.length != 7 && word.length != 7 && maxWord.length > word.length) { + maxWord = word; + } + + } else if (maxPoints < score) { + maxWord = word; + maxPoints = score; + } + + }); + return maxWord; + } +} - }, -}; Scrabble.Player = class { + constructor(name, plays = []) { + if (name === undefined ) { + throw "Player must have a name" + } + + this.name = name; + this.plays = plays; + } + + play(word) { + checkWord(word); + return (this.hasWon() ? false : this.plays.push(word)); + } + + totalScore() { + let wordsPlayed = this.plays; + let total = 0; + wordsPlayed.forEach(function (word) { + total += Scrabble.score(word); + }) + return total; + } + + hasWon() { + let total = this.totalScore(); + return (total >= 100); + } + + highestScoringWord() { + let plays = this.plays; + return Scrabble.highestScoreFrom(plays); + } + highestWordScore() { + let word = this.highestScoringWord(); + return Scrabble.score(word); + } }; diff --git a/specs/scrabble.spec.js b/specs/scrabble.spec.js index b562037..afd416f 100644 --- a/specs/scrabble.spec.js +++ b/specs/scrabble.spec.js @@ -11,46 +11,46 @@ describe('score', () => { expect(Scrabble.score('pig')).toBe(6); }); - test.skip('adds 50 points for a 7-letter word', () => { + test('adds 50 points for a 7-letter word', () => { expect(Scrabble.score('academy')).toBe(65); }); - test.skip('throws on bad characters', () => { + test('throws on bad characters', () => { expect(() => { Scrabble.score('char^'); }).toThrow(); }); - test.skip('handles all upper- and lower-case letters', () => { + test('handles all upper- and lower-case letters', () => { expect(Scrabble.score('dog')).toBe(5); expect(Scrabble.score('DOG')).toBe(5); expect(Scrabble.score('DoG')).toBe(5); }); - test.skip('does not allow words > 7 letters', () => { + test('does not allow words > 7 letters', () => { expect(() => { Scrabble.score('abcdefgh'); }).toThrow(); }); - test.skip('does not allow empty words', () => { + test('does not allow empty words', () => { expect(() => { Scrabble.score(''); }).toThrow(); }); }); describe('highestScoreFrom', () => { - test.skip('is defined', () => { + test('is defined', () => { expect(Scrabble.highestScoreFrom).toBeDefined(); }); - test.skip('throws if no words were passed', () => { + test('throws if no words were passed', () => { expect(() => { Scrabble.highestScoreFrom([]); }).toThrow(); expect(() => { Scrabble.highestScoreFrom('not array'); }).toThrow(); }); - test.skip('returns the only word in a length-1 array', () => { + test('returns the only word in a length-1 array', () => { expect(Scrabble.highestScoreFrom(['dog'])).toBe('dog'); }); - test.skip('returns the highest word if there are two words', () => { + test('returns the highest word if there are two words', () => { // Check score assumptions expect(Scrabble.score('dog')).toBe(5); expect(Scrabble.score('pig')).toBe(6); @@ -60,7 +60,7 @@ describe('highestScoreFrom', () => { expect(Scrabble.highestScoreFrom(['pig', 'dog'])).toBe('pig'); }); - test.skip('if tied, prefer a word with 7 letters', () => { + test('if tied, prefer a word with 7 letters', () => { const loser = 'zzzzzz'; const winner = 'iiiiddd'; @@ -73,7 +73,7 @@ describe('highestScoreFrom', () => { expect(Scrabble.highestScoreFrom([winner, loser])).toBe(winner); }); - test.skip('if tied and no word has 7 letters, prefers the word with fewer letters', () => { + test('if tied and no word has 7 letters, prefers the word with fewer letters', () => { // Check score assumptions expect(Scrabble.score('dog')).toBe(5); expect(Scrabble.score('goat')).toBe(5); @@ -83,7 +83,7 @@ describe('highestScoreFrom', () => { expect(Scrabble.highestScoreFrom(['goat', 'dog'])).toBe('dog'); }); - test.skip('returns the first word of a tie with same letter count', () => { + test('returns the first word of a tie with same letter count', () => { // Check score assumptions expect(Scrabble.score('i')).toBe(1); expect(Scrabble.score('dog')).toBe(5); @@ -98,19 +98,19 @@ describe('highestScoreFrom', () => { }); describe('Player', () => { - test.skip('is defined', () => { + test('is defined', () => { expect(Scrabble.Player).toBeDefined(); }); describe('Constructor', () => { - test.skip('Creates a new player', () => { + test('Creates a new player', () => { const name = 'test name'; const player = new Scrabble.Player(name); expect(player.name).toBe(name); }); - test.skip('Requires a name', () => { + test('Requires a name', () => { expect(() => { new Scrabble.Player(); }).toThrow(); @@ -118,7 +118,7 @@ describe('Player', () => { }); describe('play', () => { - test.skip('Records the played word', () => { + test('Records the played word', () => { const word = 'dog'; const player = new Scrabble.Player('test player'); @@ -130,7 +130,7 @@ describe('Player', () => { expect(player.plays[0]).toBe(word); }); - test.skip('Requires a real word', () => { + test('Requires a real word', () => { const player = new Scrabble.Player('test player'); expect(player.plays.length).toBe(0); @@ -142,7 +142,7 @@ describe('Player', () => { expect(player.plays.length).toBe(0); }); - test.skip('Returns false and does not update plays if the player has already won', () => { + test('Returns false and does not update plays if the player has already won', () => { const player = new Scrabble.Player('test player'); expect(player.play('zzzzzzz')).toBeTruthy(); // +120 pts @@ -155,13 +155,13 @@ describe('Player', () => { }); describe('totalScore', () => { - test.skip('Is zero if the player has not played anything', () => { + test('Is zero if the player has not played anything', () => { const player = new Scrabble.Player('test player'); expect(player.totalScore()).toBe(0); }); - test.skip('Is updated by play', () => { + test('Is updated by play', () => { // Arrange const player = new Scrabble.Player('test player'); const words = [{word: 'dog', score: 5}, {word: 'cat', score: 5}, {word: 'goat', score: 5}]; @@ -181,45 +181,71 @@ describe('Player', () => { }); describe('hasWon', () => { - test.skip('returns false when score < 100', () => { - + test('returns false when score < 100', () => { + const player = new Scrabble.Player('test player'); + expect(player.play('zzz')).toBeTruthy(); + expect(player.plays.length).toBe(1); + expect(player.hasWon()).toBe(false); }); - test.skip('returns true when score == 100', () => { - + test('returns true when score == 100', () => { + const player = new Scrabble.Player('test player'); + expect(player.play('zzzzz')).toBeTruthy(); + expect(player.play('zzzzz')).toBeTruthy(); + expect(player.plays.length).toBe(2); + expect(player.hasWon()).toBe(true); }); - test.skip('returns true when score > 100', () => { - + test('returns true when score > 100', () => { + const player = new Scrabble.Player('test player'); + expect(player.play('zzzzzzz')).toBeTruthy(); // +120 pts + expect(player.plays.length).toBe(1); + expect(player.hasWon()).toBe(true); }); }); describe('highestScoringWord', () => { // Tie-breaking logic is already described in the tests // for highestWordFrom, so we will not repeat it here. - test.skip('returns the highest scoring word played', () => { - + test('returns the highest scoring word played', () => { + const player = new Scrabble.Player('test player'); + expect(player.play('dog')).toBeTruthy(); + expect(player.play('zzzzz')).toBeTruthy(); + expect(player.plays.length).toBe(2); + expect(player.highestScoringWord()).toBe('zzzzz'); }); - test.skip('throws an error if no words have been played', () => { - + test('throws an error if no words have been played', () => { + const player = new Scrabble.Player('test player'); + expect(player.plays.length).toBe(0); + expect(() => { + player.highestScoringWord(); + }).toThrow(); }); }); describe('highestWordScore', () => { - test.skip('returns the score of the highest scoring word played', () => { - + test('returns the score of the highest scoring word played', () => { + const player = new Scrabble.Player('test player'); + expect(player.play('dog')).toBeTruthy(); + expect(player.play('zzzzz')).toBeTruthy(); + expect(player.plays.length).toBe(2); + expect(player.highestWordScore()).toBe(50); }); - test.skip('throws an error if no words have been played', () => { - + test('throws an error if no words have been played', () => { + const player = new Scrabble.Player('test player'); + expect(player.plays.length).toBe(0); + expect(() => { + player.highestWordScore(); + }).toThrow(); }); }); });