Skip to content

Commit f69f4a5

Browse files
committed
wip incremental updates
1 parent 9225bd6 commit f69f4a5

File tree

6 files changed

+152
-16
lines changed

6 files changed

+152
-16
lines changed

src/main/client/src/Game.jsx

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ export const Game = () => {
4747
let stompClient = useContext(StompContext)
4848
let auth = useAuthStore(state => state.auth)
4949
let setGameState = useGameStore(state => state.setGameState)
50+
let addMove = useGameStore(state => state.addMove)
5051
let { board, currentColor, currentPlayer, counting, forbidden } = useGameStore(state => state.gameState)
5152
let [forbidden_x, forbidden_y] = forbidden
5253
let initialized = useRef()
@@ -192,13 +193,9 @@ export const Game = () => {
192193
return
193194
}
194195
initialized.current = true
195-
let sub1 = stompClient.subscribe("/topic/game/" + gameId, (message) => {
196-
let game = JSON.parse(message.body)
197-
setGameState(game)
198-
})
199196
let sub2 = stompClient.subscribe("/topic/move/" + gameId, (message) => {
200197
let move = JSON.parse(message.body)
201-
console.log(move) // TODO
198+
addMove(move)
202199
})
203200
doTry(async () => {
204201
let game = await tfetch("/api/game/" + gameId, {
@@ -209,10 +206,9 @@ export const Game = () => {
209206
setGameState(game)
210207
})
211208
return () => {
212-
sub1.unsubscribe()
213209
sub2.unsubscribe()
214210
}
215-
}, [setGameState, initialized, stompClient, gameId, auth])
211+
}, [setGameState, addMove, initialized, stompClient, gameId, auth])
216212
if (!board.length) {
217213
return <div>Loading...</div>
218214
}

