Categories
Programming

Apple’s Snakes and Ladders Swift Example

All the cool kids are learning Swift this week! Not wanting to be left out I downloaded Xcode beta 6 and the iBook introduction and started following long with the code sample in Xcode’s new playground.

Swift is impressive as it fixes a number of issues with Objective-C by replacing it wholesale with a modern language that feels like a well thought-out JavaScript. I love the idea of optional values, implicit types, simple generics, and how let and var are used to create immutable and mutable objects. I’m still digesting the class vs struct vs enum idea. I’m not sure why they are just not all classes but give me time, I’m sure I’ll see the light.

The Snakes and Ladders example is a fine bit of sample code and shows off Swift’s power as a teaching language. But I had a couple of issues with it and tweaked it. See below and check out the comments for why I did what I did. You should be able to copy and paste this code into a playground and watch it run!

// Playground - noun: a place where people can play

import Cocoa

// Snakes and Ladders Game

let finalSquare = 25 // 25 squares in the game (0 to 24)

// init all squares to 0 and included a 26th square (to simplify the code)
// Note: you can use var or let to define the array board (Apple uses var, I'm using let)
// - let makes board a constant but values of a const array are still mutable
// - its the number of elements in the array that are immutable
// - using let allows the compiler to optimize looking up values in the array
let board = Int[] (count: finalSquare + 1, repeatedValue: 0)

// in 4 squares as ladders (+ values) and 4 squares as snakes (- values)
// ladders move the player forward by value in square
// snakes move the player backward by value in square
board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02
board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08

var square = 0   // player position
var diceRoll = 0 // moves are determined by an 8-sided die

println("Game Starting at square \(square)")
// start the game
while square 

Update!

I could not get the sweet while loop with the label "gameLoop" to work in the playground. It's no surprise that Swift has a couple of bugs. So with a bit of fiddling I got it to work with a gameOver flag. And while I was at it I created a swifty function to hide the ugly arc4Rand_uniform() call and refactored the print statements so you can follow along with the game in the console.

func randNum(limit: Int) -> Int {
  return Int(arc4random_uniform(UInt32(limit)))
}

// start the game
println("Game Starting at square \(square)")

var gameOver = false

gameLoop: while square != finalSquare {
  diceRoll = randNum(7)
  switch square + diceRoll {
  case finalSquare:
    // diceRolled moved player to finalSquare
    // game over
    print("starting \(square), ")
    print("diceRoll \(diceRoll), ")
    print("destination \(square + diceRoll), Game Over")
    println()
    
    // Swift didn't recognise the loop's label so I commented it out
    // This teams the break only breaks out of the switch
    // The gameOver flag is used to break out of the while loop
    gameOver = true
    break //gameloop
  case let newSquare where newSquare > finalSquare:
    // diceRoll moved player beyound finalSquare
    // roll again
    print("starting \(square), ")
    print("diceRoll \(diceRoll), ")
    print("destination \(square + diceRoll), Re-roll")
    println()
    
    // Swift didn't recognise the loop's label but in this case
    // it doesn't matter...
    continue //gameloop
  default:
    // valid move
    // update board
    print("starting \(square), ")
    print("diceRoll \(diceRoll), ")
    square += diceRoll
    print("destination \(square), ")
    print("instruction \(board[square]), ")
    square += board[square]
    print("result \(square)")
    println()
  }
  // if flag is set break out of the while loop
  if gameOver {
    break
  }
}