Difference between revisions of "RosettaCode Monty Hall"

m
(Monty Hall implementation that compiles and runs)
Line 8: Line 8:
 
==Eiffel code==
 
==Eiffel code==
  
Here's an initial implementation, just to get things started. I just typed this straight into the wiki, so it might not even compile.
+
Here's a candidate implementation. This compiles and runs, producing output similar to this:
  
Please feel free to edit this in place, I won't be offended.
+
Staying wins 333504 times.
 +
Switching wins 666496 times.
  
 
<e>
 
<e>
class MONTY_HALL
+
class
 +
MONTY_HALL
  
feature
+
create
 +
make
 +
 
 +
feature {NONE} -- Initialization
 +
 
 +
make
 +
local
 +
games_count: INTEGER
 +
do
 +
create random_generator.make
 +
games_count := 1000000
 +
 
 +
across 1 |..| games_count as game loop
 +
play
 +
end
 +
 
 +
print ("Staying wins " + staying_wins.out + " times.%N")
 +
print ("Switching wins " + (games_count - staying_wins).out + " times.%N")
 +
end
 +
 
 +
feature -- Commands
  
 
play
 
play
 
local
 
local
games: INTEGER
 
random: RANDOM
 
 
doors: ARRAYED_LIST [BOOLEAN]
 
doors: ARRAYED_LIST [BOOLEAN]
 
chosen, shown: INTEGER
 
chosen, shown: INTEGER
stayWins: INTEGER
 
 
do
 
do
games := 1000000
+
create doors.make_filled (Door_count) -- False is a goat, True is a car
create random.make
+
doors [next_random_door] := True -- Put a car behind a random door
 +
chosen := next_random_door -- Pick a door, any door
  
across 1 |..| games as plays loop
+
-- Monty selects a door which is neither the winner nor the choice
create doors.make_filled (3) -- False is a goat, True is a car
+
from
random.forth
+
shown := next_random_door
doors [random.item \\ 3 + 1] := True -- Put a car behind a random door
+
until
+
shown /= chosen and not doors [shown]
random.forth
+
loop
chosen := random.item \\ 3 + 1 -- Pick a door, any door
+
shown := next_random_door
+
end
from shown := chosen until shown /= chosen and not doors [shown] loop
+
random.forth
+
shown := random.item \\ 3 + 1
+
end
+
  
if doors [chosen] then -- If you would have won by staying, count it
+
if doors [chosen] then -- If you would have won by staying, count it
stay_wins := stay_wins + 1
+
staying_wins := staying_wins + 1
end
+
 
end
 
end
 +
ensure
 +
staying_wins_valid: staying_wins = old staying_wins or staying_wins = old staying_wins + 1
 +
end
  
out ("Staying wins " + stay_wins + " times.%N")
+
feature {NONE} -- Implementation
out ("Switching wins " + games - stay_wins + " times.%N")
+
 
 +
Door_count: INTEGER = 3
 +
-- The total number of doors.
 +
 
 +
staying_wins: INTEGER
 +
-- The number of times that the strategy of staying would win.
 +
 
 +
random_generator: RANDOM
 +
-- A random number generator for selecting doors.
 +
 
 +
next_random_door: INTEGER
 +
-- A door chosen at random.
 +
do
 +
random_generator.forth
 +
Result := random_generator.item \\ Door_count + 1
 +
ensure
 +
valid_door: Result >= 1 and Result <= Door_count
 
end
 
end
  

Revision as of 18:38, 11 August 2012


Reference

Statement of the Monty Hall problem on RosettaCode: here.
Deadline for adding to RosettaCode page: 31 Aug 2012; submitter:

Eiffel code

Here's a candidate implementation. This compiles and runs, producing output similar to this:

Staying wins 333504 times. Switching wins 666496 times.

class
	MONTY_HALL
 
create
	make
 
feature {NONE} -- Initialization
 
	make
		local
			games_count: INTEGER
		do
			create random_generator.make
			games_count := 1000000
 
			across 1 |..| games_count as game loop
				play
			end
 
			print ("Staying wins " + staying_wins.out + " times.%N")
			print ("Switching wins " + (games_count - staying_wins).out + " times.%N")
		end
 
feature -- Commands
 
	play
		local
			doors: ARRAYED_LIST [BOOLEAN]
			chosen, shown: INTEGER
		do
			create doors.make_filled (Door_count)	-- False is a goat, True is a car
			doors [next_random_door] := True	-- Put a car behind a random door
 			chosen := next_random_door	-- Pick a door, any door
 
			-- Monty selects a door which is neither the winner nor the choice
			from
				shown := next_random_door
			until
				shown /= chosen and not doors [shown]
			loop
				shown := next_random_door
			end
 
			if doors [chosen] then	-- If you would have won by staying, count it
				staying_wins := staying_wins + 1
			end
		ensure
			staying_wins_valid: staying_wins = old staying_wins or staying_wins = old staying_wins + 1
		end
 
feature {NONE} -- Implementation
 
	Door_count: INTEGER = 3
			-- The total number of doors.
 
	staying_wins: INTEGER
			-- The number of times that the strategy of staying would win.
 
	random_generator: RANDOM
			-- A random number generator for selecting doors.
 
	next_random_door: INTEGER
			-- A door chosen at random.
		do
			random_generator.forth
			Result := random_generator.item \\ Door_count + 1
		ensure
			valid_door: Result >= 1 and Result <= Door_count
		end
 
end

Comments

Note that the implementations in many other languages maintain a separate variable to count the number of switch wins. They calculate whether switching wins at each step via some funky logic that relies on zero-based array indexing, which would be inconvenient in Eiffel. But we don't need to do that at all anyway, because calculating it at each step is completely redundant: we can just do a final subtraction at the end, right?