Skip to content

Commit

Permalink
for each move, remember dead stones
Browse files Browse the repository at this point in the history
  • Loading branch information
h908714124 committed Aug 4, 2024
1 parent cf5933a commit c217180
Show file tree
Hide file tree
Showing 9 changed files with 95 additions and 46 deletions.
18 changes: 18 additions & 0 deletions src/main/client/src/model/PointList.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ export class PointList {
static LO = 0xffff
static HI = 0xffff0000

static empty() {
return {
size: 0,
forEach: () => {},
}
}

constructor(dim) {
if (!dim) {
throw new Error("expecting argument: dim")
Expand All @@ -29,6 +36,13 @@ export class PointList {
this.pos++
}

addAll(other) {
if (!other) {
return
}
other.forEach((x, y) => this.add(x, y))
}

#get(i) {
let code = this.buffer[Math.trunc(i / 2)]
return i % 2 === 0 ? code & PointList.LO : (code >> 16)
Expand Down Expand Up @@ -57,6 +71,10 @@ export class PointList {
return this.pos
}

isEmpty() {
return !this.pos
}

toSet() {
let result = new PointSet(this.dim)
this.forEach((x, y) => result.add(x, y))
Expand Down
54 changes: 29 additions & 25 deletions src/main/client/src/model/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,36 +15,47 @@ import {
export function updateBoard(board, move) {
let {pass, x, y, color} = move
if (pass) {
return board
return [PointList.empty(), board]
}
board = applyMove(board, move)
let oppositeColor = color ^ (WHITE | BLACK)
board = removeDeadGroup(board, x, y - 1, oppositeColor)
board = removeDeadGroup(board, x, y + 1, oppositeColor)
board = removeDeadGroup(board, x - 1, y, oppositeColor)
board = removeDeadGroup(board, x + 1, y, oppositeColor)
return board
let dead = new PointList(board.length)
dead.addAll(findDeadStones(board, x, y - 1, oppositeColor))
dead.addAll(findDeadStones(board, x, y + 1, oppositeColor))
dead.addAll(findDeadStones(board, x - 1, y, oppositeColor))
dead.addAll(findDeadStones(board, x + 1, y, oppositeColor))
if (dead.isEmpty()) {
return [PointList.empty(), board]
}
let updated = board.slice()
dead.forEach((x, y) => {
if (updated[y] === board[y]) {
updated[y] = board[y].slice()
}
updated[y][x] = 0
})
return [dead, updated]
}

function removeDeadGroup(board, xx, yy, color) {
function findDeadStones(board, xx, yy, color) {
let dim = board.length
if (Math.min(xx, yy) < 0 || Math.max(xx, yy) >= dim) {
return board
return undefined
}
if (board[yy][xx] !== color) {
return board
return undefined
}
if (yy > 0 && board[yy - 1][xx] == 0) {
return board
return undefined
}
if (yy < dim - 1 && board[yy + 1][xx] == 0) {
return board
return undefined
}
if (xx > 0 && board[yy][xx - 1] == 0) {
return board
return undefined
}
if (xx < dim - 1 && board[yy][xx + 1] == 0) {
return board
return undefined
}
let acc = new PointList(dim)
let pointsChecked = new PointSet(dim)
Expand All @@ -59,7 +70,7 @@ function removeDeadGroup(board, xx, yy, color) {
if (y > 0) {
let bpt = board[y - 1][x]
if (bpt === 0) {
return board
return undefined
} else if (bpt === color && !pointsChecked.has(x, y - 1)) {
pointsChecked.add(x, y - 1)
pointsToCheck.offer(x, y - 1)
Expand All @@ -68,7 +79,7 @@ function removeDeadGroup(board, xx, yy, color) {
if (y < dim - 1) {
let bpt = board[y + 1][x]
if (bpt === 0) {
return board
return undefined
} else if (bpt === color && !pointsChecked.has(x, y + 1)) {
pointsChecked.add(x, y + 1)
pointsToCheck.offer(x, y + 1)
Expand All @@ -77,7 +88,7 @@ function removeDeadGroup(board, xx, yy, color) {
if (x > 0) {
let bpt = board[y][x - 1]
if (bpt === 0) {
return board
return undefined
} else if (bpt === color && !pointsChecked.has(x - 1, y)) {
pointsChecked.add(x - 1, y)
pointsToCheck.offer(x - 1, y)
Expand All @@ -86,21 +97,14 @@ function removeDeadGroup(board, xx, yy, color) {
if (x < dim - 1) {
let bpt = board[y][x + 1]
if (bpt === 0) {
return board
return undefined
} 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
return acc
}

function applyMove(board, {color, x, y}) {
Expand Down
11 changes: 9 additions & 2 deletions src/main/client/src/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ import {
BLACK,
WHITE,
} from "./util.js"
import {
PointList,
} from "./model/PointList.js"
import {
rehydrate,
} from "./model/board.js"
Expand Down Expand Up @@ -61,19 +64,23 @@ export const useGameStore = create((set, get) => ({
},
addMove: (move) => {
set(produce(state => {
if (move.n < get().moves.length) {
return
}
if (get().moves.length < move.n) {
state.queueStatus = "behind"
return
}
state.queueStatus = "up_to_date"
state.moves.push(move)
if (move.counting) {
state.moves.push({...move, dead: PointList.empty()})
state.gameState.counting = true
state.baseBoard = move.board
state.gameState.board = rehydrate(move.board)
return
}
let updated = updateBoard(get().baseBoard, move)
let [dead, updated] = updateBoard(get().baseBoard, move)
state.moves.push({...move, dead})
state.baseBoard = updated
state.gameState.board = rehydrate(updated)
state.gameState.currentColor = get().gameState.currentColor ^ (BLACK | WHITE)
Expand Down
38 changes: 28 additions & 10 deletions src/main/java/com/bernd/game/MoveList.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import com.bernd.model.GameMove;
import com.bernd.model.Move;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
Expand All @@ -15,6 +14,8 @@ public final class MoveList {
private static final int HI = 0xffff0000;
private static final int WHITE = 0x1000;
private static final int PASS = 0x2000;
private static final int COUNTING = 0x4000;
private static final int GAME_END = 0x8000;
private static final int DATA = 0x0fff;

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

public void add(int color, Move move) {
if (pos >= capacity) {
int boardSize = dim * dim;
int newCapacity = capacity < boardSize ? boardSize : capacity + boardSize;
buffer = Arrays.copyOf(buffer, divUp(newCapacity, 2));
capacity = newCapacity;
}
public void gameEnd() {
ensureCapacity();
set(GAME_END);
pos++;
}

public void add(int color, Move move, boolean counting) {
ensureCapacity();
int ptId;
if (move.pass()) {
ptId = PASS;
Expand All @@ -54,21 +56,37 @@ public void add(int color, Move move) {
if (color == Board.W) {
ptId |= WHITE;
}
if (counting) {
ptId |= COUNTING;
}
set(ptId);
pos++;
}

private void ensureCapacity() {
if (pos >= capacity) {
int boardSize = dim * dim;
int newCapacity = capacity < boardSize ? boardSize : capacity + boardSize;
buffer = Arrays.copyOf(buffer, divUp(newCapacity, 2));
capacity = newCapacity;
}
}

public GameMove get(int i) {
int code = buffer[i / 2];
int ptId = i % 2 == 0 ? code & LO : (code >> 16);
int color = (ptId & WHITE) != 0 ? Board.W : Board.B;
if ((ptId & GAME_END) != 0) {
return new GameMove(i, 0, true, -1, -1, true, true, new int[]{-1, -1});
}
boolean counting = (ptId & COUNTING) != 0;
if ((ptId & PASS) != 0) {
return new GameMove(i, color, true, -1, -1, new int[]{-1, -1});
return new GameMove(i, color, true, -1, -1, counting, false, new int[]{-1, -1});
} else {
int data = ptId & DATA;
int x = data % dim;
int y = data / dim;
return new GameMove(i, color, true, x, y, new int[]{-1, -1});
return new GameMove(i, color, false, x, y, counting, false, new int[]{-1, -1});
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/bernd/model/CountingMove.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ public record CountingMove(
int color,
boolean pass,
boolean counting,
int [][] board) {
int[][] board) {

public static CountingMove create(int color, int n, int[][] board) {
return new CountingMove(n, color, true, true, board);
}
}
}
2 changes: 1 addition & 1 deletion src/main/java/com/bernd/model/Game.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public Game update(Move move) {
}

private Game updateInternal(Move move) {
moves.add(currentColor, move, counting);
if (counting) {
if (move.resetCounting()) {
int[][] resetted = Toggle.resetCounting(board);
Expand All @@ -50,7 +51,6 @@ private Game updateInternal(Move move) {
int[][] toggled = Toggle.toggleStonesAt(board, move.x(), move.y());
return game(Count.count(toggled), NOT_FORBIDDEN);
}
moves.add(currentColor, move);
if (move.pass()) {
if (opponentPassed) {
return startCounting();
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/com/bernd/model/GameMove.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@ public record GameMove(
boolean pass,
int x,
int y,
boolean counting,
boolean end,
int[] forbidden) {
}
}
2 changes: 1 addition & 1 deletion src/main/java/com/bernd/model/Move.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ public record Move(
int y) {

public GameMove toView(int color, int moveNumber, int[] forbidden) {
return new GameMove(moveNumber, color, pass, x, y, forbidden);
return new GameMove(moveNumber, color, pass, x, y, false, false, forbidden);
}
}
8 changes: 4 additions & 4 deletions src/test/java/com/bernd/game/MoveListTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ class MoveListTest {
@Test
void testGet() {
MoveList list = MoveList.create(9);
list.add(Board.B, move(0, 1));
list.add(Board.W, move(2, 3));
list.add(Board.B, move(0, 1), false);
list.add(Board.W, move(2, 3), false);
assertEquals(2, list.size());
assertEquals(0, list.get(0).x());
assertEquals(1, list.get(0).y());
Expand All @@ -26,7 +26,7 @@ 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));
list.add(Board.B, move(x, y), false);
}
}
assertEquals(81, list.size());
Expand All @@ -35,4 +35,4 @@ void testGrow() {
private Move move(int x, int y) {
return new Move("", false, false, x, y);
}
}
}

0 comments on commit c217180

Please sign in to comment.