From 00ad4e7ef1cb4e9c0f9e78f0a3b969fa3a5be111 Mon Sep 17 00:00:00 2001 From: Jon Ko Date: Sun, 24 Nov 2024 04:43:50 +0100 Subject: [PATCH] fix liberty check for fractional go Wrong intersection indices were compared. E.g. the surrounded corner stone in the test was not checked, because it was changedIntersection[7] and AbstractBaduk's this.intersection[7] was already checked as a part of the long black chain. --- .../src/lib/abstractBaduk/abstractBaduk.ts | 3 +- .../variants/fractional/fractional.test.ts | 65 +++++++++++++------ 2 files changed, 46 insertions(+), 22 deletions(-) diff --git a/packages/shared/src/lib/abstractBaduk/abstractBaduk.ts b/packages/shared/src/lib/abstractBaduk/abstractBaduk.ts index 59d77319..2b9aeb1e 100644 --- a/packages/shared/src/lib/abstractBaduk/abstractBaduk.ts +++ b/packages/shared/src/lib/abstractBaduk/abstractBaduk.ts @@ -49,13 +49,14 @@ export abstract class AbstractBaduk< []; const checkedIntersections: Map> = new Map(); - changedIntersections.forEach((intersection, index) => { + changedIntersections.forEach((intersection) => { if (!intersection.stone) { // This shouldn't be possible. // Maybe use better typing to show that all intersections here have stones. return; } + const index = this.intersections.indexOf(intersection); const uncheckedChainTypes = new Set( Array.from(intersection.stone.getChainTypes()).filter( (chainType) => diff --git a/packages/shared/src/variants/fractional/fractional.test.ts b/packages/shared/src/variants/fractional/fractional.test.ts index 35a66785..fdf183ea 100644 --- a/packages/shared/src/variants/fractional/fractional.test.ts +++ b/packages/shared/src/variants/fractional/fractional.test.ts @@ -6,7 +6,7 @@ import { } from "./fractional"; class FractionalTestGame extends Fractional { - readonly firstCorner: FractionalIntersection | undefined; + readonly corners: FractionalIntersection[]; constructor(config: Pick) { super({ @@ -14,14 +14,16 @@ class FractionalTestGame extends Fractional { board: { type: BoardPattern.Grid, width: 9, height: 9 }, }); - this.firstCorner = this.intersections.find( - (i) => i.neighbours.length === 2, - ); + this.corners = this.intersections.filter((i) => i.neighbours.length === 2); } - indexOf(intersection: FractionalIntersection): number | undefined { + indexOf(intersection: FractionalIntersection): number { return this.intersections.indexOf(intersection); } + idOf(intersection: FractionalIntersection): string | "" { + const index = this.intersections.indexOf(intersection); + return index < 0 ? "" : `${index}`; + } } test("Surrounded merge stone", () => { @@ -33,28 +35,21 @@ test("Surrounded merge stone", () => { ], }); - // TODO: Better typing - - expect(game.firstCorner).toBeTruthy(); - expect(game.firstCorner?.neighbours.length).toBe(2); - expect(game.firstCorner?.neighbours[0]).toBeTruthy(); - expect(game.firstCorner?.neighbours[1]).toBeTruthy(); + expect(game.corners).toHaveLength(4); + expect(game.corners[0]).toBeTruthy(); + expect(game.corners[0]?.neighbours.length).toBe(2); + expect(game.corners[0]?.neighbours[0]).toBeTruthy(); + expect(game.corners[0]?.neighbours[1]).toBeTruthy(); - const cornerId = game.firstCorner - ? game.indexOf(game.firstCorner)?.toString() ?? "" - : ""; - const neighbour0Id = game.firstCorner - ? game.indexOf(game.firstCorner.neighbours[0])?.toString() ?? "" - : ""; - const neighbour1Id = game.firstCorner - ? game.indexOf(game.firstCorner.neighbours[1])?.toString() ?? "" - : ""; + const cornerId = game.idOf(game.corners[0]); + const neighbour0Id = game.idOf(game.corners[0].neighbours[0]); + const neighbour1Id = game.idOf(game.corners[0].neighbours[1]); // Round 1 game.playMove(0, neighbour0Id); game.playMove(1, neighbour1Id); game.playMove(2, cornerId); - expect(game.firstCorner?.stone).toBeNull(); + expect(game.corners[0]?.stone).toBeNull(); // Round 2 game.playMove(0, cornerId); @@ -65,3 +60,31 @@ test("Surrounded merge stone", () => { expect(state.boardState.filter((i) => i).length).toBe(2); expect(state.boardState.at(Number(cornerId))).toBeNull(); }); + +test("A surrounded stone with other long chains on the board", () => { + const game = new FractionalTestGame({ + players: [ + { primaryColor: "black", secondaryColor: "green" }, + { primaryColor: "white", secondaryColor: "green" }, + ], + }); + + // . . . . .(B)B B B // Additional chains on the board have historically + // . . . . . . W W W // caused issues with the liberty check + // . ...5 lines... . + // . . . . . . . . W + // . . . . . . .(W)B // White's last move should capture black's corner stone + + game.playMove(0, game.idOf(game.corners[3])); + game.playMove(1, game.idOf(game.corners[3].neighbours[0])); + + for (let i = 8; i >= 6; --i) { + game.playMove(0, `${i}`); + game.playMove(1, `${i + 9}`); + } + + game.playMove(0, "5"); + game.playMove(1, game.idOf(game.corners[3].neighbours[1])); + + expect(game.corners[3].stone).toBeFalsy(); +});