Skip to content

Commit ade5216

Browse files
author
Daniel Barclay
committed
ManualTicTacToe: Simplified and clarified hasThreeInARow.
1 parent 4b59c6b commit ade5216

File tree

4 files changed

+55
-43
lines changed

4 files changed

+55
-43
lines changed

src/main/scala/com/us/dsb/explore/algs/ttt/manual/ManualTicTacToe.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import com.us.dsb.explore.algs.ttt.manual.ui.{ColoredConsoleTextIO, GameUI}
44

55
object ManualTicTacToe extends App {
66

7-
val gameResult = GameUI.runGame(ColoredConsoleTextIO) // ?? specify starting user?
7+
val gameResult = GameUI.runGame(ColoredConsoleTextIO)
88
println("Game result: " + gameResult.text)
99

1010
}

src/main/scala/com/us/dsb/explore/algs/ttt/manual/game/Board.scala

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -53,32 +53,33 @@ private[game] class Board(private val cellStates: Vector[Cell]) {
5353
def hasNoMovesLeft: Boolean = ! cellStates.exists(_.state.isEmpty)
5454

5555

56-
// (note almost completely unoptimized; do we care?)
57-
// ?? revisit passing player (which made check simpler)
58-
def hasThreeInARow(player: Player): Boolean = {
59-
// ?? Q: How to use Tuple3 in data and then convert to or use as 3-element
60-
// List and call .forall?
61-
// ?? any way auto-generate this simply? or factor out repeated cell pairs?
62-
type CellRawIndices = Tuple2[Int, Int]
63-
val linesData: List[Tuple3[CellRawIndices, CellRawIndices, CellRawIndices]] =
64-
List(
65-
((1, 1), (1, 2), (1, 3)),
66-
((2, 1), (2, 2), (2, 3)),
67-
((3, 1), (3, 2), (3, 3)),
68-
((1, 1), (2, 1), (3, 1)),
69-
((1, 2), (2, 2), (3, 2)),
70-
((1, 3), (2, 3), (3, 3)),
71-
((1, 1), (2, 2), (3, 3)),
72-
((1, 3), (2, 2), (3, 1))
73-
)
74-
// See if there _exists_ line where _all_ cells are marked by user:
56+
// ?? Q: How to use Tuple3 in data and then convert to or use as 3-element
57+
// List and call .forall?
58+
// ?? any way auto-generate this simply? or factor out repeated cell pairs?
59+
private type CellRawIndices = Tuple2[Int, Int]
60+
private val linesData: List[Tuple3[CellRawIndices, CellRawIndices, CellRawIndices]] =
61+
List(
62+
((1, 1), (1, 2), (1, 3)),
63+
((2, 1), (2, 2), (2, 3)),
64+
((3, 1), (3, 2), (3, 3)),
65+
((1, 1), (2, 1), (3, 1)),
66+
((1, 2), (2, 2), (3, 2)),
67+
((1, 3), (2, 3), (3, 3)),
68+
((1, 1), (2, 2), (3, 3)),
69+
((1, 3), (2, 2), (3, 1)))
70+
71+
def hasThreeInARow: Boolean = {
72+
// See if there _exists_ line where _all_ cells are marked by the same player:
7573
linesData.exists { case (cell1, cell2, cell3) =>
76-
val lineList = List(cell1, cell2, cell3)
77-
lineList.forall { case (row, column) =>
78-
player.some ==
79-
getMarkAt(RowIndex(Index.unsafeFrom(row)),
80-
ColumnIndex(Index.unsafeFrom(column)))
74+
val lineCellValues =
75+
List(cell1, cell2, cell3) .map { case (row, column) =>
76+
getMarkAt(RowIndex(Index.unsafeFrom(row)),
77+
ColumnIndex(Index.unsafeFrom(column)))
8178
}
79+
// if first not None and all same as that first one:
80+
// compare all to first (if not None)
81+
val firstCellState = lineCellValues.head // .get -- list size > 0
82+
firstCellState.isDefined && lineCellValues.forall(_ == firstCellState)
8283
}
8384
}
8485

src/main/scala/com/us/dsb/explore/algs/ttt/manual/game/GameState.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ case class GameState(board: Board,
4141
case None =>
4242
val markedBoard = board.withCellMarkedForPlayer(row, column, currentPlayer)
4343
val newGameResult =
44-
if (markedBoard.hasThreeInARow(currentPlayer)) {
44+
if (markedBoard.hasThreeInARow) {
4545
GameState.GameResult.Win(currentPlayer).some
4646
}
4747
else if (markedBoard.hasNoMovesLeft) {

src/test/scala/com/us/dsb/explore/algs/ttt/manual/game/BoardTest.scala

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -200,37 +200,48 @@ class BoardTest extends AnyFunSpec {
200200
implicit def intToRow(int: Int) = RowIndex(Index.unsafeFrom(int))
201201
implicit def intToCol(int: Int) = ColumnIndex(Index.unsafeFrom(int))
202202

203+
lazy val `<XX-/---/OO->` = {
204+
Board.initial
205+
.withCellMarkedForPlayer(1, 1, X)
206+
.withCellMarkedForPlayer(3, 1, O)
207+
.withCellMarkedForPlayer(1, 2, X)
208+
.withCellMarkedForPlayer(3, 2, O)
209+
}
210+
lazy val `<XXX/---/OO->` = {
211+
`<XX-/---/OO->`
212+
.withCellMarkedForPlayer(1, 3, X)
213+
}
214+
lazy val `<XX-/X--/OOO>` = {
215+
`<XX-/---/OO->`
216+
.withCellMarkedForPlayer(2, 1, X)
217+
.withCellMarkedForPlayer(3, 3, O)
218+
}
219+
203220
it("should not detect for empty board") {
204221
val testBoard = Board.initial
205-
assertResult(false, s" (from .hasThreeInARow(X) for $testBoard)") {
206-
testBoard.hasThreeInARow(X)
222+
assertResult(false, s" (from .hasThreeInARow for $testBoard)") {
223+
testBoard.hasThreeInARow
207224
}
208225
}
209226

210-
lazy val `<XXX/---/OO->` = {
211-
Board.initial
212-
.withCellMarkedForPlayer(1, 1, X)
213-
.withCellMarkedForPlayer(3, 1, O)
214-
.withCellMarkedForPlayer(1, 2, X)
215-
.withCellMarkedForPlayer(3, 2, O)
216-
.withCellMarkedForPlayer(1, 3, X)
217-
}
218-
219-
it("should detect for some three-in-a-row case, w/right player") {
220-
assertResult(true, s" (from .hasThreeInARow(X) for ${`<XXX/---/OO->`})") {
221-
`<XXX/---/OO->`.hasThreeInARow(X)
227+
it("should detect for some three-in-a-row case for X ") {
228+
assertResult(true, s" (from .hasThreeInARow for ${`<XXX/---/OO->`})") {
229+
`<XXX/---/OO->`.hasThreeInARow
222230
}
223231
}
224232

225-
it("should not detect for wrong player") {
226-
assertResult(false, s" (from .hasThreeInARow(O) for ${`<XXX/---/OO->`})") {
227-
`<XXX/---/OO->`.hasThreeInARow(O)
233+
it("should for detect some three-in-a-row case for O") {
234+
assertResult(true, s" (from .hasThreeInARow for ${`<XX-/X--/OOO>`})") {
235+
`<XX-/X--/OOO>`.hasThreeInARow
228236
}
229237
}
230238

231239
ignore("possibly check all lines (algorithmically)") {
232240
}
233241

242+
ignore("possibly check more/all non-wins (algorithmically)") {
243+
}
244+
234245
}
235246

236247
describe("Board.vectorIndex (private method we want to test directly):") {

0 commit comments

Comments
 (0)