implement model for rounds
This commit is contained in:
parent
b9ded8c367
commit
41823cd8ad
135
models/round.js
Normal file
135
models/round.js
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
/** A specific team.
|
||||||
|
* @enum {number}
|
||||||
|
*/
|
||||||
|
export const Team = Object.freeze({
|
||||||
|
/** The "we" team, from the perspective of the score keeper. */
|
||||||
|
We: 1,
|
||||||
|
/** The "they" team, from the perspective of the score keeper. */
|
||||||
|
They: 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
/** A single round of watten.
|
||||||
|
*
|
||||||
|
* A game consists of multiple rounds, for each of which points can be won.
|
||||||
|
* Rounds are mostly independet from each other. The only bleedover is how
|
||||||
|
* often each team can raise the points available.
|
||||||
|
*
|
||||||
|
* This class is specifically meant to represent the current round, and is not
|
||||||
|
* ideal for storing past results.
|
||||||
|
*
|
||||||
|
* This project is not concerned with creating an online version of the game,
|
||||||
|
* the aim is to create a convenient score keeping system. Therefore this class
|
||||||
|
* only implements the raising mechanics, and no actual game play.
|
||||||
|
*/
|
||||||
|
export class Round {
|
||||||
|
/** The maximum the "we" team may raise to. */
|
||||||
|
#weLimit = 11;
|
||||||
|
/** The maximum the "they" team may raise to. */
|
||||||
|
#theyLimit = 11;
|
||||||
|
|
||||||
|
constructor(weLimit, theyLimit) {
|
||||||
|
if (weLimit !== undefined && weLimit !== null) {
|
||||||
|
if (typeof weLimit !== "number")
|
||||||
|
throw new TypeError("if specified, `weLimit` must be a number");
|
||||||
|
if (weLimit < this.#points)
|
||||||
|
throw new RangeError("`weLimit` must be larger than default points");
|
||||||
|
this.#weLimit = weLimit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (theyLimit !== undefined && theyLimit !== null) {
|
||||||
|
if (typeof theyLimit !== "number")
|
||||||
|
throw new TypeError("if specified, `theyLimit` must be a number");
|
||||||
|
if (theyLimit < this.#points)
|
||||||
|
throw new RangeError("`theyLimit` must be larger than default points");
|
||||||
|
this.#theyLimit = theyLimit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** How many points the game is worth. */
|
||||||
|
#points = 2;
|
||||||
|
|
||||||
|
/** Get how many points the current game is worth. */
|
||||||
|
get points() {
|
||||||
|
return this.#points;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Which team raised last.
|
||||||
|
* @type {?Team}
|
||||||
|
*/
|
||||||
|
#raisedLast = null;
|
||||||
|
|
||||||
|
/** Who won the round.
|
||||||
|
* @type {?Team}
|
||||||
|
*/
|
||||||
|
#winner = null;
|
||||||
|
|
||||||
|
/** Get the winner of the round.
|
||||||
|
*
|
||||||
|
* @returns {?Team} The winning team, or `null` if the round is not yet
|
||||||
|
* decided.
|
||||||
|
*/
|
||||||
|
get winner() {
|
||||||
|
return this.#winner;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Check whether the round has been decided. */
|
||||||
|
get decided() {
|
||||||
|
return this.#winner !== null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A team has won the round.
|
||||||
|
*
|
||||||
|
* @param {Team} team The team that won the round.
|
||||||
|
*/
|
||||||
|
won(team) {
|
||||||
|
if (team !== Team.We && team !== Team.They)
|
||||||
|
throw new TypeError("only actual teams can win");
|
||||||
|
if (this.decided)
|
||||||
|
throw new Error("decided round cannot be won again");
|
||||||
|
|
||||||
|
this.#winner = team;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Check whether a team can raise.
|
||||||
|
*
|
||||||
|
* Note that this only checks if the team can raise. It does not check
|
||||||
|
* whether the team may raise.
|
||||||
|
*
|
||||||
|
* @param {Team} team The team to check for.
|
||||||
|
* @returns {boolean} Whether the team can raise.
|
||||||
|
*/
|
||||||
|
canRaise(team) {
|
||||||
|
if (team !== Team.We && team !== Team.They)
|
||||||
|
throw new TypeError("only actual teams can raise");
|
||||||
|
return !this.decided && this.#raisedLast !== team;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** A team raises the points.
|
||||||
|
*
|
||||||
|
* Does nothing if the team cannot raise. Ends the round if a team raises
|
||||||
|
* that may not do so. Raises the points otherwise.
|
||||||
|
*
|
||||||
|
* @param {Team} team The team that wishes to raise.
|
||||||
|
*/
|
||||||
|
raise(team) {
|
||||||
|
if (team !== Team.We && team !== Team.They)
|
||||||
|
throw new TypeError("only actual teams can raise");
|
||||||
|
|
||||||
|
if (!this.canRaise(team)) return;
|
||||||
|
|
||||||
|
if (team === Team.We && this.points >= this.#weLimit) {
|
||||||
|
this.#winner = Team.They;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (team === Team.They && this.points >= this.#theyLimit) {
|
||||||
|
this.#winner = Team.We;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#raisedLast = team;
|
||||||
|
this.#points += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
95
models/round.test.js
Normal file
95
models/round.test.js
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
import { Round, Team } from "./round.js";
|
||||||
|
|
||||||
|
QUnit.module("models", function() {
|
||||||
|
QUnit.module("round", function() {
|
||||||
|
QUnit.test("setup", function(assert) {
|
||||||
|
let round = new Round();
|
||||||
|
assert.strictEqual(round.points, 2, "initial points");
|
||||||
|
assert.strictEqual(round.winner, null, "no initial winner");
|
||||||
|
assert.false(round.decided, "initially undecided");
|
||||||
|
assert.true(round.canRaise(Team.We), "we initially can raise");
|
||||||
|
assert.true(round.canRaise(Team.They), "they initially can raise");
|
||||||
|
});
|
||||||
|
|
||||||
|
QUnit.test("immediate victory", function(assert) {
|
||||||
|
let round = new Round();
|
||||||
|
round.won(Team.We);
|
||||||
|
assert.strictEqual(round.points, 2, "initial points");
|
||||||
|
assert.true(round.decided, "there is a winner");
|
||||||
|
assert.strictEqual(round.winner, Team.We, "correct winner");
|
||||||
|
assert.false(round.canRaise(Team.We), "cannot raise finished game");
|
||||||
|
assert.false(round.canRaise(Team.They), "cannot raise finished game");
|
||||||
|
});
|
||||||
|
|
||||||
|
QUnit.test("multiple victories", function(assert) {
|
||||||
|
let round = new Round();
|
||||||
|
round.won(Team.They);
|
||||||
|
assert.throws(function() {
|
||||||
|
round.won(Team.We);
|
||||||
|
}, "victory cannot be stolen");
|
||||||
|
});
|
||||||
|
|
||||||
|
QUnit.test("single raise", function(assert) {
|
||||||
|
let round = new Round();
|
||||||
|
round.raise(Team.We);
|
||||||
|
assert.strictEqual(round.points, 3, "raised points");
|
||||||
|
assert.false(round.canRaise(Team.We), "raising team cannot raise");
|
||||||
|
assert.true(round.canRaise(Team.They), "other team can raise");
|
||||||
|
});
|
||||||
|
|
||||||
|
QUnit.test("double raise", function(assert) {
|
||||||
|
let round = new Round();
|
||||||
|
round.raise(Team.We);
|
||||||
|
round.raise(Team.They);
|
||||||
|
assert.strictEqual(round.points, 4, "raised points");
|
||||||
|
assert.true(round.canRaise(Team.We), "first raiser can raise");
|
||||||
|
assert.false(round.canRaise(Team.They), "second raiser cannot raise");
|
||||||
|
});
|
||||||
|
|
||||||
|
QUnit.test("raise to eleven and above", function(assert) {
|
||||||
|
let round = new Round();
|
||||||
|
round.raise(Team.We); // 3
|
||||||
|
round.raise(Team.They); // 4
|
||||||
|
round.raise(Team.We); // 5
|
||||||
|
round.raise(Team.They); // 6
|
||||||
|
round.raise(Team.We); // 7
|
||||||
|
round.raise(Team.They); // 8
|
||||||
|
round.raise(Team.We); // 9
|
||||||
|
|
||||||
|
round.raise(Team.They); // 10
|
||||||
|
assert.strictEqual(round.points, 10, "points before limit are reached");
|
||||||
|
assert.false(round.decided, "round is not decided before limit");
|
||||||
|
|
||||||
|
round.raise(Team.We); // 11
|
||||||
|
assert.strictEqual(round.points, 11, "points limit is reached");
|
||||||
|
assert.false(round.decided, "round is not decidid at limit");
|
||||||
|
|
||||||
|
round.raise(Team.They); // 12
|
||||||
|
assert.strictEqual(round.points, 11, "no invalid raise");
|
||||||
|
assert.true(round.decided, "round is decided");
|
||||||
|
assert.strictEqual(round.winner, Team.We, "we team won");
|
||||||
|
assert.false(round.canRaise(Team.We), "winner cannot raise");
|
||||||
|
assert.false(round.canRaise(Team.They), "looser cannot raise");
|
||||||
|
});
|
||||||
|
|
||||||
|
QUnit.test("raise to lower limit and above", function(assert) {
|
||||||
|
let round = new Round(3, 4);
|
||||||
|
round.raise(Team.We); // 3
|
||||||
|
assert.strictEqual(round.points, 3, "our points limit is reached");
|
||||||
|
assert.false(round.decided, "round is not decidid at our limit");
|
||||||
|
|
||||||
|
round.raise(Team.They); // 4
|
||||||
|
assert.strictEqual(round.points, 4, "their points limit is reached");
|
||||||
|
assert.false(round.decided, "round is not decidid at their limit");
|
||||||
|
|
||||||
|
round.raise(Team.We); // 5
|
||||||
|
assert.strictEqual(round.points, 4, "no invalid raise");
|
||||||
|
assert.true(round.decided, "round is decided");
|
||||||
|
assert.strictEqual(round.winner, Team.They, "they team won");
|
||||||
|
assert.false(round.canRaise(Team.We), "looser cannot raise");
|
||||||
|
assert.false(round.canRaise(Team.They), "winner cannot raise");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -11,6 +11,7 @@
|
|||||||
<div id="qunit"></div>
|
<div id="qunit"></div>
|
||||||
<div id="qunit-fixture"></div>
|
<div id="qunit-fixture"></div>
|
||||||
<script src="vendored/qunit-2.25.0.js"></script>
|
<script src="vendored/qunit-2.25.0.js"></script>
|
||||||
|
<script src="models/round.test.js" type="module"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
Loading…
Reference in New Issue
Block a user