Browse files

Add Scala Day 1 TicTacToe exercise and tests

  • Loading branch information...
1 parent 38ce320 commit a383f67f652b595ab27ed0d143393d3c40ace8c4 @mbbx6spp committed Jul 6, 2011
View
12 scala/build.sbt
@@ -0,0 +1,12 @@
+name := "sevenlanguages"
+
+version := "0.1.0"
+
+scalaVersion := "2.9.0"
+
+autoCompilerPlugins := true
+
+libraryDependencies += "org.scalatest" %% "scalatest" % "1.6.1" % "test"
+
+//resolvers += "Proguard plugin repo" at "http://siasia.github.com/maven2"
+//libraryDependencies <+= sbtVersion("com.github.siasia" %% "xsbt-proguard-plugin" % _)
View
0 scala/project/build.properties
No changes.
View
102 scala/src/main/scala/day1/tictactoe.scala
@@ -0,0 +1,102 @@
+/**
+ * @author Susan Potter <@SusanPotter>
+ *
+ * This is my simple attempt to model a tictactoe game in Scala Day 1.
+ * From the Seven Languages Seven Weeks book.
+ */
+package day1.tictactoe {
+
+ import scala.collection.mutable._
+
+ class TicTacToeSymbol(symbol : java.lang.Character) {
+ def print = println(symbol)
+ def toChar = symbol
+ override def toString = symbol.toString
+ }
+
+ // Psuedo flyweights via object declarations
+ // I could just use java.lang.Characters or even Strings,
+ // but I wanted to see what would happen with extending object
+ // definitions this way.
+
+ // PS a Nought is an 'oh' and a Cross is an 'ex' for American readers
+ object Nought extends TicTacToeSymbol('O')
+ object Cross extends TicTacToeSymbol('X')
+ object Empty extends TicTacToeSymbol(' ')
+
+ class TicTacToeLine(cells : List[TicTacToeSymbol]) {
+ def isWinning = {
+ val first = cells.first
+ if (Nought == first || Cross == first) {
+ cells.forall { cell =>
+ first == cell
+ }
+ } else {
+ false
+ }
+ }
+
+ def isEmpty = {
+ cells.forall { cell => cell == Empty }
+ }
+
+ def toList = {
+ cells
+ }
+ }
+
+ object EmptyLine extends TicTacToeLine(List(Empty, Empty, Empty))
+
+ // immutable so precalculate all "views" of matrix
+ class TicTacToeMatrix(rows : List[TicTacToeLine]) {
+ val length = rows.length
+ val range = 0 until length
+ val columns = new ArrayBuffer[TicTacToeLine](length)
+ range.foreach { colIdx =>
+ val l = new ArrayBuffer[TicTacToeSymbol](length)
+ rows.foreach { row =>
+ l.append(row.toList(colIdx))
+ }
+ columns.append(new TicTacToeLine(l.toList))
+ }
+ println(columns)
+
+ def winner : Option[TicTacToeLine] = {
+ List(winningHorizontal, winningVertical, winningDiagonal).find { line =>
+ line.isWinning
+ }
+ }
+
+ private def winningHorizontal : TicTacToeLine = {
+ rows.find { row => row.isWinning }.getOrElse(EmptyLine)
+ }
+
+ private def winningVertical : TicTacToeLine = {
+ columns.find { col => col.isWinning }.getOrElse(EmptyLine)
+ }
+
+ private def winningDiagonal : TicTacToeLine = {
+ val left = new ArrayBuffer[TicTacToeSymbol](length)
+ val right = new ArrayBuffer[TicTacToeSymbol](length)
+ range.foreach { idx =>
+ left.append(getAt(idx, idx))
+ right.append(getAt((length - idx - 1), idx))
+ }
+ List(new TicTacToeLine(left.toList),
+ new TicTacToeLine(right.toList)).find { diag =>
+ diag.isWinning
+ }.getOrElse(EmptyLine)
+ }
+
+ private def getAt(X : Int, Y : Int) : TicTacToeSymbol = {
+ val row = rows.toList(Y)
+ row.toList(X)
+ }
+ }
+
+ class TicTacToeBoard(matrix : TicTacToeMatrix) {
+ def whoWins : TicTacToeSymbol = {
+ matrix.winner.getOrElse(EmptyLine).toList.head
+ }
+ }
+}
View
89 scala/src/test/scala/day1/tictactoe_spec.scala
@@ -0,0 +1,89 @@
+import org.scalatest.FlatSpec
+import org.scalatest.matchers.ShouldMatchers
+import day1.tictactoe._
+
+class TicTacToeSpec extends FlatSpec with ShouldMatchers {
+ "A Nought" should "return 'O' from #toChar" in {
+ assert(Nought.toChar === 'O')
+ }
+
+ "A Cross" should "return 'X' from #toChar" in {
+ assert(Cross.toChar === 'X')
+ }
+
+ "A Cross winning 4x4 TicTacToe line" should "return Cross from #isWinning" in {
+ val winningLine = new TicTacToeLine(List(Cross, Cross, Cross, Cross))
+ assert(winningLine.isWinning)
+ }
+
+ "An empty TicTacToe board" should "return Empty as the winner" in {
+ val board = new TicTacToeBoard(
+ new TicTacToeMatrix(List(EmptyLine, EmptyLine, EmptyLine)))
+ assert(Empty === board.whoWins)
+ }
+
+ "An partial TicTacToe board" should "return Empty as the winner" in {
+ val row1 = new TicTacToeLine(List(Nought, Empty, Empty))
+ val row2 = new TicTacToeLine(List(Empty, Cross, Empty))
+ val row3 = new TicTacToeLine(List(Empty, Empty, Nought))
+ val board = new TicTacToeBoard(new TicTacToeMatrix(List(row1, row2, row3)))
+ assert(Empty === board.whoWins)
+ }
+
+ "A tied TicTacToe board" should "return Empty as the winner" in {
+ val row1 = new TicTacToeLine(List(Nought, Cross, Nought))
+ val row2 = new TicTacToeLine(List(Nought, Cross, Cross))
+ val row3 = new TicTacToeLine(List(Cross, Nought, Nought))
+ val board = new TicTacToeBoard(new TicTacToeMatrix(List(row1, row2, row3)))
+ assert(Empty === board.whoWins)
+ }
+
+ "A Nought left diagonal winning TicTacToe board" should "return Nought as the winner" in {
+ val row1 = new TicTacToeLine(List(Nought, Cross, Empty))
+ val row2 = new TicTacToeLine(List(Empty, Nought, Empty))
+ val row3 = new TicTacToeLine(List(Empty, Cross, Nought))
+ val board = new TicTacToeBoard(new TicTacToeMatrix(List(row1, row2, row3)))
+ assert(Nought === board.whoWins)
+ }
+
+ "A Cross column winning TicTacToe board" should "return Cross as the winner" in {
+ val row1 = new TicTacToeLine(List(Nought, Cross, Nought))
+ val row2 = new TicTacToeLine(List(Empty, Cross, Empty))
+ val row3 = new TicTacToeLine(List(Empty, Cross, Nought))
+ val board = new TicTacToeBoard(new TicTacToeMatrix(List(row1, row2, row3)))
+ assert(Cross === board.whoWins)
+ }
+
+ "A Cross row winning TicTacToe board" should "return Cross as the winner" in {
+ val row1 = new TicTacToeLine(List(Cross, Cross, Cross))
+ val row2 = new TicTacToeLine(List(Empty, Nought, Empty))
+ val row3 = new TicTacToeLine(List(Empty, Nought, Nought))
+ val board = new TicTacToeBoard(new TicTacToeMatrix(List(row1, row2, row3)))
+ assert(Cross === board.whoWins)
+ }
+
+ "A Nought right diagonal winning TicTacToe board" should "return Nought as the winner" in {
+ val row1 = new TicTacToeLine(List(Cross, Cross, Nought))
+ val row2 = new TicTacToeLine(List(Empty, Nought, Empty))
+ val row3 = new TicTacToeLine(List(Nought, Cross, Nought))
+ val board = new TicTacToeBoard(new TicTacToeMatrix(List(row1, row2, row3)))
+ assert(Nought === board.whoWins)
+ }
+
+ "A Cross 4x4 column winning TicTacToe board" should "return Cross as the winner" in {
+ val row1 = new TicTacToeLine(List(Nought, Cross, Nought, Empty))
+ val row2 = new TicTacToeLine(List(Empty, Cross, Nought, Empty))
+ val row3 = new TicTacToeLine(List(Empty, Cross, Nought, Cross))
+ val row4 = new TicTacToeLine(List(Nought, Cross, Empty, Nought))
+ val board = new TicTacToeBoard(new TicTacToeMatrix(List(row1, row2, row3, row4)))
+ assert(Cross === board.whoWins)
+ }
+ "A Nought 4x4 left diagonal winning TicTacToe board" should "return Nought as the winner" in {
+ val row1 = new TicTacToeLine(List(Nought, Cross, Nought, Empty))
+ val row2 = new TicTacToeLine(List(Empty, Nought, Empty, Empty))
+ val row3 = new TicTacToeLine(List(Empty, Cross, Nought, Cross))
+ val row4 = new TicTacToeLine(List(Nought, Cross, Empty, Nought))
+ val board = new TicTacToeBoard(new TicTacToeMatrix(List(row1, row2, row3, row4)))
+ assert(Nought === board.whoWins)
+ }
+}

0 comments on commit a383f67

Please sign in to comment.