From 255cb6fecd349c52dee30174d3b12d9a7936127d Mon Sep 17 00:00:00 2001 From: jbock Date: Sat, 20 Jul 2024 08:44:16 +0200 Subject: [PATCH] count disputed territory as 0 --- src/main/client/src/util.js | 4 +- src/main/java/com/bernd/game/Board.java | 11 +-- src/main/java/com/bernd/game/Count.java | 45 ++++++++---- src/main/java/com/bernd/model/Game.java | 2 +- src/main/java/com/bernd/util/BoardUpdate.java | 10 ++- src/test/java/com/bernd/game/BoardTest.java | 52 ++++++++------ src/test/java/com/bernd/game/CountTest.java | 70 +++++++++++-------- .../java/com/bernd/util/BoardUpdateTest.java | 47 +++++++++++++ 8 files changed, 166 insertions(+), 75 deletions(-) create mode 100644 src/test/java/com/bernd/util/BoardUpdateTest.java diff --git a/src/main/client/src/util.js b/src/main/client/src/util.js index 5b5f914..c8cfcf4 100644 --- a/src/main/client/src/util.js +++ b/src/main/client/src/util.js @@ -5,8 +5,8 @@ import { export const StompContext = createContext() export const base = "/app" -export const BLACK = 2 -export const WHITE = 4 +export const BLACK = 32 +export const WHITE = 64 export async function tfetch(url, options) { let response diff --git a/src/main/java/com/bernd/game/Board.java b/src/main/java/com/bernd/game/Board.java index 0b09a85..a86edee 100644 --- a/src/main/java/com/bernd/game/Board.java +++ b/src/main/java/com/bernd/game/Board.java @@ -4,8 +4,11 @@ public class Board { - public static final int BLACK = 2; - public static final int WHITE = 4; + public static final int B = 32; + public static final int W = 64; + public static final int FORBIDDEN = 1; + public static final int TERRITORY = 2; + public static final int REMOVED = 4; private static StoneGroup getStoneGroup( int[][] board, @@ -13,7 +16,7 @@ private static StoneGroup getStoneGroup( int yy) { int color = board[yy][xx]; int dim = board.length; - BoardUpdate update = BoardUpdate.builder(dim, 16); + BoardUpdate update = BoardUpdate.builder(dim); int liberties = 0; PointSet pointsChecked = PointSet.create(dim); PointQueue pointsToCheck = PointQueue.create(dim); @@ -70,7 +73,7 @@ public static int[][] removeDeadStonesAround( if (color == 0) { return board; } - int oppositeColor = color == WHITE ? BLACK : WHITE; + int oppositeColor = color == W ? B : W; int size = board.length; int[][] result = board; // Above diff --git a/src/main/java/com/bernd/game/Count.java b/src/main/java/com/bernd/game/Count.java index a7f0fa9..ae4cc21 100644 --- a/src/main/java/com/bernd/game/Count.java +++ b/src/main/java/com/bernd/game/Count.java @@ -1,5 +1,12 @@ package com.bernd.game; +import com.bernd.util.BoardUpdate; +import java.util.Arrays; + +import static com.bernd.game.Board.B; +import static com.bernd.game.Board.TERRITORY; +import static com.bernd.game.Board.W; + public class Count { private static int getImpliedColor( @@ -19,7 +26,7 @@ private static int getImpliedColor( int x = ptId % dim; pointsChecked.add(x, y); if (board[y][x] != 0) { - return board[y][x] + 1; // add territory flag + return board[y][x] + TERRITORY; } if (y > 0 && !pointsChecked.has(x, y - 1)) { pointsToCheck.offer(x, y - 1); @@ -37,18 +44,21 @@ private static int getImpliedColor( throw new RuntimeException("empty board"); } - private static void getStoneGroup( + private static void markStonesAround( int[][] acc, int[][] board, int xx, int yy) { int color = getImpliedColor(board, xx, yy); - if (color % 2 == 0) { + if ((color & TERRITORY) == 0) { acc[yy][xx] = color; return; } - int baseColor = color - 1; // remove territory flag + boolean oppositeStonesFound = false; + int baseColor = color - TERRITORY; + int oppositeColor = baseColor == W ? B : W; int dim = board.length; + BoardUpdate updater = BoardUpdate.builder(dim, 64); PointQueue pointsToCheck = PointQueue.create(dim); pointsToCheck.offer(xx, yy); while (!pointsToCheck.isEmpty()) { @@ -56,10 +66,11 @@ private static void getStoneGroup( int y = ptId / dim; int x = ptId % dim; acc[y][x] = color; + updater.add(x, y); if (y > 0) { int c = board[y - 1][x]; - if (c != 0 && c != baseColor) { - throw new RuntimeException("remove dead stones"); + if (c == oppositeColor) { + oppositeStonesFound = true; } if (c == 0 && acc[y - 1][x] != color) { pointsToCheck.offer(x, y - 1); @@ -67,8 +78,8 @@ private static void getStoneGroup( } if (y < dim - 1) { int c = board[y + 1][x]; - if (c != 0 && c != baseColor) { - throw new RuntimeException("remove dead stones"); + if (c == oppositeColor) { + oppositeStonesFound = true; } if (c == 0 && acc[y + 1][x] != color) { pointsToCheck.offer(x, y + 1); @@ -76,8 +87,8 @@ private static void getStoneGroup( } if (x > 0) { int c = board[y][x - 1]; - if (c != 0 && c != baseColor) { - throw new RuntimeException("remove dead stones"); + if (c == oppositeColor) { + oppositeStonesFound = true; } if (c == 0 && acc[y][x - 1] != color) { pointsToCheck.offer(x - 1, y); @@ -85,14 +96,19 @@ private static void getStoneGroup( } if (x < dim - 1) { int c = board[y][x + 1]; - if (c != 0 && c != baseColor) { - throw new RuntimeException("remove dead stones"); + if (c == oppositeColor) { + oppositeStonesFound = true; } if (c == 0 && acc[y][x + 1] != color) { pointsToCheck.offer(x + 1, y); } } } + if (oppositeStonesFound) { + for (int i = 0; i < updater.size(); i++) { + acc[updater.y(i)][updater.x(i)] = 0; + } + } } public static int[][] count( @@ -101,8 +117,8 @@ public static int[][] count( for (int y = 0; y < board.length; y++) { int[] row = board[y]; for (int x = 0; x < row.length; x++) { - if (acc[y][x] == 0) { - getStoneGroup(acc, board, x, y); + if (acc[y][x] == -1) { + markStonesAround(acc, board, x, y); } } } @@ -113,6 +129,7 @@ private static int[][] createAcc(int[][] board) { int[][] result = new int[board.length][]; for (int i = 0; i < board.length; i++) { result[i] = new int[result.length]; + Arrays.fill(result[i], -1); } return result; } diff --git a/src/main/java/com/bernd/model/Game.java b/src/main/java/com/bernd/model/Game.java index 0f3c071..571fd82 100644 --- a/src/main/java/com/bernd/model/Game.java +++ b/src/main/java/com/bernd/model/Game.java @@ -15,7 +15,7 @@ public record Game( public Game update(Move move) { int x = move.x(); int y = move.y(); - int color = currentUser.equals(black().name()) ? Board.BLACK : Board.WHITE; + int color = currentUser.equals(black().name()) ? Board.B : Board.W; Function update = BoardUpdate.create(board.length, x, y, color); int[][] rows = update.apply(board); int[][] newRows = Board.removeDeadStonesAround(rows, x, y); diff --git a/src/main/java/com/bernd/util/BoardUpdate.java b/src/main/java/com/bernd/util/BoardUpdate.java index f8dd4ab..9f685f5 100644 --- a/src/main/java/com/bernd/util/BoardUpdate.java +++ b/src/main/java/com/bernd/util/BoardUpdate.java @@ -6,7 +6,7 @@ public class BoardUpdate implements Function { - private static final int SHIFT = 256; + private static final int SHIFT = 256; // > max(B, W) private int pos; private final int dim; private int[] updates; @@ -22,6 +22,10 @@ public static BoardUpdate builder(int dim, int size) { return new BoardUpdate(dim, new int[size]); } + public static BoardUpdate builder(int dim) { + return new BoardUpdate(dim, new int[16]); + } + public static Function create( int dim, int x, int y, int value) { BoardUpdate result = builder(dim, 1); @@ -38,6 +42,10 @@ public void add(int x, int y, int value) { pos++; } + public void add(int x, int y) { + add(x, y, 0); + } + public void add(Point point, int value) { add(point.x(), point.y(), value); } diff --git a/src/test/java/com/bernd/game/BoardTest.java b/src/test/java/com/bernd/game/BoardTest.java index faf3bc6..6c9e207 100644 --- a/src/test/java/com/bernd/game/BoardTest.java +++ b/src/test/java/com/bernd/game/BoardTest.java @@ -2,6 +2,8 @@ import org.junit.jupiter.api.Test; +import static com.bernd.game.Board.B; +import static com.bernd.game.Board.W; import static org.junit.jupiter.api.Assertions.assertArrayEquals; class BoardTest { @@ -9,45 +11,51 @@ class BoardTest { @Test void testRemoveOneStone() { int[][] position = new int[][]{ - new int[]{2, 4}, - new int[]{4, 0}, + new int[]{B, W}, + new int[]{W, 0}, }; int[][] result = Board.removeDeadStonesAround(position, 0, 1); - assertArrayEquals(new int[]{0, 4}, result[0]); - assertArrayEquals(new int[]{4, 0}, result[1]); + assertArrayEquals(new int[][]{ + new int[]{0, W}, + new int[]{W, 0}, + }, result); } @Test void testRemoveFourStones() { int[][] position = new int[][]{ new int[]{0, 0, 0, 0, 0}, - new int[]{0, 0, 2, 2, 0}, - new int[]{0, 2, 4, 4, 2}, - new int[]{2, 4, 4, 2, 0}, - new int[]{0, 2, 2, 0, 0}, + new int[]{0, 0, B, B, 0}, + new int[]{0, B, W, W, B}, + new int[]{B, W, W, B, 0}, + new int[]{0, B, B, 0, 0}, }; int[][] result = Board.removeDeadStonesAround(position, 4, 2); - assertArrayEquals(new int[]{0, 0, 0, 0, 0}, result[0]); - assertArrayEquals(new int[]{0, 0, 2, 2, 0}, result[1]); - assertArrayEquals(new int[]{0, 2, 0, 0, 2}, result[2]); - assertArrayEquals(new int[]{2, 0, 0, 2, 0}, result[3]); - assertArrayEquals(new int[]{0, 2, 2, 0, 0}, result[4]); + assertArrayEquals(new int[][]{ + new int[]{0, 0, 0, 0, 0}, + new int[]{0, 0, B, B, 0}, + new int[]{0, B, 0, 0, B}, + new int[]{B, 0, 0, B, 0}, + new int[]{0, B, B, 0, 0}, + }, result); } @Test void testRemoveStones() { int[][] position = new int[][]{ - new int[]{4, 2, 0, 0, 0}, - new int[]{2, 4, 0, 0, 0}, - new int[]{2, 4, 0, 0, 0}, - new int[]{4, 2, 0, 0, 0}, + new int[]{W, B, 0, 0, 0}, + new int[]{B, W, 0, 0, 0}, + new int[]{B, W, 0, 0, 0}, + new int[]{W, B, 0, 0, 0}, new int[]{0, 0, 0, 0, 0}, }; int[][] result = Board.removeDeadStonesAround(position, 0, 0); - assertArrayEquals(new int[]{4, 2, 0, 0, 0}, result[0]); - assertArrayEquals(new int[]{0, 4, 0, 0, 0}, result[1]); - assertArrayEquals(new int[]{0, 4, 0, 0, 0}, result[2]); - assertArrayEquals(new int[]{4, 2, 0, 0, 0}, result[3]); - assertArrayEquals(new int[]{0, 0, 0, 0, 0}, result[4]); + assertArrayEquals(new int[][]{ + new int[]{W, B, 0, 0, 0}, + new int[]{0, W, 0, 0, 0}, + new int[]{0, W, 0, 0, 0}, + new int[]{W, B, 0, 0, 0}, + new int[]{0, 0, 0, 0, 0}, + }, result); } } diff --git a/src/test/java/com/bernd/game/CountTest.java b/src/test/java/com/bernd/game/CountTest.java index fb52a16..6c6ce95 100644 --- a/src/test/java/com/bernd/game/CountTest.java +++ b/src/test/java/com/bernd/game/CountTest.java @@ -2,24 +2,28 @@ import org.junit.jupiter.api.Test; +import static com.bernd.game.Board.B; +import static com.bernd.game.Board.TERRITORY; +import static com.bernd.game.Board.W; import static org.junit.jupiter.api.Assertions.assertArrayEquals; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; class CountTest { + private static final int C = B + TERRITORY; + private static final int X = W + TERRITORY; + @Test void testRemoveOneStone() { int[][] position = new int[][]{ - new int[]{2, 2, 2}, - new int[]{2, 4, 4}, - new int[]{2, 2, 4}, + new int[]{B, B, B}, + new int[]{B, W, W}, + new int[]{B, B, W}, }; int[][] result = Count.count(position); assertArrayEquals(new int[][]{ - new int[]{2, 2, 2}, - new int[]{2, 4, 4}, - new int[]{2, 2, 4}, + new int[]{B, B, B}, + new int[]{B, W, W}, + new int[]{B, B, W}, }, result); } @@ -27,48 +31,52 @@ void testRemoveOneStone() { void testCountBlackTerritory() { int[][] position = new int[][]{ new int[]{0, 0, 0, 0, 0}, - new int[]{0, 2, 2, 2, 0}, - new int[]{0, 2, 0, 2, 0}, - new int[]{0, 2, 2, 2, 0}, + new int[]{0, B, B, B, 0}, + new int[]{0, B, 0, B, 0}, + new int[]{0, B, B, B, 0}, new int[]{0, 0, 0, 0, 0}, }; int[][] result = Count.count(position); assertArrayEquals(new int[][]{ - new int[]{3, 3, 3, 3, 3}, - new int[]{3, 2, 2, 2, 3}, - new int[]{3, 2, 3, 2, 3}, - new int[]{3, 2, 2, 2, 3}, - new int[]{3, 3, 3, 3, 3}, + new int[]{C, C, C, C, C}, + new int[]{C, B, B, B, C}, + new int[]{C, B, C, B, C}, + new int[]{C, B, B, B, C}, + new int[]{C, C, C, C, C}, }, result); } @Test - void testCountMixed() { + void testCountFull() { int[][] position = new int[][]{ new int[]{0, 0, 0, 0}, - new int[]{2, 2, 2, 2}, - new int[]{4, 4, 4, 4}, + new int[]{B, B, B, B}, + new int[]{W, W, W, W}, new int[]{0, 0, 0, 0}, }; int[][] result = Count.count(position); assertArrayEquals(new int[][]{ - new int[]{3, 3, 3, 3}, - new int[]{2, 2, 2, 2}, - new int[]{4, 4, 4, 4}, - new int[]{5, 5, 5, 5}, + new int[]{C, C, C, C}, + new int[]{B, B, B, B}, + new int[]{W, W, W, W}, + new int[]{X, X, X, X}, }, result); } @Test - void testRemoveDead() { + void testCountPartial() { int[][] position = new int[][]{ - new int[]{0, 4, 0, 0}, - new int[]{2, 2, 2, 2}, - new int[]{4, 4, 4, 4}, + new int[]{0, W, 0, 0}, + new int[]{B, B, B, B}, + new int[]{W, W, W, W}, new int[]{0, 0, 0, 0}, }; - RuntimeException error = assertThrows(RuntimeException.class, - () -> Count.count(position)); - assertEquals("remove dead stones", error.getMessage()); + int[][] result = Count.count(position); + assertArrayEquals(new int[][]{ + new int[]{0, W, 0, 0}, + new int[]{B, B, B, B}, + new int[]{W, W, W, W}, + new int[]{X, X, X, X}, + }, result); } -} \ No newline at end of file +} diff --git a/src/test/java/com/bernd/util/BoardUpdateTest.java b/src/test/java/com/bernd/util/BoardUpdateTest.java new file mode 100644 index 0000000..d16ab19 --- /dev/null +++ b/src/test/java/com/bernd/util/BoardUpdateTest.java @@ -0,0 +1,47 @@ +package com.bernd.util; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class BoardUpdateTest { + + @Test + void testAdd() { + BoardUpdate update = BoardUpdate.builder(9); + update.add(1, 8); + update.add(2, 3); + assertEquals(2, update.size()); + assertEquals(1, update.x(0)); + assertEquals(8, update.y(0)); + assertEquals(2, update.x(1)); + assertEquals(3, update.y(1)); + } + + @Test + void testGrow() { + BoardUpdate update = BoardUpdate.builder(9); + for (int i = 0; i < 9; i++) { + update.add(i, 0); + } + for (int i = 0; i < 9; i++) { + update.add(i, 1); + } + for (int i = 0; i < 9; i++) { + update.add(i, 2); + } + assertEquals(27, update.size()); + for (int i = 0; i < 9; i++) { + assertEquals(i % 9, update.x(i)); + assertEquals(0, update.y(i)); + } + for (int i = 10; i < 18; i++) { + assertEquals(i % 9, update.x(i)); + assertEquals(1, update.y(i)); + } + for (int i = 19; i < 27; i++) { + assertEquals(i % 9, update.x(i)); + assertEquals(2, update.y(i)); + } + } +}