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

πŸš€ 1단계 - 지뒰 μ°ΎκΈ°(그리기) #417

Open
wants to merge 4 commits into
base: giibeom
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
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

## λ―Έμ…˜ λ‚΄μš©

### STEP 1

<details>
<summary>μ ‘κΈ°/펼치기</summary>
<div markdown="1">

#### [μš”κ΅¬ 사항 뢄석]

- 높이와 λ„ˆλΉ„, 지뒰 개수λ₯Ό μž…λ ₯받을 수 μžˆλ‹€.
- μ§€λ’°λŠ” λˆˆμ— 잘 λ„λŠ” κ²ƒμœΌλ‘œ ν‘œκΈ°ν•œλ‹€.
- μ§€λ’°λŠ” 가급적 λžœλ€μ— κ°€κΉκ²Œ λ°°μΉ˜ν•œλ‹€.

#### [κΈ°λŠ₯ λͺ©λ‘]

- [x] 높이λ₯Ό μž…λ ₯ λ°›λŠ”λ‹€.
- [x] λ„ˆλΉ„λ₯Ό μž…λ ₯ λ°›λŠ”λ‹€.
- [x] 지뒰 개수λ₯Ό μž…λ ₯λ°›λŠ”λ‹€.
- [x] 2μ°¨ 배열에 μž…λ ₯된 지뒰 개수만큼 랜덀으둜 지뒰(πŸ’£)λ₯Ό μƒμ„±ν•œλ‹€.
- [x] 2μ°¨ 배열을 좜λ ₯ν•œλ‹€.

</div>
</details>

