Tennis Kata

Another solution to the Tennis Kata, to score a tennis game.

Copy Source
Copy Link
Tools:
 1: /// The two players
 2: type Player = A | B
 3: 
 4: /// The point score in for a player in a game
 5: type PlayerPoints = Zero | Fifteen | Thirty | Forty 
 6: 
 7: /// The score of a game
 8: type Score = 
 9:     | Points of PlayerPoints * PlayerPoints 
10:     | Advantage of Player 
11:     | Deuce 
12:     | Game of Player
13: 
14: /// Compute the next score in a game 
15: let nextPointScore a = 
16:     match a with 
17:     | Zero -> Fifteen
18:     | Fifteen -> Thirty
19:     | Thirty -> Forty
20:     | Forty -> failwith "what??"
21: 
22: /// Check if we've reached deuce
23: let normalize score = 
24:     match score with 
25:     | Points(Forty,Forty) -> Deuce
26:     | _ -> score
27: 
28: /// Score a point in a game
29: let scorePoint score point =
30:     match score, point with 
31:     | Advantage player1, player2 when  player1 = player2 -> Game player1
32:     | Advantage player1, player2 -> Deuce
33:     | Deuce, player -> Advantage player
34:     | Points(Forty, _), A -> Game A
35:     | Points(_, Forty), B -> Game B
36:     | Points(a, b), A -> normalize (Points (nextPointScore a, b))
37:     | Points(a, b), B -> normalize (Points (a, nextPointScore b))
38:     | Game _ , _ -> (* printfn "the game is over!"; *) score
39: 
40: /// Score a whole game, where the game is represented as a sequence of points
41: let scoreGame (points: seq<Player>) = 
42:     Seq.scan scorePoint (Points(Zero,Zero)) points
43: 
44: /// A sample game - A wins every point
45: let game1 = seq { while true do yield A }
46: 
47: /// A sample game - A and B swap points indefinitely
48: let game2 = seq { while true do 
49:                      yield A 
50:                      yield B }
51: 
52: /// A sample game - A and B trade points but A wins more points than B
53: let game3 = seq { while true do 
54:                      yield A 
55:                      yield B 
56:                      yield A }
57: 
58: scoreGame game1 |> Seq.truncate 10 |> Seq.toList
59: 
60: 
61: scoreGame game2 |> Seq.truncate 10 |> Seq.toList
62: 
63: scoreGame game3 |> Seq.truncate 10 |> Seq.toList
64: 
65: 
66: /// Generate a random game
67: let randomGame i = 
68:     let rnd = new System.Random(i) 
69:     seq { while true do if rnd.NextDouble() < 0.5 then yield A else yield B }
70: 
71: // Random testing of 1000 games
72: for i in 1 .. 1000 do 
73:     scoreGame (randomGame i)
74:        |> Seq.nth 10 
75:        |> printfn "result is %A"
76: 
77: 
union case Player.A: Player
union case Player.B: Player
type PlayerPoints =
  | Zero
  | Fifteen
  | Thirty
  | Forty

Full name: Snippet.PlayerPoints

  type: PlayerPoints
  implements: System.IEquatable<PlayerPoints>
  implements: System.Collections.IStructuralEquatable
  implements: System.IComparable<PlayerPoints>
  implements: System.IComparable
  implements: System.Collections.IStructuralComparable


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: Snippet.Score

  type: Score
  implements: System.IEquatable<Score>
  implements: System.Collections.IStructuralEquatable
  implements: System.IComparable<Score>
  implements: System.IComparable
  implements: System.Collections.IStructuralComparable


The score of a game
union case Score.Points: PlayerPoints * PlayerPoints -> Score
union case Score.Advantage: Player -> Score
type Player =
  | A
  | B

Full name: Snippet.Player

  type: Player
  implements: System.IEquatable<Player>
  implements: System.Collections.IStructuralEquatable
  implements: System.IComparable<Player>
  implements: System.IComparable
  implements: System.Collections.IStructuralComparable


The two players
union case Score.Deuce: Score
union case Score.Game: Player -> Score
val nextPointScore : PlayerPoints -> PlayerPoints

Full name: Snippet.nextPointScore

