diff --git a/src/main/client/src/Game.jsx b/src/main/client/src/Game.jsx
index 5c912a6..8e8239e 100644
--- a/src/main/client/src/Game.jsx
+++ b/src/main/client/src/Game.jsx
@@ -47,6 +47,7 @@ export const Game = () => {
let stompClient = useContext(StompContext)
let auth = useAuthStore(state => state.auth)
let setGameState = useGameStore(state => state.setGameState)
+ let addMove = useGameStore(state => state.addMove)
let { board, currentColor, currentPlayer, counting, forbidden } = useGameStore(state => state.gameState)
let [forbidden_x, forbidden_y] = forbidden
let initialized = useRef()
@@ -192,13 +193,9 @@ export const Game = () => {
return
}
initialized.current = true
- let sub1 = stompClient.subscribe("/topic/game/" + gameId, (message) => {
- let game = JSON.parse(message.body)
- setGameState(game)
- })
let sub2 = stompClient.subscribe("/topic/move/" + gameId, (message) => {
let move = JSON.parse(message.body)
- console.log(move) // TODO
+ addMove(move)
})
doTry(async () => {
let game = await tfetch("/api/game/" + gameId, {
@@ -209,10 +206,9 @@ export const Game = () => {
setGameState(game)
})
return () => {
- sub1.unsubscribe()
sub2.unsubscribe()
}
- }, [setGameState, initialized, stompClient, gameId, auth])
+ }, [setGameState, addMove, initialized, stompClient, gameId, auth])
if (!board.length) {
return
Loading...
}
diff --git a/src/main/client/src/feature/GamePanel.jsx b/src/main/client/src/feature/GamePanel.jsx
index e28bebc..267d220 100644
--- a/src/main/client/src/feature/GamePanel.jsx
+++ b/src/main/client/src/feature/GamePanel.jsx
@@ -46,7 +46,8 @@ function Panel({zoom, setZoom}) {
let { gameId } = useParams()
let stompClient = useContext(StompContext)
let auth = useAuthStore(state => state.auth)
- let { black, white} = useGameStore(state => state)
+ let black = useGameStore(state => state.black)
+ let white = useGameStore(state => state.white)
let { board, currentPlayer, counting } = useGameStore(state => state.gameState)
let navigate = useNavigate()
let onExit = useCallback(() => {
diff --git a/src/main/client/src/model/board.js b/src/main/client/src/model/board.js
index f0602fd..864ea59 100644
--- a/src/main/client/src/model/board.js
+++ b/src/main/client/src/model/board.js
@@ -9,6 +9,8 @@ import {
} from "./PointSet.js"
import {
hasStone,
+ BLACK,
+ WHITE,
} from "../util.js"
export function getGroup(board, xx, yy) {
@@ -117,7 +119,7 @@ export function isForbidden(board, groupInfo, currentColor) {
return true
}
if (y > 0) {
- let { color, liberties, hasStone } = board[y - 1][x]
+ let {color, liberties, hasStone} = board[y - 1][x]
if (!hasStone) {
return false
}
@@ -129,7 +131,7 @@ export function isForbidden(board, groupInfo, currentColor) {
}
}
if (y < dim - 1) {
- let { color, liberties, hasStone } = board[y + 1][x]
+ let {color, liberties, hasStone} = board[y + 1][x]
if (!hasStone) {
return false
}
@@ -141,7 +143,7 @@ export function isForbidden(board, groupInfo, currentColor) {
}
}
if (x > 0) {
- let { color, liberties, hasStone } = board[y][x - 1]
+ let {color, liberties, hasStone} = board[y][x - 1]
if (!hasStone) {
return false
}
@@ -153,7 +155,7 @@ export function isForbidden(board, groupInfo, currentColor) {
}
}
if (x < dim - 1) {
- let { color, liberties, hasStone } = board[y][x + 1]
+ let {color, liberties, hasStone} = board[y][x + 1]
if (!hasStone) {
return false
}
@@ -166,3 +168,106 @@ export function isForbidden(board, groupInfo, currentColor) {
}
return true
}
+
+export function updateBoard(boardBeforeMove, move) {
+ let {pass, x, y, color} = move
+ if (pass) {
+ return boardBeforeMove
+ }
+ let board = applyMove(boardBeforeMove, move)
+ let oppositeColor = color ^ (WHITE | BLACK)
+ let size = board.length
+ let result = board
+ if (y > 0 && board[y - 1][x] === oppositeColor) {
+ result = removeDeadGroup(board, x, y - 1)
+ }
+ if (y < size - 1 && board[y + 1][x] === oppositeColor) {
+ result = removeDeadGroup(board, x, y + 1)
+ }
+ if (x > 0 && board[y][x - 1] === oppositeColor) {
+ result = removeDeadGroup(board, x - 1, y)
+ }
+ if (x < size - 1 && board[y][x + 1] === oppositeColor) {
+ result = removeDeadGroup(board, x + 1, y)
+ }
+ return result
+}
+
+function removeDeadGroup(board, xx, yy) {
+ let dim = board.length
+ if (yy > 0 && board[yy - 1][xx] == 0) {
+ return board
+ }
+ if (yy < dim - 1 && board[yy + 1][xx] == 0) {
+ return board
+ }
+ if (xx > 0 && board[yy][xx - 1] == 0) {
+ return board
+ }
+ if (xx < dim - 1 && board[yy][xx + 1] == 0) {
+ return board
+ }
+ let color = board[yy][xx]
+ let acc = new PointList(dim)
+ let pointsChecked = new PointSet(dim)
+ pointsChecked.add(xx, yy)
+ let pointsToCheck = new PointQueue(dim)
+ pointsToCheck.offer(xx, yy)
+ while (!pointsToCheck.isEmpty()) {
+ let ptId = pointsToCheck.poll()
+ let y = Math.trunc(ptId / dim)
+ let x = ptId % dim
+ acc.add(x, y)
+ if (y > 0) {
+ let bpt = board[y - 1][x]
+ if (bpt === 0) {
+ return board
+ } else if (bpt === color && !pointsChecked.has(x, y - 1)) {
+ pointsChecked.add(x, y - 1)
+ pointsToCheck.offer(x, y - 1)
+ }
+ }
+ if (y < dim - 1) {
+ let bpt = board[y + 1][x]
+ if (bpt === 0) {
+ return board
+ } else if (bpt === color && !pointsChecked.has(x, y + 1)) {
+ pointsChecked.add(x, y + 1)
+ pointsToCheck.offer(x, y + 1)
+ }
+ }
+ if (x > 0) {
+ let bpt = board[y][x - 1]
+ if (bpt === 0) {
+ return board
+ } else if (bpt === color && !pointsChecked.has(x - 1, y)) {
+ pointsChecked.add(x - 1, y)
+ pointsToCheck.offer(x - 1, y)
+ }
+ }
+ if (x < dim - 1) {
+ let bpt = board[y][x + 1]
+ if (bpt === 0) {
+ return board
+ } else if (bpt === color && !pointsChecked.has(x + 1, y)) {
+ pointsChecked.add(x + 1, y)
+ pointsToCheck.offer(x + 1, y)
+ }
+ }
+ }
+ let result = board.slice()
+ acc.forEach((x, y) => {
+ if (result[y] === board[y]) {
+ result[y] = board[y].slice()
+ }
+ result[y][x] = 0
+ })
+ return result
+}
+
+function applyMove(board, {color, x, y}) {
+ let result = board.slice()
+ result[y] = board[y].slice()
+ result[y][x] = color
+ return result
+}
diff --git a/src/main/client/src/store.js b/src/main/client/src/store.js
index 511a773..e495424 100644
--- a/src/main/client/src/store.js
+++ b/src/main/client/src/store.js
@@ -6,9 +6,11 @@ import {
} from "immer"
import {
BLACK,
+ WHITE,
} from "./util.js"
import {
rehydrate,
+ updateBoard,
} from "./model/board.js"
export const useAuthStore = create((set) => ({
@@ -31,7 +33,10 @@ export const useAuthStore = create((set) => ({
},
}))
-export const useGameStore = create((set) => ({
+export const useGameStore = create((set, get) => ({
+ moves: [],
+ baseBoard: [],
+ queueStatus: "up_to_date",
editMode: false,
black: {
name: "",
@@ -52,11 +57,28 @@ export const useGameStore = create((set) => ({
counting: false,
forbidden: [-1, -1],
},
+ addMove: (move) => {
+ set(produce(state => {
+ if (get().moves.length < move.n) {
+ state.queueStatus = "behind"
+ return
+ }
+ state.queueStatus = "up_to_date"
+ state.moves.push(move)
+ let updated = updateBoard(get().baseBoard, move)
+ state.baseBoard = updated
+ state.gameState.board = rehydrate(updated)
+ state.gameState.currentColor = get().gameState.currentColor ^ (BLACK | WHITE)
+ state.gameState.currentPlayer = get().gameState.currentPlayer === get().black.name ? get().white.name : get().black.name
+ }))
+ },
setGameState: (game) => {
set(produce(state => {
state.black = game.black
state.white = game.white
state.editMode = game.editMode
+ state.baseBoard = game.board
+ state.moves = game.moves
state.gameState.board = rehydrate(game.board)
state.gameState.currentPlayer = game.currentPlayer
state.gameState.currentColor = game.currentColor
diff --git a/src/main/java/com/bernd/game/MoveList.java b/src/main/java/com/bernd/game/MoveList.java
index cf727b5..b06e133 100644
--- a/src/main/java/com/bernd/game/MoveList.java
+++ b/src/main/java/com/bernd/game/MoveList.java
@@ -24,7 +24,7 @@ public final class MoveList {
private MoveList(
int dim,
int[] buffer) {
- this.capacity = dim * dim;
+ this.capacity = 2 * buffer.length;
this.dim = dim;
this.buffer = buffer;
}
@@ -39,7 +39,8 @@ public static MoveList create(int dim) {
public void add(int color, Move move) {
if (pos >= capacity) {
- int newCapacity = 2 * capacity;
+ int boardSize = dim * dim;
+ int newCapacity = capacity < boardSize ? boardSize : capacity + boardSize;
buffer = Arrays.copyOf(buffer, divUp(newCapacity, 2));
capacity = newCapacity;
}
diff --git a/src/test/java/com/bernd/game/MoveListTest.java b/src/test/java/com/bernd/game/MoveListTest.java
index 19af4af..3a1daf6 100644
--- a/src/test/java/com/bernd/game/MoveListTest.java
+++ b/src/test/java/com/bernd/game/MoveListTest.java
@@ -8,7 +8,7 @@
class MoveListTest {
@Test
- void get() {
+ void testGet() {
MoveList list = MoveList.create(9);
list.add(Board.B, move(0, 1));
list.add(Board.W, move(2, 3));
@@ -21,6 +21,17 @@ void get() {
assertEquals(Board.W, list.get(1).color());
}
+ @Test
+ void testGrow() {
+ MoveList list = MoveList.create(9);
+ for (int y = 0; y < 9; y++) {
+ for (int x = 0; x < 9; x++) {
+ list.add(Board.B, move(x, y));
+ }
+ }
+ assertEquals(81, list.size());
+ }
+
private Move move(int x, int y) {
return new Move("", false, false, x, y);
}