Created
September 5, 2016 13:27
-
-
Save xianny/06382e3f63037fbc5f514c5d5b7ed2b0 to your computer and use it in GitHub Desktop.
This file contains 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
import scala.io.StdIn | |
object Game { | |
val cols = Seq("1", "2", "3") | |
val rows = Seq("A", "B", "C") | |
val default = "_" | |
def token(player: Boolean) = if (player) "X" else "O" | |
def main(args: Array[String]) = { | |
val gameState = squares.map((_, default)).toMap | |
prettyPrintGame(gameState) | |
run(true, gameState) | |
} | |
def run(player: Boolean, currState: Map[String, String]): Unit = { | |
val nextState = playTurn(player, currState) | |
prettyPrintGame(nextState) | |
findWinner(nextState) match { | |
case None => run(!player, nextState) | |
case Some("ERR") => println("Illegal game state. Ending game.") | |
case Some("DRAW") => println("Draw! Ending game.") | |
case Some(token) => println(s"Game over, player `$token` wins") | |
} | |
} | |
def playTurn(player: Boolean, currState: Map[String, String]): Map[String, String] = { | |
println("Enter square to fill, e.g. A1") | |
val input = readLine(s"Player `${token(player)}`: ") | |
if (squares.contains(input) && currState.get(input) == Some(default)) { | |
currState + (input -> token(player)) | |
} else { | |
println("Invalid input") | |
playTurn(player, currState) | |
} | |
} | |
def findWinner(state: Map[String, String]): Option[String] = { | |
val xs = state.filter(_._2 == "X").keys.toSet | |
val os = state.filter(_._2 == "O").keys.toSet | |
val xWin = wins.exists(set => set.toSet.subsetOf(xs)) | |
val oWin = wins.exists(set => set.toSet.subsetOf(os)) | |
if (xWin && oWin) { | |
Some("ERR") | |
} else if (xWin) { | |
Some("X") | |
} else if (oWin) { | |
Some("O") | |
} else if (xs.size + os.size == state.size) { | |
Some("DRAW") | |
} else { | |
None | |
} | |
} | |
def crossX(as: Seq[String], bs: Seq[String]): Seq[String] = { | |
for (a <- as; | |
b <- bs) yield | |
a+b | |
} | |
def inverse(as: Seq[String], bs: Seq[String]) = { | |
for (i <- 0 until as.length; | |
a = as(i); | |
b = bs(bs.length - 1 - i)) yield | |
a+b | |
} | |
val squares = crossX(rows, cols) | |
val colSquares = cols.map(c => crossX(rows, Seq(c))) | |
val rowSquares = rows.map(r => crossX(Seq(r), cols)) | |
val diagonals = Seq(inverse(rows, cols), inverse(rows.reverse, cols)) | |
val wins: Seq[Seq[String]] = colSquares ++ rowSquares ++ diagonals | |
def prettyPrintGame(state: Map[String, String]) = { | |
val _rows = for ( | |
(sqs, i) <- squares.sliding(rows.length, rows.length).zipWithIndex; | |
values = sqs.map(sq => state.get(sq).getOrElse("_")); | |
label = rows(i)) yield label ++ values | |
val _cols = " " ++ cols | |
println(_cols.mkString(" | ")) | |
_rows.foreach(r => println(r.mkString(" | "))) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
to run:
$ scala tictactoe.scala