Skip to content

Instantly share code, notes, and snippets.

@dgouyette
Last active November 8, 2016 10:34
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dgouyette/bbf941d34e1a14c901ea to your computer and use it in GitHub Desktop.
Save dgouyette/bbf941d34e1a14c901ea to your computer and use it in GitHub Desktop.
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