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=" + } + } +} diff --git a/scrabble.js b/scrabble.js index 7a1f161..1bc8435 100644 --- a/scrabble.js +++ b/scrabble.js @@ -1,14 +1,128 @@ +const LETTER_VALUES = { + 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 UserException = function userException(message) { + this.message = message; + this.name = 'UserException'; +}; + const Scrabble = { - score: function(word) { - // TODO: implement score - } - // TODO: add the highestScoreFrom method + score: function score(word) { + if (word.length > 7) { + throw new UserException('Words longer than 7 letters are not allowed.'); + } else if (!(/^[a-zA-Z]+$/.test(word))) { + throw new UserException('You must provide a valid word.'); + } else { + let points = 0; + word.split('').forEach((char) => { + points += LETTER_VALUES[`${char.toLowerCase()}`]; + }); + if (word.length === 7) { + points += 50; + } + return points; + } + }, + tie: function tie(word, maxWord) { + if (((word.length === 7) && (maxWord.length !== 7)) || ((word.length < maxWord.length) && (maxWord.length !== 7))) { + maxWord = word; + } + return maxWord; + }, + + highestScoreFrom: function highestScoreFrom(words) { + let maxScore = 0; + let maxWord = ''; + if (words.length === 0) { + throw new UserException('You must provide words to score.'); + } else { + words.forEach((word) => { + if (this.score(word) === maxScore) { + maxWord = this.tie(word, maxWord); + maxScore = this.score(maxWord); + } else if (this.score(word) > maxScore) { + maxScore = this.score(word); + maxWord = word; + } + }); + return maxWord; + } + }, }; Scrabble.Player = class { - // TODO: implement the Player class + constructor(name) { + if (name === undefined) { + throw new UserException('You must provide a name'); + } + this.name = name; + this.plays = []; + } + + play(word) { + if (word === undefined || !(/^[a-zA-Z]+$/.test(word))) { + throw new UserException('You must provide a word'); + } else if (this.hasWon()) { + return false; + } else { + this.plays.push(word); + return true; + } + } + + hasWon() { + if (this.totalScore() >= 100) { + return true; + } else { + return false; + } + } + + totalScore() { + let result = 0; + this.plays.forEach((word) => { + result += Scrabble.score(word); + }); + return result; + } + + highestScoringWord() { + let highestWord = Scrabble.highestScoreFrom(this.plays); + return highestWord; + } + + highestWordScore() { + let highestWordScore = Scrabble.score(this.highestScoringWord()); + return highestWordScore; + } }; module.exports = Scrabble;