Compute the next score in a game
val a : PlayerPoints

  type: PlayerPoints
  implements: System.IEquatable<PlayerPoints>
  implements: System.Collections.IStructuralEquatable
  implements: System.IComparable<PlayerPoints>
  implements: System.IComparable
  implements: System.Collections.IStructuralComparable
val failwith : string -> 'T

Full name: Microsoft.FSharp.Core.Operators.failwith
val normalize : Score -> Score

Full name: Snippet.normalize

Check if we've reached deuce
val score : Score

  type: Score
  implements: System.IEquatable<Score>
  implements: System.Collections.IStructuralEquatable
  implements: System.IComparable<Score>
  implements: System.IComparable
  implements: System.Collections.IStructuralComparable
val scorePoint : Score -> Player -> Score

Full name: Snippet.scorePoint

Score a point in a game
val point : Player

  type: Player
  implements: System.IEquatable<Player>
  implements: System.Collections.IStructuralEquatable
  implements: System.IComparable<Player>
  implements: System.IComparable
  implements: System.Collections.IStructuralComparable
val player1 : Player

  type: Player
  implements: System.IEquatable<Player>
  implements: System.Collections.IStructuralEquatable
  implements: System.IComparable<Player>
  implements: System.IComparable
  implements: System.Collections.IStructuralComparable
val player2 : Player

  type: Player
  implements: System.IEquatable<Player>
  implements: System.Collections.IStructuralEquatable
  implements: System.IComparable<Player>
  implements: System.IComparable
  implements: System.Collections.IStructuralComparable
val player : Player

  type: Player
  implements: System.IEquatable<Player>
  implements: System.Collections.IStructuralEquatable
  implements: System.IComparable<Player>
  implements: System.IComparable
  implements: System.Collections.IStructuralComparable
val b : PlayerPoints

  type: PlayerPoints
  implements: System.IEquatable<PlayerPoints>
  implements: System.Collections.IStructuralEquatable
  implements: System.IComparable<PlayerPoints>
  implements: System.IComparable
  implements: System.Collections.IStructuralComparable
val scoreGame : seq<Player> -> seq<Score>

Full name: Snippet.scoreGame

Score a whole game, where the game is represented as a sequence of points
val points : seq<Player>

  type: seq<Player>
  inherits: System.Collections.IEnumerable
Multiple items
val seq : 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<_>

  type: seq<'T>
  inherits: System.Collections.IEnumerable
module Seq

from Microsoft.FSharp.Collections
val scan : ('State -> 'T -> 'State) -> 'State -> seq<'T> -> seq<'State>

Full name: Microsoft.FSharp.Collections.Seq.scan
val game1 : seq<Player>

Full name: Snippet.game1

  type: seq<Player>
  inherits: System.Collections.IEnumerable


A sample game - A wins every point
val game2 : seq<Player>

Full name: Snippet.game2

  type: seq<Player>
  inherits: System.Collections.IEnumerable


A sample game - A and B swap points indefinitely
val game3 : seq<Player>

Full name: Snippet.game3

  type: seq<Player>
  inherits: System.Collections.IEnumerable


A sample game - A and B trade points but A wins more points than B
val truncate : int -> seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.truncate
val toList : seq<'T> -> 'T list

Full name: Microsoft.FSharp.Collections.Seq.toList
val randomGame : int -> seq<Player>

Full name: Snippet.randomGame

Generate a random game
val i : int

  type: int
  implements: System.IComparable
  implements: System.IFormattable
  implements: System.IConvertible
  implements: System.IComparable<int>
  implements: System.IEquatable<int>
  inherits: System.ValueType
val rnd : System.Random
namespace System
type Random =
  class
    new : unit -> System.Random
    new : int -> System.Random
    member Next : unit -> int
    member Next : int -> int
    member Next : int * int -> int
    member NextBytes : System.Byte [] -> unit
    member NextDouble : unit -> float
  end

Full name: System.Random
System.Random.NextDouble() : float
val i : int32

  type: int32
  implements: System.IComparable
  implements: System.IFormattable
  implements: System.IConvertible
  implements: System.IComparable<int>
  implements: System.IEquatable<int>
  inherits: System.ValueType
val nth : int -> seq<'T> -> 'T

Full name: Microsoft.FSharp.Collections.Seq.nth
val printfn : Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn

More information

Link: http://fssnip.net/8R
Posted: 3 months ago
Author: Don Syme
Tags: Tennis; Sample; Functional Data; Kata