Last active
October 15, 2016 02:13
-
-
Save countingtoten/8c413ddb1cedf9c8624a146983bf8e52 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Player() | |
case class X() extends Player { | |
override def toString(): String = { | |
"X" | |
} | |
} | |
case class O() extends Player { | |
override def toString(): String = { | |
"O" | |
} | |
} | |
type Owner = Option[Player] | |
class Status() | |
case class Winner(player: Player) extends Status | |
case class InProgress() extends Status | |
case class Draw() extends Status | |
case class Tile(loc: Int, owner: Owner) { | |
override def toString(): String = { | |
owner match { | |
case Some(player) => player.toString | |
case _ => s"$loc" | |
} | |
} | |
} | |
val blankState = (0 to 8).map(loc => new Tile(loc, None)).toList | |
case class Board(state: List[Tile] = blankState, nextPlayer: Player = X()) { | |
def move(loc: Int) : Board = { | |
val (front, back) = state.splitAt(loc) | |
back match { | |
case Tile(_, None) :: tail => { | |
val newState = front ::: new Tile(loc, Some(nextPlayer)) :: tail | |
new Board(newState, otherPlayer) | |
} | |
case _ => throw new Error(s"Invalid location $loc") | |
} | |
} | |
def otherPlayer = { | |
nextPlayer match { | |
case X() => O() | |
case O() => X() | |
} | |
} | |
// val (x, y) = (v % 3, v / 3) | |
// 0,0 | 1,0 | 2,0 | |
// 0,1 | 1,1 | 2,1 | |
// 0,2 | 1,2 | 2,2 | |
def gameState : Status = { | |
val (placements, movesLeft) = state.foldLeft(Map[String, Owner](), 0) { (result, tile) => | |
val (collection, movesLeft) = result | |
def newVal(key: String) = { | |
collection.get(key) match { | |
case None => { | |
tile.owner | |
} | |
case Some(owner) if owner == tile.owner => { | |
owner | |
} | |
case _ => { | |
None | |
} | |
} | |
} | |
val (x, y) = (tile.loc % 3, tile.loc / 3) | |
val rowKey = s"row$y" | |
val rowVal = newVal(rowKey) | |
val colKey = s"col$x" | |
val colVal = newVal(colKey) | |
val diag1Key = "diag1" | |
val diag1Val = newVal(diag1Key) | |
val diag2Key = "diag2" | |
val diag2Val = newVal(diag2Key) | |
val newVals = if (x == y && x + y == 2) { | |
Map(diag1Key -> diag1Val, diag2Key -> diag2Val, rowKey -> rowVal, colKey -> colVal) | |
} else if (x == y) { | |
Map(diag1Key -> diag1Val, rowKey -> rowVal, colKey -> colVal) | |
} else if (x + y == 2) { | |
Map(diag2Key -> diag2Val, rowKey -> rowVal, colKey -> colVal) | |
} else { | |
Map(rowKey -> rowVal, colKey -> colVal) | |
} | |
val move = if (tile.owner.isEmpty) 1 else 0 | |
(collection ++ newVals, movesLeft + move) | |
} | |
def findWinner(values: List[Owner]) : Status = values match { | |
case List() => InProgress() | |
case head :: tail => head match { | |
case Some(x) => Winner(x) | |
case None => findWinner(tail) | |
} | |
} | |
if (movesLeft == 0) { | |
Draw() | |
} else { | |
findWinner(placements.values.toList) | |
} | |
} | |
override def toString(): String = { | |
state.grouped(3).map(_.mkString("|")).mkString("\n") | |
} | |
} | |
def playGame(game: Board = new Board()) : Unit = { | |
game.gameState match { | |
case Winner(player) => println(s"$player is victorious!\n$game") | |
case Draw() => println(s"There are no moves left. It's a stupid tie.\n$game") | |
case InProgress() => { | |
try { | |
game.nextPlayer match { | |
case X() => println("Player 1, your move") | |
case O() => println("Player 2, your move") | |
} | |
println(s"$game\n") | |
val nextMove = scala.io.StdIn.readInt() | |
playGame(game.move(nextMove)) | |
} catch { | |
case e: Throwable => { | |
println(s"Error making a move\n${e.getMessage}") | |
playGame(game) | |
} | |
} | |
} | |
} | |
} | |
playGame() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment