-
Notifications
You must be signed in to change notification settings - Fork 199
Step2 #232
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
base: jpoh281
Are you sure you want to change the base?
Step2 #232
Changes from 34 commits
6ce91cc
288f98a
420c9f2
13926cd
d9b1a77
563b905
cdbdfb7
de0089e
90f6ef0
b196d6a
70b8fda
257b76b
4133782
e7e1a31
ada31aa
cb645f4
77a340b
19bdc2c
9820e71
3d033cd
f9e24c6
b9b28d3
eea4988
15dee1e
f5b8a13
e1aace3
b37a91c
943e4d5
0e68951
74acd9a
28edd9d
b8babef
322b8ca
001d298
75508fc
8e04e5f
520a042
1c4ee11
e95a24c
11ac2ce
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,8 +1,8 @@ | ||
| package minesweeper.controller | ||
|
|
||
| import minesweeper.domain.Block | ||
| import minesweeper.domain.MineSweeperBoard | ||
| import minesweeper.domain.Point | ||
| import minesweeper.domain.exception.MineSweeperException | ||
| import minesweeper.domain.plant_strategy.RemainderPlantStrategy | ||
| import minesweeper.view.InputView | ||
| import minesweeper.view.InputViewImpl | ||
| import minesweeper.view.ResultView | ||
|
|
@@ -12,17 +12,25 @@ class GameController( | |
| private val inputView: InputView = InputViewImpl(), | ||
| private val resultView: ResultView = ResultViewImpl() | ||
| ) { | ||
| fun run(): Map<Point, Block> { | ||
| val gameBoard = setUp() | ||
| resultView.renderInitialBoard(gameBoard.state) | ||
| return gameBoard.state | ||
| fun run(): MineSweeperBoard? { | ||
| return try { | ||
| val gameBoard = setUp() | ||
| resultView.renderInitialBoard(gameBoard.state) | ||
| gameBoard | ||
| } catch (e: MineSweeperException) { | ||
| resultView.printKnownException(e) | ||
| throw e | ||
| } catch (e: Exception) { | ||
| resultView.printUnknownException(e) | ||
| throw e | ||
| } | ||
|
Comment on lines
+19
to
+26
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.
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. 게임을 종료시킬 수 있는것을 컨트롤러에서 제어가 가능해지죠. |
||
| } | ||
|
|
||
| private fun setUp(): MineSweeperBoard { | ||
| val height = inputView.readHeight() | ||
| val width = inputView.readWidth() | ||
| val mineCount = inputView.readMineCount() | ||
|
|
||
| return MineSweeperBoard(height, width, mineCount) | ||
| return MineSweeperBoard(height, width, mineCount, RemainderPlantStrategy()) | ||
| } | ||
| } | ||
This file was deleted.
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,19 @@ | ||
| package minesweeper.domain | ||
|
|
||
| import java.util.Random | ||
| import minesweeper.domain.block.Block | ||
| import minesweeper.domain.block.MineBlock | ||
| import minesweeper.domain.block.SafeBlock | ||
| import minesweeper.domain.exception.ExceptionReason | ||
| import minesweeper.domain.exception.MineSweeperException | ||
| import minesweeper.domain.plant_strategy.PlantStrategy | ||
| import minesweeper.domain.plant_strategy.RemainderPlantStrategy | ||
|
|
||
| class MineSweeperBoard(private val width: Int, private val height: Int, mineCount: Int = 0) { | ||
| class MineSweeperBoard( | ||
| private val width: Int, | ||
| private val height: Int, | ||
| mineCount: Int = 0, | ||
| private val strategy: PlantStrategy = RemainderPlantStrategy() | ||
| ) { | ||
|
|
||
| private val _state: MutableMap<Point, Block> | ||
|
|
||
|
|
@@ -20,17 +31,12 @@ class MineSweeperBoard(private val width: Int, private val height: Int, mineCoun | |
| } | ||
| _state = buildBoard(width, height).toMutableMap() | ||
| plantMines(mineCount) | ||
| _mineCount = countMine() | ||
| } | ||
|
|
||
| private fun buildBoard(maxXAxis: Int, maxYAxis: Int): Map<Point, Block> { | ||
| val pairs = mutableListOf<Pair<Point, Block>>() | ||
|
|
||
| (0 until maxXAxis).forEach { currentXAixs -> | ||
| pairs.addAll(buildLine(currentXAixs, maxYAxis)) | ||
| } | ||
|
|
||
| return pairs.toMap() | ||
| return (0 until maxXAxis).flatMap { currentXAxis -> | ||
| buildLine(currentXAxis, maxYAxis) | ||
| }.toMap() | ||
| } | ||
|
|
||
| private fun buildLine(currentXAxis: Int, maxYAxis: Int): List<Pair<Point, Block>> { | ||
|
|
@@ -44,13 +50,25 @@ class MineSweeperBoard(private val width: Int, private val height: Int, mineCoun | |
| } | ||
|
|
||
| private fun plantMines(plantingMineCount: Int) { | ||
| while (countMine() < plantingMineCount) { | ||
| val width = Random().nextInt(width) | ||
| val height = Random().nextInt(height) | ||
| _state[Point(width, height)] = MineBlock() | ||
| val minePoints = strategy.createMines(width, height, plantingMineCount) | ||
| minePoints.forEach { | ||
| _state[it] = MineBlock() | ||
| } | ||
| _mineCount = countMine() | ||
| updateSafeBlock() | ||
|
Comment on lines
+53
to
+58
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. 전략을 바꿀 수 있으니, 여러 장점이 있을것 같아요. |
||
| } | ||
|
|
||
| private fun updateSafeBlock() { | ||
| val safeBlockPoints = _state.filterValues { block: Block -> block is SafeBlock }.keys | ||
| safeBlockPoints.forEach { currentPoint: Point -> | ||
| _state[currentPoint] = SafeBlock(sumNearPointMines(currentPoint.getNearPoints(width, height))) | ||
| } | ||
| } | ||
|
|
||
| private fun sumNearPointMines(points: List<Point>): Int { | ||
| return points.count { _state[it] is MineBlock } | ||
| } | ||
|
|
||
| private fun countMine(): Int { | ||
| return _state.values.count { block: Block -> block is MineBlock } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,8 @@ | ||
| package minesweeper.domain | ||
|
|
||
| import minesweeper.domain.exception.ExceptionReason | ||
| import minesweeper.domain.exception.MineSweeperException | ||
|
|
||
| data class Point(val x: Int, val y: Int) : Comparable<Point> { | ||
|
|
||
| init { | ||
|
|
@@ -8,5 +11,38 @@ data class Point(val x: Int, val y: Int) : Comparable<Point> { | |
| } | ||
| } | ||
|
|
||
| fun getNearPoints(width: Int, height: Int): List<Point> { | ||
| val nearPoints = nearPoints.toList() | ||
| return nearPoints.mapNotNull { plusOrNull(it.first, it.second, width, height) } | ||
| } | ||
|
|
||
| override fun compareTo(other: Point) = compareValuesBy(this, other, { it.y }, { it.x }) | ||
|
|
||
| private fun plusOrNull(x: Int, y: Int, maxX: Int, maxY: Int): Point? { | ||
|
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. 연산자 오버로딩을 해도 괜찮겠네요~ |
||
| if (isValidateX(x, maxX) && isValidateY(y, maxY)) { | ||
| return Point(this.x + x, this.y + y) | ||
| } | ||
| return null | ||
| } | ||
|
|
||
| private fun isValidateX(x: Int, maxX: Int): Boolean { | ||
| return (this.x + x) in 0 until maxX | ||
| } | ||
|
|
||
| private fun isValidateY(y: Int, maxY: Int): Boolean { | ||
| return (this.y + y) in 0 until maxY | ||
| } | ||
|
|
||
| companion object { | ||
| private val nearPoints = listOf( | ||
| -1 to -1, | ||
| -1 to 0, | ||
| -1 to 1, | ||
| 0 to -1, | ||
| 0 to 1, | ||
| 1 to -1, | ||
| 1 to 0, | ||
| 1 to 1 | ||
| ) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| package minesweeper.domain.block | ||
|
|
||
| sealed class Block { | ||
| abstract fun open() | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package minesweeper.domain.block | ||
|
|
||
| class MineBlock : Block() { | ||
| override fun open() { | ||
| TODO("Not yet implemented") | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| package minesweeper.domain.block | ||
|
|
||
| import minesweeper.domain.exception.ExceptionReason | ||
| import minesweeper.domain.exception.MineSweeperException | ||
|
|
||
| class SafeBlock(val nearMineCount: Int = 0) : Block() { | ||
|
|
||
| init { | ||
| if (nearMineCount !in nearMineRange) throw MineSweeperException(ExceptionReason.ILLEGAL_NEAR_MINE_RANGE) | ||
| } | ||
|
|
||
| override fun open() { | ||
| TODO("Not yet implemented") | ||
| } | ||
|
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. 구현이 안될 메서드를 만들어야 하는건 조금 아쉽네요. Block을 세분화 해보는건 어떨까요? |
||
|
|
||
| companion object { | ||
| private val nearMineRange = (0..8) | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| package minesweeper.domain.exception | ||
|
|
||
| enum class ExceptionReason { | ||
| ILLEGAL_POINT, | ||
| NEGATIVE_POINT_VALUE, | ||
| MINE_COUNT_OVER_BLOCKS, | ||
| ILLEGAL_NEAR_MINE_RANGE | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| package minesweeper.domain | ||
| package minesweeper.domain.exception | ||
|
|
||
| class MineSweeperException(val reason: ExceptionReason) : Exception() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package minesweeper.domain.plant_strategy | ||
|
|
||
| import minesweeper.domain.Point | ||
|
|
||
| interface PlantStrategy { | ||
| fun createMines(width: Int, height: Int, mineCount: Int): Set<Point> | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| package minesweeper.domain.plant_strategy | ||
|
|
||
| import minesweeper.domain.Point | ||
| import java.util.* | ||
|
|
||
| class RandomPlantStrategy : PlantStrategy { | ||
| override fun createMines(width: Int, height: Int, mineCount: Int): Set<Point> { | ||
| val minePoints = mutableSetOf<Point>() | ||
| while (minePoints.size < mineCount) { | ||
| val currentWidth = Random().nextInt(width) | ||
| val currentHeight = Random().nextInt(height) | ||
| minePoints.add(Point(currentWidth, currentHeight)) | ||
| } | ||
| return minePoints | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| package minesweeper.domain.plant_strategy | ||
|
|
||
| import minesweeper.domain.Point | ||
|
|
||
| class RemainderPlantStrategy : PlantStrategy { | ||
|
|
||
| override fun createMines(width: Int, height: Int, mineCount: Int): Set<Point> { | ||
| val minePoints = mutableSetOf<Point>() | ||
|
|
||
| val term = width * height / mineCount | ||
| val maxNumber = term * mineCount | ||
| for (i: Int in 0 until maxNumber step term) { | ||
| val currentWidth = i % width | ||
| val currentHeight = i / width | ||
|
|
||
| minePoints.add(Point(currentWidth, currentHeight)) | ||
| } | ||
|
|
||
|
|
||
|
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. 린트 돌려주세요~ |
||
| return minePoints | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,12 @@ | ||
| package minesweeper.view | ||
|
|
||
| import minesweeper.domain.Block | ||
| import minesweeper.domain.block.Block | ||
| import minesweeper.domain.exception.MineSweeperException | ||
| import minesweeper.domain.Point | ||
|
|
||
| interface ResultView { | ||
| fun renderInitialBoard(state: Map<Point, Block>) | ||
|
|
||
| fun printKnownException(exception: MineSweeperException) | ||
| fun printUnknownException(exception: Exception) | ||
| } |
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.
타입이 나오면 좋겠네요~