-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathGame.kt
111 lines (99 loc) · 3.07 KB
/
Game.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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package tictactoe
import kotlinx.html.js.onClickFunction
import react.RBuilder
import react.RComponent
import react.RProps
import react.RState
import react.dom.button
import react.dom.div
import react.dom.li
import react.dom.ol
import react.setState
class Game(): RComponent<RProps, Game.State>() {
init {
state.apply {
history = arrayOf(HistoryEntry(Array<String?>(9) { null }))
stepNumber = 0
xIsNext = true
}
}
fun handleClick(i: Int) {
val history = state.history.sliceArray(0..state.stepNumber)
val current = history.last()
val squares = current.squares.copyOf()
if (calculateWinner(squares) != null || squares[i] != null)
return
squares[i] = if (state.xIsNext) "X" else "O"
setState {
this.history = history + HistoryEntry(squares)
stepNumber = history.size
xIsNext = !state.xIsNext
}
}
fun calculateWinner(squares: Array<String?>): String? {
val solutions = arrayOf(
arrayOf(0, 1, 2),
arrayOf(3, 4, 5),
arrayOf(6, 7, 8),
arrayOf(0, 3, 6),
arrayOf(1, 4, 7),
arrayOf(2, 5, 8),
arrayOf(0, 4, 8),
arrayOf(2, 4, 6))
for (solution in solutions){
val (a, b, c) = solution
if (squares[a] != null && squares[a] == squares[b] && squares[a] == squares[c])
return squares[a]
}
return null
}
fun jumpTo(step: Int) {
setState {
stepNumber = step
xIsNext = (step % 2) == 0
}
}
fun RBuilder.movesNodes() =
state.history.mapIndexed { step, move ->
val desc =
if (step != 0)
"Go to move #$step"
else
"Go to game start"
li {
key = step.toString()
button {
+desc
attrs.onClickFunction = { jumpTo(step) }
}
}
}
override fun RBuilder.render() {
val history = state.history
val current = history[state.stepNumber]
val winner = calculateWinner(current.squares)
val status =
if (winner != null)
"Winner: $winner"
else
"Next player: ${if (state.xIsNext) "X" else "O"}"
div(classes = "game") {
div(classes = "game-board") {
board(current.squares) {
handleClick(it)
}
}
div(classes = "game-info") {
div { +status }
ol { movesNodes() }
}
}
}
interface State: RState {
var history: Array<HistoryEntry>
var xIsNext: Boolean
var stepNumber: Int
}
data class HistoryEntry(var squares: Array<String?>)
}
fun RBuilder.game() = child(Game::class) {}