-
-
Save dgouyette/bbf941d34e1a14c901ea to your computer and use it in GitHub Desktop.
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
import org.scalatest._ | |
import shapeless._ | |
object Bowling { | |
type Round = Int :: Int :: HNil | |
type LastRound = Int :: Int :: Int :: HNil | |
type GameWithOneRound = Round :: HNil | |
type GameWithTwoRound = Round :: Round :: HNil | |
type GameWithThreeRound = Round :: Round :: Round :: HNil | |
type MixedGame = Round :: Round :: LastRound :: HNil | |
type FullGame = Round :: Round :: Round :: Round :: Round :: Round :: Round :: Round :: Round :: LastRound :: HNil | |
object Score extends Poly1 { | |
implicit def caseRound = at[Round](sum) | |
implicit def caseLastRound = at[LastRound](sum) | |
implicit def caseGameWithOneRound = at[GameWithOneRound](rounds2Score) | |
implicit def caseGameWithTwoRound = at[GameWithTwoRound](rounds2Score) | |
implicit def caseGameWithThreeRound = at[GameWithThreeRound](rounds2Score) | |
implicit def caseFullGame = at[FullGame](rounds2Score) | |
def hasStrike(round: Round) = { | |
round match { | |
case 10 :: _ :: HNil => true | |
case _ => false | |
} | |
} | |
def hasSpare(round: Round) = round match { | |
case h1 :: h2 :: HNil if !hasStrike(round) && h1 + h2 == 10 => true | |
case _ => false | |
} | |
def sum(round: HList):Int = round match { | |
case (h1: Int) :: (h2: Int) :: HNil => h1 + h2 | |
case (h1: Int) :: (h2: Int) :: (h3: Int) :: HNil => h1 + sum(h2 :: h3 :: HNil) | |
case _ => 0 | |
} | |
def rounds2Score: (HList) => Int = { | |
case (10 :: _ :: HNil) :: ((b1: Int) :: (b2: Int) :: (b3: Int) :: HNil) :: HNil => 10 + b1 + b2 + b1 + b2 + b3 | |
case (m1: Round) :: (m2: Round) :: ((b1: Int) :: (b2: Int) :: xs) :: tail if hasStrike(m1) && hasStrike(m2) => 10 + strike(m2) + b1 + rounds2Score(m2 :: (b1 :: b2 :: xs) :: tail) | |
case (10 :: _ :: HNil) :: (m2: Round) :: tail => 10 + strike(m2) + rounds2Score(m2 :: tail) | |
case (m1: Round) :: (m2: Round) :: tail if hasSpare(m1) => sum(m1) + spare(m2) + rounds2Score(m2 :: tail) | |
case (m1: Round) :: (t: HList) => Score(m1) + rounds2Score(t) | |
case HNil => 0 | |
} | |
} | |
def spare(m: Round): Int = { | |
m match { | |
case (a:Int)::_ => a | |
case _ => 0 | |
} | |
} | |
def strike(m: HList): Int = { | |
m match { | |
case (a:Int)::(b:Int)::(c:Int)::HNil => a+b+c | |
case (a:Int)::(b:Int)::HNil => a+b | |
case _ => 0 | |
} | |
} | |
} | |
class ShapeLessSpec extends FunSuite with ShouldMatchers { | |
import Bowling._ | |
val fluke = 0::0::HNil | |
val spare = 5::5::HNil | |
val strike = 10::0::HNil | |
val lastSpare = 5::5::5::HNil | |
val lastStrike = 10::10::10::HNil | |
test("A round 0 + 0 = 0"){ | |
Score(0::0::HNil) shouldEqual 0 | |
} | |
test("two strikes = 30"){ | |
Score(strike :: strike :: HNil) shouldEqual 30 | |
} | |
test("three strikes = 60"){ | |
Score(strike :: strike :: strike :: HNil) shouldEqual 60 | |
} | |
test("A round 3 + 1 = 4") { | |
Score(3::1::HNil) shouldEqual 4 | |
} | |
test(" Last round 0 + 0 + 0 = 0" ) { | |
Score(0:: 0:: 0::HNil) shouldEqual 0 | |
} | |
test("Two rounds 0 + 10 and 1 + 2 = 0+10+1 + 1+2") { | |
Score((0::10::HNil) :: (1::2::HNil ) :: HNil) shouldEqual 0 + 10 + 1 + 1 + 2 | |
} | |
test("Two rounds 0+10 + 1+2 = de 0+10 + 1+1 + 2") { | |
Score((0::10::HNil) :: (1::2::HNil) :: HNil) shouldEqual 0+10 + 1+1 + 2 | |
} | |
test("Three rounds 1 + 2 + + 1 + 2 + 1 + 2 = 1+2 + 1+2 + 1+2") { | |
Score((1::2::HNil) :: (1::2::HNil) :: (1::2::HNil) :: HNil) shouldEqual 1+2 + 1+2 + 1+2 | |
} | |
test("Three rounds 0+10 + 5+5 + 1+2 = 0+10+ 5+5+5 + 1+1 + 2") { | |
Score((0::10::HNil) :: (5::5::HNil) :: (1::2::HNil) :: HNil) shouldEqual 0+10 + 5+5+5 + 1+1 + 2 | |
} | |
test("A round 3+1 + 0+10 + 5+1 = 3+1 + 0+10+5 + 5+1") { | |
Score((3::1::HNil) :: (0::10::HNil) :: (5::1::HNil) :: HNil ) shouldEqual 3+1 + 0+10+5 + 5+1 | |
} | |
test("A Round 10 + 2 + 5 = 10 + 2+5 + 2+5") { | |
Score((10::0::HNil) :: (2::5::HNil) :: HNil ) shouldEqual 10 + 2+2 + 5+5 | |
} | |
test("A game 5+5 + 5+5 + 5+5 + 5+5 + 5+5 + 5+5 + 5+5 + 5+5 + 5+5 + 5+5+5 = 5+5 + 5*2+5 + 5*2+5 + 5*2+5 + 5*2+5 + 5*2+5 + 5*2+5 + 5*2+5 + 5*2+5 + 5*2+5+5"){ | |
Score(spare :: spare :: spare :: spare :: spare :: spare :: spare :: spare :: spare :: lastSpare :: HNil) shouldEqual 5+5 + 5+5+5 + 5+5+5 + 5+5+5 + 5+5+5 + 5+5+5 + 5+5+5 + 5+5+5 + 5+5+5 + 5+5+5+5 | |
} | |
test("too much") { | |
Score(fluke :: fluke :: fluke :: fluke :: fluke :: | |
fluke :: fluke :: strike :: strike :: lastStrike :: HNil) shouldEqual 90 | |
} | |
test("A perfect game with 10 + 10 + 10 + 10 + 10 + 10 + 10 + 10 + 10 + 10 + 10 + 10 + 10 = 300") { | |
Score(strike :: strike :: strike :: strike :: strike :: | |
strike :: strike :: strike :: strike :: lastStrike :: HNil) shouldEqual 300 | |
} | |
test("A game with 10 + 10 + 10 + 10 + 10 + 10 + 10 + 10 + 10 + 10 + 1 +3 = 249") { | |
Score(strike :: strike :: strike :: strike :: strike :: | |
strike :: strike :: strike :: strike :: (1 :: 3 :: 0 ::HNil) :: HNil) shouldEqual 210 + 21 + 14 + 4 | |
} | |
test("A game with 10 + 10 + 10 + 10 + 10 + 10 + 10 + 10 + 10 + 10 + 1 +2 = 247") { | |
Score(strike :: strike :: strike :: strike :: strike :: | |
strike :: strike :: strike :: strike :: (1 :: 2 :: 0 ::HNil) :: HNil) shouldEqual 210 + 21 + 13 + 3 | |
} | |
test("A game with 10 + 10 + 10 + 10 + 10 + 10 + 10 + 10 + 10 + 11 + 10 +1 = 291") { | |
Score(strike :: strike :: strike :: strike :: strike :: | |
strike :: strike :: strike :: strike :: (10 :: 10 :: 1 ::HNil) :: HNil) shouldEqual 291 | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment