Created
October 24, 2013 19:00
-
-
Save martinei/7143036 to your computer and use it in GitHub Desktop.
KataTennis
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object Tennis { | |
// A Typesafe solution for http://codingdojo.org/cgi-bin/wiki.pl?KataTennis | |
sealed trait Player | |
case class Player1() extends Player | |
case class Player2() extends Player | |
sealed trait Score | |
case class NScore [+P <: Score]() extends Score() | |
type Score0 = NScore[Score] | |
type Score15 = NScore[Score0] | |
type Score30 = NScore[Score15] | |
type Score40 = NScore[Score30] | |
case class State[S1 <: Score, S2 <: Score]() | |
val start = State[Score0, Score0]() | |
trait Player1MayScore[S1 <: Score, S2<:Score] { | |
def score(p : Player1) : State[NScore[S1], S2] = State[NScore[S1],S2]() | |
} | |
trait Player2MayScore[S1 <: Score, S2<:Score] { | |
def score(p : Player2) : State[S1,NScore[S2]] = State[S1,NScore[S2]]() | |
} | |
case class Normal [S1 <: Score, S2 <: Score]() extends Player1MayScore[S1,S2] with Player2MayScore[S1,S2] | |
implicit def pimpToNormal[ S1 >: Score30 <: Score, S2 >: Score15 <: Score] (s : State[S1,S2]) : Normal[S1,S2]= Normal() | |
implicit def pimpToNormal2[ S1 >: Score15 <: Score, S2 >: Score30 <: Score30] (s : State[S1,S2]) : Normal[S1,S2]= Normal() | |
case class Won[P <: Player]() | |
case class AdvantageP1() { | |
def score(p : Player1) : Won[Player1] = Won() | |
def score (p : Player2) : Deuce = Deuce() | |
} | |
case class AdvantageP2() { | |
def score(p : Player2) : Won[Player2] = Won() | |
def score (p : Player1) : Deuce = Deuce() | |
} | |
case class Deuce(){ | |
def score(p : Player1) : AdvantageP1 = AdvantageP1() | |
def score (p : Player2) :AdvantageP2 = AdvantageP2() | |
} | |
implicit def pimpToDeuce (s : State[Score30,Score30]) = Deuce() | |
start.score(Player1()) | |
val oneScored = start.score(Player1()) | |
// Player1 can score three times in a row, now he has won! | |
start.score(Player1()).score(Player1()).score(Player1()) | |
// Scoring four times is not possible | |
//start.score(Player1()).score(Player1()).score(Player1()).score(Player1()) | |
// Same for Player2 | |
start.score(Player2()).score(Player2()).score(Player2()) | |
//start.score(Player1()).score(Player1()).score(Player1()).score(Player2()) | |
// a Mixed Game | |
val p1Won = start.score(Player1()).score(Player2()).score(Player1()).score(Player1()) | |
// Now lets Enter an Deuce | |
val deuce = start.score(Player1()).score(Player1()).score(Player2()).score(Player2()) | |
// Let Player One win | |
deuce.score(Player1()).score(Player1()) | |
// Cant do this:\ | |
//deuce.score(Player1()).score(Player1()).score(Player1()) | |
// To Advantage and Back to Deuce: | |
deuce.score(Player1()).score(Player2()) | |
// And another Point is Possible | |
deuce.score(Player1()).score(Player2()).score(Player1()) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I think one can actually simplify furhter by having a "target types T1,T2" in Player1MayScore hat defaults to NScore[S1] , S2 and are used in the return type of score.
The Advantage and Deuce Classes would then be subclasses of Normale with different Target Types, thus that
State[Score30,Score30] represent Deuce, State[Score40,Score30] and State[Score30,Score40] the Advantage for on player. Scores would thatn move back into on of the other existing states.