# F# and Monopoly Simulation Redux

Now that I am 4 months into my F# adventure, I thought I would revisit the monopoly simulation that I wrote in August.  There are some pretty big differences

1)  I am not using the ‘if…then’ construct at all –> rather I am using pattern matching.  For example, consider the original communityChest function:

1. let communityChest x y =
2.     if y = 1 then
3.         0
4.     else if y = 2 then
5.         10
6.      else
7.         x

and the most recent one:

1. let communityChest (tile, randomNumber) =
2.     match randomNumber with
3.         | 1 -> 0
4.         | 2 -> 10
5.         | _ -> tile

“Big deal”, you are saying to yourself (or at least I did).  But the power of pattern matching is put on display with the revised chance.  The code is much more readable and understandable.

Original:

1. let chance x y =
2.     if y = 1 then
3.         0
4.     else if y = 2 then
5.         10
6.     else if y = 3 then
7.         11
8.     else if y = 4 then
9.         39
10.     else if y = 5 then
11.         x – 3
12.     else if y = 6 then
13.         5
14.     else if y = 7 then
15.         24
16.     else if y = 8 then
17.         if x < 5 then
18.             5
19.         else if x < 15 then
20.             15
21.         else if x < 25 then
22.             25
23.         else if x < 35 then
24.             35
25.         else
26.             5
27.     else if y = 9 then
28.         if x < 12 then
29.             12
30.         else if x < 28 then
31.             28
32.         else
33.             12
34.     else
35.         x

Revised:

2.     match tile with
3.         | 36|2 -> 5
4.         | 7 -> 15
5.         | 17|22 -> 25
6.         | 33 -> 35
7.         | _ -> failwith "not on chance"
8.
9. let goToNearestUtility tile =
10.     match tile with
11.         | 36|2|7 -> 12
12.         | 12|22|33-> 28
13.         | _ -> failwith "not on chance"
14.
15. let chance (tile, randomNumber) =
16.     match randomNumber with
17.         | 1 -> 0
18.         | 2 -> 10
19.         | 3 -> 11
20.         | 4 -> 39
21.         | 5 -> tile – 3
22.         | 6 -> 5
23.         | 7 -> 24
24.         | 8 -> goToNearestRailroad tile
25.         | 9 -> goToNearestUtility tile
26.         | _ -> tile

As a side note, I ditched the x and y values because they are unreadable.  When I went back to the code after 3 months, I spent way too long trying to figure out what the heck ‘x’ was.  I know that scientific code uses cryptic values, but clean code does not.  I changed them and the code became much better.

I then took a look at the move() function.  The original:

1. let move x y z =
2.     if x + y > 39 then
3.         x + y – 40
4.     else if x + y = 30 then
5.         10
6.     else if x + y = 2 then
7.         communityChest 2 z
8.     else if x + y = 7 then
9.         chance 7 z
10.     else if x + y = 17 then
11.         communityChest 17 z
12.     else if x + y = 22 then
13.         chance 22 z
14.     else if x + y = 33 then
15.         communityChest 33 z
16.     else if x + y = 36 then
17.         chance 36 z
18.     else
19.         x + y

and the revised:

1. let getBoardMove (currentTile, dieTotal) =
2.     let initialTile = currentTile + dieTotal
3.       matchinitialTile with
4.           | 2 ->communityChest (2, random.Next())
5.           | 7 ->chance (7, random.Next())
6.           | 17 ->communityChest (17, random.Next())
7.           | 22 ->chance (22, random.Next())
8.         | 30 -> 10
9.           | 33 ->communityChest (2, random.Next())
10.           | 36 ->chance (7, random.Next())
11.         | 40|41|42|43|44|45|46|47|48|49|50|51 -> initialTile – 40
12.         | _ -> initialTile

I am not happy with line 11 above – but apparently there is not a way in F# to do this ‘>40’ or even ‘[40 .. 51]’ in the left hand side of the pattern match.

So far, the biggest changes were to make the values more understandable and to get rid of the if…then statements and replace them with pattern matching.  Both these techniques make the code more readable and understandable.  The next big change came with the actual game play itself.  The original version:

