Skip to content

Instantly share code, notes, and snippets.

@alexkalderimis
Created January 31, 2018 02:28
Show Gist options
  • Save alexkalderimis/a01697173fabe8606aa5c17ac572b9d7 to your computer and use it in GitHub Desktop.
Save alexkalderimis/a01697173fabe8606aa5c17ac572b9d7 to your computer and use it in GitHub Desktop.
JS Bin // source http://jsbin.com/xamokot
<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>
/* 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