Skip to content

Commit 6859900

Browse files
committed
wip client count
1 parent 066cf47 commit 6859900

File tree

13 files changed

+252
-49
lines changed

13 files changed

+252
-49
lines changed

src/main/client/src/Game.jsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export const Game = () => {
4545
let auth = useAuthStore(state => state.auth)
4646
let setGameState = useGameStore(state => state.setGameState)
4747
let queueStatus = useGameStore(state => state.queueStatus)
48+
let queueLength = useGameStore(state => state.queueLength)
4849
let addMove = useGameStore(state => state.addMove)
4950
let currentPlayer = useGameStore(state => state.currentPlayer)
5051
let { board, currentColor, counting, forbidden } = useGameStore(state => state.gameState)
@@ -157,11 +158,12 @@ export const Game = () => {
157158
destination: "/app/game/move",
158159
body: JSON.stringify({
159160
id: gameId,
161+
n: queueLength(),
160162
x: cursor_x,
161163
y: cursor_y,
162164
}),
163165
})
164-
}, [context, currentPlayer, currentColor, auth, board, gameId, stompClient, counting, forbidden_x, forbidden_y])
166+
}, [context, currentPlayer, currentColor, auth, board, gameId, stompClient, counting, forbidden_x, forbidden_y, queueLength])
165167

166168
useEffect(() => {
167169
if (!board.length) {

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ function Panel({zoom, setZoom}) {
4848
let auth = useAuthStore(state => state.auth)
4949
let black = useGameStore(state => state.black)
5050
let white = useGameStore(state => state.white)
51+
let queueLength = useGameStore(state => state.queueLength)
5152
let currentPlayer = useGameStore(state => state.currentPlayer)
5253
let { board, counting } = useGameStore(state => state.gameState)
5354
let navigate = useNavigate()
@@ -59,19 +60,21 @@ function Panel({zoom, setZoom}) {
5960
destination: "/app/game/move",
6061
body: JSON.stringify({
6162
id: gameId,
63+
n: queueLength(),
6264
pass: true,
6365
}),
6466
})
65-
}, [stompClient, gameId])
67+
}, [stompClient, gameId, queueLength])
6668
let onResetCounting = useCallback(() => {
6769
stompClient.publish({
6870
destination: "/app/game/move",
6971
body: JSON.stringify({
7072
id: gameId,
73+
n: queueLength(),
7174
resetCounting: true,
7275
}),
7376
})
74-
}, [stompClient, gameId])
77+
}, [stompClient, gameId, queueLength])
7578
if (!board.length) {
7679
return <span>Loading...</span>
7780
}

src/main/client/src/model/count.js

Lines changed: 110 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,94 @@ import {
1717
TERRITORY,
1818
REMOVED_B,
1919
REMOVED_W,
20+
TOGGLE_B,
21+
TOGGLE_W,
22+
TOGGLE_STUFF,
2023
} from "../util.js"
2124

