-
Notifications
You must be signed in to change notification settings - Fork 180
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 - 지뢰 찾기(그리기) #333
base: sumniy
Are you sure you want to change the base?
Step1 - 지뢰 찾기(그리기) #333
Changes from 7 commits
9f63f5b
a30cf29
88f25ef
c73e707
4ba37f9
7dcf403
0d1adf3
1ace61c
802cd55
af2ae00
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,6 @@ | ||
# kotlin-minesweeper | ||
# kotlin-minesweeper | ||
|
||
- [x] 지뢰 찾기에 필요한 정보(높이, 너비, 지뢰 개수)를 입력 받는다 | ||
- [x] 높이 * 너비 만큼의 좌표 정보를 생성한다 | ||
- [x] 지뢰 개수만큼 랜덤한 지뢰의 위치를 구해 해당 좌표에 지뢰를 설치한다 | ||
- [x] 지뢰 찾기 게임을 출력한다 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package minesweeper | ||
|
||
import minesweeper.domain.Height | ||
import minesweeper.domain.MineCount | ||
import minesweeper.domain.MineMap | ||
import minesweeper.domain.Width | ||
import minesweeper.view.InputView | ||
import minesweeper.view.ResultView | ||
|
||
fun main() { | ||
val height = Height(InputView.receiveHeight()) | ||
val width = Width(InputView.receiveWidth()) | ||
val mineCount = MineCount(InputView.receiveMineCount()) | ||
|
||
val mineMap = MineMap(height, width, mineCount) | ||
|
||
ResultView.printMineGame(mineMap) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package minesweeper.domain | ||
|
||
class Height(val value: Int) { | ||
init { | ||
require(value >= MIN_HEIGHT_VALUE) { "height는 $MIN_HEIGHT_VALUE 이상만 허용됩니다." } | ||
} | ||
|
||
companion object { | ||
const val MIN_HEIGHT_VALUE = 1 | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package minesweeper.domain | ||
|
||
class MineCount(val value: Int) { | ||
init { | ||
require(value >= MIN_MINE_COUNT_VALUE) { "지뢰 개수는 $MIN_MINE_COUNT_VALUE 이상만 허용됩니다." } | ||
} | ||
|
||
companion object { | ||
private const val MIN_MINE_COUNT_VALUE = 0 | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package minesweeper.domain | ||
|
||
class MineMap(height: Height, val width: Width, mineCount: MineCount) { | ||
private val size: Int = height.value * width.value | ||
val map: List<Point> | ||
|
||
init { | ||
require(size >= mineCount.value) { "지도 크기는 지뢰 개수이상이어야 합니다." } | ||
|
||
val mineIndexes = (0..size) | ||
.shuffled() | ||
.take(mineCount.value) | ||
|
||
val mutableList = mutableListOf<Point>() | ||
(1..height.value).forEach { y -> | ||
(1..width.value).forEach { x -> | ||
val index = (y - 1) * width.value + (x - 1) | ||
|
||
mutableList.add(point(mineIndexes.contains(index), x, y)) | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 객체지향 생활 체조 원칙에는 아래와 같은 항목이 있습니다.
이 요구사항을 적용해보면 어떨까요? |
||
|
||
map = mutableList.toList() | ||
} | ||
|
||
private fun point(isMine: Boolean, x: Int, y: Int): Point { | ||
if (isMine) { | ||
return MinePoint(x, y) | ||
} | ||
|
||
return Point(x, y) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package minesweeper.domain | ||
|
||
class MinePoint(x: Int, y: Int) : Point(x, y) { | ||
override val symbol = MINE_SYMBOL | ||
|
||
companion object { | ||
private const val MINE_SYMBOL = "*" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package minesweeper.domain | ||
|
||
open class Point(x: Int, y: Int) { | ||
open val symbol: String = POINT_SYMBOL | ||
|
||
init { | ||
require(x >= Width.MIN_WIDTH_VALUE) { "x 좌표 값은 width의 최소 값 이상이어야합니다." } | ||
require(y >= Height.MIN_HEIGHT_VALUE) { "y 좌표 값은 height의 최소 값 이상이어야합니다." } | ||
} | ||
|
||
fun symbol(): String { | ||
return symbol | ||
} | ||
|
||
companion object { | ||
private const val POINT_SYMBOL = "C" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package minesweeper.domain | ||
|
||
class Width(val value: Int) { | ||
init { | ||
require(value >= MIN_WIDTH_VALUE) { "width는 $MIN_WIDTH_VALUE 이상만 허용됩니다." } | ||
} | ||
|
||
companion object { | ||
const val MIN_WIDTH_VALUE = 1 | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package minesweeper.view | ||
|
||
object InputView { | ||
fun receiveHeight(): Int { | ||
println("높이를 입력하세요.") | ||
|
||
return receiveInt() | ||
} | ||
|
||
fun receiveWidth(): Int { | ||
println() | ||
println("너비를 입력하세요.") | ||
|
||
return receiveInt() | ||
} | ||
|
||
fun receiveMineCount(): Int { | ||
println() | ||
println("지뢰는 몇 개인가요?") | ||
|
||
return receiveInt() | ||
} | ||
|
||
private fun receiveString(): String { | ||
var input: String? = null | ||
|
||
do { | ||
input = readlnOrNull() | ||
} while (input.isNullOrBlank()) | ||
|
||
return input | ||
} | ||
|
||
private fun receiveInt(): Int { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 함수명만 봤을 때에는 "Int를 받는다" 라고 이해가 되는데요. |
||
var int: Int? = receiveString().toIntOrNull() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 변수는 상태를 나타냅니다. |
||
|
||
while (int == null) { | ||
int = receiveString().toIntOrNull() | ||
} | ||
|
||
return int | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package minesweeper.view | ||
|
||
import minesweeper.domain.MineMap | ||
|
||
object ResultView { | ||
fun printMineGame(mineMap: MineMap) { | ||
println() | ||
println("지뢰찾기 게임 시작") | ||
|
||
mineMap.map | ||
.chunked(mineMap.width.value) | ||
.map { line -> | ||
println(line.joinToString(" ") { it.symbol }) | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package minesweeper | ||
|
||
import io.kotest.assertions.throwables.shouldThrow | ||
import minesweeper.domain.Height | ||
import org.junit.jupiter.api.Test | ||
|
||
class HeightTest { | ||
@Test | ||
fun `height는 음수 값으로 생성 시 예외가 발생한다`() { | ||
shouldThrow<IllegalArgumentException> { Height(0) } | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package minesweeper | ||
|
||
import io.kotest.assertions.throwables.shouldThrow | ||
import minesweeper.domain.MineCount | ||
import org.junit.jupiter.api.Test | ||
|
||
class MineCountTest { | ||
@Test | ||
fun `mineCount는 지도 크기를 초과하면 예외가 발생한다`() { | ||
shouldThrow<IllegalArgumentException> { MineCount(-1) } | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package minesweeper | ||
|
||
import io.kotest.assertions.throwables.shouldThrow | ||
import minesweeper.domain.Height | ||
import minesweeper.domain.MineCount | ||
import minesweeper.domain.MineMap | ||
import minesweeper.domain.Width | ||
import org.junit.jupiter.api.Test | ||
|
||
class MineMapTest { | ||
@Test | ||
fun `지뢰 개수가 지도 크기를 초과하면 예외가 발생한다`() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 내가 원하는 좌표에 지뢰를 심어보고, 그 좌표에 정말 지뢰가 있는지 확인해볼 수 있도록 테스트 코드를 작성해보면 어떨까요? |
||
val height = Height(1) | ||
val width = Width(1) | ||
val mineCount = MineCount(2) | ||
|
||
shouldThrow<IllegalArgumentException> { MineMap(height, width, mineCount) } | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package minesweeper | ||
|
||
import io.kotest.assertions.throwables.shouldThrow | ||
import minesweeper.domain.Point | ||
import org.junit.jupiter.api.Test | ||
|
||
class PointTest { | ||
@Test | ||
fun `좌표정보는 height와 width 의 최소 값 조건을 따른다`() { | ||
shouldThrow<IllegalArgumentException> { Point(0, 1) } | ||
shouldThrow<IllegalArgumentException> { Point(1, 0) } | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package minesweeper | ||
|
||
import io.kotest.assertions.throwables.shouldThrow | ||
import minesweeper.domain.Width | ||
import org.junit.jupiter.api.Test | ||
|
||
class WidthTest { | ||
@Test | ||
fun `width는 음수 값으로 생성 시 예외가 발생한다`() { | ||
shouldThrow<IllegalArgumentException> { Width(0) } | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Width와 Height를 묶을 수 있지 않을까요? 🤔