Skip to content

Commit e0f3b99

Browse files
committed
feat(plugin26): implement sensible moves via GameRuleLogic
1 parent 2efde1d commit e0f3b99

File tree

3 files changed

+92
-62
lines changed

3 files changed

+92
-62
lines changed

plugin2026/src/main/kotlin/sc/plugin2026/Board.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class Board(gameField: MutableTwoDBoard<FieldS> = randomFields()): RectangularBo
3131

3232
override fun clone(): Board =
3333
Board(Array(gameField.size) { column -> this.gameField[column].clone() })
34-
34+
3535
fun getTeam(pos: Coordinates): Team? =
3636
this[pos].state.team
3737

plugin2026/src/main/kotlin/sc/plugin2026/GameState.kt

Lines changed: 11 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -52,73 +52,23 @@ data class GameState @JvmOverloads constructor(
5252
if (board.getTeam(move.from) != currentTeam) {
5353
throw InvalidMoveException(PiranhaMoveMistake.WRONG_START, move)
5454
}
55-
checkMove(move)?.let { throw InvalidMoveException(it, move) }
56-
val distance = movementDistance(move)
55+
GameRuleLogic.checkMove(board, move)?.let { throw InvalidMoveException(it, move) }
56+
val distance = GameRuleLogic.movementDistance(board, move)
5757
board[move.from].state = FieldState.EMPTY
5858
board[move.from + move.direction.vector * distance].state = FieldState.from(currentTeam)
5959
}
6060

61-
fun movementDistance(move: Move): Int {
62-
var count = 1
63-
var pos = move.from
64-
while(true) {
65-
pos += move.direction
66-
val field = board.getOrNull(pos) ?: break
67-
if(field.state.team != null) {
68-
count++
69-
}
70-
}
71-
pos = move.from
72-
while(true) {
73-
pos += move.direction.opposite
74-
val field = board.getOrNull(pos) ?: break
75-
if(field.state.team != null) {
76-
count++
77-
}
78-
}
79-
return count
80-
}
81-
82-
fun checkMove(move: Move): IMoveMistake? {
83-
val distance = movementDistance(move)
84-
var pos = move.from
85-
var moved = 1
86-
while(moved < distance) {
87-
pos += move.direction
88-
val field = board.getOrNull(pos) ?: return MoveMistake.DESTINATION_OUT_OF_BOUNDS
89-
if(field.state.team == otherTeam) {
90-
return PiranhaMoveMistake.JUMP_OVER_OPPONENT
91-
}
92-
moved++
93-
}
94-
pos += move.direction
95-
val state = board.getOrNull(pos)?.state
96-
return when(state) {
97-
null -> MoveMistake.DESTINATION_OUT_OF_BOUNDS
98-
FieldState.OBSTRUCTED -> MoveMistake.DESTINATION_BLOCKED
99-
else -> {
100-
if(state.team == currentTeam) {
101-
MoveMistake.DESTINATION_BLOCKED_BY_SELF
102-
} else {
103-
null
104-
}
105-
}
106-
}
61+
override fun getSensibleMoves(): List<Move> {
62+
val piranhas = board.filterValues { field -> field.state.team == currentTeam }
63+
val moves = ArrayList<Move>(piranhas.size * 2)
64+
for(piranha in piranhas) {
65+
moves.addAll(GameRuleLogic.possibleMovesFor(board, piranha.key))
66+
}
67+
return moves
10768
}
10869

109-
override fun moveIterator(): Iterator<Move> {
110-
val piranhas = board.filterValues { field -> field.state.team == currentTeam }
111-
val moves = ArrayList<Move>(piranhas.size * 2)
112-
for(piranha in piranhas) {
113-
for(direction in Direction.values()) {
114-
val move = Move(piranha.key, direction)
115-
if(checkMove(move) == null) {
116-
moves.add(move)
117-
}
118-
}
119-
}
120-
return moves.iterator()
121-
}
70+
override fun moveIterator(): Iterator<Move> =
71+
getSensibleMoves().iterator()
12272

12373
override fun clone(): TwoPlayerGameState<Move> =
12474
copy(board = board.clone())

plugin2026/src/main/kotlin/sc/plugin2026/util/GameRuleLogic.kt

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,91 @@
11
package sc.plugin2026.util
22

3+
import sc.api.plugins.Coordinates
34
import sc.api.plugins.Direction
45
import sc.api.plugins.Team
56
import sc.plugin2026.Board
67
import sc.plugin2026.Field
8+
import sc.plugin2026.FieldState
9+
import sc.plugin2026.Move
10+
import sc.plugin2026.PiranhaMoveMistake
11+
import sc.shared.IMoveMistake
12+
import sc.shared.MoveMistake
713

814
object GameRuleLogic {
15+
/** Anzahl der Fische in der Bewegungsachse des Zuges. */
16+
@JvmStatic
17+
fun movementDistance(board: Board, move: Move): Int {
18+
var count = 1
19+
var pos = move.from
20+
while(true) {
21+
pos += move.direction
22+
val field = board.getOrNull(pos) ?: break
23+
if(field.state.team != null) {
24+
count++
25+
}
26+
}
27+
pos = move.from
28+
while(true) {
29+
pos += move.direction.opposite
30+
val field = board.getOrNull(pos) ?: break
31+
if(field.state.team != null) {
32+
count++
33+
}
34+
}
35+
return count
36+
}
37+
38+
/** Prüft ob ein Zug gültig ist.
39+
* @team null wenn der Zug valide ist, sonst ein entsprechender [IMoveMistake]. */
40+
@JvmStatic
41+
fun checkMove(board: Board, move: Move): IMoveMistake? {
42+
val distance = movementDistance(board, move)
43+
var pos = move.from
44+
45+
val team = board[move.from].state.team ?: return MoveMistake.START_EMPTY
46+
val opponent = team.opponent()
47+
48+
var moved = 1
49+
while(moved < distance) {
50+
pos += move.direction
51+
val field = board.getOrNull(pos) ?: return MoveMistake.DESTINATION_OUT_OF_BOUNDS
52+
if(field.state.team == opponent) {
53+
return PiranhaMoveMistake.JUMP_OVER_OPPONENT
54+
}
55+
moved++
56+
}
57+
pos += move.direction
58+
val state = board.getOrNull(pos)?.state
59+
return when(state) {
60+
null -> MoveMistake.DESTINATION_OUT_OF_BOUNDS
61+
FieldState.OBSTRUCTED -> MoveMistake.DESTINATION_BLOCKED
62+
else -> {
63+
if(state.team == team) {
64+
MoveMistake.DESTINATION_BLOCKED_BY_SELF
65+
} else {
66+
null
67+
}
68+
}
69+
}
70+
}
71+
72+
@JvmStatic
73+
fun possibleMovesFor(board: Board, pos: Coordinates): Collection<Move> {
74+
val moves: MutableList<Move> = ArrayList()
75+
for(direction in Direction.values()) {
76+
val move = Move(pos, direction)
77+
if(checkMove(board, move) == null) {
78+
moves.add(move)
79+
}
80+
}
81+
return moves
82+
}
83+
84+
fun possibleMovesSequence(board: Board, pos: Coordinates): Sequence<Move> =
85+
Direction.values().asSequence()
86+
.map { direction -> Move(pos, direction)}
87+
.filter { move -> checkMove(board, move) == null }
88+
989
private fun getDirectNeighbour(board: Board, f: Field, parentSet: Set<Field>): Set<Field> {
1090
val returnSet: MutableSet<Field> = java.util.HashSet()
1191
for(i in -1..1) {

0 commit comments

Comments
 (0)