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