10 people like it.
Like the snippet!
Tennis Kata
Another solution to the Tennis Kata, to score a tennis game.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
|
/// The two players
type Player = A | B
/// The point score in for a player in a game
type PlayerPoints = Zero | Fifteen | Thirty | Forty
/// The score of a game
type Score =
| Points of PlayerPoints * PlayerPoints
| Advantage of Player
| Deuce
| Game of Player
/// Compute the next score in a game
let nextPointScore a =
match a with
| Zero -> Fifteen
| Fifteen -> Thirty
| Thirty -> Forty
| Forty -> failwith "what??"
/// Check if we've reached deuce
let normalize score =
match score with
| Points(Forty,Forty) -> Deuce
| _ -> score
/// Score a point in a game
let scorePoint score point =
match score, point with
| Advantage player1, player2 when player1 = player2 -> Game player1
| Advantage player1, player2 -> Deuce
| Deuce, player -> Advantage player
| Points(Forty, _), A -> Game A
| Points(_, Forty), B -> Game B
| Points(a, b), A -> normalize (Points (nextPointScore a, b))
| Points(a, b), B -> normalize (Points (a, nextPointScore b))
| Game _ , _ -> (* printfn "the game is over!"; *) score
/// Score a whole game, where the game is represented as a sequence of points
let scoreGame (points: seq<Player>) =
Seq.scan scorePoint (Points(Zero,Zero)) points
/// A sample game - A wins every point
let game1 = seq { while true do yield A }
/// A sample game - A and B swap points indefinitely
let game2 = seq { while true do
yield A
yield B }
/// A sample game - A and B trade points but A wins more points than B
let game3 = seq { while true do
yield A
yield B
yield A }
scoreGame game1 |> Seq.truncate 10 |> Seq.toList
scoreGame game2 |> Seq.truncate 10 |> Seq.toList
scoreGame game3 |> Seq.truncate 10 |> Seq.toList
/// Generate a random game
let randomGame i =
let rnd = new System.Random(i)
seq { while true do if rnd.NextDouble() < 0.5 then yield A else yield B }
// Random testing of 1000 games
for i in 1 .. 1000 do
scoreGame (randomGame i)
|> Seq.nth 10
|> printfn "result is %A"
|
union case Player.A: Player
union case Player.B: Player
type PlayerPoints =
| Zero
| Fifteen
| Thirty
| Forty
Full name: Script.PlayerPoints
The point score in for a player in a game
union case PlayerPoints.Zero: PlayerPoints
union case PlayerPoints.Fifteen: PlayerPoints
union case PlayerPoints.Thirty: PlayerPoints
union case PlayerPoints.Forty: PlayerPoints
type Score =
| Points of PlayerPoints * PlayerPoints
| Advantage of Player
| Deuce
| Game of Player
Full name: Script.Score
The score of a game
union case Score.Points: PlayerPoints * PlayerPoints -> Score
union case Score.Advantage: Player -> Score
type Player =
| A
| B
Full name: Script.Player
The two players
union case Score.Deuce: Score
union case Score.Game: Player -> Score
val nextPointScore : a:PlayerPoints -> PlayerPoints
Full name: Script.nextPointScore
Compute the next score in a game
val a : PlayerPoints
val failwith : message:string -> 'T
Full name: Microsoft.FSharp.Core.Operators.failwith
val normalize : score:Score -> Score
Full name: Script.normalize
Check if we've reached deuce
val score : Score
val scorePoint : score:Score -> point:Player -> Score
Full name: Script.scorePoint
Score a point in a game
val point : Player
val player1 : Player
val player2 : Player
val player : Player
val b : PlayerPoints
val scoreGame : points:seq<Player> -> seq<Score>
Full name: Script.scoreGame
Score a whole game, where the game is represented as a sequence of points
val points : seq<Player>
Multiple items
val seq : sequence:seq<'T> -> seq<'T>
Full name: Microsoft.FSharp.Core.Operators.seq
--------------------
type seq<'T> = System.Collections.Generic.IEnumerable<'T>
Full name: Microsoft.FSharp.Collections.seq<_>
module Seq
from Microsoft.FSharp.Collections
val scan : folder:('State -> 'T -> 'State) -> state:'State -> source:seq<'T> -> seq<'State>
Full name: Microsoft.FSharp.Collections.Seq.scan
val game1 : seq<Player>
Full name: Script.game1
A sample game - A wins every point
val game2 : seq<Player>
Full name: Script.game2
A sample game - A and B swap points indefinitely
val game3 : seq<Player>
Full name: Script.game3
A sample game - A and B trade points but A wins more points than B
val truncate : count:int -> source:seq<'T> -> seq<'T>
Full name: Microsoft.FSharp.Collections.Seq.truncate
val toList : source:seq<'T> -> 'T list
Full name: Microsoft.FSharp.Collections.Seq.toList
val randomGame : i:int -> seq<Player>
Full name: Script.randomGame
Generate a random game
val i : int
val rnd : System.Random
namespace System
Multiple items
type Random =
new : unit -> Random + 1 overload
member Next : unit -> int + 2 overloads
member NextBytes : buffer:byte[] -> unit
member NextDouble : unit -> float
Full name: System.Random
--------------------
System.Random() : unit
System.Random(Seed: int) : unit
System.Random.NextDouble() : float
val i : int32
val nth : index:int -> source:seq<'T> -> 'T
Full name: Microsoft.FSharp.Collections.Seq.nth
val printfn : format:Printf.TextWriterFormat<'T> -> 'T
Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
More information