Skip to content

Commit d013b19

Browse files
committed
fix(plugin26): swarm size calculation
The loop sometimes exited too early because it did not keep fish sizes in mind
1 parent 4d8d9b5 commit d013b19

File tree

2 files changed

+14
-6
lines changed

2 files changed

+14
-6
lines changed

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

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,15 @@ object GameRuleLogic {
8989
.map { direction -> Move(pos, direction)}
9090
.filter { move -> checkMove(board, move) == null }
9191

92-
private fun getDirectNeighbour(f: Coordinates, parentSet: Set<Coordinates>): Set<Coordinates> {
93-
val returnSet: MutableSet<Coordinates> = HashSet()
92+
private fun getDirectNeighbour(f: Coordinates, parentSet: Collection<Coordinates>): Collection<Coordinates> {
93+
val returnSet = ArrayList<Coordinates>(8)
9494
for(i in -1..1) {
9595
for(j in -1..1) {
9696
val x = f.x + i
9797
val y = f.y + j
98-
if(x < 0 || x >= PiranhaConstants.BOARD_LENGTH || y < 0 || y >= PiranhaConstants.BOARD_LENGTH || (i == 0 && j == 0)) continue
98+
if(x < 0 || x >= PiranhaConstants.BOARD_LENGTH ||
99+
y < 0 || y >= PiranhaConstants.BOARD_LENGTH ||
100+
(i == 0 && j == 0)) continue
99101

100102
val coord = Coordinates(x, y)
101103
if(parentSet.contains(coord)) {
@@ -108,7 +110,7 @@ object GameRuleLogic {
108110

109111
/** Called with a single fish in [swarm] and the [looseFishes] left,
110112
* recursively calling with neighbors added to [swarm] to find the whole swarm. */
111-
private fun getSwarm(looseFishes: Set<Coordinates>, swarm: List<Coordinates>): List<Coordinates> {
113+
private fun getSwarm(looseFishes: Collection<Coordinates>, swarm: List<Coordinates>): List<Coordinates> {
112114
val swarmNeighbours =
113115
swarm.flatMap { getDirectNeighbour(it, looseFishes) }
114116

@@ -127,11 +129,15 @@ object GameRuleLogic {
127129
var maxSwarm: Map<Coordinates, Int>? = null
128130

129131
// this is a maximum of MAX_FISH iterations, so it is a linear iteration altogether
130-
while(!fieldsLeft.isEmpty() && fieldsLeft.size > maxSize) {
131-
val swarmCoords = getSwarm(fieldsToCheck.keys, listOf(fieldsLeft.removeLast()))
132+
while(!fieldsLeft.isEmpty() && fieldsLeft.size * 3 > maxSize) {
133+
val swarmStart = listOf(fieldsLeft.removeLast())
134+
//println("$swarmStart - $fieldsLeft")
135+
val swarmCoords = getSwarm(fieldsLeft, swarmStart)
136+
132137
fieldsLeft.removeAll(swarmCoords)
133138
val swarm = fieldsToCheck.filterKeys { swarmCoords.contains(it) }
134139
val swarmSize = swarm.values.sum()
140+
//println("$swarmCoords - $swarm - $swarmSize")
135141
if(maxSize < swarmSize) {
136142
maxSwarm = swarm
137143
maxSize = swarmSize

plugin2026/src/test/kotlin/sc/plugin2026/GameRuleLogicTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import io.kotest.inspectors.forAll
55
import io.kotest.matchers.*
66
import io.kotest.matchers.collections.*
77
import io.kotest.matchers.ints.*
8+
import io.kotest.matchers.maps.*
89
import sc.api.plugins.Coordinates
910
import sc.api.plugins.Direction
1011
import sc.api.plugins.Team
@@ -31,6 +32,7 @@ class GameRuleLogicTest: FunSpec({
3132
val board = Board(arrayOf(arrayOf(FieldState.ONE_S, FieldState.ONE_L, FieldState.TWO_M, FieldState.ONE_L)))
3233
GameRuleLogic.isSwarmConnected(board, Team.ONE) shouldBe false
3334
GameRuleLogic.isSwarmConnected(board, Team.TWO) shouldBe true
35+
GameRuleLogic.greatestSwarm(board.fieldsForTeam(Team.ONE))?.shouldHaveSize(2)
3436
GameRuleLogic.greatestSwarmSize(board, Team.ONE) shouldBe 4
3537
GameRuleLogic.greatestSwarmSize(board, Team.TWO) shouldBe 2
3638
}

0 commit comments

Comments
 (0)