@@ -8,129 +8,16 @@ import scala.annotation.tailrec
88
99object ManualTicTacToe extends App {
1010
11- sealed trait UICommand extends EnumEntry
12- object UICommand {
13- // ?? why doesn't UICommand's "sealed" obviate the following one (for exhaustive-match checks?)
14- sealed trait UIMoveCommand extends UICommand
15- case object Up extends UIMoveCommand
16- case object Down extends UIMoveCommand
17- case object Left extends UIMoveCommand
18- case object Right extends UIMoveCommand
19- case object Mark extends UICommand
20- case object Quit extends UICommand
21- }
2211
23- def parseCommand (rawCmd : String ): Either [String , UICommand ] = {
24- import UICommand ._
25- rawCmd match {
26- case " u" => Up .asRight
27- case " d" => Down .asRight
28- case " l" => Left .asRight
29- case " r" => Right .asRight
30- case " m" => Mark .asRight
31- case " q" => Quit .asRight
32- case _ =>
33- s " Invalid input \" $rawCmd\" ; try u(p), d(own), l(eft), r(right), m(ark), or q(uit) " .asLeft
34- }
35- }
3612
37- @ tailrec
38- def getCommand (player : Player ): UICommand = {
39- // ?? clean embedded reference to stdin/console and stdout
40- print(s " Player $player command?: " )
41- val rawCmd = scala.io.StdIn .readLine()
42-
43- parseCommand(rawCmd) match {
44- case Right (cmd) => cmd
45- case Left (msg) =>
46- println(msg)
47- getCommand(player) // loop
48- }
49- }
50-
51- // ??? enhance; maybe just put clean strings in; maybe build on GameResult (plus quit case)
52- case class GameUIResult (text : String )
53-
54-
55- object UICommandMethods {
56-
57- import UICommand .UIMoveCommand
58- def moveSelection (uiState : GameUIState ,
59- moveCommand : UIMoveCommand ): GameUIState = {
60- import UICommand ._
61- moveCommand match {
62- case Up => uiState.withRowAdustedBy(- 1 )
63- case Down => uiState.withRowAdustedBy(1 )
64- case Left => uiState.withColumnAdustedBy(- 1 )
65- case Right => uiState.withColumnAdustedBy(1 )
66- }
67- }
68-
69- // ?? "place mark"?
70- def markAtSelection (uiState : GameUIState ): GameUIState = {
71- val moveResult = uiState.gameState.tryMoveAt(uiState.selectedRow,
72- uiState.selectedColumn)
73- moveResult match {
74- case Right (newGameState) =>
75- uiState.copy(gameState = newGameState)
76- case Left (errorMsg) =>
77- // ?? clean I/O? add to result and hjave cmd loop show? call ~injected error reporter?
78- println(errorMsg)
79- uiState // no change
80- }
81- }
82-
83- def doQuit (uiState : GameUIState ): GameUIResult = {
84- GameUIResult (" Game was quit" )
85- }
86- }
87-
88- // ?? clean looping more (was while mess, now recursive; is there better Scala way?)
89- /**
90- * Logically, loops on prompting for and executing user UI ~commands until
91- * game over or quit.
92- */
93- @ tailrec
94- def getAndDoUiCommands (uiState : GameUIState ): GameUIResult = {
95- println()
96- println(uiState.toDisplayString)
97-
98- val command = getCommand(uiState.gameState.currentPlayer)
99-
100- import UICommand ._
101- import UICommandMethods ._
102- command match {
103- // ?? can we factor down the multiple getAndDoUiCommands calls (usefully, in this small case)?
104- case Quit =>
105- doQuit(uiState)
106- case move : UIMoveCommand => // any move-selection command
107- getAndDoUiCommands(moveSelection(uiState, move))
108- case Mark =>
109- val newUiState = markAtSelection(uiState)
110- newUiState.gameState.gameResult match {
111- case None => // game not done yet
112- getAndDoUiCommands(newUiState)
113- case Some (gameResult) =>
114-
115- import GameState .GameResult ._
116- val textResult =
117- gameResult match {
118- case Draw => " Game ended in draw"
119- case Win (player) => s " Player $player won "
120- }
121- GameUIResult (textResult) // ?? refine from text
122- }
123- }
124- }
125-
126- // ////////////////////////////////////////////////////////////////////
12713
14+ // ???? move to GameUI
12815 val initialState =
12916 // ?? maybe clean getting indices; maybe get from index ranges, not
13017 // constructing here (though here exercises refined type_)
13118 GameUIState (GameState .initial, RowIndex (Index (1 )), ColumnIndex (Index (1 )))
13219
133- val gameResult : GameUIResult = getAndDoUiCommands(initialState)
20+ val gameResult : GameUI . GameUIResult = GameUI . getAndDoUiCommands(initialState)
13421 println(" Result: " + gameResult.text)
13522
13623}
0 commit comments