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] minesweeper(draw) #437

Merged
merged 15 commits into from
Dec 14, 2024
29 changes: 28 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,28 @@
# kotlin-minesweeper
# kotlin-minesweeper

## step1

### requirements

- [x] 높이와 너비, 지뢰 개수를 입력받을 수 있다
- [x] 지뢰는 눈에 잘 띄는 것으로 표기한다
- 지뢰(*), 일반(C)
- [x] 지뢰는 가급적 랜덤에 가깝게 배치한다

### Board

- [x] 높이와 너비, 지뢰 갯수를 가지고 있어야 한다
- [x] Board 라인(Row)들을 가지고 있어야 한다

### Cell

- [x] Island, Mine 두개로 구분된다

### BoardLine

- [x] Cell들을 가지고 있다(너비)

### BoardLines

- [x] BoardLine들을 가지고 있다(높이)

Empty file removed src/main/kotlin/.gitkeep
Empty file.
26 changes: 26 additions & 0 deletions src/main/kotlin/minsweeper/MinesweeperRunner.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package minsweeper

import minsweeper.domain.Board
import minsweeper.domain.BoardParam
import minsweeper.view.InputView
import minsweeper.view.ResultView

class MinesweeperRunner {

fun run() {
val boardParam = BoardParam(
InputView.showAndGetHeight(),
InputView.showAndGetWidth(),
InputView.showAndGetMineCount(),
)

val board = Board(boardParam)

ResultView.printBoard(board.boardLines)
}

}

fun main() {
MinesweeperRunner().run()
}
9 changes: 9 additions & 0 deletions src/main/kotlin/minsweeper/domain/Board.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package minsweeper.domain

class Board(
private val params: BoardParam,
boardLinesGenerator: BoardLinesGenerator = BoardLinesGenerator(),
) {
val boardLines: BoardLines = boardLinesGenerator.generate(params)

}
3 changes: 3 additions & 0 deletions src/main/kotlin/minsweeper/domain/BoardLine.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package minsweeper.domain

data class BoardLine(val cells: List<Cell>)
3 changes: 3 additions & 0 deletions src/main/kotlin/minsweeper/domain/BoardLines.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package minsweeper.domain

data class BoardLines(val lines: List<BoardLine>)
19 changes: 19 additions & 0 deletions src/main/kotlin/minsweeper/domain/BoardLinesGenerator.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package minsweeper.domain

class BoardLinesGenerator(
private val minePositionsGenerator: MinePositionsGenerator = DefaultMinePositionsGenerator(),
) {

fun generate(boardParam: BoardParam): BoardLines {
val minePositions = minePositionsGenerator.generate(boardParam)
return BoardLines(List(boardParam.height) { row ->
BoardLine(List(boardParam.width) { col ->
val position = row * boardParam.width + col

if (position in minePositions) Cell.Mine
else Cell.Island

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

프로그래밍 요구사항에는 아래와 같은 항목이 있습니다.

else 예약어를 쓰지 않는다.

이 요구사항을 반영해보면 어떨까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3d2f7a2
프로그래밍 요구사항을 제대로 체크 못하였네요. 인지하여 작업하겠습니다🙏

})
})

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

프로그래밍 요구사항에는 아래와 같은 항목이 있습니다.

한 메서드에 오직 한 단계의 들여쓰기만 한다.

이 요구사항을 반영해보면 어떨까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

}
15 changes: 15 additions & 0 deletions src/main/kotlin/minsweeper/domain/BoardParam.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package minsweeper.domain

data class BoardParam(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BoardParam 라는 이름만 봤을 때에는 어떤 것을 의미하는지 잘 모르겠는데요.
이름만 보고서 의미를 이해할 수 있도록 개선해보면 어떨까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addd195
BoardSize로 이름 명명하고 mineCount 삭제하였습니다

val height: Int,
val width: Int,
val mineCount: Int,
) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

프로그래밍 요구사항에는 아래와 같은 항목이 있습니다.

3개 이상의 인스턴스 변수를 가진 클래스를 쓰지 않는다.

이 요구사항을 반영해보면 어떨까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

init {
require(mineCount <= height * width) { TOO_MANY_MINE_COUNT_EXCEPTION }
}

companion object {
private const val TOO_MANY_MINE_COUNT_EXCEPTION = "지뢰 갯수가 높이 x 넓이를 초과할 수 없습니다"
}
}
6 changes: 6 additions & 0 deletions src/main/kotlin/minsweeper/domain/Cell.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package minsweeper.domain