<br>
3 changes: 2 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ repositories {
dependencies {
testImplementation("org.junit.jupiter", "junit-jupiter", "5.8.2")
testImplementation("org.assertj", "assertj-core", "3.22.0")
testImplementation("io.kotest", "kotest-runner-junit5", "5.2.3")
testImplementation("io.kotest", "kotest-runner-junit5", "5.7.2")
testImplementation("io.kotest", "kotest-property", "5.7.2")
}

tasks {
Expand Down
Empty file removed src/main/kotlin/.gitkeep
Empty file.
18 changes: 18 additions & 0 deletions src/main/kotlin/game/minesweeper/MinesweeperApplication.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package game.minesweeper

import game.minesweeper.domain.GameBoard
import game.minesweeper.ui.Input
import game.minesweeper.ui.Output

fun main() {
val height = Input.getHeight()
val width = Input.getWidth()
val minesNumber = Input.getMinesNumber()

val gameBoard = GameBoard(height, width)

Output.printStartGamePrompt()
gameBoard.startGame(minesNumber)

Output.printGameResult(gameBoard)
}
15 changes: 15 additions & 0 deletions src/main/kotlin/game/minesweeper/domain/GameBoard.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package game.minesweeper.domain

class GameBoard(height: Int, width: Int) {
private val board = Array(height) { Array(width) { "C" } }

Choose a reason for hiding this comment

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

"C"λΌλŠ”κ±΄ 무엇을 μ˜λ―Έν• κΉŒμš”?

λͺ¨λ“  μ›μ‹œ κ°’κ³Ό λ¬Έμžμ—΄μ„ 포μž₯ν•œλ‹€.

μš”κ΅¬μ‚¬ν•­μ„ μ§€μΌœλ³΄μ•„μš”!


fun startGame(minesNumber: Int) {
MineGenerator.create(board, minesNumber)

Choose a reason for hiding this comment

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

MineGeneratorλΌλŠ” 싱글턴객체에 μ ‘κ·Όν•˜λŠ” κ΅¬μ‘°λ„€μš”
μ‹±κΈ€ν„΄νŒ¨ν„΄μ€ 객체간 결합도λ₯Ό μ˜¬λ¦¬λŠ” κ²½μš°λ„ λ§Žμ•„μ„œ μ‚¬μš©μ— μ£Όμ˜ν•˜λŠ”κ²Œ μ’‹μ•„μš”!

}

override fun toString(): String {
return board.joinToString("\n") { row ->
row.joinToString(" ")
}
Comment on lines +11 to +13

Choose a reason for hiding this comment

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

ν•΄λ‹Ή λ‘œμ§μ€ Viewκ΄€λ ¨ λ‘œμ§μ€ μ•„λ‹κΉŒμš”?
Viewκ°€ ν…μŠ€νŠΈλ‘œ μ§„ν–‰λ˜μ§€ μ•ŠλŠ”λ‹€λ©΄ domainλ‘œμ§μ—λ„ 영ν–₯이 κ°€λŠ”κ΅¬μ‘°λ„€μš”!

}
}
19 changes: 19 additions & 0 deletions src/main/kotlin/game/minesweeper/domain/MineGenerator.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package game.minesweeper.domain

object MineGenerator {
fun create(board: Array<Array<String>>, minesNumber: Int) {

Choose a reason for hiding this comment

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

Array<Array>λŠ” 무엇을 μ˜λ―Έν• κΉŒμš”?

일급 μ»¬λ ‰μ…˜μ„ μ“΄λ‹€.

을 ν™œμš©ν•΄λ³΄λ©΄ μ–΄λ–¨κΉŒμš”?

val height = board.size
val width = board[0].size
var minesPlaced = 0

while (minesPlaced < minesNumber) {
val randomRow = (0 until height).random()
val randomCol = (0 until width).random()

if (board[randomRow][randomCol] != "*") {
board[randomRow][randomCol] = "*"

Choose a reason for hiding this comment

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

"*"은 무엇을 μ˜λ―Έν• κΉŒμš”? λ§ˆμ°¬κ°€μ§€λ‘œ 객체둜 관리해보면 μ–΄λ–¨κΉŒμš”?

Choose a reason for hiding this comment

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

νŒŒλ¦¬λ―Έν„°λ‘œ 전달받은 boardκ°€ λ³€κ²½λ˜λŠ” κ΅¬μ‘°λ„€μš”,
μ™ΈλΆ€μ—μ„œ boardκ°€ λ³€κ²½λ˜μ—ˆλ‹€λŠ”κ±Έ μ•Œμˆ˜μžˆμ„κΉŒμš”?
μΆ”κ°€λ‘œ κ³ λ―Όν•΄λ³΄μ•„μš”!

minesPlaced++
}

Choose a reason for hiding this comment

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

ν•œ λ©”μ„œλ“œμ— 였직 ν•œ λ‹¨κ³„μ˜ λ“€μ—¬μ“°κΈ°λ§Œ ν•œλ‹€.

μš”κ΅¬μ‚¬ν•­μ„ μ§€μΌœλ³΄μ•„μš”!

}
}
}
56 changes: 56 additions & 0 deletions src/main/kotlin/game/minesweeper/ui/ConsoleView.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package game.minesweeper.ui

import game.minesweeper.domain.GameBoard

object Input {
private const val HEIGHT_PROMPT = "높이λ₯Ό μž…λ ₯ν•˜μ„Έμš”."
private const val WIDTH_PROMPT = "λ„ˆλΉ„λ₯Ό μž…λ ₯ν•˜μ„Έμš”."
private const val NUMBER_OF_MINES_PROMPT = "μ§€λ’°λŠ” λͺ‡ κ°œμΈκ°€μš”?"

private const val INVALID_NUMBER_PROMPT = "μœ νš¨ν•œ 숫자λ₯Ό μž…λ ₯ν•΄μ•Ό ν•©λ‹ˆλ‹€."
private const val INVALID_HEIGHT_RANGE_PROMPT = "λ†’μ΄λŠ” 0보닀 컀야 ν•©λ‹ˆλ‹€."
private const val INVALID_WIDTH_RANGE_PROMPT = "λ„ˆλΉ„λŠ” 0보닀 컀야 ν•©λ‹ˆλ‹€."
private const val INVALID_MINES_NUMBER_PROMPT = "지뒰 κ°œμˆ˜λŠ” 0보닀 컀야 ν•©λ‹ˆλ‹€."

fun getHeight(): Int {
println(HEIGHT_PROMPT)

val height = readlnOrNull()?.toIntOrNull()
requireNotNull(height) { INVALID_NUMBER_PROMPT }
require(height > 0) { INVALID_HEIGHT_RANGE_PROMPT }
Comment on lines +18 to +20
Copy link
Author

Choose a reason for hiding this comment

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

readln()을 μ‚¬μš©ν• κΉŒ ν•˜λ‹€κ°€IllegalArgumentException둜 ν†΅μΌν•˜λŠ”κ²Œ 쒋을 것 κ°™μ•„μ„œ μœ„μ™€ 같이 μ½”λ“œλ₯Ό μ§œλ³΄μ•˜μŠ΅λ‹ˆλ‹Ή πŸ€”


return height
}

fun getWidth(): Int {
println(WIDTH_PROMPT)

val width = readlnOrNull()?.toIntOrNull()
requireNotNull(width) { INVALID_NUMBER_PROMPT }
require(width > 0) { INVALID_WIDTH_RANGE_PROMPT }

return width
}

fun getMinesNumber(): Int {
println(NUMBER_OF_MINES_PROMPT)

val minesNumber = readlnOrNull()?.toIntOrNull()
requireNotNull(minesNumber) { INVALID_NUMBER_PROMPT }
require(minesNumber > 0) { INVALID_MINES_NUMBER_PROMPT }

return minesNumber
}
}

object Output {
private const val GAME_START_PROMPT = "지뒰찾기 κ²Œμž„ μ‹œμž‘"

fun printStartGamePrompt() {
println(GAME_START_PROMPT)
}

fun printGameResult(gameBoard: GameBoard) {
println(gameBoard)
}
}
27 changes: 27 additions & 0 deletions src/test/kotlin/game/minesweeper/domain/MineGeneratorTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package game.minesweeper.domain

import io.kotest.core.spec.style.StringSpec
import io.kotest.data.forAll
import io.kotest.data.row
import io.kotest.matchers.shouldBe

class MineGeneratorTest : StringSpec({

Choose a reason for hiding this comment

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

GameBoard κ΄€λ ¨ ν…ŒμŠ€νŠΈ μ½”λ“œλ„ μž‘μ„±ν•΄λ³΄λ©΄ μ–΄λ–¨κΉŒμš”?


"지뒰 생성은 같은 곳에 μ€‘λ³΅ν•΄μ„œ μƒμ„±λ˜μ§€ μ•Šκ³ , 지뒰 개수만큼 랜덀으둜 μƒμ„±λœλ‹€." {
forAll(
row(10),
row(9),
row(8),
row(7),
row(6),
row(2),
row(1),
) { minesNumber: Int ->
val gameBoard = Array(10) { Array(10) { "C" } }
MineGenerator.create(gameBoard, minesNumber)

val minesCount = gameBoard.sumOf { row -> row.count { cell -> cell == "*" } }
minesCount shouldBe minesNumber
}
}
})