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); }