sealed interface Cell {
data object Island : Cell
data object Mine : Cell
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package minsweeper.domain

class DefaultMinePositionsGenerator : MinePositionsGenerator {

override fun generate(param: BoardParam): List<Int> =
(0 until param.height * param.width).shuffled().take(param.mineCount)

}
7 changes: 7 additions & 0 deletions src/main/kotlin/minsweeper/domain/MinePositionsGenerator.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package minsweeper.domain

interface MinePositionsGenerator {

fun generate(param: BoardParam): List<Int>

}
20 changes: 20 additions & 0 deletions src/main/kotlin/minsweeper/view/InputView.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package minsweeper.view

object InputView {

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

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

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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

너비와 높이를 곱한 값보다 큰 수치의 값을 입력하게 되면 어떻게 될까요? 🤔

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

}
22 changes: 22 additions & 0 deletions src/main/kotlin/minsweeper/view/ResultView.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package minsweeper.view

import minsweeper.domain.BoardLines
import minsweeper.domain.Cell

object ResultView {

fun printBoard(boardLines: BoardLines) {
println(buildString {
append("지뢰찾기 게임 시작\n")
append(boardLines.lines.joinToString(separator = "\n") { boardLine ->
boardLine.cells.joinToString(separator = " ") { it.print() }
})
})
}

private fun Cell.print(): String = when (this) {
Cell.Island -> "*"
Cell.Mine -> "C"
}

}
Empty file removed src/test/kotlin/.gitkeep
Empty file.
32 changes: 32 additions & 0 deletions src/test/kotlin/minsweeper/domain/BoardLinesGeneratorTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package minsweeper.domain

import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test

class BoardLinesGeneratorTest {

@Test
fun `지뢰를 내가 원하는 위치에 심을 수 있다`() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

// given
val boardParam = BoardParam(10, 10, 7)
val mines = listOf(0, 12, 24, 30, 41, 57, 69)
val boardLinesGenerator = BoardLinesGenerator(
object : MinePositionsGenerator {
override fun generate(param: BoardParam): List<Int> = mines
},
)

// when
val result = boardLinesGenerator.generate(boardParam)

// then
assertThat(result.lines[0].cells[0]).isEqualTo(Cell.Mine)
assertThat(result.lines[1].cells[2]).isEqualTo(Cell.Mine)
assertThat(result.lines[2].cells[4]).isEqualTo(Cell.Mine)
assertThat(result.lines[3].cells[0]).isEqualTo(Cell.Mine)
assertThat(result.lines[4].cells[1]).isEqualTo(Cell.Mine)
assertThat(result.lines[5].cells[7]).isEqualTo(Cell.Mine)
assertThat(result.lines[6].cells[9]).isEqualTo(Cell.Mine)
}

}
23 changes: 23 additions & 0 deletions src/test/kotlin/minsweeper/domain/BoardParamTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package minsweeper.domain

import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Assertions.assertThrows
import org.junit.jupiter.api.Test

class BoardParamTest {

@Test
fun `높이 x 넓이보다 지뢰갯수 크면 에러를 던져야 한다`() {
// given
val height = 10
val width = 10
val mineCount = 101

// when
val result = assertThrows(IllegalArgumentException::class.java) { BoardParam(height, width, mineCount) }

// then
assertThat(result.message).isEqualTo("지뢰 갯수가 높이 x 넓이를 초과할 수 없습니다")
}

}