Charlie Harvey

Scala — Day One

Tate compares Scala to Edward Scissorhands in his metaphorical introduction to the chapter. What I’ve seen of the language so far certainly made me feel it was a little on the odd side. Its just near enough to Java that it feels wrong when it works more Rubyishly or more Lispishly. The first day very much focussed on the very basics of the language, especially the more Java-like side of the language. In working my way through the homework and searching the internets for syntax examples, I’ve come across a fair bit of quite cool looking code. Mine isn't!

My initial impressions are rather varied. Its seems a powerful language, not as crazy out there as prolog, and much simpler to master. The manual pages could do with some code examples, but between Getting Started with Scala and Stackoverflow, I got there in the end. My install of Vim didn't have syntax highlighting for Scala set up in it so I followed Lorenzo's Getting scala syntax hightlighting to work in Vim tute. I got very baffled by some syntax issues that were the kind of annoying statically-typed bullshit that would annoy me when I used to write a lot more Java. Listen Scala, we all know its an Int, stop being such a pedant about it. I know, I know, there are good arguments for static typing. Guess it just isn't my bag so much! I’d have liked an increment operator and a ternary operator too. What can I say? I’m lazy.

tictactoe.scala

  • Write a game that will take a tic-tac-toe board with X, O and blank characters and detect the winner or whether there is a tie or no winner yet. Use classes where appropriate.
  • Bonus problem: Let two players play tic tac toe

I took a pretty liberal approach to this. I basically assumed the task was "write a game of tic tac toe". Because that is a bit more interesting. Here is a video.

