Created
January 31, 2018 02:28
-
-
Save alexkalderimis/a01697173fabe8606aa5c17ac572b9d7 to your computer and use it in GitHub Desktop.
JS Bin // source http://jsbin.com/xamokot
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.7.3/immutable.min.js"></script> | |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width"> | |
<title>JS Bin</title> | |
</head> | |
<body> | |
<script id="jsbin-javascript"> | |
/* jshint esnext: true, laxbreak: true */ | |
/** | |
* All Tests Pass: Week 2 | |
* Provide a class that calculates the total score of a bowling game. | |
* | |
* Class should expose at least two methods, score() and clear(). Score | |
* should accept an arbitrary number of integers representing individual | |
* throws. | |
* | |
* Class should also expose the property totalScore, which shows the current | |
* score for the game. This implementation is calculated via a get accessor method, | |
* but you can choose to re-implement as you wish. | |
* | |
* Reference: | |
* https://en.wikipedia.org/wiki/Ten-pin_bowling#Traditional_scoring | |
*/ | |
function sum(nums) { return nums.reduce((a, b) => a + b, 0); } | |
class BowlingScoreTracker { | |
constructor() { | |
this._balls = []; | |
} | |
score(...balls) { | |
this._balls.push.apply(this._balls, balls); | |
} | |
clear() { | |
this._balls = []; | |
} | |
get totalScore () { | |
return sum(this.frames.map(frame => frame.score())); | |
} | |
// process the array of balls, returning the game as an array of frames. | |
get frames () { | |
const root = new Frame(); | |
this._balls.reduce((current, ball) => current.addBall(ball), root); | |
return Array.from(root).slice(0, 10); | |
} | |
} | |
class Frame { | |
constructor() { | |
this.balls = []; | |
this.pins = 0; | |
this.next = null; | |
} | |
// frame is complete when all 10 pins are knocked down, or both throws have been taken | |
get isComplete () { | |
return this.balls.length >= 2 || this.pins >= 10; | |
} | |
// strike: next 2 balls | |
// spare: " 1 balls | |
// otherwise: none | |
get bonuses () { | |
return (this.pins === 10) ? (this.balls.length === 1 ? 2 : 1) : 0; | |
} | |
get bonusPins () { | |
const required = this.bonuses; | |
let got = []; | |
let frame = this.next; | |
while (frame && got.length < required) { | |
got = got.concat(frame.balls.slice(0, required - got.length)); | |
frame = frame.next; | |
} | |
return sum(got); | |
} | |
addBall(ball) { | |
let scoring = this.isComplete ? this.next = new Frame() : this; | |
scoring.balls.push(ball); | |
scoring.pins += ball; // pins is cached to avoid recalculation. | |
return scoring; | |
} | |
// the score for a frame is the the number of pins, and any bonuses | |
score() { | |
return this.pins + this.bonusPins; | |
} | |
// apply a reduction to the frameset | |
reduce(f, zero) { | |
let fx = f(zero, this); | |
return this.next == null ? fx : this.next.reduce(f, fx); | |
} | |
[Symbol.iterator]() { | |
let current = this; | |
return { | |
next: () => { | |
const ret = {value: current, done: current == null}; | |
current = current && current.next; | |
return ret; | |
} | |
}; | |
} | |
} | |
// Don't edit anything below this line. | |
let tracker = new BowlingScoreTracker(); | |
assertEqual(tracker.totalScore, 0, "Starts at 0"); | |
// All 1's | |
tracker.score(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); | |
assertEqual(tracker.totalScore, 20, "All ones equals 20"); | |
tracker.clear(); | |
// All 5's (spares) | |
tracker.score(5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5); | |
assertEqual(tracker.totalScore, 150, "An all spare game equals 150"); | |
tracker.clear(); | |
// All Strikes | |
tracker.score(10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10); | |
assertEqual(tracker.totalScore, 300, "Perfect game equals 300"); | |
console.log("All clear 🎉"); | |
function assertEqual(got, expected, output) { | |
try { | |
if (got !== expected) { | |
throw `${output} (expecting "${expected}", got "${got}")` | |
} | |
} catch (e) { | |
throw `${output} (expecting "${expected}", got "${got}")` | |
} | |
} | |
</script> | |
<script id="jsbin-source-javascript" type="text/javascript">/* jshint esnext: true, laxbreak: true */ | |
/** | |
* All Tests Pass: Week 2 | |
* Provide a class that calculates the total score of a bowling game. | |
* | |
* Class should expose at least two methods, score() and clear(). Score | |
* should accept an arbitrary number of integers representing individual | |
* throws. | |
* | |
* Class should also expose the property totalScore, which shows the current | |
* score for the game. This implementation is calculated via a get accessor method, | |
* but you can choose to re-implement as you wish. | |
* | |
* Reference: | |
* https://en.wikipedia.org/wiki/Ten-pin_bowling#Traditional_scoring | |
*/ | |
function sum(nums) { return nums.reduce((a, b) => a + b, 0); } | |
class BowlingScoreTracker { | |
constructor() { | |
this._balls = []; | |
} | |
score(...balls) { | |
this._balls.push.apply(this._balls, balls); | |
} | |
clear() { | |
this._balls = []; | |
} | |
get totalScore () { | |
return sum(this.frames.map(frame => frame.score())); | |
} | |
// process the array of balls, returning the game as an array of frames. | |
get frames () { | |
const root = new Frame(); | |
this._balls.reduce((current, ball) => current.addBall(ball), root); | |
return Array.from(root).slice(0, 10); | |
} | |
} | |
class Frame { | |
constructor() { | |
this.balls = []; | |
this.pins = 0; | |
this.next = null; | |
} | |
// frame is complete when all 10 pins are knocked down, or both throws have been taken | |
get isComplete () { | |
return this.balls.length >= 2 || this.pins >= 10; | |
} | |
// strike: next 2 balls | |
// spare: " 1 balls | |
// otherwise: none | |
get bonuses () { | |
return (this.pins === 10) ? (this.balls.length === 1 ? 2 : 1) : 0; | |
} | |
get bonusPins () { | |
const required = this.bonuses; | |
let got = []; | |
let frame = this.next; | |
while (frame && got.length < required) { | |
got = got.concat(frame.balls.slice(0, required - got.length)); | |
frame = frame.next; | |
} | |
return sum(got); | |
} | |
addBall(ball) { | |
let scoring = this.isComplete ? this.next = new Frame() : this; | |
scoring.balls.push(ball); | |
scoring.pins += ball; // pins is cached to avoid recalculation. | |
return scoring; | |
} | |
// the score for a frame is the the number of pins, and any bonuses | |
score() { | |
return this.pins + this.bonusPins; | |
} | |
// apply a reduction to the frameset | |
reduce(f, zero) { | |
let fx = f(zero, this); | |
return this.next == null ? fx : this.next.reduce(f, fx); | |
} | |
[Symbol.iterator]() { | |
let current = this; | |
return { | |
next: () => { | |
const ret = {value: current, done: current == null}; | |
current = current && current.next; | |
return ret; | |
} | |
}; | |
} | |
} | |
// Don't edit anything below this line. | |
let tracker = new BowlingScoreTracker(); | |
assertEqual(tracker.totalScore, 0, "Starts at 0"); | |
// All 1's | |
tracker.score(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); | |
assertEqual(tracker.totalScore, 20, "All ones equals 20"); | |
tracker.clear(); | |
// All 5's (spares) | |
tracker.score(5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5); | |
assertEqual(tracker.totalScore, 150, "An all spare game equals 150"); | |
tracker.clear(); | |
// All Strikes | |
tracker.score(10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10); | |
assertEqual(tracker.totalScore, 300, "Perfect game equals 300"); | |
console.log("All clear 🎉"); | |
function assertEqual(got, expected, output) { | |
try { | |
if (got !== expected) { | |
throw `${output} (expecting "${expected}", got "${got}")` | |
} | |
} catch (e) { | |
throw `${output} (expecting "${expected}", got "${got}")` | |
} | |
} | |
</script></body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* jshint esnext: true, laxbreak: true */ | |
/** | |
* All Tests Pass: Week 2 | |
* Provide a class that calculates the total score of a bowling game. | |
* | |
* Class should expose at least two methods, score() and clear(). Score | |
* should accept an arbitrary number of integers representing individual | |
* throws. | |
* | |
* Class should also expose the property totalScore, which shows the current | |
* score for the game. This implementation is calculated via a get accessor method, | |
* but you can choose to re-implement as you wish. | |
* | |
* Reference: | |
* https://en.wikipedia.org/wiki/Ten-pin_bowling#Traditional_scoring | |
*/ | |
function sum(nums) { return nums.reduce((a, b) => a + b, 0); } | |
class BowlingScoreTracker { | |
constructor() { | |
this._balls = []; | |
} | |
score(...balls) { | |
this._balls.push.apply(this._balls, balls); | |
} | |
clear() { | |
this._balls = []; | |
} | |
get totalScore () { | |
return sum(this.frames.map(frame => frame.score())); | |
} | |
// process the array of balls, returning the game as an array of frames. | |
get frames () { | |
const root = new Frame(); | |
this._balls.reduce((current, ball) => current.addBall(ball), root); | |
return Array.from(root).slice(0, 10); | |
} | |
} | |
class Frame { | |
constructor() { | |
this.balls = []; | |
this.pins = 0; | |
this.next = null; | |
} | |
// frame is complete when all 10 pins are knocked down, or both throws have been taken | |
get isComplete () { | |
return this.balls.length >= 2 || this.pins >= 10; | |
} | |
// strike: next 2 balls | |
// spare: " 1 balls | |
// otherwise: none | |
get bonuses () { | |
return (this.pins === 10) ? (this.balls.length === 1 ? 2 : 1) : 0; | |
} | |
get bonusPins () { | |
const required = this.bonuses; | |
let got = []; | |
let frame = this.next; | |
while (frame && got.length < required) { | |
got = got.concat(frame.balls.slice(0, required - got.length)); | |
frame = frame.next; | |
} | |
return sum(got); | |
} | |
addBall(ball) { | |
let scoring = this.isComplete ? this.next = new Frame() : this; | |
scoring.balls.push(ball); | |
scoring.pins += ball; // pins is cached to avoid recalculation. | |
return scoring; | |
} | |
// the score for a frame is the the number of pins, and any bonuses | |
score() { | |
return this.pins + this.bonusPins; | |
} | |
// apply a reduction to the frameset | |
reduce(f, zero) { | |
let fx = f(zero, this); | |
return this.next == null ? fx : this.next.reduce(f, fx); | |
} | |
[Symbol.iterator]() { | |
let current = this; | |
return { | |
next: () => { | |
const ret = {value: current, done: current == null}; | |
current = current && current.next; | |
return ret; | |
} | |
}; | |
} | |
} | |
// Don't edit anything below this line. | |
let tracker = new BowlingScoreTracker(); | |
assertEqual(tracker.totalScore, 0, "Starts at 0"); | |
// All 1's | |
tracker.score(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); | |
assertEqual(tracker.totalScore, 20, "All ones equals 20"); | |
tracker.clear(); | |
// All 5's (spares) | |
tracker.score(5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5); | |
assertEqual(tracker.totalScore, 150, "An all spare game equals 150"); | |
tracker.clear(); | |
// All Strikes | |
tracker.score(10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10); | |
assertEqual(tracker.totalScore, 300, "Perfect game equals 300"); | |
console.log("All clear 🎉"); | |
function assertEqual(got, expected, output) { | |
try { | |
if (got !== expected) { | |
throw `${output} (expecting "${expected}", got "${got}")` | |
} | |
} catch (e) { | |
throw `${output} (expecting "${expected}", got "${got}")` | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment