From 8affa353dae54da970cacfe542b8978d5e092f9c Mon Sep 17 00:00:00 2001 From: djmil Date: Fri, 29 Sep 2023 13:59:34 +0200 Subject: [PATCH] move: mandatory capture --- .../djmil/cordacheckers/CheckersMoveTest.java | 2 +- .../cordaclient/GameBoardTests.java | 16 +++++++++ .../djmil/cordacheckers/checkers/Move.java | 33 +++++++++++++++++-- 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/backend/src/test/java/djmil/cordacheckers/CheckersMoveTest.java b/backend/src/test/java/djmil/cordacheckers/CheckersMoveTest.java index 2c020ac..815cc24 100644 --- a/backend/src/test/java/djmil/cordacheckers/CheckersMoveTest.java +++ b/backend/src/test/java/djmil/cordacheckers/CheckersMoveTest.java @@ -21,7 +21,7 @@ public class CheckersMoveTest { Map.entry(2, Arrays.asList(6, 7, 9, 11)), Map.entry(3, Arrays.asList(7, 8, 10, 12)), Map.entry(4, Arrays.asList(8, 11)), - Map.entry(5, Arrays.asList(1, 9, 14, 9, 11)), + Map.entry(5, Arrays.asList(1, 9, 14)), Map.entry(6, Arrays.asList(1, 2, 9, 10, 13, 15)), Map.entry(7, Arrays.asList(2, 3, 10, 11, 14, 16)), Map.entry(8, Arrays.asList(3, 4, 11, 12, 15)), diff --git a/backend/src/test/java/djmil/cordacheckers/cordaclient/GameBoardTests.java b/backend/src/test/java/djmil/cordacheckers/cordaclient/GameBoardTests.java index 3d9ccfd..c5753c2 100644 --- a/backend/src/test/java/djmil/cordacheckers/cordaclient/GameBoardTests.java +++ b/backend/src/test/java/djmil/cordacheckers/cordaclient/GameBoardTests.java @@ -110,6 +110,22 @@ public class GameBoardTests { assertThat(m2.board().get(15)).isEqualTo(BLACK_MAN); assertThat(m2.moveNumber() == 2); assertThat(m2.status()).isEqualByComparingTo(Status.GAME_BOARD_WAIT_FOR_OPPONENT); + + assertThatThrownBy(() -> { + cordaClient.gameBoardMove(hiWhite, game.uuid(), move(24, 19), + "An attempt to ignore mandatory capture"); + }); + + final var m3 = cordaClient.gameBoardMove(hiWhite, game.uuid(), move(18, 11), null); + assertThat(m2.board().get(18)).isEqualTo(WHITE_MAN); + assertThat(m2.board().get(11)).isNull(); + assertThat(m2.board().get(15)).isEqualTo(BLACK_MAN); + assertThat(m3.board().get(11)).isEqualTo(WHITE_MAN); + assertThat(m3.board().get(18)).isNull(); + assertThat(m3.board().get(15)).isNull(); + assertThat(m3.moveNumber() == 3); + assertThat(m3.status()).isEqualByComparingTo(Status.GAME_BOARD_WAIT_FOR_OPPONENT); + } ArrayList move(int from, int to) { diff --git a/corda/contracts/src/main/java/djmil/cordacheckers/checkers/Move.java b/corda/contracts/src/main/java/djmil/cordacheckers/checkers/Move.java index d6e4196..91bafb5 100644 --- a/corda/contracts/src/main/java/djmil/cordacheckers/checkers/Move.java +++ b/corda/contracts/src/main/java/djmil/cordacheckers/checkers/Move.java @@ -42,7 +42,9 @@ public class Move { if (!allMoves.contains(this)) throw new Exception("Prohibited move"); - // TODO: check for mandatory captures + final Set mandatoryJumps = getMandatoryJumps(board, expectedMoveColor); + if (mandatoryJumps.size() != 0 && !mandatoryJumps.contains(this)) + throw new Exception("A mandatory opponent's stone capture must be performed"); movingStone = movingStone.promoteIfPossible(to); if (board.put(to, movingStone) != null) @@ -66,7 +68,7 @@ public class Move { intersection.retainAll(b); if (intersection.size() != 1) - // A legit move is characterized by single intersection point + // A legit move is characterized by a single intersection point throw new Exception("Prohibited move"); return intersection.iterator().next(); @@ -113,7 +115,7 @@ public class Move { Map.entry(2, Arrays.asList(6, 7, 9, 11)), Map.entry(3, Arrays.asList(7, 8, 10, 12)), Map.entry(4, Arrays.asList(8, 11)), - Map.entry(5, Arrays.asList(1, 9, 14, 9, 11)), + Map.entry(5, Arrays.asList(1, 9, 14)), Map.entry(6, Arrays.asList(1, 2, 9, 10, 13, 15)), Map.entry(7, Arrays.asList(2, 3, 10, 11, 14, 16)), Map.entry(8, Arrays.asList(3, 4, 11, 12, 15)), @@ -149,6 +151,31 @@ public class Move { } } + public static Set getMandatoryJumps(Map board, Stone.Color color) { + Set res = new HashSet(); + + for (Map.Entry entry : board.entrySet()) { + final Integer from = entry.getKey(); + final Stone stone = entry.getValue(); + if (stone.getColor() != color) + continue; + + final Stone.Color opponentsColor = color.opposite(); + final Set allJumps = stone.getJumps(from); + + allJumps.removeIf( j -> { + if (board.get(j.to) != null) + return true; // must be an empty jumpTo tile + final Stone jumpOverStone = board.get(j.jumpOver); + return jumpOverStone == null || jumpOverStone.getColor() != opponentsColor; + }); + + res.addAll(allJumps); + } + + return res; + } + @Override public int hashCode() { final int prime = 31;