25+
export function count(board) {
26+
let acc = createAcc(board.length)
27+
for (let y = 0; y < board.length; y++) {
28+
let row = board[y]
29+
for (let x = 0; x < row.length; x++) {
30+
if (acc[y][x] === -1) {
31+
colorEmptyTerritory(board, acc, x, y)
32+
}
33+
}
34+
}
35+
return acc
36+
}
37+
38+
function updateToggleStonesAt(board, x, y, color, pointsChecked, pointsToCheck) {
39+
let dim = board.length
40+
if (Math.min(x, y) < 0 || Math.max(x, y) >= dim) {
41+
return
42+
}
43+
let c = board[y][x]
44+
if (c !== color) {
45+
return
46+
}
47+
if (pointsChecked.has(x, y)) {
48+
return
49+
}
50+
pointsChecked.add(x, y)
51+
pointsToCheck.offer(x, y)
52+
}
53+
54+
export function toggleStonesAt(board, xx, yy) {
55+
let color = board[yy][xx]
56+
if (!(color & TOGGLE_STUFF)) {
57+
return board
58+
}
59+
let dim = board.length
60+
let result = new PointList(dim)
61+
let pointsToCheck = new PointQueue(dim)
62+
let pointsChecked = new PointSet(dim)
63+
pointsChecked.add(xx, yy)
64+
pointsToCheck.offer(xx, yy)
65+
while (!pointsToCheck.isEmpty()) {
66+
let ptId = pointsToCheck.poll()
67+
let y = Math.trunc(ptId / dim)
68+
let x = ptId % dim
69+
result.add(x, y)
70+
updateToggleStonesAt(board, x, y - 1, color, pointsChecked, pointsToCheck)
71+
updateToggleStonesAt(board, x, y + 1, color, pointsChecked, pointsToCheck)
72+
updateToggleStonesAt(board, x - 1, y, color, pointsChecked, pointsToCheck)
73+
updateToggleStonesAt(board, x + 1, y, color, pointsChecked, pointsToCheck)
74+
}
75+
let updated = board.slice()
76+
result.forEach((x, y) => {
77+
if (updated[y] === board[y]) {
78+
updated[y] = board[y].slice()
79+
}
80+
updated[y][x] = toggleRemoved(updated[y][x])
81+
})
82+
return updated
83+
}
84+
85+
export function resetCounting(board) {
86+
let dim = board.length
87+
let updated = board.slice()
88+
for (let y = 0; y < dim; y++) {
89+
updated[y] = board[y].slice()
90+
for (let x = 0; x < dim; x++) {
91+
updated[y][x] = resurrect(board[y][x]) & COLORS
92+
}
93+
}
94+
return updated
95+
}
96+
97+
function updateFindStone(dim, x, y, pointsChecked, pointsToCheck) {
98+
if (Math.min(x, y) < 0 || Math.max(x, y) >= dim) {
99+
return
100+
}
101+
if (pointsChecked.has(x, y)) {
102+
return
103+
}
104+
pointsChecked.add(x, y)
105+
pointsToCheck.offer(x, y)
106+
}
107+
22108
function findStone(board, xx, yy) {
23109
if (hasStone(board[yy][xx])) {
24110
return board[yy][xx]
@@ -35,22 +121,10 @@ function findStone(board, xx, yy) {
35121
if (hasStone(board[y][x])) {
36122
return board[y][x]
37123
}
38-
if (y > 0 && !pointsChecked.has(x, y - 1)) {
39-
pointsChecked.add(x, y - 1)
40-
pointsToCheck.offer(x, y - 1)
41-
}
42-
if (y < dim - 1 && !pointsChecked.has(x, y + 1)) {
43-
pointsChecked.add(x, y + 1)
44-
pointsToCheck.offer(x, y + 1)
45-
}
46-
if (x > 0 && !pointsChecked.has(x - 1, y)) {
47-
pointsChecked.add(x - 1, y)
48-
pointsToCheck.offer(x - 1, y)
49-
}
50-
if (x < dim - 1 && !pointsChecked.has(x + 1, y)) {
51-
pointsChecked.add(x + 1, y)
52-
pointsToCheck.offer(x + 1, y)
53-
}
124+
updateFindStone(dim, x, y - 1, pointsChecked, pointsToCheck)
125+
updateFindStone(dim, x, y + 1, pointsChecked, pointsToCheck)
126+
updateFindStone(dim, x - 1, y, pointsChecked, pointsToCheck)
127+
updateFindStone(dim, x + 1, y, pointsChecked, pointsToCheck)
54128
}
55129
return 0
56130
}
@@ -117,19 +191,6 @@ function colorEmptyTerritory(board, acc, xx, yy) {
117191
}
118192
}
119193

