Skip to content

Commit e0572f2

Browse files
committed
Declaring a Winner
1 parent 8deaba7 commit e0572f2

File tree

1 file changed

+85
-36
lines changed

1 file changed

+85
-36
lines changed

react_learn/src/main/scala/tutorial/webapp/TutorialApp.scala

Lines changed: 85 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
package tutorial.webapp
22

3+
package object webapp {
4+
type Squares = List[Option[String]]
5+
}
6+
import webapp._
7+
38
import japgolly.scalajs.react._
49
import japgolly.scalajs.react.vdom.html_<^._
510
import org.scalajs.dom
@@ -29,80 +34,124 @@ object Square {
2934

3035
object Board {
3136

32-
case class State(
33-
square:List[Option[String]],
34-
xIsNext:Boolean
37+
case class Props(
38+
squares: Squares,
39+
xIsNext: Boolean,
40+
handleClick: Int => Callback,
3541
)
3642

37-
class Backend(bs: BackendScope[Unit, State]) {
43+
class Backend(bs: BackendScope[Props, Unit]) {
3844

39-
def render(state: State) = {
40-
val status = "Next player: " + {if (state.xIsNext) "X" else "O"}
45+
def render(props: Props) = {
4146
<.div(
42-
<.div(
43-
^.cls := "status",
44-
status
45-
),
4647
<.div(
4748
^.cls := "board-row",
48-
renderSquare(state, 0),
49-
renderSquare(state, 1),
50-
renderSquare(state, 2)
49+
renderSquare(props, 0),
50+
renderSquare(props, 1),
51+
renderSquare(props, 2)
5152
),
5253
<.div(
5354
^.cls := "board-row",
54-
renderSquare(state, 3),
55-
renderSquare(state, 4),
56-
renderSquare(state, 5)
55+
renderSquare(props, 3),
56+
renderSquare(props, 4),
57+
renderSquare(props, 5)
5758
),
5859
<.div(
5960
^.cls := "board-row",
60-
renderSquare(state, 6),
61-
renderSquare(state, 7),
62-
renderSquare(state, 8)
61+
renderSquare(props, 6),
62+
renderSquare(props, 7),
63+
renderSquare(props, 8)
6364
)
6465
)
6566
}
6667

67-
def renderSquare(state: State, i: Int) = {
68+
def renderSquare(props: Props, i: Int) = {
6869
Square(
69-
state.square(i),
70-
handleClick(i)
70+
props.squares(i),
71+
props.handleClick(i),
7172
)
7273
}
73-
74-
def handleClick(i: Int) = bs.modState(
75-
s => s.copy(
76-
square=s.square.updated(i, Some(if (s.xIsNext) "X" else "O")),
77-
xIsNext= !s.xIsNext
78-
)
79-
)
8074
}
8175

82-
val component = ScalaComponent.builder[Unit]("Board")
83-
.initialState(State(List.fill(9)(None), true))
76+
val component = ScalaComponent.builder[Props]("Board")
8477
.renderBackend[Backend]
8578
.build
8679

87-
def apply() = component()
80+
def apply(squares: Squares, xIsNext: Boolean, handleClick: Int => Callback)
81+
= component(Props(squares, xIsNext, handleClick))
8882
}
8983

9084

9185
object Game {
92-
val component = ScalaComponent.builder[Unit]("Game")
93-
.renderStatic(
86+
87+
case class State(
88+
history: List[Squares],
89+
xIsNext: Boolean,
90+
)
91+
92+
class Backend(bs: BackendScope[Unit, State]) {
93+
94+
def render(state: State) = {
95+
val current = state.history.last
96+
val status = calculateWinner(current) match {
97+
case Some(s) => "Winner is " + s
98+
case None => "Next player: " + {if (state.xIsNext) "X" else "O"}
99+
}
94100
<.div(
95101
^.cls := "game",
96102
<.div(
97103
^.cls := "game-board",
98-
Board(),
104+
Board(current, state.xIsNext, handleClick(_)),
99105
),
100106
<.div(
101-
<.div(/*Status*/),
107+
^.cls := "game-info",
108+
<.div(status),
102109
<.ol(/* TODO */),
103110
),
104111
)
112+
}
113+
114+
def calculateWinner(squares: Squares) = {
115+
val lines = List(
116+
List(0,1,2),
117+
List(3,4,5),
118+
List(6,7,8),
119+
List(0,3,6),
120+
List(1,4,7),
121+
List(2,5,8),
122+
List(0,4,8),
123+
List(6,4,2),
124+
)
125+
val winner = lines.map(
126+
line => line.map(
127+
element => squares(element)
128+
)
129+
).filter(
130+
_.toSet.size == 1
131+
).filter(
132+
! _(0).isEmpty
133+
)
134+
if (!winner.isEmpty) winner(0)(0) else None
135+
}
136+
137+
def handleClick(i: Int) = bs.modState(
138+
s => {
139+
val latest = s.history.last
140+
if (!latest(i).isEmpty || !calculateWinner(latest).isEmpty) {
141+
s
142+
} else {
143+
s.copy(
144+
history=s.history:+latest.updated(i, Some(if (s.xIsNext) "X" else "O")),
145+
xIsNext= !s.xIsNext
146+
)
147+
}
148+
}
105149
)
150+
}
151+
152+
val component = ScalaComponent.builder[Unit]("Board")
153+
.initialState(State(List(List.fill(9)(None)), true))
154+
.renderBackend[Backend]
106155
.build
107156

108157
def apply() = component()

0 commit comments

Comments
 (0)