From 561f105ba44ce83970335718f68809a414674496 Mon Sep 17 00:00:00 2001 From: Akita Noek Date: Fri, 5 Jul 2024 07:28:51 -0600 Subject: [PATCH] Fix end-of-game removed stones being used when analyzing past moves and score estimations fixes https://github.com/online-go/online-go.com/issues/2735 --- src/engine/GobanEngine.ts | 38 +++++++++++++++++++++++++------- test/unit_tests/GoEngine.test.ts | 27 +++++++++++++++++++++++ 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/src/engine/GobanEngine.ts b/src/engine/GobanEngine.ts index b07cfb5a..8df70f82 100644 --- a/src/engine/GobanEngine.ts +++ b/src/engine/GobanEngine.ts @@ -22,6 +22,7 @@ import { decodePrettyCoordinates, encodeMove, encodeMoves, + makeMatrix, positionId, prettyCoordinates, sortMoves, @@ -751,7 +752,7 @@ export class GobanEngine extends BoardState { //this.goban_callback?.setState(state.udata_state); this.goban_callback?.setState?.(); - const redrawn: { [s: string]: boolean } = {}; + const redrawn = makeMatrix(this.width, this.height, false); for (let y = 0; y < this.height; ++y) { for (let x = 0; x < this.width; ++x) { @@ -760,10 +761,23 @@ export class GobanEngine extends BoardState { (this.cur_move.x === x && this.cur_move.y === y) ) { this.board[y][x] = state.board[y][x]; - if (this.goban_callback) { - this.goban_callback.set(x, y, this.board[y][x]); - } - redrawn[x + "," + y] = true; + redrawn[y][x] = true; + } + + if ( + this.removal[y][x] !== state.removal[y][x] || + (this.cur_move.x === x && this.cur_move.y === y) + ) { + this.removal[y][x] = state.removal[y][x]; + redrawn[y][x] = true; + } + } + } + + if (this.goban_callback) { + for (let y = 0; y < this.height; ++y) { + for (let x = 0; x < this.width; ++x) { + this.goban_callback.set(x, y, this.board[y][x]); } } } @@ -914,9 +928,7 @@ export class GobanEngine extends BoardState { return; } this.move_before_jump = this.cur_move; - if (node.state) { - this.setState(node.state); - } + this.setState(node.state); this.cur_move = node; if (node.player_update) { //console.log("Engine jumpTo doing player_update..."); @@ -2531,4 +2543,14 @@ export class GobanEngine extends BoardState { } return ret; } + + public override setRemoved( + x: number, + y: number, + removed: boolean, + emit_stone_removal_updated: boolean = true, + ): void { + this.cur_move.state.setRemoved(x, y, removed, false); + super.setRemoved(x, y, removed, emit_stone_removal_updated); + } } diff --git a/test/unit_tests/GoEngine.test.ts b/test/unit_tests/GoEngine.test.ts index 93f63fd6..ce58508c 100644 --- a/test/unit_tests/GoEngine.test.ts +++ b/test/unit_tests/GoEngine.test.ts @@ -726,3 +726,30 @@ describe("groups", () => { expect(engine.getStoneRemovalString()).toBe("aabb"); }); }); + +describe("state", () => { + const engine = new GobanEngine({}); + + engine.place(0, 0); + const move1 = engine.cur_move; + engine.place(1, 1); + const move2 = engine.cur_move; + + expect(engine.board[0][0]).toBe(1); + expect(engine.board[1][1]).toBe(2); + expect(engine.removal[1][1]).toBe(false); + expect(engine.cur_move.state.removal[1][1]).toBe(false); + + engine.setRemoved(1, 1, true); + expect(engine.removal[1][1]).toBe(true); + expect(engine.cur_move.state.removal[1][1]).toBe(true); + expect(engine.getStoneRemovalString()).toBe("bb"); + + engine.jumpTo(move1); + expect(engine.removal[1][1]).toBe(false); + expect(engine.getStoneRemovalString()).toBe(""); + + engine.jumpTo(move2); + expect(engine.removal[1][1]).toBe(true); + expect(engine.getStoneRemovalString()).toBe("bb"); +});