From 685359ebd92267c47a0874fd4714a370cf8d6274 Mon Sep 17 00:00:00 2001 From: Adrian Wannenmacher Date: Mon, 16 Feb 2026 23:10:51 +0100 Subject: [PATCH] switch game over to a general change event --- models/game.js | 13 ++++++++----- models/game.test.js | 36 ++++++++++++++++++++++++++++++++---- models/session.js | 20 +++++++++++--------- 3 files changed, 51 insertions(+), 18 deletions(-) diff --git a/models/game.js b/models/game.js index 4312ee1..c28bd53 100644 --- a/models/game.js +++ b/models/game.js @@ -15,8 +15,8 @@ import RoundResult from "./round_result.js"; * Note that game points are punitive, players want to avoid earning them. */ export default class Game extends EventTarget { - /** The event triggered when the game is finished. */ - static finishedEvent = "gameFinished"; + /** The event triggered when something about the game changes. */ + static get EVENT_CHANGE() { return "wb:game:change"; } /** The finished rounds. * @type {RoundResult[]} @@ -68,6 +68,11 @@ export default class Game extends EventTarget { } } + /** Check whether the game is finished. */ + get decided() { + return this.#currentRound === null; + } + /** Get the results of the game. */ get result() { let ourPoints = 0; @@ -136,12 +141,10 @@ export default class Game extends EventTarget { Math.max(this.#goal - result.theirPoints, 2)); this.#currentRound.addEventListener( Round.EVENT_CHANGE, this.#boundHandleRoundChange); - } else { - this.dispatchEvent(new CustomEvent(Game.finishedEvent)); } } - + this.dispatchEvent(new CustomEvent(Game.EVENT_CHANGE)); } /** #handleRoundChange, but bound to this instance. */ diff --git a/models/game.test.js b/models/game.test.js index ec19eda..311c3fb 100644 --- a/models/game.test.js +++ b/models/game.test.js @@ -58,6 +58,7 @@ export default function() { game.currentRound.winner = Team.We; assert.equal(game.rounds.length, 1, "one round played"); + assert.false(game.decided, "game is not decided"); assert.strictEqual(game.rounds[0].points, 2, "first round points"); assert.strictEqual(game.rounds[0].winner, Team.We, "first round winner"); assert.notStrictEqual(game.currentRound, null, "current round there"); @@ -81,6 +82,7 @@ export default function() { game.currentRound.winner = Team.They; assert.equal(game.rounds.length, 2, "two round played"); + assert.false(game.decided, "game is not decided"); assert.strictEqual(game.rounds[1].points, 3, "second round points"); assert.strictEqual( game.rounds[1].winner, Team.They, "second round winner"); @@ -110,6 +112,31 @@ export default function() { assert.equal(game.rounds.length, 7, "seven rounds played"); assert.strictEqual(game.currentRound, null, "no further rounds"); + assert.true(game.decided, "game is decided"); + assert.deepEqual( + game.result, + { + winner: Team.We, + points: 1, + ourPoints: 12, + theirPoints: 2, + }, + "final results", + ); + }); + + QUnit.test("regular victory after near tailor", function(assert) { + let game = new Game(); + game.currentRound.winner = Team.We; // 2 + game.currentRound.winner = Team.We; // 4 + game.currentRound.winner = Team.We; // 6 + game.currentRound.winner = Team.We; // 8 + game.currentRound.winner = Team.We; // 10 + game.currentRound.winner = Team.They; // 2 + game.currentRound.winner = Team.We; // 12 + + assert.equal(game.rounds.length, 7, "seven rounds played"); + assert.true(game.decided, "no further rounds"); assert.deepEqual( game.result, { @@ -193,13 +220,14 @@ export default function() { ); }); - QUnit.test("finished event", function(assert) { - let game = new Game(2); - game.addEventListener(Game.finishedEvent, function() { + QUnit.test("round change triggers event", function(assert) { + let game = new Game(3); + game.addEventListener(Game.EVENT_CHANGE, function() { assert.step("event"); }); + game.currentRound.raise(Team.We); game.currentRound.winner = Team.They; - assert.verifySteps(["event"], "event was triggered"); + assert.verifySteps(["event", "event"], "events were triggered"); }); QUnit.test("toStruct - unfinished", function(assert) { diff --git a/models/session.js b/models/session.js index 3ea485b..323f1fc 100644 --- a/models/session.js +++ b/models/session.js @@ -74,7 +74,7 @@ export default class Session { if (this.#currentGame === null) { this.#currentGame = new Game(this.goal); this.#currentGame.addEventListener( - Game.finishedEvent, this.#boundGameFinishedHandler); + Game.EVENT_CHANGE, this.#boundHandleGameChange); } } @@ -98,16 +98,18 @@ export default class Session { return { ourPoints, theirPoints }; } - /** Handle it when the current game is finished. */ - #gameFinishedHandler() { - this.#currentGame.removeEventListener( - Game.finishedEvent, this.#boundGameFinishedHandler); - this.#games.push(this.#currentGame); - this.#currentGame = null; + /** Handle changes to the current game. */ + #handleGameChange() { + if (this.#currentGame.decided) { + this.#currentGame.removeEventListener( + Game.EVENT_CHANGE, this.#boundHandleGameChange); + this.#games.push(this.#currentGame); + this.#currentGame = null; + } } - /** #gameFinishedHandler, but bound to this instance. */ - #boundGameFinishedHandler = this.#gameFinishedHandler.bind(this); + /** #handleGameChange, but bound to this instance. */ + #boundHandleGameChange = this.#handleGameChange.bind(this); constructor(value) { if (value === undefined) {