Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kiera - jsscrabble - Octos #28

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
138 changes: 138 additions & 0 deletions scrabble.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,152 @@
const SCORECHART = {
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 REGEX = /[A-Z]/

const Scrabble = {
score(word) {
let wordUp = word.toUpperCase()
let wordSplits = wordUp.split('');

let totalScore = 0;
if (wordSplits.length > 7 || wordSplits.length === 0) {
throw 'Invalid word';
}

if (wordSplits.length === 7) {
totalScore += 50;
}

wordSplits.forEach(function(letter) {
if (REGEX.test(letter)) {
totalScore += SCORECHART[letter];
} else {
throw 'Not a valid word';
}

});

return totalScore
},

highestScoreFrom(arrayOfWords) {
if (arrayOfWords.length === 0) {
throw 'Unable to calculate highest score without any words.';
}
if (Array.isArray(arrayOfWords) !== true) {
throw 'Unable to calculate highest score without an array of words';
}
if (arrayOfWords.length === 1){
return arrayOfWords[0];
} else {
let word_score = {};
arrayOfWords.forEach(function(word) {
word_score[word] = Scrabble.score(word);

Choose a reason for hiding this comment

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

I like the way you're storing the scores in an object so you don't need to recalculate the scores each time

});

let highest_score = 0;
let winWord = null;
for(const word in word_score) {
if (word_score[word] > highest_score) {
highest_score = word_score[word];
winWord = word;
} if (word_score[word] === highest_score && winWord.length === 7) {

Choose a reason for hiding this comment

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

These conditionals are structured like you want them to be nested in the else ifs, but they're all independent conditions. Recommend switching to else if

return winWord;
} if (word_score[word] === highest_score && word.length === 7) {
return word;
} if (word_score[word] === highest_score && winWord.length < word.length) {
return winWord;
} if (word_score[word] === highest_score && winWord.length > word.length) {
return word;
}
} //for loop
return winWord;
}
},
};

Scrabble.Player = class {
constructor(name) {
this.name = name;
this.plays = [];
if (name === undefined) {
throw 'Player must have a name';
}
}

play(word) {
if (this.hasWon()){
return false;
} else {
if (word === undefined) {
throw 'Must play a word';
}
if (REGEX.test(word.toUpperCase)!== true){
throw 'Must play a real word';
}
this.plays.push(word);
}
return this.plays;

}

totalScore() {
let points = 0;
this.plays.forEach(function(word) {
let wScore = Scrabble.score(word);
points += wScore;
});
return points;
}

hasWon(){
if (this.totalScore() >= 100) {
return true;
} else {
return false;
}
}

highestScoringWord() {
if (this.plays.length === 0) {
throw 'Cannot calculate highest scoring word without a played word';
}
return Scrabble.highestScoreFrom(this.plays);
}

highestWordScore(){
if (this.plays.length === 0) {
throw 'Cannot calculate highest word score without a played word';
}
return Scrabble.score(this.highestScoringWord());

}

};

Expand Down
88 changes: 54 additions & 34 deletions specs/scrabble.spec.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const Scrabble = require('../scrabble');
const Scrabble = require('../scrabble');

describe('score', () => {
test('is defined', () => {
Expand All @@ -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);
Expand All @@ -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';

Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -98,27 +98,27 @@ 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();
});
});

describe('play', () => {
test.skip('Records the played word', () => {
test('Records the played word', () => {
const word = 'dog';
const player = new Scrabble.Player('test player');

Expand All @@ -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);
Expand All @@ -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
Expand All @@ -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}];
Expand All @@ -181,44 +181,64 @@ describe('Player', () => {
});

describe('hasWon', () => {
test.skip('returns false when score < 100', () => {

test('returns false when score < 100', () => {
const player = new Scrabble.Player('test player');
player.play('zzzzz')
player.totalScore();

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');
player.play('zzzzz')
player.play('zzzzz')
player.totalScore();

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');
player.play('zzzzzzz');
player.totalScore();

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');
player.play('zzz');
player.play('dog');

expect(player.highestScoringWord()).toBe('zzz');
expect(player.plays.length).toBe(2);
});

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.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');
player.play('zzz');
player.play('dog');

expect(player.highestWordScore()).toBe(30);
});

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.highestWordScore(); }).toThrow();

});
});
Expand Down