forked from woowacourse/kotlin-omok
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Stones.kt
61 lines (47 loc) · 2.15 KB
/
Stones.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package domain.stone
import domain.position.Position
data class Stones(private val stones: List<Stone>) {
val lastStone: Stone
get() = stones.last().copy()
constructor(vararg stones: Stone) : this(stones.toList())
init {
require(stones.distinct().size == stones.size) { DUPLICATED_ERROR_MESSAGE }
}
fun getPositions(): List<Position> = stones.map { it.position.copy() }
fun add(newStone: Stone): Stones = Stones(stones + newStone)
fun hasStone(stone: Stone): Boolean = stones.contains(stone)
fun checkWin(startStone: Stone): Boolean {
val directions = listOf(RIGHT_DIRECTION, TOP_DIRECTION, RIGHT_TOP_DIRECTION, LEFT_BOTTOM_DIRECTION)
for (moveDirection in directions) {
if (checkStraight(startStone.position, moveDirection, FORWARD_WEIGHT)) return true
if (checkStraight(startStone.position, moveDirection, BACK_WEIGHT)) return true
}
return false
}
private fun checkStraight(
startPosition: Position,
direction: Pair<Int, Int>,
weight: Int = FORWARD_WEIGHT
): Boolean {
val (startX, startY) = Pair(startPosition.row, startPosition.col)
var count = 1
var (currentX, currentY) = Pair(startX + direction.first * weight, startY + direction.second * weight)
while (inRange(currentX, currentY) && hasStone(Stone.of(currentX, currentY))) {
count++
currentX += direction.first * weight
currentY += direction.second * weight
}
return count >= MINIMUM_WIN_CONDITION
}
private fun inRange(x: Int, y: Int) = x in Position.POSITION_RANGE && y in Position.POSITION_RANGE
companion object {
private const val DUPLICATED_ERROR_MESSAGE = "중복되는 위치의 오목알을 가질 수 없습니다."
private const val MINIMUM_WIN_CONDITION = 5
private val RIGHT_DIRECTION = Pair(1, 0)
private val TOP_DIRECTION = Pair(0, 1)
private val RIGHT_TOP_DIRECTION = Pair(1, 1)
private val LEFT_BOTTOM_DIRECTION = Pair(-1, -1)
private const val FORWARD_WEIGHT = 1
private const val BACK_WEIGHT = -1
}
}