Add MinefieldCreator class
This commit is contained in:
parent
2f3bfc6a96
commit
12b604c3ae
3 changed files with 166 additions and 0 deletions
|
@ -0,0 +1,73 @@
|
||||||
|
package dev.lucasnlm.antimine.common.level.logic
|
||||||
|
|
||||||
|
import dev.lucasnlm.antimine.common.level.models.Area
|
||||||
|
import dev.lucasnlm.antimine.common.level.models.Minefield
|
||||||
|
import kotlin.math.absoluteValue
|
||||||
|
import kotlin.math.floor
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
class MinefieldCreator(
|
||||||
|
private val minefield: Minefield,
|
||||||
|
private val randomGenerator: Random
|
||||||
|
) {
|
||||||
|
private class MapItem(
|
||||||
|
val id: Int,
|
||||||
|
val posX: Int,
|
||||||
|
val posY: Int,
|
||||||
|
var minesAround: Int = 0,
|
||||||
|
var hasMine: Boolean = false
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun createEmptyField(): List<MapItem> {
|
||||||
|
val width = minefield.width
|
||||||
|
val height = minefield.height
|
||||||
|
val fieldSize = width * height
|
||||||
|
|
||||||
|
return (0 until fieldSize).map { index ->
|
||||||
|
val yPosition = floor((index / width).toDouble()).toInt()
|
||||||
|
val xPosition = (index % width)
|
||||||
|
MapItem(
|
||||||
|
index,
|
||||||
|
xPosition,
|
||||||
|
yPosition
|
||||||
|
)
|
||||||
|
}.toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createMap(safeIndex: Int): List<Area> {
|
||||||
|
val minefieldMap = createEmptyField()
|
||||||
|
val safeArea = minefieldMap.getArea(safeIndex)
|
||||||
|
|
||||||
|
// Plant mines and setup number tips
|
||||||
|
minefieldMap
|
||||||
|
.filterNot {
|
||||||
|
((it.posX - safeArea.posX).absoluteValue <= 1 && (it.posY - safeArea.posY).absoluteValue <= 1)
|
||||||
|
}
|
||||||
|
.toSet()
|
||||||
|
.shuffled(randomGenerator)
|
||||||
|
.take(minefield.mines)
|
||||||
|
.onEach {
|
||||||
|
it.hasMine = true
|
||||||
|
it.findNeighbors(minefieldMap).forEach { neighbor ->
|
||||||
|
neighbor.minesAround = neighbor.minesAround + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.onEach {
|
||||||
|
it.minesAround = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return minefieldMap.map {
|
||||||
|
Area(it.id, it.posX, it.posY, it.minesAround, false, it.hasMine)
|
||||||
|
}.toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun List<MapItem>.getArea(id: Int) = this.first { it.id == id }
|
||||||
|
|
||||||
|
private fun MapItem.findNeighbors(onMap: List<MapItem>) = sequenceOf(
|
||||||
|
1 to 0, 1 to 1, 0 to 1, -1 to 1, -1 to 0, -1 to -1, 0 to -1, 1 to -1
|
||||||
|
).map { (x, y) -> getNeighbor(x, y, onMap) }.filterNotNull()
|
||||||
|
|
||||||
|
private fun MapItem.getNeighbor(x: Int, y: Int, onMap: List<MapItem>) = onMap.firstOrNull {
|
||||||
|
(it.posX == this.posX + x) && (it.posY == this.posY + y)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package dev.lucasnlm.antimine.common.level.logic
|
||||||
|
|
||||||
|
import dev.lucasnlm.antimine.common.level.models.Area
|
||||||
|
import dev.lucasnlm.antimine.common.level.models.Mark
|
||||||
|
import kotlin.math.absoluteValue
|
||||||
|
|
||||||
|
class MinefieldHandler(
|
||||||
|
private val minefield: MutableList<Area>
|
||||||
|
) {
|
||||||
|
|
||||||
|
fun openArea(index: Int) {
|
||||||
|
val area = minefield[index]
|
||||||
|
minefield[index] = area.copy(
|
||||||
|
isCovered = false,
|
||||||
|
mark = Mark.None,
|
||||||
|
mistake = area.hasMine
|
||||||
|
)
|
||||||
|
|
||||||
|
if (area.minesAround == 0) {
|
||||||
|
minefield.filter {
|
||||||
|
it.isCovered && ((it.posX - area.posX).absoluteValue == 1 || (it.posY - area.posY).absoluteValue == 1)
|
||||||
|
}.forEach {
|
||||||
|
openArea(it.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun result(): List<Area> = minefield.toList()
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
package dev.lucasnlm.antimine.common.level.logic
|
||||||
|
|
||||||
|
import dev.lucasnlm.antimine.common.level.models.Minefield
|
||||||
|
import org.junit.Assert.*
|
||||||
|
import org.junit.Test
|
||||||
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
class MinefieldCreatorTest {
|
||||||
|
@Test
|
||||||
|
fun testMinefieldCreation() {
|
||||||
|
val creator = MinefieldCreator(Minefield(4, 4, 9), Random(200))
|
||||||
|
val map = creator.createMap(2)
|
||||||
|
assertEquals(
|
||||||
|
listOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15),
|
||||||
|
map.map { it.id }.toList()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testMinefieldCreationMines() {
|
||||||
|
val creator = MinefieldCreator(Minefield(5, 5, 99), Random(200))
|
||||||
|
val map = creator.createMap(12)
|
||||||
|
assertEquals(
|
||||||
|
listOf(
|
||||||
|
1, 1, 1, 1, 1,
|
||||||
|
1, 0, 0, 0, 1,
|
||||||
|
1, 0, 0, 0, 1,
|
||||||
|
1, 0, 0, 0, 1,
|
||||||
|
1, 1, 1, 1, 1
|
||||||
|
),
|
||||||
|
map.map { if (it.hasMine) 1 else 0 }.toList()
|
||||||
|
)
|
||||||
|
assertEquals(16, map.count { it.hasMine })
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testMinefieldCreationMinesTips() {
|
||||||
|
val creator = MinefieldCreator(Minefield(4, 4, 9), Random(200))
|
||||||
|
val map = creator.createMap(2)
|
||||||
|
assertEquals(
|
||||||
|
listOf(
|
||||||
|
0, 2, 0, 0,
|
||||||
|
0, 5, 3, 2,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 5, 0, 0),
|
||||||
|
map.map { it.minesAround }.toList()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testMinefieldCreationPosition() {
|
||||||
|
val creator = MinefieldCreator(Minefield(4, 4, 9), Random(200))
|
||||||
|
val map = creator.createMap(2)
|
||||||
|
assertEquals(
|
||||||
|
listOf(
|
||||||
|
(0 to 0), (1 to 0), (2 to 0), (3 to 0),
|
||||||
|
(0 to 1), (1 to 1), (2 to 1), (3 to 1),
|
||||||
|
(0 to 2), (1 to 2), (2 to 2), (3 to 2),
|
||||||
|
(0 to 3), (1 to 3), (2 to 3), (3 to 3)
|
||||||
|
),
|
||||||
|
map.map { it.posX to it.posY }.toList()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue