Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Step1: 지뢰 찾기(그리기) #423

Open
wants to merge 6 commits into
base: wilgur513
Choose a base branch
from
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
45 changes: 45 additions & 0 deletions src/main/kotlin/Main.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
fun main() {
val height = inputHeight()
val width = inputWidth()
val mineSize = inputMineSize()

val mineSweeper = MineSweeper(width, height, mineSize, RandomMinePositionsGenerator(width, height))
printMineSweeperMap(mineSweeper)
}

private fun inputHeight(): Int {
println("높이를 입력하세요.")
return readln().toInt()
}

private fun inputWidth(): Int {
println("너비를 입력하세요.")
return readln().toInt()
}

private fun inputMineSize(): Int {
println("지뢰는 몇 개인가요?")
return readln().toInt()
}

private fun printMineSweeperMap(mineSweeper: MineSweeper) {
println("지뢰찾기 게임 시작")
(0 until mineSweeper.height).forEach{ y ->
printRowOfMineSweeperMap(mineSweeper, y)
}
}

private fun printRowOfMineSweeperMap(mineSweeper: MineSweeper, y: Int) {
val row = (0 until mineSweeper.width)
.map { x -> Position(y, x) }
.map { mineSweeper.cells().getValue(it) }
.joinToString(separator = " ") { statusToText(it) }
println(row)
}

private fun statusToText(status: Status): String {
return when(status) {
Status.EMPTY -> "C"
Status.MINE -> "*"
}
}
4 changes: 4 additions & 0 deletions src/main/kotlin/MinePositionGenerator.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
fun interface MinePositionGenerator {

fun generate(size: Int): List<Position>
}
21 changes: 21 additions & 0 deletions src/main/kotlin/MineSweeper.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
class MineSweeper(
val width: Int,
val height: Int,
mineSize: Int,
minePositionGenerator: MinePositionGenerator
) {
private val minePositions = minePositionGenerator.generate(mineSize)

fun cells(): Map<Position, Status> {
return Position.createInRange(width, height)
.associateWith { cellValue(it) }
}

private fun cellValue(position: Position): Status {
return if (minePositions.contains(position)) {
Status.MINE
} else {
Status.EMPTY
}
}
}
11 changes: 11 additions & 0 deletions src/main/kotlin/Position.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
data class Position(val y: Int, val x: Int) {
companion object {
fun createInRange(width: Int, height: Int): List<Position> {
return (0 until width).flatMap { x ->
(0 until height).map { y ->
Position(y, x)
}
}
}
}
}
12 changes: 12 additions & 0 deletions src/main/kotlin/RandomMinePositionsGenerator.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class RandomMinePositionsGenerator(
private val maxWidth: Int,
private val maxHeight: Int,
): MinePositionGenerator {
override fun generate(size: Int): List<Position> {
require(size <= maxWidth * maxHeight) { "생성할 수 있는 지뢰 위치 갯수보다 많이 생성하려합니다." }

return Position.createInRange(maxWidth, maxHeight)
.shuffled()
.subList(0, size)
}
}
4 changes: 4 additions & 0 deletions src/main/kotlin/Status.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
enum class Status {
EMPTY,
MINE,
}
43 changes: 43 additions & 0 deletions src/test/kotlin/MineSweeperTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.MethodSource

class MineSweeperTest {

@ParameterizedTest
@MethodSource("minePositionsForDrawMap")
fun `지뢰찾기 맵을 그린다`(minePositions: List<Position>) {
val mineSweeper = MineSweeper(5, 5, minePositions.size) { _ -> minePositions }

val cells = mineSweeper.cells()

assertThat(cells)
.isEqualTo(expectedMap(minePositions, 5, 5))
}

private fun expectedMap(minePositions: List<Position>, width:Int, height: Int): Map<Position, Status> {
val expected = allPositions(width, height)
.associateWith { Status.EMPTY }
.toMutableMap()
minePositions.forEach { expected[it] = Status.MINE }
return expected
}

private fun allPositions(width: Int, height: Int): List<Position> {
return (0 until width).flatMap { x ->
(0 until height).map { y ->
Position(y, x)
}
}
}

companion object {
@JvmStatic
fun minePositionsForDrawMap(): List<List<Position>> {
return listOf(
listOf(),
listOf(Position(0, 0), Position(1, 1), Position(2, 2))
)
}
}
}
29 changes: 29 additions & 0 deletions src/test/kotlin/RandomMinePositionsGeneratorTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
import java.lang.IllegalArgumentException

class RandomMinePositionsGeneratorTest {

@Test
fun `랜덤 지뢰 위치 생성`() {
val generator = RandomMinePositionsGenerator(5, 5)

val actual = generator.generate(5)

assertThat(actual).hasSize(5)
assertThat(actual)
.hasSize(5)
.allMatch { it.x in (0 until 5) }
.allMatch { it.y in (0 until 5) }
}

@Test
fun `생성할 수 있는 지뢰 위치 갯수 넘길 경우 예외 발`() {
val generator = RandomMinePositionsGenerator(2, 2)

assertThrows<IllegalArgumentException> {
generator.generate(5)
}
}
}