1. let simulation =
2.     let mutable startingTile = 0
3.     let mutable endingTile = 0
4.     let mutable doublesCount = 0
5.     let mutable inJail = false
6.     let mutable jailRolls = 0
7.     for diceRoll in 1 .. 10000 do
8.         let dieOneValue = random.Next(1,7)
9.         let dieTwoValue = random.Next(1,7)
10.         let cardDraw = random.Next(1,17)
11.         let numberOfMoves = dieOneValue + dieTwoValue
12.
13.         if dieOneValue = dieTwoValue then
14.             doublesCount <- doublesCount + 1
15.         else
16.             doublesCount <- 0
17.         if inJail = true then
18.             if doublesCount > 1 then
19.                 inJail <- false
20.                 jailRolls <- 0
21.                 endingTile <- move 10 numberOfMoves cardDraw
22.             else
23.                 if jailRolls = 3 then
24.                     inJail <- false
25.                     jailRolls <- 0
26.                     endingTile <- move 10 numberOfMoves cardDraw
27.                 else
28.                     inJail <- true
29.                     jailRolls <- jailRolls + 1
30.         else
31.             if doublesCount = 3 then
32.                 inJail <- true
33.                 endingTile <- 10
34.             else
35.                 endingTile <- move startingTile numberOfMoves cardDraw
36.
37.         printfn "die1: %A + die2: %A = %A FROM %A TO %A"
38.             dieOneValue dieTwoValue numberOfMoves startingTile endingTile
39.         startingTile <- endingTile
40.         tiles.[endingTile] <- tiles.[endingTile] + 1

You will notice that the word ‘’mutable” shows up six times.  Using the word mutable in F# is a code smell so I refactored it out like so:

1. let rec rollDice (currentTile, rollCount, doublesCount, inJail, jailRollCount)=
2.     let dieOneValue = random.Next(1,7)
3.     let dieTwoValue = random.Next(1,7)
4.     let dieTotal = dieOneValue + dieTwoValue
5.     let newRollCount = rollCount + 1
6.
7.     let newDoublesCount =
8.         if dieOneValue = dieTwoValue then doublesCount + 1
9.         else 0
10.
11.     let newTile = getTileMove(currentTile,dieTotal,newDoublesCount,inJail,jailRollCount)
12.
13.     let newInJail =
14.         if newTile = 10 then true
15.         else false
16.
17.     let newJailRollCount =
18.         if newInJail = inJail then jailRollCount + 1
19.         else 0
20.
21.     let targetTuple = scorecard.[newTile]
22.     let newTuple = (fst targetTuple, snd targetTuple + 1)
23.     scorecard.[newTile] <- newTuple
24.
25.             if rollCount < 10000 then
26.         rollDice (newTile, newRollCount, newDoublesCount, newInJail, newJailRollCount)
27.     else
28.         scorecard

No “mutable” (thanks to recursion) and only 1 assignment.  I also wanted to get rid of that one ‘<-‘ and Thomas Petrick was kind enough to demonstrate the correct way to do this on stack overflow.  Finally, I had to throw in a supporting function to make the decision logic account for rolling doubles that may put you in jail or may get you out of jail depending on prior state (were you in jail when you rolled doubles, were you out of jail when you rolled doubles for the 3rd time, etc…).  I spent way too much time monkeying around with a series of nest if…then statements when it hit me that I should be using tuples and pattern matching:

1. let getTileMove (currentTile, dieTotal, doublesCount, inJail, jailRollCount) =
2.     match (inJail,jailRollCount, doublesCount) with
3.         | (true,3,_) -> getBoardMove(10,dieTotal)
4.         | (true,_,_) -> 10
5.         | (false,_,3) -> 10
6.         | (false,_,_) -> getBoardMove(10,dieTotal)

So here if the real power of F# on display.  I can think of hundreds of applications that I have seen in C#/VB.NET that have a high cyclomatic complexity and hidden bugs that have reared their head at the most inopportune time because of complex business logic using a series of case..switch and/or if..then. statements. Even by putting step into its own function only helps partially because the code is still there –> it is just labeled better.

By using tupled pattern matching, all of that complexity goes away and we have a succinct series of statements that actually reflect how the brain thinks about the problem.  By using F#, there are fewer lines of code (and therefore fewer unit tests to maintain) and you can write code that better represents how the wetware is approaching the problem.

### 2 Responses to F# and Monopoly Simulation Redux

1. Gustavo Guerra says:

You can use | i when i >= 40 && i … instead of | 40|41|42|43|44|45|46|47|48|49|50|51 -> …