120-
export function count(board) {
121-
let acc = createAcc(board.length)
122-
for (let y = 0; y < board.length; y++) {
123-
let row = board[y]
124-
for (let x = 0; x < row.length; x++) {
125-
if (acc[y][x] === -1) {
126-
colorEmptyTerritory(board, acc, x, y)
127-
}
128-
}
129-
}
130-
return acc
131-
}
132-
133194
function getTerritoryMarker(found, empty) {
134195
if ((empty & asRemoved(found)) !== 0) {
135196
return found // resurrect
@@ -157,6 +218,26 @@ function asRemoved(color) {
157218
return color
158219
}
159220

221+
function toggleRemoved(color) {
222+
if (color & TOGGLE_B) {
223+
return color ^ TOGGLE_B
224+
}
225+
if (color & TOGGLE_W) {
226+
return color ^ TOGGLE_W
227+
}
228+
return color
229+
}
230+
231+
function resurrect(color) {
232+
if (color & REMOVED_B) {
233+
return color ^ TOGGLE_B
234+
}
235+
if (color & REMOVED_W) {
236+
return color ^ TOGGLE_W
237+
}
238+
return color
239+
}
240+
160241
function createAcc(dim) {
161242
let result = Array(dim)
162243
for (let y = 0; y < dim; y++) {
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import {
2+
expect,
3+
test,
4+
} from "vitest"
5+
import {
6+
count,
7+
toggleStonesAt,
8+
resetCounting,
9+
} from "./count.js"
10+
import {
11+
BLACK,
12+
WHITE,
13+
TERRITORY_B,
14+
TERRITORY_W,
15+
REMOVED_W,
16+
REMOVED_B,
17+
} from "../util.js"
18+
19+
test("territoryChangeOwner", () => {
20+
let B = BLACK
21+
let t = TERRITORY_W
22+
let r = TERRITORY_W | REMOVED_B
23+
let v = TERRITORY_B
24+
let k = REMOVED_W
25+
let s = REMOVED_W | TERRITORY_B
26+
let position = [
27+
[t, r, k, 0, 0],
28+
[r, r, k, 0, 0],
29+
[k, k, k, B, 0],
30+
[0, 0, 0, 0, 0],
31+
[0, 0, 0, 0, 0],
32+
]
33+
let counted = count(position)
34+
expect(counted).toEqual(mapInt([
35+
[v, B, s, v, v],
36+
[B, B, s, v, v],
37+
[s, s, s, B, v],
38+
[v, v, v, v, v],
39+
[v, v, v, v, v],
40+
]))
41+
})
42+
43+
test("toggle", () => {
44+
let B = BLACK
45+
let W = WHITE
46+
let t = TERRITORY_W
47+
let r = TERRITORY_W | REMOVED_B
48+
let k = REMOVED_W
49+
let position = [
50+
[t, r, W, 0, 0],
51+
[r, r, W, 0, 0],
52+
[W, W, W, B, 0],
53+
[0, 0, 0, 0, 0],
54+
[0, 0, 0, 0, 0],
55+
]
56+
let toggled = toggleStonesAt(position, 0, 2)
57+
expect(toggled).toEqual([
58+
[t, r, k, 0, 0],
59+
[r, r, k, 0, 0],
60+
[k, k, k, B, 0],
61+
[0, 0, 0, 0, 0],
62+
[0, 0, 0, 0, 0],
63+
])
64+
})
65+
66+
test("reset", () => {
67+
let B = BLACK
68+
let W = WHITE
69+
let f = REMOVED_W | TERRITORY_B
70+
let t = TERRITORY_B
71+
let position = [
72+
[t, B, f, t, t],
73+
[B, B, f, t, t],
74+
[f, f, f, t, t],
75+
[t, t, t, t, t],
76+
[t, t, t, t, t],
77+
]
78+
let result = resetCounting(position)
79+
expect(result).toEqual([
80+
[0, B, W, 0, 0],
81+
[B, B, W, 0, 0],
82+
[W, W, W, 0, 0],
83+
[0, 0, 0, 0, 0],
84+
[0, 0, 0, 0, 0],
85+
])
86+
})
87+
88+
function mapInt(ar) {
89+
let result = Array(ar.length)
90+
for (let y = 0; y < ar.length; y++) {
91+
result[y] = new Int32Array(ar[y])
92+
}
93+
return result
94+
}

src/main/client/src/store.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ import {
2020
import {
2121
getForbidden,
2222
} from "./model/ko.js"
23+
import {
24+
count,
25+
toggleStonesAt,
26+
resetCounting,
27+
} from "./model/count.js"
2328

2429
export const useAuthStore = create((set) => ({
2530
auth: {
@@ -63,6 +68,9 @@ export const useGameStore = create((set, get) => ({
6368
get().white.name :
6469
get().black.name
6570
},
71+
queueLength: () => {
72+
return get().moves.length
73+
},
6674
gameState: {
6775
board: [],
6876
currentColor: BLACK,
@@ -82,8 +90,15 @@ export const useGameStore = create((set, get) => ({
8290
if (move.counting) {
8391
state.moves.push({...move, dead: PointList.empty()})
8492
state.gameState.counting = true
85-
state.baseBoard = move.board
86-
state.gameState.board = rehydrate(move.board)
93+
if (move.resetCounting) {
94+
let updated = count(resetCounting(get().baseBoard))
95+
state.baseBoard = updated
96+
state.gameState.board = rehydrate(updated)
97+
} else {
98+
let updated = count(toggleStonesAt(get().baseBoard, move.x, move.y))
99+
state.baseBoard = updated
100+
state.gameState.board = rehydrate(updated)
101+
}
87102
return
88103
}
89104
let [dead, updated] = updateBoard(get().baseBoard, move)

src/main/client/src/util.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ export const TERRITORY_W = 4
1414
export const REMOVED_B = 8
1515
export const REMOVED_W = 16
1616

17+
export const TOGGLE_B = REMOVED_B | BLACK
18+
export const TOGGLE_W = REMOVED_W | WHITE
19+
export const TOGGLE_STUFF = TOGGLE_B | TOGGLE_W
20+
1721
export const TERRITORY = TERRITORY_W | TERRITORY_B
1822
export const ANY_REMOVED = REMOVED_W | REMOVED_B
1923

src/main/java/com/bernd/GameController.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.bernd;
22

3+
import com.bernd.game.Board;
34
import com.bernd.model.AcceptRequest;
45
import com.bernd.model.ActiveGame;
56
import com.bernd.model.CountingMove;
@@ -58,16 +59,16 @@ public void action(Move move, Principal principal) {
5859
}
5960
int moveNumber = game.moves().size();
6061
int color = game.currentColor();
61-
if (!principal.getName().equals(game.currentPlayer())) {
62+
String currentPlayer = game.currentColor() == Board.B ? game.black().name() : game.white().name();
63+
if (!principal.getName().equals(currentPlayer)) {
6264
return; // discard
6365
}
66+
if (move.n() != moveNumber) {
67+
return;
68+
}
6469
Game updated = game.update(move);
6570
games.put(updated);
66-
if (updated.counting()) {
67-
operations.convertAndSend("/topic/move/" + game.id(), CountingMove.create(color, moveNumber, updated.board()));
68-
} else {
69-
operations.convertAndSend("/topic/move/" + game.id(), move.toView(color, moveNumber));
70-
}
71+
operations.convertAndSend("/topic/move/" + game.id(), move.toView(color, updated.counting()));
7172
}
7273

7374
@ResponseBody

0 commit comments

Comments
 (0)