views:

635

answers:

7

I'm wondering what language would be most suitable to simulate the game Chutes and Ladders (Snakes and Ladders in some countries). I'm looking to collect basic stats, like average and standard deviation of game length (in turns), probability of winning based on turn order (who plays first, second, etc.), and anything else of interest you can think of. Specifically, I'm looking for the implementation that is most readable, maintainable, and modifiable. It also needs to be very brief.

If you're a grown-up and don't spend much time around young kids then you probably don't remember the game that well. I'll remind you:

  • There are 100 squares on the board.
  • Each player takes turn spinning a random number from 1-6 (or throwing a dice).
  • The player then advances that many squares.
  • Some squares are at the base of a ladder; landing on one of these squares means the player gets to climb the ladder, advancing the player's position to a predetermined square.
  • Some squares are at the top of a slide (chute or snake); landing on one of these squares means the player must slide down, moving the player's position back to a predetermined square.
  • Whichever player gets to position 100 first is the winner.
+14  A: 

You should check out something along the lines of Ruby or Python. Both are basically executable psuedocode.

You might be able to get a shorter, more brilliant program with Haskell, but I would imagine Ruby or Python would probably be actually understandable.

Ben Hughes
+1 for Python, since the question was most readable.
paxdiablo
If your Haskell program isn't easy to understand, you're doing it wrong. ("It" is either the coding, or the learning.)
ShreevatsaR
+22  A: 

This is a bit rough, but it should work:

class Board
  attr_accessor :winner

  def initialize(players, &blk)
    @chutes, @ladders = {}, {}
    @players = players
    @move = 0
    @player_locations = Hash.new(0)
    self.instance_eval(&blk)
  end

  def chute(location)
    @chutes[location[:from]] = location[:to]
  end

  def ladder(location)
    @ladders[location[:from]] = location[:to]
  end

  def spin
    player = @move % @players
    die = rand(6) + 1
    location = (@player_locations[player] += die)

    if endpoint = @chutes[location] || endpoint = @ladders[location]
      @player_locations[player] = endpoint
    end

    if @player_locations[player] >= 100
      @winner = player
    end

    @move += 1
  end
end

num_players = 4

board = Board.new num_players, do
  ladder :from => 4, :to => 14
  ladder :from => 9, :to => 31
  # etc.
  chute :from => 16, :to => 6
  # etc.
end

until board.winner
  board.spin
end

puts "Player #{board.winner} is the winner!"
Yehuda Katz
how did I get points for just giving a generic response of "use ruby or python", while this guy actually went ahead and did it? Doesn't really seem fair.
Ben Hughes
@Ben: Welcome to StackOverflow's voting system, where fast is better than useful, correct-looking is better than correct, and people vote to say "I like this answer" rather than "This answer is helpful". :-)
ShreevatsaR
Because the question was specifically "what language is most readable?", not "please do it for me" :-)
paxdiablo
@Ben: I considered removing my upvote on yours once I saw this answer, but I reconsidered after remembering your note on Haskell.
Domenic
I like this answer :P
Osama ALASSIRY
I made a few fixes in the code so that it should now run.
lillq
+1  A: 

I remember about 4 years ago being it a Top Coders competition where the question was what is the probability that player 1 win at snakes and ladders.

There was a really good write-up how to do the puzzle posted after the match. Can't find it now but this write-up is quite good

C/C++ seemed enough to solve the problem well.

Simeon Pilgrim
Any language would be enough.
Osama ALASSIRY
Yes agreed, I was pointing out that even old-school language are good in this domain.
Simeon Pilgrim
+1  A: 

Pick any object oriented language, they were invented for simulation.

Since you want it to be brief (why?), pick a dynamically typed language such as Smalltalk, Ruby or Python.

starblue
Readability implies brevity. Other things being equal, it's easier to read one page than two.
David Thornley
Except that other things aren't equal. Explicitly writing down the types give you extra information, which may make it easier to understand the code.
starblue
+3  A: 

For many statistics, you don't need to simulate. Using Markov Chains, you can reduce many problems to matrix operations on a 100x100-matrix, which only take about 1 millisecond to compute.

mattiast
Would you mind providing a little more information, or links to sources? This sounds very interesting.
landon9720
http://en.wikipedia.org/wiki/Examples_of_Markov_chains <- There is an example with 2 states, you will need 100 states (corresponding the 100 squares). Basically from each state there is always 1/6 probability to move to six different states. Don't read the actual Wikipedia article on Markov Chains, that'll only confuse you!
mattiast
This idea should have gotten more votes. But keep in mind that if you wanted to deal with two players, you would have either to move up to a (100x100)x(100x100) matrix or to be a lot more clever.
othercriteria
+2  A: 

I'm going to disagree with some of the earlier posters, and say that an object oriented approach is the wrong thing to do here, as it makes things more complicated.

All you need is to track the position of each player, and a vector to represent the board. If the board position is empty of a chute or ladder, it is 0. If it contains a ladder, the board contains a positive number that indicates how many positions to move forward. If it contains a chute, it contains a negative number to move you back. Just track the number of turns and positions of each player.

The actual simulation with this method is quite simple, and you could do it in nearly any programming language. I would suggest R or python, but only because those are the ones I use most these days.

I don't have a copy of chutes and ladders, so I made up a small board. You'll have to put in the right board:

#!/usr/bin/python

import random, numpy

board = [0, 0, 0, 3, 0, -3, 0, 1, 0, 0]
numplayers = 2
numruns = 100

def simgame(numplayers, board):
    winner = -1
    winpos = len(board)
    pos = [0] * numplayers
    turns = 0
    while max(pos) < winpos:
        turns += 1
        for i in range(0, numplayers):
            pos[i] += random.randint(1,6)
            if pos[i] < winpos:
                pos[i] += board[pos[i]]
            if pos[i] >= winpos and winner == -1:
                winner = i
    return (turns, winner)

# simulate games, then extract turns and winners
games = [simgame(numplayers, board) for x in range(numruns)]
turns = [n for (n, w) in games]
winner = [w for (t, w) in games]
pwins = [len([p for p in winner if p == i]) for i in range(numplayers)]

print "runs:", numruns
print "mean(turns):", numpy.mean(turns)
print "sd(turns):", numpy.std(turns)
for i in range(numplayers):
    print "Player", (i+1), "won with proportion:", (float(pwins[i])/numruns)
leif
Triple loop with conditional statement. Is this most readable? I bet that python can do better.
Arnis L.
I bet it can too. Sadly, I'm not the greatest with python, I spend too much time writing R code. I got rid of the loop conditional by tracking the winner, and I got rid of some of the loops by (a probably poor attempt) using list comprehensions.
leif
+1  A: 

F# isn't too ugly as well, its hard to beat a functional language for conciseness:

#light
open System 

let snakes_and_ladders = dict [(1,30);(2,5);(20,10);(50,11)]

let roll_dice(sides) =  
    Random().Next(sides) + 1

let turn(starting_position) =
    let new_pos = starting_position + roll_dice(6)   
    let found, after_snake_or_ladder = snakes_and_ladders.TryGetValue(new_pos)
    if found then after_snake_or_ladder else new_pos 

let mutable player_positions = [0;0]

while List.max player_positions < 100 do
    player_positions <- List.map turn player_positions 

if player_positions.Head > 100 then printfn "Player 1 wins" else printf "Player 2 wins"
Sam Saffron