Skip to content

Instantly share code, notes, and snippets.

@CraftyFella
Last active August 18, 2020 12:59
Show Gist options
  • Save CraftyFella/243a690f093e25db024e0acf6d7caea9 to your computer and use it in GitHub Desktop.
Save CraftyFella/243a690f093e25db024e0acf6d7caea9 to your computer and use it in GitHub Desktop.
open Domain
let awardPoint player state =
let result = Domain.awardPoint state player
printfn "Point to %A. Game is now %A" player result.Score
result
[<EntryPoint>]
let main argv =
let player1 = "Foo"
let player2 = "Bar"
GameState.NewGame player1 player2
|> awardPoint player1
|> awardPoint player2
|> awardPoint player1
|> awardPoint player2
|> awardPoint player2
|> awardPoint player2
|> awardPoint player1
|> awardPoint player2
|> awardPoint player2
|> awardPoint player2
|> ignore
0 // return an integer exit code
module Domain
type Point =
| Love
| Fifteen
| Thirty
| Forty
type Player = string
type Score =
| LoveGame
| Points of Point * Point
| Deuce
| Advantage of Player
| Game of Player
type GameState =
{ Player1: Player
Player2: Player
Score: Score }
module GameState =
let NewGame p1 p2 =
{ Player1 = p1
Player2 = p2
Score = LoveGame }
let updateScore (originalScore: Score) (toPlayer: Player) =
match originalScore with
| LoveGame -> Points(Fifteen, Point.Love)
| Game _ -> originalScore
| Points (Point.Love, b) -> Points(Fifteen, b)
| Points (Point.Fifteen, b) -> Points(Thirty, b)
| Points (Thirty, Forty) -> Deuce
| Points (Point.Thirty, b) -> Points(Forty, b)
| Points (Forty, _) -> Game toPlayer
| Deuce -> Advantage toPlayer
| Advantage player when player <> toPlayer -> Deuce
| Advantage player when player = toPlayer -> Game player
let flip (originalScore: Score) =
match originalScore with
| Points (a, b) -> Points(b, a)
| _ -> originalScore
let awardPoint (currentScore: GameState) (toPlayer: Player): GameState =
match currentScore with
| { Player1 = player } when player = toPlayer ->
{ currentScore with
Score = updateScore currentScore.Score toPlayer }
| { Player2 = player } when player = toPlayer ->
{ currentScore with
Score = flip (updateScore (flip currentScore.Score) toPlayer) }
@jhewlett
Copy link

jhewlett commented Aug 17, 2020

Very nice!

LoveGame is a redundant state and could be covered by Points (Love, Love) (especially since there's no special logic you'll need to switch on to handle Love - Love).

Points (Forty, Forty) is similarly redundant, though in this case it's better to keep Deuce as a separate case like you have it because of the special logic associated with it. So then the tricky thing is how to outlaw 40 - 40 but still allow 40 - 30, etc. to be represented.

(If you want to just see the canonical solution that I like, you can see that here)

Awesome work!

@CraftyFella
Copy link
Author

No no.. I won't cheat.. I'll take on the comments.. only way to learn.. and attempt to make 40-40 unrepresentable..

@jhewlett
Copy link

Also, just noticed Player could be better represented

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment