Skip to content

Commit e78effd

Browse files
committed
for each move, remember dead stones
1 parent cf5933a commit e78effd

File tree

8 files changed

+91
-42
lines changed

8 files changed

+91
-42
lines changed

src/main/client/src/model/PointList.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ export class PointList {
77
static LO = 0xffff
88
static HI = 0xffff0000
99

10+
static empty() {
11+
return {
12+
size: 0,
13+
forEach: () => {},
14+
}
15+
}
16+
1017
constructor(dim) {
1118
if (!dim) {
1219
throw new Error("expecting argument: dim")
@@ -29,6 +36,13 @@ export class PointList {
2936
this.pos++
3037
}
3138

39+
addAll(other) {
40+
if (!other) {
41+
return
42+
}
43+
other.forEach((x, y) => this.add(x, y))
44+
}
45+
3246
#get(i) {
3347
let code = this.buffer[Math.trunc(i / 2)]
3448
return i % 2 === 0 ? code & PointList.LO : (code >> 16)
@@ -57,6 +71,10 @@ export class PointList {
5771
return this.pos
5872
}
5973

74+
isEmpty() {
75+
return !this.pos
76+
}
77+
6078
toSet() {
6179
let result = new PointSet(this.dim)
6280
this.forEach((x, y) => result.add(x, y))

src/main/client/src/model/base.js

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,36 +15,47 @@ import {
1515
export function updateBoard(board, move) {
1616
let {pass, x, y, color} = move
1717
if (pass) {
18-
return board
18+
return [PointList.empty(), board]
1919
}
2020
board = applyMove(board, move)
2121
let oppositeColor = color ^ (WHITE | BLACK)
22-
board = removeDeadGroup(board, x, y - 1, oppositeColor)
23-
board = removeDeadGroup(board, x, y + 1, oppositeColor)
24-
board = removeDeadGroup(board, x - 1, y, oppositeColor)
25-
board = removeDeadGroup(board, x + 1, y, oppositeColor)
26-
return board
22+
let dead = new PointList(board.length)
23+
dead.addAll(findDeadStones(board, x, y - 1, oppositeColor))
24+
dead.addAll(findDeadStones(board, x, y + 1, oppositeColor))
25+
dead.addAll(findDeadStones(board, x - 1, y, oppositeColor))
26+
dead.addAll(findDeadStones(board, x + 1, y, oppositeColor))
27+
if (dead.isEmpty()) {
28+
return [PointList.empty(), board]
29+
}
30+
let updated = board.slice()
31+
dead.forEach((x, y) => {
32+
if (updated[y] === board[y]) {
33+
updated[y] = board[y].slice()
34+
}
35+
updated[y][x] = 0
36+
})
37+
return [dead, updated]
2738
}
2839

29-
function removeDeadGroup(board, xx, yy, color) {
40+
function findDeadStones(board, xx, yy, color) {
3041
let dim = board.length
3142
if (Math.min(xx, yy) < 0 || Math.max(xx, yy) >= dim) {
32-
return board
43+
return undefined
3344
}
3445
if (board[yy][xx] !== color) {
35-
return board
46+
return undefined
3647
}
3748
if (yy > 0 && board[yy - 1][xx] == 0) {
38-
return board
49+
return undefined
3950
}
4051
if (yy < dim - 1 && board[yy + 1][xx] == 0) {
41-
return board
52+
return undefined
4253
}
4354
if (xx > 0 && board[yy][xx - 1] == 0) {
44-
return board
55+
return undefined
4556
}
4657
if (xx < dim - 1 && board[yy][xx + 1] == 0) {
47-
return board
58+
return undefined
4859
}
4960
let acc = new PointList(dim)
5061
let pointsChecked = new PointSet(dim)
@@ -59,7 +70,7 @@ function removeDeadGroup(board, xx, yy, color) {
5970
if (y > 0) {
6071
let bpt = board[y - 1][x]
6172
if (bpt === 0) {
62-
return board
73+
return undefined
6374
} else if (bpt === color && !pointsChecked.has(x, y - 1)) {
6475
pointsChecked.add(x, y - 1)
6576
pointsToCheck.offer(x, y - 1)
@@ -68,7 +79,7 @@ function removeDeadGroup(board, xx, yy, color) {
6879
if (y < dim - 1) {
6980
let bpt = board[y + 1][x]
7081
if (bpt === 0) {
71-
return board
82+
return undefined
7283
} else if (bpt === color && !pointsChecked.has(x, y + 1)) {
7384
pointsChecked.add(x, y + 1)
7485
pointsToCheck.offer(x, y + 1)
@@ -77,7 +88,7 @@ function removeDeadGroup(board, xx, yy, color) {
7788
if (x > 0) {
7889
let bpt = board[y][x - 1]
7990
if (bpt === 0) {
80-
return board
91+
return undefined
8192
} else if (bpt === color && !pointsChecked.has(x - 1, y)) {
8293
pointsChecked.add(x - 1, y)
8394
pointsToCheck.offer(x - 1, y)
@@ -86,21 +97,14 @@ function removeDeadGroup(board, xx, yy, color) {
8697
if (x < dim - 1) {
8798
let bpt = board[y][x + 1]
8899
if (bpt === 0) {
89-
return board
100+
return undefined
90101
} else if (bpt === color && !pointsChecked.has(x + 1, y)) {
91102
pointsChecked.add(x + 1, y)
92103
pointsToCheck.offer(x + 1, y)
93104
}
94105
}
95106
}
96-
let result = board.slice()
97-
acc.forEach((x, y) => {
98-
if (result[y] === board[y]) {
99-
result[y] = board[y].slice()
100-
}
101-
result[y][x] = 0
102-
})
103-
return result
107+
return acc
104108
}
105109

106110
function applyMove(board, {color, x, y}) {

src/main/client/src/store.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ import {
88
BLACK,
99
WHITE,
1010
} from "./util.js"
11+
import {
12+
PointList,
13+
} from "./model/PointList.js"
1114
import {
1215
rehydrate,
1316
} from "./model/board.js"
@@ -61,19 +64,23 @@ export const useGameStore = create((set, get) => ({
6164
},
6265
addMove: (move) => {
6366
set(produce(state => {
67+
if (move.n < get().moves.length) {
68+
return
69+
}
6470
if (get().moves.length < move.n) {
6571
state.queueStatus = "behind"
6672
return
6773
}
6874
state.queueStatus = "up_to_date"
69-
state.moves.push(move)
7075
if (move.counting) {
76+
state.moves.push({...move, dead: PointList.empty()})
7177
state.gameState.counting = true
7278
state.baseBoard = move.board
7379
state.gameState.board = rehydrate(move.board)
7480
return
7581
}
76-
let updated = updateBoard(get().baseBoard, move)
82+
let [dead, updated] = updateBoard(get().baseBoard, move)
83+
state.moves.push({...move, dead})
7784
state.baseBoard = updated
7885
state.gameState.board = rehydrate(updated)
7986
state.gameState.currentColor = get().gameState.currentColor ^ (BLACK | WHITE)

src/main/java/com/bernd/game/MoveList.java

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import com.bernd.model.GameMove;
44
import com.bernd.model.Move;
5-
65
import java.util.ArrayList;
76
import java.util.Arrays;
87
import java.util.List;
@@ -15,6 +14,8 @@ public final class MoveList {
1514
private static final int HI = 0xffff0000;
1615
private static final int WHITE = 0x1000;
1716
private static final int PASS = 0x2000;
17+
private static final int COUNTING = 0x4000;
18+
private static final int GAME_END = 0x8000;
1819
private static final int DATA = 0x0fff;
1920

2021
private int pos;
@@ -38,13 +39,14 @@ public static MoveList create(int dim) {
3839
return new MoveList(dim, new int[16]);
3940
}
4041

41-
public void add(int color, Move move) {
42-
if (pos >= capacity) {
43-
int boardSize = dim * dim;
44-
int newCapacity = capacity < boardSize ? boardSize : capacity + boardSize;
45-
buffer = Arrays.copyOf(buffer, divUp(newCapacity, 2));
46-
capacity = newCapacity;
47-
}
42+
public void gameEnd() {
43+
ensureCapacity();
44+
set(GAME_END);
45+
pos++;
46+
}
47+
48+
public void add(int color, Move move, boolean counting) {
49+
ensureCapacity();
4850
int ptId;
4951
if (move.pass()) {
5052
ptId = PASS;
@@ -54,21 +56,37 @@ public void add(int color, Move move) {
5456
if (color == Board.W) {
5557
ptId |= WHITE;
5658
}
59+
if (counting) {
60+
ptId |= COUNTING;
61+
}
5762
set(ptId);
5863
pos++;
5964
}
6065

66+
private void ensureCapacity() {
67+
if (pos >= capacity) {
68+
int boardSize = dim * dim;
69+
int newCapacity = capacity < boardSize ? boardSize : capacity + boardSize;
70+
buffer = Arrays.copyOf(buffer, divUp(newCapacity, 2));
71+
capacity = newCapacity;
72+
}
73+
}
74+
6175
public GameMove get(int i) {
6276
int code = buffer[i / 2];
6377
int ptId = i % 2 == 0 ? code & LO : (code >> 16);
6478
int color = (ptId & WHITE) != 0 ? Board.W : Board.B;
79+
if ((ptId & GAME_END) != 0) {
80+
return new GameMove(i, 0, true, -1, -1, true, true, new int[]{-1, -1});
81+
}
82+
boolean counting = (ptId & COUNTING) != 0;
6583
if ((ptId & PASS) != 0) {
66-
return new GameMove(i, color, true, -1, -1, new int[]{-1, -1});
84+
return new GameMove(i, color, true, -1, -1, counting, false, new int[]{-1, -1});
6785
} else {
6886
int data = ptId & DATA;
6987
int x = data % dim;
7088
int y = data / dim;
71-
return new GameMove(i, color, true, x, y, new int[]{-1, -1});
89+
return new GameMove(i, color, false, x, y, counting, false, new int[]{-1, -1});
7290
}
7391
}
7492

src/main/java/com/bernd/model/CountingMove.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ public record CountingMove(
55
int color,
66
boolean pass,
77
boolean counting,
8-
int [][] board) {
8+
int[][] board) {
99

1010
public static CountingMove create(int color, int n, int[][] board) {
1111
return new CountingMove(n, color, true, true, board);
1212
}
13-
}
13+
}

src/main/java/com/bernd/model/Game.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ public Game update(Move move) {
4242
}
4343

4444
private Game updateInternal(Move move) {
45+
moves.add(currentColor, move, counting);
4546
if (counting) {
4647
if (move.resetCounting()) {
4748
int[][] resetted = Toggle.resetCounting(board);
@@ -50,7 +51,6 @@ private Game updateInternal(Move move) {
5051
int[][] toggled = Toggle.toggleStonesAt(board, move.x(), move.y());
5152
return game(Count.count(toggled), NOT_FORBIDDEN);
5253
}
53-
moves.add(currentColor, move);
5454
if (move.pass()) {
5555
if (opponentPassed) {
5656
return startCounting();

src/main/java/com/bernd/model/GameMove.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,7 @@ public record GameMove(
66
boolean pass,
77
int x,
88
int y,
9+
boolean counting,
10+
boolean end,
911
int[] forbidden) {
10-
}
12+
}

src/main/java/com/bernd/model/Move.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ public record Move(
88
int y) {
99

1010
public GameMove toView(int color, int moveNumber, int[] forbidden) {
11-
return new GameMove(moveNumber, color, pass, x, y, forbidden);
11+
return new GameMove(moveNumber, color, pass, x, y, false, false, forbidden);
1212
}
1313
}

0 commit comments

Comments
 (0)