Adventures in F# - Rock Paper Scissors Lizard Spock
I can learn by doing so after I’ve started learning F# I had to develop some application to practice. The one I came up with is a simple game: Rock Paper Scissors Lizard Spock. First version only gets a bunch of moves from the player, generates random moves for the computer and displays the outcome as shown below:
First, it gets a list of moves from the user. It should be a space-separated list of moves: R (Rock), P (Paper), S (Scissors), L (Lizard) and M (M for Mr. Spock as S was taken!)
Then it converts the characters to corresponding moves and generates equal number of moves for the computer.
Next it compares both lists of moves. It uses overloaded “-“ operator of the discriminated union. If the difference is 1 it means first player won, if it’s 2 then the second move won. 0 means draw.
Finally it displays the output of each round the score after that.
Program has two files only and basic game implementation is as follows:
module Game type Move = | Rock | Paper | Scissors | Lizard | Spock static member (-) (x, y) = match x, y with | Move.Scissors, Move.Paper -> 1 | Move.Scissors, Move.Lizard -> 1 | Move.Scissors, Move.Rock -> 2 | Move.Scissors, Move.Spock -> 2 | Move.Lizard, Move.Paper -> 1 | Move.Lizard, Move.Rock -> 2 | Move.Lizard, Move.Scissors -> 2 | Move.Lizard, Move.Spock -> 1 | Move.Paper, Move.Lizard -> 1 | Move.Paper, Move.Rock -> 2 | Move.Paper, Move.Scissors -> 2 | Move.Paper, Move.Spock -> 1 | Move.Spock, Move.Paper -> 2 | Move.Spock, Move.Rock -> 1 | Move.Spock, Move.Scissors -> 1 | Move.Spock, Move.Lizard -> 2 | Move.Rock, Move.Paper -> 2 | Move.Rock, Move.Spock -> 2 | Move.Rock, Move.Scissors -> 1 | Move.Rock, Move.Lizard -> 1 | (x, y) when (x = y) -> 0 let GetRandomMove n = let rnd = System.Random(); let output = [ for i in 1 .. n -> let index = rnd.Next(0, 5) match index with | 0 -> Move.Rock | 1 -> Move.Paper | 2 -> Move.Scissors | 3 -> Move.Lizard | 4 -> Move.Spock ] output let GetRoundOutputText moves = match moves with | (Move.Scissors, Move.Paper) | (Move.Paper, Move.Scissors) -> "Scissors cuts Paper" | (Move.Paper, Move.Rock) | (Move.Rock, Move.Paper) -> "Paper covers Rock" | (Move.Rock, Move.Lizard) | (Move.Lizard, Move.Rock) -> "Rock crushes Lizard" | (Move.Lizard, Move.Spock) | (Move.Spock, Move.Lizard) -> "Lizard poisons Spock" | (Move.Spock, Move.Scissors) | (Move.Scissors, Move.Spock) -> "Spock smashes Scissors" | (Move.Scissors, Move.Lizard) | (Move.Lizard, Move.Scissors) -> "Scissors decapitates Lizard" | (Move.Lizard, Move.Paper) | (Move.Paper, Move.Lizard) -> "Lizard eats Paper" | (Move.Paper, Move.Spock) | (Move.Spock, Move.Paper) -> "Paper disproves Spock" | (Move.Spock, Move.Rock) | (Move.Rock, Move.Spock) -> "Spock vaporizes Rock" | (Move.Rock, Move.Scissors) | (Move.Scissors, Move.Rock) -> "Rock crushes scissors" | (x, y) when (x = y) -> "Draw" | (_, _) -> "Unknown move pair" let GetMovesFromInput (input : string) = let inputList = Array.toList (input.Trim().Split [|' '|]) let moves = List.map (fun (x: string) -> match x.ToUpper() with | "R" -> Move.Rock | "P" -> Move.Paper | "S" -> Move.Scissors | "L" -> Move.Lizard | "M" -> Move.Spock ) inputList moves
And the entry point of the program that gets user input and displays the results is :
open Game open System [<EntryPoint>] let main argv = let mutable playerScore = 0 let mutable computerScore = 0 let playerMoves = GetMovesFromInput (Console.ReadLine()) let n = playerMoves.Length printfn "You played: " for i in 0 .. n - 1 do printfn "%A" (playerMoves.Item(i)) printfn "" printfn "Generating computer moves" let computerMoves = GetRandomMove n printfn "Computer played: " for i in 0 .. n - 1 do printfn "%A" (computerMoves.Item(i)) printfn "" printfn "Results:" for i in 0 .. n - 1 do printfn "%s" (GetRoundOutputText (playerMoves.Item(i), computerMoves.Item(i))) let diff = (int)(playerMoves.Item(i) - computerMoves.Item(i)) if diff = 1 then playerScore <- playerScore + 1 elif diff = 2 then computerScore <- computerScore + 1 printfn "Player: %d \t Computer: %d" playerScore computerScore let s = Console.ReadLine() printfn "%s" s 0
This is just the initial version (v0.1). I will keep improving it but for the time being I’m satisfied that I have a fully-working program developed in F# that uses the basics like discriminated unions, operator overloading and pattern matching. More to come soon…