From 2b9f780af552c90c1d9ebc5a16d383af4a5eb759 Mon Sep 17 00:00:00 2001 From: "verus.j" Date: Fri, 29 Dec 2023 18:08:12 +0900 Subject: [PATCH 1/6] =?UTF-8?q?feature:=20=EC=A7=80=EB=A2=B0=EA=B0=80=20?= =?UTF-8?q?=EC=97=86=EB=8A=94=20=EB=A7=B5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/MineSweeper.kt | 13 +++++++++++++ src/main/kotlin/Position.kt | 1 + src/test/kotlin/MineSweeperTest.kt | 23 +++++++++++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 src/main/kotlin/MineSweeper.kt create mode 100644 src/main/kotlin/Position.kt create mode 100644 src/test/kotlin/MineSweeperTest.kt diff --git a/src/main/kotlin/MineSweeper.kt b/src/main/kotlin/MineSweeper.kt new file mode 100644 index 000000000..87019dfa6 --- /dev/null +++ b/src/main/kotlin/MineSweeper.kt @@ -0,0 +1,13 @@ + +class MineSweeper( + private val width: Int, + private val height: Int, +) { + fun cells(): Map { + return (0 until width).flatMap { x -> + (0 until height).map { y-> + Position(y, x) to "C" + } + }.toMap() + } +} diff --git a/src/main/kotlin/Position.kt b/src/main/kotlin/Position.kt new file mode 100644 index 000000000..309e360d2 --- /dev/null +++ b/src/main/kotlin/Position.kt @@ -0,0 +1 @@ +data class Position(val y: Int, val x: Int) diff --git a/src/test/kotlin/MineSweeperTest.kt b/src/test/kotlin/MineSweeperTest.kt new file mode 100644 index 000000000..fb1514448 --- /dev/null +++ b/src/test/kotlin/MineSweeperTest.kt @@ -0,0 +1,23 @@ +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +class MineSweeperTest { + + @Test + fun `지뢰가 없는 맵을 그린다`() { + val mineSweeper = MineSweeper(5, 5) + + val cells = mineSweeper.cells() + + assertThat(cells) + .containsExactlyInAnyOrderEntriesOf(allPositions(5, 5).associateWith { "C" }) + } + + private fun allPositions(width: Int, height: Int): List { + return (0 until width).flatMap { x -> + (0 until height).map { y -> + Position(y, x) + } + } + } +} From c5b9aff418b1cb5e8a6454e22dd381835e54f788 Mon Sep 17 00:00:00 2001 From: "verus.j" Date: Fri, 29 Dec 2023 18:57:05 +0900 Subject: [PATCH 2/6] =?UTF-8?q?feat:=20=EC=A7=80=EB=A2=B0=EA=B0=80=20?= =?UTF-8?q?=EC=9E=88=EB=8A=94=20=EB=A7=B5=20=EA=B7=B8=EB=A6=AC=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/MineSweeper.kt | 25 ++++++++++++++++++++----- src/main/kotlin/Status.kt | 4 ++++ src/test/kotlin/MineSweeperTest.kt | 30 +++++++++++++++++++++++++----- 3 files changed, 49 insertions(+), 10 deletions(-) create mode 100644 src/main/kotlin/Status.kt diff --git a/src/main/kotlin/MineSweeper.kt b/src/main/kotlin/MineSweeper.kt index 87019dfa6..1eaaebb66 100644 --- a/src/main/kotlin/MineSweeper.kt +++ b/src/main/kotlin/MineSweeper.kt @@ -1,13 +1,28 @@ - class MineSweeper( private val width: Int, private val height: Int, + mineSize: Int, + generateMinePositions: (Int) -> List ) { - fun cells(): Map { + private val minePositions = generateMinePositions(mineSize) + + fun cells(): Map { + return allPositions().associateWith { cellValue(it) } + } + + private fun allPositions(): List { return (0 until width).flatMap { x -> - (0 until height).map { y-> - Position(y, x) to "C" + (0 until height).map { y -> + Position(y, x) } - }.toMap() + } + } + + private fun cellValue(position: Position): Status { + return if (minePositions.contains(position)) { + Status.MINE + } else { + Status.EMPTY + } } } diff --git a/src/main/kotlin/Status.kt b/src/main/kotlin/Status.kt new file mode 100644 index 000000000..a933c1948 --- /dev/null +++ b/src/main/kotlin/Status.kt @@ -0,0 +1,4 @@ +enum class Status { + EMPTY, + MINE, +} diff --git a/src/test/kotlin/MineSweeperTest.kt b/src/test/kotlin/MineSweeperTest.kt index fb1514448..f434a9dc0 100644 --- a/src/test/kotlin/MineSweeperTest.kt +++ b/src/test/kotlin/MineSweeperTest.kt @@ -1,16 +1,26 @@ import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.MethodSource class MineSweeperTest { - @Test - fun `지뢰가 없는 맵을 그린다`() { - val mineSweeper = MineSweeper(5, 5) + @ParameterizedTest + @MethodSource("minePositionsForDrawMap") + fun `지뢰찾기 맵을 그린다`(minePositions: List) { + val mineSweeper = MineSweeper(5, 5, minePositions.size) { _ -> minePositions } val cells = mineSweeper.cells() assertThat(cells) - .containsExactlyInAnyOrderEntriesOf(allPositions(5, 5).associateWith { "C" }) + .isEqualTo(expectedMap(minePositions, 5, 5)) + } + + private fun expectedMap(minePositions: List, width:Int, height: Int): Map { + 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 { @@ -20,4 +30,14 @@ class MineSweeperTest { } } } + + companion object { + @JvmStatic + fun minePositionsForDrawMap(): List> { + return listOf( + listOf(), + listOf(Position(0, 0), Position(1, 1), Position(2, 2)) + ) + } + } } From 02d248753faf477d5014f64ddc04f26f536b04a8 Mon Sep 17 00:00:00 2001 From: "verus.j" Date: Fri, 29 Dec 2023 19:11:19 +0900 Subject: [PATCH 3/6] =?UTF-8?q?feat:=20=EB=9E=9C=EB=8D=A4=20=EC=A7=80?= =?UTF-8?q?=EB=A2=B0=20=EC=9C=84=EC=B9=98=20=EC=83=9D=EC=84=B1=EA=B8=B0=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/RandomMinePositionsGenerator.kt | 15 ++++++++++ .../RandomMinePositionsGeneratorTest.kt | 29 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 src/main/kotlin/RandomMinePositionsGenerator.kt create mode 100644 src/test/kotlin/RandomMinePositionsGeneratorTest.kt diff --git a/src/main/kotlin/RandomMinePositionsGenerator.kt b/src/main/kotlin/RandomMinePositionsGenerator.kt new file mode 100644 index 000000000..d42438805 --- /dev/null +++ b/src/main/kotlin/RandomMinePositionsGenerator.kt @@ -0,0 +1,15 @@ +class RandomMinePositionsGenerator( + private val maxWidth: Int, + private val maxHeight: Int, +) { + fun generate(size: Int): List { + require(size <= maxWidth * maxHeight) { "생성할 수 있는 지뢰 위치 갯수보다 많이 생성하려합니다." } + + return (0 until maxWidth).flatMap { x -> + (0 until maxHeight).map { y -> + Position(y, x) + } + }.shuffled() + .subList(0, size) + } +} diff --git a/src/test/kotlin/RandomMinePositionsGeneratorTest.kt b/src/test/kotlin/RandomMinePositionsGeneratorTest.kt new file mode 100644 index 000000000..938ce8163 --- /dev/null +++ b/src/test/kotlin/RandomMinePositionsGeneratorTest.kt @@ -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 { + generator.generate(5) + } + } +} From 43592697d93d835b3a2cda01e9a8b72eca47e09d Mon Sep 17 00:00:00 2001 From: "verus.j" Date: Fri, 29 Dec 2023 19:14:20 +0900 Subject: [PATCH 4/6] =?UTF-8?q?refactor:=20=EC=9C=84=EC=B9=98=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=ED=8C=A9=ED=84=B0=EB=A6=AC=20=EB=A7=A4=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/MineSweeper.kt | 11 ++--------- src/main/kotlin/Position.kt | 12 +++++++++++- src/main/kotlin/RandomMinePositionsGenerator.kt | 9 +++------ 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/main/kotlin/MineSweeper.kt b/src/main/kotlin/MineSweeper.kt index 1eaaebb66..241290018 100644 --- a/src/main/kotlin/MineSweeper.kt +++ b/src/main/kotlin/MineSweeper.kt @@ -7,15 +7,8 @@ class MineSweeper( private val minePositions = generateMinePositions(mineSize) fun cells(): Map { - return allPositions().associateWith { cellValue(it) } - } - - private fun allPositions(): List { - return (0 until width).flatMap { x -> - (0 until height).map { y -> - Position(y, x) - } - } + return Position.createInRange(width, height) + .associateWith { cellValue(it) } } private fun cellValue(position: Position): Status { diff --git a/src/main/kotlin/Position.kt b/src/main/kotlin/Position.kt index 309e360d2..95afcd15c 100644 --- a/src/main/kotlin/Position.kt +++ b/src/main/kotlin/Position.kt @@ -1 +1,11 @@ -data class Position(val y: Int, val x: Int) +data class Position(val y: Int, val x: Int) { + companion object { + fun createInRange(width: Int, height: Int): List { + return (0 until width).flatMap { x -> + (0 until height).map { y -> + Position(y, x) + } + } + } + } +} diff --git a/src/main/kotlin/RandomMinePositionsGenerator.kt b/src/main/kotlin/RandomMinePositionsGenerator.kt index d42438805..33544ea6c 100644 --- a/src/main/kotlin/RandomMinePositionsGenerator.kt +++ b/src/main/kotlin/RandomMinePositionsGenerator.kt @@ -5,11 +5,8 @@ class RandomMinePositionsGenerator( fun generate(size: Int): List { require(size <= maxWidth * maxHeight) { "생성할 수 있는 지뢰 위치 갯수보다 많이 생성하려합니다." } - return (0 until maxWidth).flatMap { x -> - (0 until maxHeight).map { y -> - Position(y, x) - } - }.shuffled() - .subList(0, size) + return Position.createInRange(maxWidth, maxHeight) + .shuffled() + .subList(0, size) } } From 4aace04c2dcc970768da6710948277c700dbb8c3 Mon Sep 17 00:00:00 2001 From: "verus.j" Date: Fri, 29 Dec 2023 19:16:54 +0900 Subject: [PATCH 5/6] =?UTF-8?q?refactor:=20MinePositionGenerator=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/MinePositionGenerator.kt | 4 ++++ src/main/kotlin/MineSweeper.kt | 4 ++-- src/main/kotlin/RandomMinePositionsGenerator.kt | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 src/main/kotlin/MinePositionGenerator.kt diff --git a/src/main/kotlin/MinePositionGenerator.kt b/src/main/kotlin/MinePositionGenerator.kt new file mode 100644 index 000000000..7a644cc35 --- /dev/null +++ b/src/main/kotlin/MinePositionGenerator.kt @@ -0,0 +1,4 @@ +fun interface MinePositionGenerator { + + fun generate(size: Int): List +} diff --git a/src/main/kotlin/MineSweeper.kt b/src/main/kotlin/MineSweeper.kt index 241290018..bedb5f48c 100644 --- a/src/main/kotlin/MineSweeper.kt +++ b/src/main/kotlin/MineSweeper.kt @@ -2,9 +2,9 @@ class MineSweeper( private val width: Int, private val height: Int, mineSize: Int, - generateMinePositions: (Int) -> List + minePositionGenerator: MinePositionGenerator ) { - private val minePositions = generateMinePositions(mineSize) + private val minePositions = minePositionGenerator.generate(mineSize) fun cells(): Map { return Position.createInRange(width, height) diff --git a/src/main/kotlin/RandomMinePositionsGenerator.kt b/src/main/kotlin/RandomMinePositionsGenerator.kt index 33544ea6c..4937834d7 100644 --- a/src/main/kotlin/RandomMinePositionsGenerator.kt +++ b/src/main/kotlin/RandomMinePositionsGenerator.kt @@ -1,8 +1,8 @@ class RandomMinePositionsGenerator( private val maxWidth: Int, private val maxHeight: Int, -) { - fun generate(size: Int): List { +): MinePositionGenerator { + override fun generate(size: Int): List { require(size <= maxWidth * maxHeight) { "생성할 수 있는 지뢰 위치 갯수보다 많이 생성하려합니다." } return Position.createInRange(maxWidth, maxHeight) From 2218c9e6f091a029d364fa7bb1d21426dcd99945 Mon Sep 17 00:00:00 2001 From: "verus.j" Date: Sat, 30 Dec 2023 00:11:49 +0900 Subject: [PATCH 6/6] =?UTF-8?q?feat:=20=EC=A7=80=EB=A2=B0=20=EC=B0=BE?= =?UTF-8?q?=EA=B8=B0=20=EC=A7=80=EB=8F=84=20=EA=B7=B8=EB=A6=AC=EA=B8=B0=20?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=ED=95=A8=EC=88=98=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/Main.kt | 45 ++++++++++++++++++++++++++++++++++ src/main/kotlin/MineSweeper.kt | 4 +-- 2 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 src/main/kotlin/Main.kt diff --git a/src/main/kotlin/Main.kt b/src/main/kotlin/Main.kt new file mode 100644 index 000000000..f986e5a75 --- /dev/null +++ b/src/main/kotlin/Main.kt @@ -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 -> "*" + } +} diff --git a/src/main/kotlin/MineSweeper.kt b/src/main/kotlin/MineSweeper.kt index bedb5f48c..0465a4f00 100644 --- a/src/main/kotlin/MineSweeper.kt +++ b/src/main/kotlin/MineSweeper.kt @@ -1,6 +1,6 @@ class MineSweeper( - private val width: Int, - private val height: Int, + val width: Int, + val height: Int, mineSize: Int, minePositionGenerator: MinePositionGenerator ) {