```On Fri, Jan 16, 2009 at 7:48 AM, Matthew Moss <matt / moss.name> wrote:

> ## Monopoly Walker
>
>
> You are not implementing the whole game; rather, you are to simulate and
> track just the players' movement. Throw dice, move tokens. Keep track of the
> properties where players land and how often.

My solution is pretty straightforward, I have a Property class and a
Board class. The board holds an array of properties. The interesting
thing comes when some properties have a special move, like "Advance to
St. Charles Place". I used some Procs to keep track of the extra move
behavior. The simulation part involves throwing the dice, then
following all moves until the token stays put (sometimes you can land
on Chance, go back three spaces, land on Community Chest, then advance
to GO).

The first argument to the program states the number of dice throws to
simulate, if none is given 100000 is used.

# Ruby Quiz #188
# Monopoly Walker
# Daniel Moore

# Get some dice action going on
class Fixnum
def d(sides)
sum = 0
self.times {sum += Kernel.rand(sides) + 1}
return sum
end
end

# Cells keep track of their own hit count and any crazy bonus moves
class Property
@@property_count = 0
attr_accessor :count

def initialize(name, block)
@count = 0
@name = name.gsub('_', ' ')
@position = @@property_count
@@property_count += 1
@move_block = block
end

# Record that the token landed on this cell
# Return any bonus move (new location)
def land
@count += 1
# Sometimes cells have a bonus move, this returns
# the new location, could be the same if no bonus move.
@move_block.call(@position)
end

# Print out this cells name and count
def to_s
"(#{"%02d" % @position}) #{@name}#{spacing}- #{@count}"
end

# Arbitrary spacing to format the output cleanly
def spacing
s = " "
(21 - @name.size).times do
s += " "
end
s
end
end

class Board
PROPERTY_NAMES = %w[GO Mediterranean Community_Chest Baltic
Jail/Just_Visiting St._Charles_Place Electric_Company States
Tennessee New_York
Free_Parking Kentucky Chance Indiana Illinois B&O_Railroad
Atlantic Ventnor Water_Works Marvin_Gardins
Go_To_Jail Pacific North_Carolina Community_Chest Pennsylvania

# Some Board positions
GO_POSITION = 0
JAIL_POSITION = 10
ST_CHARLES_POSITION = 11
ELECTRIC_COMPANY_POSITION = 12
ILLINOIS_POSITION = 24
WATER_WORKS_POSITION = 28
BOARDWALK_POSITION = 39

CHANCE_CARDS = 15
COMMUNITY_CHEST_CARDS = 16
BOARD_SIZE = 40

COMMUNITY_CHEST_EFFECT = Proc.new do |cur_pos|
# Simulate 16 card Community chest deck
case Kernel.rand(COMMUNITY_CHEST_CARDS)
when 0
GO_POSITION
when 1
JAIL_POSITION
else
# This card does not have an effect on position
cur_pos
end
end

CHANCE_EFFECT = Proc.new do |cur_pos|
case Kernel.rand(CHANCE_CARDS)
when 0
GO_POSITION
when 1
ILLINOIS_POSITION
when 2
# Nearest Utility
if (cur_pos >= WATER_WORKS_POSITION) || (cur_pos <
ELECTRIC_COMPANY_POSITION)
ELECTRIC_COMPANY_POSITION
else
WATER_WORKS_POSITION
end
when 3..4
case cur_pos
when 5..14
15
when 15..24
25
when 25..34
35
else
end
when 5
ST_CHARLES_POSITION
when 6
# Go back three spaces
cur_pos - 3
when 7
JAIL_POSITION
when 8
when 9
BOARDWALK_POSITION
else
# This card does not have an effect on position
cur_pos
end
end

# Roll 2d6
def roll
2.d 6
end

def initialize
# Stay put Proc, used in most regular cells
stay_put = Proc.new {|cur_pos| cur_pos}

proc_for_name = {
"Community_Chest" => COMMUNITY_CHEST_EFFECT,
"Chance" => CHANCE_EFFECT,
"Go_To_Jail" => Proc.new do |cur_pos|
JAIL_POSITION
end
}

@properties = PROPERTY_NAMES.map do |name|
# Create the property and give it it's bonus move behavior proc
Property.new(name, proc_for_name[name] || stay_put)
end
end

def simulate(moves)
@moves = moves
position = 0

@moves.times do
position += roll

# Land on the properties and keep following the cards until we stay put
while( position != (new_position = (@properties[position %
BOARD_SIZE]).land) ) do
position = new_position
# Track the extra moves
@moves += 1
end
end
end

# Displays the results of the simulation
# Permanently alters the cells making them unsuitable for
# further simulation.
def display
puts "Total hits in board order after #{@moves} turns:"
puts @properties
puts "------"

puts "Sorted by Relative Frequency: "
# Sort and display results
@properties.sort{|a, b| b.count <=> a.count }.each do |property|
property.count = "%1.4f%" % (property.count * 100 / @moves.to_f)
puts property
end
puts "------"
end
end

board = Board.new

board.simulate((ARGV[0] || 100000).to_i)
board.display

------
Sorted by Relative Frequency:
(10) Jail/Just Visiting    - 5.0612%
(00) GO                    - 4.4737%
(01) Mediterranean         - 3.5400%
(03) Baltic                - 3.3674%
(04) Income Tax            - 3.3528%
(02) Community Chest       - 3.2069%
(06) Oriental              - 2.7579%
(24) Illinois              - 2.6526%
(19) New York              - 2.5675%
(08) Vermont               - 2.4062%
(17) Community Chest       - 2.3746%
(21) Kentucky              - 2.3462%
(18) Tennessee             - 2.3341%
(16) St. James Place       - 2.3292%
(20) Free Parking          - 2.3227%
(22) Chance                - 2.3154%
(11) St. Charles Place     - 2.3130%
(09) Connecticut           - 2.3090%
(28) Water Works           - 2.3033%
(26) Atlantic              - 2.2676%
(31) Pacific               - 2.1947%
(39) Boardwalk             - 2.1923%
(33) Community Chest       - 2.1898%
(30) Go To Jail            - 2.1817%
(12) Electric Company      - 2.1525%
(23) Indiana               - 2.1404%
(07) Chance                - 2.1193%
(32) North Carolina        - 2.1145%
(29) Marvin Gardins        - 2.1023%
(27) Ventnor               - 2.0861%
(34) Pennsylvania          - 2.0610%
(14) Virginia              - 2.0350%
(35) Short Line Railroad   - 2.0026%
(13) States                - 1.8964%
(36) Chance                - 1.8778%
(38) Luxury Tax            - 1.7376%
(37) Park Place            - 1.6882%
------

--
-Daniel
http://strd6.com

```