Add MinefieldCreator class

This commit is contained in:
Lucas Lima 2020-07-04 10:48:31 -03:00 committed by Lucas Lima
parent 2f3bfc6a96
commit 12b604c3ae
No known key found for this signature in database
GPG key ID: 0259A3F43EC1027A
3 changed files with 166 additions and 0 deletions

View file

@ -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)
}
}

View file

@ -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()
}

View file

@ -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()
)
}
}