Skip to content

Instantly share code, notes, and snippets.

@countingtoten
Last active October 15, 2016 02:13
Show Gist options
  • Save countingtoten/8c413ddb1cedf9c8624a146983bf8e52 to your computer and use it in GitHub Desktop.
Save countingtoten/8c413ddb1cedf9c8624a146983bf8e52 to your computer and use it in GitHub Desktop.
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