Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ C C C C C C C C C C
- 높이와 너비, 지뢰 개수를 입력받을 수 있다.
- [x] Test 1 : 높이와 너비, 지뢰 개수를 입력받아 MineMap 객체를 생성할 수 있다.
- 지뢰 갯수가 높이와 너비의 곱보다 크지 못하도록 설정함
- [x] Test 2 : mineMap을 입력받으면 주위에 몇 개의 mine이 있는지 표시할 수 있다.
- 각 EmptyElement에서 mineCnt 필드를 갖도록 함
- 주위를 순회하며 지뢰의 갯수를 mineCnt에 기록
- 지뢰는 눈에 잘 띄는 것으로 표기한다.
- MineMap 출력하는 기능 추가
- 지뢰는 가급적 랜덤에 가깝게 배치한다.
Expand Down
16 changes: 16 additions & 0 deletions src/main/kotlin/MineCounter.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import domain.MapElement
import domain.MineMap

object MineCounter {
// mineMap을 입력받아 한 바퀴 순회하면서 cnt 계산
fun count(mineMap: MineMap) {
mineMap.elements.forEach {
it.forEach {
elementCount(it)
}
}
}

private fun elementCount(mapElement: MapElement) {
}
}
23 changes: 21 additions & 2 deletions src/main/kotlin/domain/EmptyElement.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,28 @@
package domain

class EmptyElement : MapElement {
override val displayCharacter = EMPTY_ELEMENT_CHAR
class EmptyElement private constructor(override val displayCharacter: String, override val location: Location) : MapElement {
var mineCnt = 0

// 주변에 지뢰가 몇 개 있는지 계산하여 mineCnt에 업데이트
fun countMine(mineMap: MineMap) {
val directions = listOf(
Pair(-1, -1), Pair(-1, 0), Pair(-1, 1),
Pair(0, -1), Pair(0, 1),
Pair(1, -1), Pair(1, 0), Pair(1, 1)
)

for (direction in directions) {
val row = location.row + direction.first
val col = location.column + direction.second
mineCnt += if (mineMap.isMine(Location(row, col))) 1 else 0
}
}

companion object {
private const val EMPTY_ELEMENT_CHAR = "C"

fun create(x: Int, y: Int): EmptyElement {
return EmptyElement(EMPTY_ELEMENT_CHAR, Location(x, y))
}
}
}
2 changes: 2 additions & 0 deletions src/main/kotlin/domain/MapElement.kt
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
package domain
// TODO : 얘가 Location을 갖도록 하고, EmptyElement는 해당 location 주위를 돌며 mine갯수 카운트하도록 설정
interface MapElement {
val displayCharacter: String
val location: Location
}
8 changes: 5 additions & 3 deletions src/main/kotlin/domain/Mine.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package domain

class Mine : MapElement {

override val displayCharacter = MINE_DISPLAY_CHAR
class Mine private constructor(override val displayCharacter: String, override val location: Location) : MapElement {

companion object {
private const val MINE_DISPLAY_CHAR = "*"

fun create(x: Int, y: Int): Mine {
return Mine(MINE_DISPLAY_CHAR, Location(x, y))
}
}
}
8 changes: 7 additions & 1 deletion src/main/kotlin/domain/MineMap.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,10 @@ package domain

class MineMap(
val elements: List<List<MapElement>>
)
) {
fun isMine(location: Location): Boolean {
if (location.row < 0 || location.row >= elements.size || location.column < 0 || location.column >= elements[0].size) return false

return elements[location.row][location.column] is Mine
}
}
23 changes: 14 additions & 9 deletions src/main/kotlin/domain/MineMapGenerator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,29 @@ import util.RandomLocationGenerator
object MineMapGenerator {

fun createMineMap(height: Int, width: Int, numOfMine: Int): MineMap {
require(numOfMine <= height * width) { "지뢰의 수는 지도의 크기(가로*세로)보다 많을 수 없습니다."}
require(numOfMine <= height * width) { "지뢰의 수는 지도의 크기(가로*세로)보다 많을 수 없습니다." }

//mine 위치 정보 받아오기
// mine 위치 정보 받아오기
val mineLocations = mutableSetOf<Location>()
while (mineLocations.size < numOfMine) {
val locationGenerator = RandomLocationGenerator(height, width)
val randomLocation = locationGenerator.generate()
mineLocations.add(randomLocation)
}

//mine 위치 정보를 바탕으로 지도 제작
// mine 위치 정보를 바탕으로 지도 제작
val elementLocations = mutableListOf<List<MapElement>>()
for (i in 0 until height) {
elementLocations += createRow(i, width, mineLocations)
}

return MineMap(elementLocations.toList())
val mineMap = MineMap(elementLocations.toList())

// EmptyElement에 대해 주변 지뢰의 수 기입
mineMap.elements.flatMap { innerList -> innerList.filterIsInstance<EmptyElement>() }
.forEach { emptyElement -> emptyElement.countMine(mineMap) }

return mineMap
}

private fun createRow(
Expand All @@ -36,15 +42,14 @@ object MineMapGenerator {
val minesOfRow = mineLocations.filter { it.row == rowNum }
.map { it.column }

for (i in 0 until rowLen) {
row += getElement(i, minesOfRow)
for (y in 0 until rowLen) {
row += getElement(rowNum, y, minesOfRow)
}

return row.toList()

}

private fun getElement(index: Int, minesOfRow: List<Int>): MapElement {
return if (minesOfRow.contains(index)) Mine() else EmptyElement()
private fun getElement(x: Int, y: Int, minesOfRow: List<Int>): MapElement {
return if (minesOfRow.contains(y)) Mine.create(x, y) else EmptyElement.create(x, y)
}
}
5 changes: 2 additions & 3 deletions src/main/kotlin/view/DisplayView.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package view

import domain.EmptyElement
import domain.MapElement
import domain.MineMap

Expand All @@ -14,7 +15,5 @@ object DisplayView {
}
}

private fun displayElement(element: MapElement): String {
return element.displayCharacter
}
private fun displayElement(element: MapElement): String = if (element is EmptyElement) element.mineCnt.toString() else element.displayCharacter
}
29 changes: 29 additions & 0 deletions src/test/kotlin/domain/EmptyElementTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package domain

import io.kotest.matchers.shouldBe
import org.junit.jupiter.api.Test

internal class EmptyElementTest {
@Test
fun `주어진 위치 주위의 지뢰 갯수를 셀 수 있다`() {
/**
* C C C
* * C *
* C C C
*/
val elements = listOf(
listOf(EmptyElement.create(0, 0), EmptyElement.create(0, 1), EmptyElement.create(0, 2)),
listOf(Mine.create(1, 0), EmptyElement.create(1, 1), Mine.create(1, 2)),
listOf(EmptyElement.create(2, 0), EmptyElement.create(2, 1), EmptyElement.create(2, 2))
)
val mineMap = MineMap(elements)
val elementWithMineCntOne = elements[0][0] as EmptyElement
val elementWithMineCntTwo = elements[0][1] as EmptyElement

elementWithMineCntOne.countMine(mineMap)
elementWithMineCntTwo.countMine(mineMap)

elementWithMineCntOne.mineCnt shouldBe 1
elementWithMineCntTwo.mineCnt shouldBe 2
}
}