From 80947b5499a36b41713eade2b68999cda3f40d50 Mon Sep 17 00:00:00 2001 From: Gale Harrington Date: Tue, 14 Nov 2017 14:29:45 -0800 Subject: [PATCH 1/7] npm install --- package-lock.json | 123 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..80043d7 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,123 @@ +{ + "name": "js-scrabble", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "add-matchers": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/add-matchers/-/add-matchers-0.5.0.tgz", + "integrity": "sha1-UCGQ5HUM1XIWGDkyaLYaFXNm52U=" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "eslint-plugin-jasmine": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jasmine/-/eslint-plugin-jasmine-2.9.1.tgz", + "integrity": "sha1-IuGaWfFvOl9kOgSroEQ40OMEcDA=" + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "jasmine": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz", + "integrity": "sha1-awicChFXax8W3xG4AUbZHU6Lij4=", + "requires": { + "exit": "0.1.2", + "glob": "7.1.2", + "jasmine-core": "2.8.0" + } + }, + "jasmine-core": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", + "integrity": "sha1-vMl5rh+f0FcB5F5S5l06XWPxok4=" + }, + "jasmine-expect": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/jasmine-expect/-/jasmine-expect-3.8.1.tgz", + "integrity": "sha512-klARdR5AVX9nZhHhYDlbDYgxgi6kl9DGS0vguhaioKoSwr8HL1uOQ7FFUBASq/sqBL/s2nkh/1efqZ2ugcknFA==", + "requires": { + "add-matchers": "0.5.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "1.1.8" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1.0.2" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } +} From 07277e00002a0021ead298602cbef3ef0009fa51 Mon Sep 17 00:00:00 2001 From: Gale Harrington Date: Tue, 14 Nov 2017 15:07:11 -0800 Subject: [PATCH 2/7] Pass basic scoring tests --- scrabble.js | 13 +++++++++---- spec/scrabble_spec.js | 26 +++++++++++++------------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/scrabble.js b/scrabble.js index 7a1f161..384c607 100644 --- a/scrabble.js +++ b/scrabble.js @@ -1,11 +1,16 @@ const Scrabble = { score: function(word) { - // TODO: implement score + let score = 0; + const LETTER_TO_VALUE = { + 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, + }; + word.split('').forEach( function (letter) { + score += parseInt(LETTER_TO_VALUE[letter.toUpperCase()]); + }); + return score; } - // TODO: add the highestScoreFrom method - -}; +} Scrabble.Player = class { // TODO: implement the Player class diff --git a/spec/scrabble_spec.js b/spec/scrabble_spec.js index c195a03..d41de1b 100644 --- a/spec/scrabble_spec.js +++ b/spec/scrabble_spec.js @@ -11,32 +11,32 @@ describe('score', function() { expect(Scrabble.score('pig')).toBe(6); }); - it ('adds 50 points for a 7-letter word', function() { + xit ('adds 50 points for a 7-letter word', function() { expect(Scrabble.score('academy')).toBe(65); }); - it ('throws on bad characters', function() { + xit ('throws on bad characters', function() { expect(function () { Scrabble.score('char^'); }).toThrow(); }); - it ('handles all upper- and lower-case letters', function() { + xit ('handles all upper- and lower-case letters', function() { expect(Scrabble.score('dog')).toBe(5); expect(Scrabble.score('DOG')).toBe(5); expect(Scrabble.score('DoG')).toBe(5); }); - it ('does not allow words > 7 letters', function() { + xit ('does not allow words > 7 letters', function() { expect(function() { Scrabble.score('abcdefgh'); }).toThrow(); }); - it ('does not allow empty words', function() { + xit ('does not allow empty words', function() { expect(function() { Scrabble.score(''); }).toThrow(); }); }); -describe('highestScoreFrom', function() { +xdescribe('highestScoreFrom', function() { it ('is defined', function() { expect(Scrabble.highestScoreFrom).toBeDefined(); }); @@ -97,12 +97,12 @@ describe('highestScoreFrom', function() { }); }); -describe('Player', function() { +xdescribe('Player', function() { it ('is defined', function() { expect(Scrabble.Player).toBeDefined(); }); - describe('Constructor', function() { + xdescribe('Constructor', function() { it('Creates a new player', function() { let name = 'test name'; let player = new Scrabble.Player(name); @@ -114,7 +114,7 @@ describe('Player', function() { }); }); - describe ('play', function() { + xdescribe ('play', function() { it ('Records the played word', function() { let word = 'dog'; let player = new Scrabble.Player('test player'); @@ -148,7 +148,7 @@ describe('Player', function() { }); }); - describe ('totalScore', function() { + xdescribe ('totalScore', function() { it ('Is zero if the player has not played anything', function() { let player = new Scrabble.Player('test player'); expect(player.totalScore()).toBe(0); @@ -166,7 +166,7 @@ describe('Player', function() { }); }); - describe('hasWon', function() { + xdescribe('hasWon', function() { it('returns false when score < 100', function() { let player = new Scrabble.Player('test player'); expect(player.totalScore()).toBe(0); @@ -196,7 +196,7 @@ describe('Player', function() { }); }); - describe('highestScoringWord', function() { + xdescribe('highestScoringWord', function() { // Tie-breaking logic is already described in the tests // for highestWordFrom, so we will not repeat it here. it('returns the highest scoring word played', function() { @@ -212,7 +212,7 @@ describe('Player', function() { }); }); - describe('highestWordScore', function() { + xdescribe('highestWordScore', function() { it('returns the score of the highest scoring word played', function() { let player = new Scrabble.Player('test player'); player.play('cat'); From d2e530a3c775768e3ca1e408f75d3aca75ca5aba Mon Sep 17 00:00:00 2001 From: Gale Harrington Date: Tue, 14 Nov 2017 15:40:04 -0800 Subject: [PATCH 3/7] Pass all scoring tests --- scrabble.js | 19 ++++++++++++++++++- spec/scrabble_spec.js | 11 ++++++----- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/scrabble.js b/scrabble.js index 384c607..4cc9896 100644 --- a/scrabble.js +++ b/scrabble.js @@ -1,12 +1,29 @@ +/*eslint-disable*/ const Scrabble = { + score: function(word) { let score = 0; const LETTER_TO_VALUE = { 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, }; + const ALPHA = /[a-zA-Z]/ + function ArgumentError(message) { + this.message = message; + this.name = 'ArgumentError'; + } + if (word.length > 7 || word.length < 1) { + throw new ArgumentError('Invalid word length detected'); + } word.split('').forEach( function (letter) { - score += parseInt(LETTER_TO_VALUE[letter.toUpperCase()]); + if (letter.match(ALPHA)) { + score += parseInt(LETTER_TO_VALUE[letter.toUpperCase()]); + } else { + throw new ArgumentError('Invalid characters detected'); + } }); + if (word.length === 7) { + score += 50; + } return score; } // TODO: add the highestScoreFrom method diff --git a/spec/scrabble_spec.js b/spec/scrabble_spec.js index d41de1b..60b6fb4 100644 --- a/spec/scrabble_spec.js +++ b/spec/scrabble_spec.js @@ -1,3 +1,4 @@ +/*eslint-disable*/ const Scrabble = require('../scrabble'); describe('score', function() { @@ -11,27 +12,27 @@ describe('score', function() { expect(Scrabble.score('pig')).toBe(6); }); - xit ('adds 50 points for a 7-letter word', function() { + it ('adds 50 points for a 7-letter word', function() { expect(Scrabble.score('academy')).toBe(65); }); - xit ('throws on bad characters', function() { + it ('throws on bad characters', function() { expect(function () { Scrabble.score('char^'); }).toThrow(); }); - xit ('handles all upper- and lower-case letters', function() { + it ('handles all upper- and lower-case letters', function() { expect(Scrabble.score('dog')).toBe(5); expect(Scrabble.score('DOG')).toBe(5); expect(Scrabble.score('DoG')).toBe(5); }); - xit ('does not allow words > 7 letters', function() { + it ('does not allow words > 7 letters', function() { expect(function() { Scrabble.score('abcdefgh'); }).toThrow(); }); - xit ('does not allow empty words', function() { + it ('does not allow empty words', function() { expect(function() { Scrabble.score(''); }).toThrow(); }); }); From 8c23ffa1cbc302b3471bc1c1a54ed34cd40fb063 Mon Sep 17 00:00:00 2001 From: Gale Harrington Date: Tue, 14 Nov 2017 15:47:17 -0800 Subject: [PATCH 4/7] Fix style issues per airbnb --- scrabble.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/scrabble.js b/scrabble.js index 4cc9896..96ebe50 100644 --- a/scrabble.js +++ b/scrabble.js @@ -4,7 +4,10 @@ const Scrabble = { score: function(word) { let score = 0; const LETTER_TO_VALUE = { - 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, + 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, }; const ALPHA = /[a-zA-Z]/ function ArgumentError(message) { @@ -16,7 +19,7 @@ const Scrabble = { } word.split('').forEach( function (letter) { if (letter.match(ALPHA)) { - score += parseInt(LETTER_TO_VALUE[letter.toUpperCase()]); + score += parseInt(LETTER_TO_VALUE[letter.toUpperCase()], 10); } else { throw new ArgumentError('Invalid characters detected'); } @@ -27,7 +30,7 @@ const Scrabble = { return score; } // TODO: add the highestScoreFrom method -} +}; Scrabble.Player = class { // TODO: implement the Player class From a3dde92a03a349e8a74ebe6b49e0dd05d41364fd Mon Sep 17 00:00:00 2001 From: Gale Harrington Date: Tue, 14 Nov 2017 16:27:57 -0800 Subject: [PATCH 5/7] Pass all highestScoreFrom tests --- scrabble.js | 30 +++++++++++++++++++++++++++++- spec/scrabble_spec.js | 2 +- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/scrabble.js b/scrabble.js index 96ebe50..00b7f2e 100644 --- a/scrabble.js +++ b/scrabble.js @@ -29,7 +29,35 @@ const Scrabble = { } return score; } - // TODO: add the highestScoreFrom method +, + highestScoreFrom: function(array) { + if (array.length === 0 || Array.isArray(array) != true) { + throw new ArgumentError('Requires at least one word'); + } else if (array.length === 1) { + return array[0]; + } else { + if (Scrabble.score(array[0]) > Scrabble.score(array[1])) { + return array[0]; + } else if (Scrabble.score(array[0]) < Scrabble.score(array[1])) { + return array[1]; + } else { + if (array[0].length === 7) { + return array[0]; + } else if (array[1].length === 7) { + return array[1]; + } else { + if (array[0].length < array[1].length) { + return array[0]; + } else if (array[0].length > array[1].length) { + return array[1]; + } else { + return array[0]; + } + } + } + } + + } }; Scrabble.Player = class { diff --git a/spec/scrabble_spec.js b/spec/scrabble_spec.js index 60b6fb4..5da7af4 100644 --- a/spec/scrabble_spec.js +++ b/spec/scrabble_spec.js @@ -37,7 +37,7 @@ describe('score', function() { }); }); -xdescribe('highestScoreFrom', function() { +describe('highestScoreFrom', function() { it ('is defined', function() { expect(Scrabble.highestScoreFrom).toBeDefined(); }); From f97ea130c1083fa8ebf32d1ec5de957b3422d539 Mon Sep 17 00:00:00 2001 From: Gale Harrington Date: Wed, 15 Nov 2017 10:57:53 -0800 Subject: [PATCH 6/7] Refactor score method to shorten check for 7 letter word --- scrabble.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/scrabble.js b/scrabble.js index 00b7f2e..22894b9 100644 --- a/scrabble.js +++ b/scrabble.js @@ -2,7 +2,7 @@ const Scrabble = { score: function(word) { - let score = 0; + let score = word.length === 7 ? 50 : 0; const LETTER_TO_VALUE = { 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, @@ -17,16 +17,13 @@ const Scrabble = { if (word.length > 7 || word.length < 1) { throw new ArgumentError('Invalid word length detected'); } - word.split('').forEach( function (letter) { + word.split('').forEach( (letter) => { if (letter.match(ALPHA)) { score += parseInt(LETTER_TO_VALUE[letter.toUpperCase()], 10); } else { throw new ArgumentError('Invalid characters detected'); } }); - if (word.length === 7) { - score += 50; - } return score; } , From 4d7ea1cf29262c1ed450766a792fac8eabc29404 Mon Sep 17 00:00:00 2001 From: Gale Harrington Date: Fri, 17 Nov 2017 07:43:27 -0800 Subject: [PATCH 7/7] Fix some style problems --- scrabble.js | 94 +++++++++++++++++++++++++++++++------------ spec/scrabble_spec.js | 14 +++---- 2 files changed, 75 insertions(+), 33 deletions(-) diff --git a/scrabble.js b/scrabble.js index 22894b9..cb05f99 100644 --- a/scrabble.js +++ b/scrabble.js @@ -1,7 +1,7 @@ -/*eslint-disable*/ + const Scrabble = { - score: function(word) { + score: function (word) { let score = word.length === 7 ? 50 : 0; const LETTER_TO_VALUE = { A: 1, E: 1, I: 1, O: 1, U: 1, L: 1, N: 1, @@ -9,7 +9,7 @@ const Scrabble = { M: 3, P: 3, F: 4, H: 4, V: 4, W: 4, Y: 4, K: 5, J: 8, X: 8, Q: 10, Z: 10, }; - const ALPHA = /[a-zA-Z]/ + const ALPHA = /[a-zA-Z]/; function ArgumentError(message) { this.message = message; this.name = 'ArgumentError'; @@ -17,7 +17,7 @@ const Scrabble = { if (word.length > 7 || word.length < 1) { throw new ArgumentError('Invalid word length detected'); } - word.split('').forEach( (letter) => { + word.split('').forEach((letter) => { if (letter.match(ALPHA)) { score += parseInt(LETTER_TO_VALUE[letter.toUpperCase()], 10); } else { @@ -25,40 +25,82 @@ const Scrabble = { } }); return score; - } -, - highestScoreFrom: function(array) { - if (array.length === 0 || Array.isArray(array) != true) { - throw new ArgumentError('Requires at least one word'); - } else if (array.length === 1) { + }, + highestScoreFrom: function (array) { + if (Array.isArray(array) !== true || array.length === 0) { + throw new Error('Requires at least one word'); + } + if (array.length === 1) { + return array[0]; + } + if (Scrabble.score(array[0]) > Scrabble.score(array[1])) { return array[0]; - } else { - if (Scrabble.score(array[0]) > Scrabble.score(array[1])) { + } else if (Scrabble.score(array[0]) < Scrabble.score(array[1])) { + return array[1]; + } else if (Scrabble.score(array[0]) === Scrabble.score(array[1])) { + if (array[0].length === 7) { return array[0]; - } else if (Scrabble.score(array[0]) < Scrabble.score(array[1])) { + } else if (array[1].length === 7) { return array[1]; } else { - if (array[0].length === 7) { + if (array[0].length < array[1].length) { return array[0]; - } else if (array[1].length === 7) { + } else if (array[0].length > array[1].length) { return array[1]; - } else { - if (array[0].length < array[1].length) { - return array[0]; - } else if (array[0].length > array[1].length) { - return array[1]; - } else { - return array[0]; - } } + return array[0]; } } - - } + }, }; Scrabble.Player = class { - // TODO: implement the Player class + constructor(name) { + if (typeof name !== 'string') { + throw new Error('Must provide player name as a string'); + } + this.name = name; + this.plays = []; + } + play(word) { + if (this.hasWon()) { + return false; + } + Scrabble.score(word); + this.plays.push(word); + return true; + } + totalScore() { + const total = + this.plays.reduce(function(total, word) { + return total + Scrabble.score(word); + }, 0); + return total; + } + hasWon() { + if (this.totalScore() < 100) { + return false; + } + return true; + } + highestWordScore() { + if (this.plays.length === 0) { + throw new Error('Requires at least one played word'); + } + const scores = + this.plays.map(word => Scrabble.score(word)); + return Math.max(...scores); + } + highestScoringWord() { + const highest = this.highestWordScore(); + let returningWord = null; + this.plays.forEach((word) => { + if (Scrabble.score(word) === highest) { + returningWord = word; + } + }); + return returningWord; + } }; module.exports = Scrabble; diff --git a/spec/scrabble_spec.js b/spec/scrabble_spec.js index 5da7af4..78a5a60 100644 --- a/spec/scrabble_spec.js +++ b/spec/scrabble_spec.js @@ -98,12 +98,12 @@ describe('highestScoreFrom', function() { }); }); -xdescribe('Player', function() { +describe('Player', function() { it ('is defined', function() { expect(Scrabble.Player).toBeDefined(); }); - xdescribe('Constructor', function() { + describe('Constructor', function() { it('Creates a new player', function() { let name = 'test name'; let player = new Scrabble.Player(name); @@ -115,7 +115,7 @@ xdescribe('Player', function() { }); }); - xdescribe ('play', function() { + describe ('play', function() { it ('Records the played word', function() { let word = 'dog'; let player = new Scrabble.Player('test player'); @@ -149,7 +149,7 @@ xdescribe('Player', function() { }); }); - xdescribe ('totalScore', function() { + describe ('totalScore', function() { it ('Is zero if the player has not played anything', function() { let player = new Scrabble.Player('test player'); expect(player.totalScore()).toBe(0); @@ -167,7 +167,7 @@ xdescribe('Player', function() { }); }); - xdescribe('hasWon', function() { + describe('hasWon', function() { it('returns false when score < 100', function() { let player = new Scrabble.Player('test player'); expect(player.totalScore()).toBe(0); @@ -197,7 +197,7 @@ xdescribe('Player', function() { }); }); - xdescribe('highestScoringWord', function() { + describe('highestScoringWord', function() { // Tie-breaking logic is already described in the tests // for highestWordFrom, so we will not repeat it here. it('returns the highest scoring word played', function() { @@ -213,7 +213,7 @@ xdescribe('Player', function() { }); }); - xdescribe('highestWordScore', function() { + describe('highestWordScore', function() { it('returns the score of the highest scoring word played', function() { let player = new Scrabble.Player('test player'); player.play('cat');