src/main/client/src/feature/GamePanel.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ function Panel({zoom, setZoom}) {
4646
let { gameId } = useParams()
4747
let stompClient = useContext(StompContext)
4848
let auth = useAuthStore(state => state.auth)
49-
let { black, white} = useGameStore(state => state)
49+
let black = useGameStore(state => state.black)
50+
let white = useGameStore(state => state.white)
5051
let { board, currentPlayer, counting } = useGameStore(state => state.gameState)
5152
let navigate = useNavigate()
5253
let onExit = useCallback(() => {

src/main/client/src/model/board.js

Lines changed: 109 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import {
99
} from "./PointSet.js"
1010
import {
1111
hasStone,
12+
BLACK,
13+
WHITE,
1214
} from "../util.js"
1315

1416
export function getGroup(board, xx, yy) {
@@ -117,7 +119,7 @@ export function isForbidden(board, groupInfo, currentColor) {
117119
return true
118120
}
119121
if (y > 0) {
120-
let { color, liberties, hasStone } = board[y - 1][x]
122+
let {color, liberties, hasStone} = board[y - 1][x]
121123
if (!hasStone) {
122124
return false
123125
}
@@ -129,7 +131,7 @@ export function isForbidden(board, groupInfo, currentColor) {
129131
}
130132
}
131133
if (y < dim - 1) {
132-
let { color, liberties, hasStone } = board[y + 1][x]
134+
let {color, liberties, hasStone} = board[y + 1][x]
133135
if (!hasStone) {
134136
return false
135137
}
@@ -141,7 +143,7 @@ export function isForbidden(board, groupInfo, currentColor) {
141143
}
142144
}
143145
if (x > 0) {
144-
let { color, liberties, hasStone } = board[y][x - 1]
146+
let {color, liberties, hasStone} = board[y][x - 1]
145147
if (!hasStone) {
146148
return false
147149
}
@@ -153,7 +155,7 @@ export function isForbidden(board, groupInfo, currentColor) {
153155
}
154156
}
155157
if (x < dim - 1) {
156-
let { color, liberties, hasStone } = board[y][x + 1]
158+
let {color, liberties, hasStone} = board[y][x + 1]
157159
if (!hasStone) {
158160
return false
159161
}
@@ -166,3 +168,106 @@ export function isForbidden(board, groupInfo, currentColor) {
166168
}
167169
return true
168170
}
171+
172+
export function updateBoard(boardBeforeMove, move) {
173+
let {pass, x, y, color} = move
174+
if (pass) {
175+
return boardBeforeMove
176+
}
177+
let board = applyMove(boardBeforeMove, move)
178+
let oppositeColor = color ^ (WHITE | BLACK)
179+
let size = board.length
180+
let result = board
181+
if (y > 0 && board[y - 1][x] === oppositeColor) {
182+
result = removeDeadGroup(board, x, y - 1)
183+
}
184+
if (y < size - 1 && board[y + 1][x] === oppositeColor) {
185+
result = removeDeadGroup(board, x, y + 1)
186+
}
187+
if (x > 0 && board[y][x - 1] === oppositeColor) {
188+
result = removeDeadGroup(board, x - 1, y)
189+
}
190+
if (x < size - 1 && board[y][x + 1] === oppositeColor) {
191+
result = removeDeadGroup(board, x + 1, y)
192+
}
193+
return result
194+
}
195+
196+
function removeDeadGroup(board, xx, yy) {
197+
let dim = board.length
198+
if (yy > 0 && board[yy - 1][xx] == 0) {
199+
return board
200+
}
201+
if (yy < dim - 1 && board[yy + 1][xx] == 0) {
202+
return board
203+
}
204+
if (xx > 0 && board[yy][xx - 1] == 0) {
205+
return board
206+
}
207+
if (xx < dim - 1 && board[yy][xx + 1] == 0) {
208+
return board
209+
}
210+
let color = board[yy][xx]
211+
let acc = new PointList(dim)
212+
let pointsChecked = new PointSet(dim)
213+
pointsChecked.add(xx, yy)
214+
let pointsToCheck = new PointQueue(dim)
215+
pointsToCheck.offer(xx, yy)
216+
while (!pointsToCheck.isEmpty()) {
217+
let ptId = pointsToCheck.poll()
218+
let y = Math.trunc(ptId / dim)
219+
let x = ptId % dim
220+
acc.add(x, y)
221+
if (y > 0) {
222+
let bpt = board[y - 1][x]
223+
if (bpt === 0) {
224+
return board
225+
} else if (bpt === color && !pointsChecked.has(x, y - 1)) {
226+
pointsChecked.add(x, y - 1)
227+
pointsToCheck.offer(x, y - 1)
228+
}
229+
}
230+
if (y < dim - 1) {
231+
let bpt = board[y + 1][x]
232+
if (bpt === 0) {
233+
return board
234+
} else if (bpt === color && !pointsChecked.has(x, y + 1)) {
235+
pointsChecked.add(x, y + 1)
236+
pointsToCheck.offer(x, y + 1)
237+
}
238+
}
239+
if (x > 0) {
240+
let bpt = board[y][x - 1]
241+
if (bpt === 0) {
242+
return board
243+
} else if (bpt === color && !pointsChecked.has(x - 1, y)) {
244+
pointsChecked.add(x - 1, y)
245+
pointsToCheck.offer(x - 1, y)
246+
}
247+
}
248+
if (x < dim - 1) {
249+
let bpt = board[y][x + 1]
250+
if (bpt === 0) {
251+
return board
252+
} else if (bpt === color && !pointsChecked.has(x + 1, y)) {
253+
pointsChecked.add(x + 1, y)
254+
pointsToCheck.offer(x + 1, y)
255+
}
256+
}
257+
}
258+
let result = board.slice()
259+
acc.forEach((x, y) => {
260+
if (result[y] === board[y]) {
261+
result[y] = board[y].slice()
262+
}
263+
result[y][x] = 0
264+
})
265+
return result
266+
}
267+
268+
function applyMove(board, {color, x, y}) {
269+
let result = board.slice()
270+
result[y] = board[y].slice()
271+
result[y][x] = color
272+
return result
273+
}

src/main/client/src/store.js

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ import {
66
} from "immer"
77
import {
88
BLACK,
9+
WHITE,
910
} from "./util.js"
1011
import {
1112
rehydrate,
13+
updateBoard,
1214
} from "./model/board.js"
1315

1416
export const useAuthStore = create((set) => ({
@@ -31,7 +33,10 @@ export const useAuthStore = create((set) => ({
3133
},
3234
}))
3335

34-
export const useGameStore = create((set) => ({
36+
export const useGameStore = create((set, get) => ({
37+
moves: [],
38+
baseBoard: [],
39+
queueStatus: "up_to_date",
3540
editMode: false,
3641
black: {
3742
name: "",
@@ -52,11 +57,28 @@ export const useGameStore = create((set) => ({
5257
counting: false,
5358
forbidden: [-1, -1],
5459
},
60+
addMove: (move) => {
61+
set(produce(state => {
62+
if (get().moves.length < move.n) {
63+
state.queueStatus = "behind"
64+
return
65+
}
66+
state.queueStatus = "up_to_date"
67+
state.moves.push(move)
68+
let updated = updateBoard(get().baseBoard, move)
69+
state.baseBoard = updated
70+
state.gameState.board = rehydrate(updated)
71+
state.gameState.currentColor = get().gameState.currentColor ^ (BLACK | WHITE)
72+
state.gameState.currentPlayer = get().gameState.currentPlayer === get().black.name ? get().white.name : get().black.name
73+
}))
74+
},
5575
setGameState: (game) => {
5676
set(produce(state => {
5777
state.black = game.black
5878
state.white = game.white
5979
state.editMode = game.editMode
80+
state.baseBoard = game.board
81+
state.moves = game.moves
6082
state.gameState.board = rehydrate(game.board)
6183
state.gameState.currentPlayer = game.currentPlayer
6284
state.gameState.currentColor = game.currentColor

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public final class MoveList {
2424
private MoveList(
2525
int dim,
2626
int[] buffer) {
27-
this.capacity = dim * dim;
27+
this.capacity = 2 * buffer.length;
2828
this.dim = dim;
2929
this.buffer = buffer;
3030
}
@@ -39,7 +39,8 @@ public static MoveList create(int dim) {
3939

4040
public void add(int color, Move move) {
4141
if (pos >= capacity) {
42-
int newCapacity = 2 * capacity;
42+
int boardSize = dim * dim;
43+
int newCapacity = capacity < boardSize ? boardSize : capacity + boardSize;
4344
buffer = Arrays.copyOf(buffer, divUp(newCapacity, 2));
4445
capacity = newCapacity;
4546
}

src/test/java/com/bernd/game/MoveListTest.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
class MoveListTest {
99

1010
@Test
11-
void get() {
11+
void testGet() {
1212
MoveList list = MoveList.create(9);
1313
list.add(Board.B, move(0, 1));
1414
list.add(Board.W, move(2, 3));
@@ -21,6 +21,17 @@ void get() {
2121
assertEquals(Board.W, list.get(1).color());
2222
}
2323

24+
@Test
25+
void testGrow() {
26+
MoveList list = MoveList.create(9);
27+
for (int y = 0; y < 9; y++) {
28+
for (int x = 0; x < 9; x++) {
29+
list.add(Board.B, move(x, y));
30+
}
31+
}
32+
assertEquals(81, list.size());
33+
}
34+
2435
private Move move(int x, int y) {
2536
return new Move("", false, false, x, y);
2637
}

0 commit comments

Comments
 (0)