@@ -102,68 +102,52 @@ object GameRuleLogic {
102102 return returnSet
103103 }
104104
105- private fun getSwarm (found : MutableSet <Coordinates >, swarm : MutableSet <Coordinates >): MutableSet <Coordinates > {
106- if (swarm.isEmpty() && ! found.isEmpty()) {
107- val field = found.iterator().next()
108- swarm.add(field)
109- found.remove(field)
110- }
105+ /* * Called with a single fish in [swarm] and the [looseFishes] left,
106+ * recursively calling with neighbors added to [swarm] to find the whole swarm. */
107+ private fun getSwarm (looseFishes : Set <Coordinates >, swarm : List <Coordinates >): List <Coordinates > {
108+ val swarmNeighbours =
109+ swarm.flatMap { getDirectNeighbour(it, looseFishes) }
111110
112- var tmpSwarm: MutableSet <Coordinates > = HashSet (swarm)
113- // O(swarm.size()) time
114- for (field in swarm) {
115- // Constant time for both calls (max of 8 neighbors)
116- val neighbours = getDirectNeighbour(field, found)
117- tmpSwarm.addAll(neighbours)
111+ // only search on if any neighbors were added
112+ if (swarmNeighbours.isNotEmpty()) {
113+ return getSwarm(looseFishes - swarmNeighbours, swarm + swarmNeighbours)
118114 }
119-
120- // O(found.size()*swarm.size()) time
121- // FIXME: Might be improved O(swarm.size()) should be possible
122- if (swarm.size != tmpSwarm.size) tmpSwarm = getSwarm(found, tmpSwarm)
123-
124- swarm.addAll(tmpSwarm)
125-
126- found.removeAll(swarm)
127115 return swarm
128116 }
129117
130118 @JvmStatic
131- fun greatestSwarm (fieldsToCheck : Set <Coordinates >): Set <Coordinates > {
119+ fun greatestSwarm (fieldsToCheck : Map <Coordinates , Int >): Map <Coordinates , Int > ? {
132120 // Make a copy, so there will be no conflict with direct calls.
133- val occupiedFields: MutableSet <Coordinates > = HashSet (fieldsToCheck)
134- var greatestSwarm: Set <Coordinates > = HashSet ()
121+ val fieldsLeft = fieldsToCheck.keys.toMutableList()
135122 var maxSize = - 1
123+ var maxSwarm: Map <Coordinates , Int >? = null
136124
137125 // this is a maximum of MAX_FISH iterations, so it is a linear iteration altogether
138- while (! occupiedFields.isEmpty() && occupiedFields.size > maxSize) {
139- val swarm: Set <Coordinates > = getSwarm(occupiedFields, HashSet ())
140- // TODO consider fish weights
141- if (maxSize < swarm.size) {
142- maxSize = swarm.size
143- greatestSwarm = swarm
126+ while (! fieldsLeft.isEmpty() && fieldsLeft.size > maxSize) {
127+ val swarmCoords = getSwarm(fieldsToCheck.keys, listOf (fieldsLeft.removeLast()))
128+ fieldsLeft.removeAll(swarmCoords)
129+ val swarm = fieldsToCheck.filterKeys { swarmCoords.contains(it) }
130+ val swarmSize = swarm.values.sum()
131+ if (maxSize < swarmSize) {
132+ maxSwarm = swarm
133+ maxSize = swarmSize
144134 }
145135 }
146- return greatestSwarm
136+ return maxSwarm
147137 }
148138
149139 @JvmStatic
150- fun greatestSwarm (board : Board , team : ITeam ): Set <Coordinates > {
151- val occupiedFields = board.fieldsForTeam(team)
152- return greatestSwarm(occupiedFields.toHashSet())
153- }
140+ fun greatestSwarmSize (fields : Map <Coordinates , Int >): Int =
141+ greatestSwarm(fields)?.values?.sum() ? : - 1
154142
155143 @JvmStatic
156144 fun greatestSwarmSize (board : Board , team : ITeam ): Int =
157- greatestSwarm(board, team).size
158-
159- @JvmStatic
160- fun greatestSwarmSize (set : Set <Coordinates >): Int =
161- greatestSwarm(set).size
145+ greatestSwarmSize(board.fieldsForTeam(team))
162146
163147 @JvmStatic
164148 fun isSwarmConnected (board : Board , team : ITeam ): Boolean {
165149 val fieldsWithFish = board.fieldsForTeam(team)
166- val numGreatestSwarm : Int = greatestSwarmSize (fieldsWithFish.toHashSet() )
167- return numGreatestSwarm == fieldsWithFish.size
150+ val greatestSwarm = greatestSwarm (fieldsWithFish)
151+ return greatestSwarm?.size == fieldsWithFish.size
168152 }
169153}
0 commit comments