I didn't do the Prolog chapter yet. I'll come back to it. I need to take some time to study what I can do in Prolog before I can do the exercises there. So now I'm on the Scala chapter.

I'm not sure how I feel about Scala yet. There's some good stuff here and some stuff that feels like it's just different for the sake of being different like class definitions and accessing array elements with () instead of []. I also don't like how some types of collections, like Arrays, don't have methods that it seems they should have such as flatten for multidimensional arrays. Flatten exists and is there for Lists but not Arrays. There's also no break statement in Scala 2.7, although it was added for 2.8.

I do like the syntactic sugar that was added to give us a language sort of like Java but closer to the code terseness that many of us have gotten used to with Perl, Python, and Ruby. In Scala the syntactic sugar has most resembled Ruby to me, but with a nice brackety syntax that I'm used to from Perl rather than typing out "end" for blocks. While I haven't read the parts of the book that cover it yet, it's well known that Scala has excellent concurrency functionality and I've seen that it has handy stuff like Actors.

Now onto the code. The project was to create a tic-tac-toe game that let two players alternate turns and would detect who won or if there was a tie. I could have taken this a bit further and created a class to represent the board positions and a class for the players, but I feel like my custom exceptions and TTTBoard class were enough. With the TTTBoard class I can split the class out into a separate file from the main game loop logic and put a different front end on with nicer graphics or Swing if I feel like it.

var gameWon = false
val myBoard = new TTTBoard()

val winner = gameLoop()
println("Game Over!!!")
if(gameWon) {
  println("Player " + winner + " wins!")
} else {
  println("Tie!")
}

def gameLoop(): String = {
  while(!gameWon) {
    draw(myBoard)
    Array("X","O").foreach {
      player => playerTurn(player,myBoard)
      draw(myBoard)
      gameWon = myBoard.checkForWin(player)
      //Scala 2.7 does not have a break keyword to get out of this foreach loop early
      //so this is all in the gameLoop method so that it can return early
      //even though that means gameWon variable is being treated as a global
      if(gameWon) return player
      if(myBoard.movesLeft <= 0) return ""
    }
  }
  return ""
}

def playerTurn(player: String, board: TTTBoard) {
  var validInput = false
  var position = new Array[Int](2)
  while(!validInput) {
    print("Enter a position on the grid for player " + player + ": ")
    val input = Console.readLine()
    try {
      position = input.split(",").map(i => i.toInt)
      position.foreach {
        i => if(i >= 0 && i <= 2) {
          validInput = true
        } else {
          validInput = false
        }
      }
    } catch {
      //Scala catch blocks are weird...
      case e: NumberFormatException => validInput = false
    }

    //This is inside the loop so that the exception can be caught
    //and the player asked again.  It used to be outside the loop
    if(validInput) {
      try {
        myBoard.updateBoard(position,player)
      } catch {
        case e: InvalidPlayerException => validInput = false
        case e: PositionTakenException => validInput = false; println("Hey, that position is taken!")
      }
    }
  }
}

def draw(board: TTTBoard) {
  println()
  for(i <- 0 until board.board.length) {
    println(board.board(i)(0) + "|" + board.board(i)(1) + "|" + board.board(i)(2))
    if(i == 1 || i == 0) println("-----")
  }
  println()
}

class TTTBoard {

  var board = Array(Array(" ", " ", " "),
                    Array(" ", " ", " "),
                    Array(" ", " ", " "));

  val winPosition = Array(List(List(0,0),List(0,1),List(0,2)),
                          List(List(1,0),List(1,1),List(1,2)),
                          List(List(2,0),List(2,1),List(2,2)),
                          List(List(0,0),List(1,1),List(2,2)),
                          List(List(0,0),List(1,0),List(2,0)),
                          List(List(0,1),List(1,1),List(2,1)),
                          List(List(0,2),List(1,2),List(2,2)),
                          List(List(0,2),List(1,1),List(2,0))
                        );

  var movesLeft = 9

  // this should take a tuple for the position
  @throws(classOf[PositionTakenException])
  @throws(classOf[InvalidPlayerException])
  def updateBoard(position: Array[Int], player: String) {
    if(player.toUpperCase != "X" && player.toUpperCase != "O") {
      throw new InvalidPlayerException()
    }
    if(board(position(0))(position(1)) != " ") throw new PositionTakenException()

    board(position(0))(position(1)) = player
    //no -- on ints?
    movesLeft -= 1
  }

  def checkForWin(player: String): Boolean = {
    var winning = false
    winPosition.foreach  {
      row =>
        val a = row(0)
        val b = row(1)
        val c = row(2)
        if(board(a(0))(a(1)) == player &&
           board(b(0))(b(1)) == player &&
           board(c(0))(c(1)) == player) {
             winning = true
           }
      //else { need more tiger blood }
    }
    return winning;
  }
}

class InvalidPlayerException extends Exception {}
class PositionTakenException extends Exception {}