It took me about twenty minutes to write out some pseudo code, then I started typing working out the syntax as I went along. I fixed 127 syntax errors in all as I wrote it. That is very different to how I’d usually write something, but it was quite cool the first time it ran. There's some notes in the code which are self explanetory. val g=new Game g.play() // The game logic, and "main" method. If this were java. // which it isn't class Game { val board = new Board() var players = new Array[Player](2) var currentPlayer = 0 board.cls() var in = Console.readLine("Player 1 type your name: ") players(0) = new Player() players(0).setName(in) players(0).setPiece(new Nought()) in = Console.readLine("Player 2 type your name: ") players(1) = new Player() players(1).setName(in) players(1).setPiece(new Cross()) println(players(0).getName() + " is playing " + players(0).getPiece().symbol) println(players(1).getName() + " is playing " + players(1).getPiece().symbol) def play() { var gameover = false var again = true while(again) { while(!gameover) { var p = getNextPlayer() board.dump() p.move(this.board) board.dump() if(board.isWinner(p.getPiece()) ) { println(p.name + " wins. Hoorah.\n") gameover=true } else if(board.isFullUp().asInstanceOf[Boolean]){ println("A strange game. The only winning move is not to play. How about a nice game of chess?") gameover=true } } var x = Console.readLine("Play Again? (Y/N) ") if(x=="n" || x=="N") { again = false } } } def getNextPlayer(): Player = { // nb no ternary operator. // Found this syntax at: http://dibblego.wordpress.com/2008/10/13/does-scala-have-javas-ternary-operator/ currentPlayer = if(currentPlayer == 0) 1 else 0 return players(currentPlayer) } } // The tic tac toe board // responsible for tracking the state of the tictactoe squares, and detecting wins/ties // can also dump itself to the screen. there is a convenience cls function. class Board { var squares = new Array[Array[Square]](3,3) var rows = new Array[Array[Square]](3,3) var cols = new Array[Array[Square]](3,3) var diags = new Array[Array[Square]](2,3) val fullUp = 9 var filledSquares = 0 for(i <- 0 until 3) { for(j <- 0 until 3) { squares(i)(j) = new Square() rows(i)(j) = squares(i)(j) } } for(i <- 0 until 3) { for(j <- 0 until 3) { cols(i)(j) = squares(j)(i) } } // I realize this is horrible. didn't find a way to say diags(0) = (x,y,z) Suckage. diags(0)(0) = squares(0)(0) diags(0)(1) = squares(1)(1) diags(0)(2) = squares(2)(2) diags(1)(0) = squares(0)(2) diags(1)(1) = squares(1)(1) diags(1)(2) = squares(2)(0) def putInSquare(squareDef: String, piece: Piece): Boolean = { //split squaredef into a and b what about newline // thx: http://stackoverflow.com/questions/5052042/how-to-split-strings-in-scala var squareDefArr = squareDef.toCharArray // Spent about an hour trying to find asDigit. That did my nut a bit. var a = squareDefArr(0).asDigit var b = squareDefArr(1).asDigit var square = squares(a)(b) if(square.isEmpty()) { // nb: No ++ :-( filledSquares += 1 square.setPiece(piece) return true } else { return false } } // Nasty way to compare things. I should maybe write a equals method in // Square or Piece def isWinner(p: Piece): Boolean = { rows.foreach{row => if( !row(0).isEmpty() && row(0).getPiece().symbol.equals(row(1).getPiece().symbol) && row(1).getPiece().symbol.equals(row(2).getPiece().symbol) ) { return true } } cols.foreach{col => if( !col(0).isEmpty() && col(0).getPiece().symbol.equals(col(1).getPiece().symbol) && col(1).getPiece().symbol.equals(col(2).getPiece().symbol) ) { return true } } diags.foreach{diag => if( !diag(0).isEmpty() && diag(0).getPiece().symbol.equals(diag(1).getPiece().symbol) && diag(1).getPiece().symbol.equals(diag(2).getPiece().symbol) ) { return true } } return false } // clear the screen a-la clear def cls() { for(i <- 0 until 80) { println() } // would rather have said 80.times{} but hey } //print a dump of the board prettily def dump() { cls() for(i <- 0 until rows.length ) { print(" ") rows(i)(0).dump print(" | ") rows(i)(1).dump print(" | ") rows(i)(2).dump println() if(i<2) println("---+---+---") } } def isFullUp(): Boolean = { if(filledSquares == fullUp) { return true } return false } } // a square on the tictactoe board class Square () { var piece = new Piece var wasSet = false def isEmpty(): Boolean = { return (wasSet == false) } def setPiece(p: Piece) { wasSet = true piece = p } def getPiece(): Piece = { return piece } def dump() { if(wasSet) print(piece.symbol) else print(" ") } } // a tictactoe player class Player { var piece = new Piece var name = new String def setPiece (p:Piece) { piece = p } def getPiece(): Piece = { return piece } def setName (n:String) { name = n } def getName(): String = { return name } def move(board: Board): Boolean = { var moveok = false while(!moveok) { // We catch all exceptions and give a vague error // try/catch documented at http://www.scala-lang.org/node/255 try { var moveSpec = Console.readLine("Your move please (00 is top left, 22 is bottom right) " + this.getName() + ": ") if(board.putInSquare(moveSpec, this.getPiece())) moveok = true else println("That square isn't empty") } catch { case e: Exception => println("Invalid move for some reason. Try again.") } } return true } } // base class for noughts and crosses // for readers in the US, tic-tac-toe is usually noughts and crosses in the uk a nought being a 0 // and a cross being an X. Hence the naming of the piece classes. class Piece { var symbol = "?" def getSymbol(): String = { return symbol } } // A nought. There wasn't really a good reason to use inheritence here, could have // used a class atrribute or something. But I figured I’d see how it worked. class Nought extends Piece { symbol = "0" } // A cross piece class Cross extends Piece { symbol = "X" }

So, a mixed first day, didn't enjoy static typing, quite liked taking a top down approach to learning syntax. Yeh, I reckon Scala might grow on me. We'll see in the next installment.


Comments

  • Be respectful. You may want to read the comment guidelines before posting.
  • You can use Markdown syntax to format your comments. You can only use level 5 and 6 headings.
  • You can add class="your language" to code blocks to help highlight.js highlight them correctly.

Privacy note: This form will forward your IP address, user agent and referrer to the Akismet, StopForumSpam and Botscout spam filtering services. I don’t log these details. Those services will. I do log everything you type into the form. Full privacy statement.