diff --git a/games/blokus/src/main/kotlin/sc/plugin2027/GameState.kt b/games/blokus/src/main/kotlin/sc/plugin2027/GameState.kt index 4bb096293..fc82f1f32 100644 --- a/games/blokus/src/main/kotlin/sc/plugin2027/GameState.kt +++ b/games/blokus/src/main/kotlin/sc/plugin2027/GameState.kt @@ -323,7 +323,7 @@ data class GameState @JvmOverloads constructor( * @return Liste der möglichen Züge der aktuellen Spielerfarbe. */ override fun getSensibleMoves(): List { - val possibleMoves = GameRuleLogic.getAllPossibleMoves(this) + val possibleMoves = GameRuleLogic.getFilteredPossibleMoves(this) if (possibleMoves.isEmpty()) { return listOf(SkipMove(currentColor)) } diff --git a/games/blokus/src/main/kotlin/sc/plugin2027/util/GamePlugin.kt b/games/blokus/src/main/kotlin/sc/plugin2027/util/GamePlugin.kt index 9748b7cf1..179523118 100644 --- a/games/blokus/src/main/kotlin/sc/plugin2027/util/GamePlugin.kt +++ b/games/blokus/src/main/kotlin/sc/plugin2027/util/GamePlugin.kt @@ -40,6 +40,7 @@ class GamePlugin: IGamePlugin { override val scoreDefinition = Companion.scoreDefinition + // FIXME unused override val turnLimit: Int = Constants.ROUND_LIMIT * 2 diff --git a/games/blokus/src/main/kotlin/sc/plugin2027/util/GameRuleLogic.kt b/games/blokus/src/main/kotlin/sc/plugin2027/util/GameRuleLogic.kt index f7a206ce3..36b1a2a78 100644 --- a/games/blokus/src/main/kotlin/sc/plugin2027/util/GameRuleLogic.kt +++ b/games/blokus/src/main/kotlin/sc/plugin2027/util/GameRuleLogic.kt @@ -324,38 +324,73 @@ object GameRuleLogic { getPossibleMoves(gameState) } + /** + * In den ersten fünf Runden gibt diese Methode nur die Liste der [SetMove]s + * mit Pentominos zurück. + * Ansonsten eine Liste an möglichen [SetMove]s zurück. + * Diese Liste enthält auch mögliche Startzüge. + * + * @param gameState der aktuelle Spielstand + * @return eine Liste aller möglichen [SetMove]s für den aktuellen Spielstand + */ + @JvmStatic + fun getFilteredPossibleMoves(gameState: GameState): List = + if (isFirstMove(gameState)) { + getPossibleStartMoves(gameState, true) + } else if (gameState.round <= 5) { + getPentominoMoves(gameState) + } else { + getPossibleMoves(gameState) + } + + /** + * Gibt alle möglichen [SetMove]s für den ersten Zug zurück. + * + * @param gameState der aktuelle Spielstand + * @return eine Liste aller möglichen [SetMove]s für den ersten Zug + */ + fun getPossibleStartMoves(gameState: GameState): List = getPossibleStartMoves(gameState, false) + /** * Gibt alle möglichen [SetMove]s für den ersten Zug zurück. * * @param gameState der aktuelle Spielstand + * @param filter ob die Startzüge gefiltert werden sollen. Falls ja, werden + * für den ersten Spieler jedes Teams nur die obere linke Hälfte und für + * den zweiten Spieler jedes Teams nur die untere rechte Hälfte + * vorgeschlagen. * @return eine Liste aller möglichen [SetMove]s für den ersten Zug */ @JvmStatic - fun getPossibleStartMoves(gameState: GameState): List { + fun getPossibleStartMoves(gameState: GameState, filter: Boolean): List { val moves = ArrayList() val filteredMoves = ArrayList() val kind = gameState.startPiece for (variant: Map.Entry, Pair> in kind.variants) { val borderCoordinates: ArrayList = ArrayList() - // Add top border - // x from [0,16], y = 0 - for (x in 0 until Constants.BOARD_LENGTH - variant.key.area.dx - 1) { - borderCoordinates.add(Coordinates(x, 0)) - } - // Add right border - // x = 20-2-1 = 17, y from [0,16] - for (y in 0 until Constants.BOARD_LENGTH - variant.key.area.dy - 1) { - borderCoordinates.add(Coordinates(Constants.BOARD_LENGTH - variant.key.area.dx - 1, y)) - } - // Add bottom border - // x from [1, 17] = 17, y = 20 - 2 - 1 = 17 - for (x in 1 until Constants.BOARD_LENGTH - variant.key.area.dx) { - borderCoordinates.add(Coordinates(x, Constants.BOARD_LENGTH - variant.key.area.dy - 1)) + if (!filter || gameState.currentColor == Color.BLUE || gameState.currentColor == Color.YELLOW) { + // Add top border + // x from [0,16], y = 0 + for(x in 0 until Constants.BOARD_LENGTH - variant.key.area.dx - 1) { + borderCoordinates.add(Coordinates(x, 0)) + } + // Add left border + // x = 0, y from [1, 17] + for (y in 1 until Constants.BOARD_LENGTH - variant.key.area.dy) { + borderCoordinates.add(Coordinates(0, y)) + } } - // Add left border - // x = 0, y from [1, 17] - for (y in 1 until Constants.BOARD_LENGTH - variant.key.area.dy) { - borderCoordinates.add(Coordinates(0, y)) + if (!filter || gameState.currentColor == Color.RED || gameState.currentColor == Color.GREEN) { + // Add right border + // x = 20-2-1 = 17, y from [0,16] + for (y in 0 until Constants.BOARD_LENGTH - variant.key.area.dy - 1) { + borderCoordinates.add(Coordinates(Constants.BOARD_LENGTH - variant.key.area.dx - 1, y)) + } + // Add bottom border + // x from [1, 17] = 17, y = 20 - 2 - 1 = 17 + for (x in 1 until Constants.BOARD_LENGTH - variant.key.area.dx) { + borderCoordinates.add(Coordinates(x, Constants.BOARD_LENGTH - variant.key.area.dy - 1)) + } } for (borderCoordinate in borderCoordinates) { val move = SetMove(Piece(gameState.currentColor, kind, variant.key, borderCoordinate)) @@ -386,6 +421,24 @@ object GameRuleLogic { return moves } + /** + * Gib eine Sammlung aller möglichen [SetMove]s zurück (ohne den Startzug). + * + * @param gameState der aktuelle Spielstand + * @return eine Sammlung aller möglichen [SetMove]s (ohne den Startzug) + */ + @JvmStatic + fun getPentominoMoves(gameState: GameState): List { + val validFields: Set = getValidFields(gameState.board, gameState.currentColor) + val moves: ArrayList = ArrayList() + for (shape in gameState.undeployedPieceShapes()) { + if (shape.size == 5) { + moves.addAll(getPossibleMovesForShape(gameState, shape, validFields)) + } + } + return moves + } + /** * Gib die Menge aller möglichen [SetMove]s für die gegebene [PieceShape] zurück. */ diff --git a/games/blokus/src/test/kotlin/sc/plugin2027/GameRuleLogicTest.kt b/games/blokus/src/test/kotlin/sc/plugin2027/GameRuleLogicTest.kt index 4a1d0e03d..f5345c4f2 100644 --- a/games/blokus/src/test/kotlin/sc/plugin2027/GameRuleLogicTest.kt +++ b/games/blokus/src/test/kotlin/sc/plugin2027/GameRuleLogicTest.kt @@ -107,7 +107,7 @@ class GameRuleLogicTest: WordSpec({ * 4 // 4 sides to consider * 17 // 18 places on a side - 1 to remove duplicates for other side ) - val actualMoves = state.getSensibleMoves() + val actualMoves = GameRuleLogic.getAllPossibleMoves(state) "has no duplicates" { actualMoves.size shouldBe actualMoves.toSet().size }