On Fri, Jan 16, 2009 at 7:48 AM, Matthew Moss <matt / moss.name> wrote: > ## Monopoly Walker > > > Your task this week is to simulate players walking about a Monopoly board. > 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 Income_Tax Reading_Railroad Oriental Chance Vermont Connecticut Jail/Just_Visiting St._Charles_Place Electric_Company States Virginia Pennsylvania_Railroad St._James_Place Community_Chest 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 Short_Line_Railroad Chance Park_Place Luxury_Tax Boardwalk] # Some Board positions GO_POSITION = 0 READING_POSITION = 5 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 # Nearest Railroad case cur_pos when 5..14 15 when 15..24 25 when 25..34 35 else READING_POSITION end when 5 ST_CHARLES_POSITION when 6 # Go back three spaces cur_pos - 3 when 7 JAIL_POSITION when 8 READING_POSITION 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% (05) Reading Railroad - 3.8067% (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% (25) B&O Railroad - 2.5140% (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% (15) Pennsylvania Railroad - 2.3057% (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