Skip to content

Instantly share code, notes, and snippets.

@ryantanner
Last active December 3, 2015 17:35
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ryantanner/4b5d7096bc7302e83501 to your computer and use it in GitHub Desktop.
Save ryantanner/4b5d7096bc7302e83501 to your computer and use it in GitHub Desktop.
First pass at using Shapeless to describe Texas Hold'em. Pocket hand categories are based on Lee Jones' "Winning Texas Hold'em"
package org.ryantanner
import scala.annotation.implicitNotFound
import shapeless._
import Nat._
import ops.nat._
import LTEq._
import GTEq._
import RankGTEq._
import RankLTEq._
sealed trait Suit
sealed trait Rank {
type Val <: Nat
}
class Card[R <: Rank, S <: Suit] // { self: Suit with Rank => }
sealed trait Clubs extends Suit
sealed trait Hearts extends Suit
sealed trait Diamonds extends Suit
sealed trait Spades extends Suit
trait Two extends Rank { type Val = _0 }
trait Three extends Rank { type Val = _1 }
trait Four extends Rank { type Val = _2 }
trait Five extends Rank { type Val = _3 }
trait Six extends Rank { type Val = _4 }
trait Seven extends Rank { type Val = _5 }
trait Eight extends Rank { type Val = _6 }
trait Nine extends Rank { type Val = _7 }
trait Ten extends Rank { type Val = _8 }
trait Jack extends Rank { type Val = _9 }
trait Queen extends Rank { type Val = _10 }
trait King extends Rank { type Val = _11 }
trait Ace extends Rank { type Val = _12 }
case object TwoOfClubs extends Card[Two, Clubs]
case object ThreeOfClubs extends Card[Three, Clubs]
case object FourOfClubs extends Card[Four, Clubs]
case object FiveOfClubs extends Card[Five, Clubs]
case object SixOfClubs extends Card[Six, Clubs]
case object SevenOfClubs extends Card[Seven, Clubs]
case object EightOfClubs extends Card[Eight, Clubs]
case object NineOfClubs extends Card[Nine, Clubs]
case object TenOfClubs extends Card[Ten, Clubs]
case object JackOfClubs extends Card[Jack, Clubs]
case object QueenOfClubs extends Card[Queen, Clubs]
case object KingOfClubs extends Card[King, Clubs]
case object AceOfClubs extends Card[Ace, Clubs]
case object TwoOfHearts extends Card[Two, Hearts]
case object ThreeOfHearts extends Card[Three, Hearts]
case object FourOfHearts extends Card[Four, Hearts]
case object FiveOfHearts extends Card[Five, Hearts]
case object SixOfHearts extends Card[Six, Hearts]
case object SevenOfHearts extends Card[Seven, Hearts]
case object EightOfHearts extends Card[Eight, Hearts]
case object NineOfHearts extends Card[Nine, Hearts]
case object TenOfHearts extends Card[Ten, Hearts]
case object JackOfHearts extends Card[Jack, Hearts]
case object QueenOfHearts extends Card[Queen, Hearts]
case object KingOfHearts extends Card[King, Hearts]
case object AceOfHearts extends Card[Ace, Hearts]
case object TwoOfDiamonds extends Card[Two, Diamonds]
case object ThreeOfDiamonds extends Card[Three, Diamonds]
case object FourOfDiamonds extends Card[Four, Diamonds]
case object FiveOfDiamonds extends Card[Five, Diamonds]
case object SixOfDiamonds extends Card[Six, Diamonds]
case object SevenOfDiamonds extends Card[Seven, Diamonds]
case object EightOfDiamonds extends Card[Eight, Diamonds]
case object NineOfDiamonds extends Card[Nine, Diamonds]
case object TenOfDiamonds extends Card[Ten, Diamonds]
case object JackOfDiamonds extends Card[Jack, Diamonds]
case object QueenOfDiamonds extends Card[Queen, Diamonds]
case object KingOfDiamonds extends Card[King, Diamonds]
case object AceOfDiamonds extends Card[Ace, Diamonds]
case object TwoOfSpades extends Card[Two, Spades]
case object ThreeOfSpades extends Card[Three, Spades]
case object FourOfSpades extends Card[Four, Spades]
case object FiveOfSpades extends Card[Five, Spades]
case object SixOfSpades extends Card[Six, Spades]
case object SevenOfSpades extends Card[Seven, Spades]
case object EightOfSpades extends Card[Eight, Spades]
case object NineOfSpades extends Card[Nine, Spades]
case object TenOfSpades extends Card[Ten, Spades]
case object JackOfSpades extends Card[Jack, Spades]
case object QueenOfSpades extends Card[Queen, Spades]
case object KingOfSpades extends Card[King, Spades]
case object AceOfSpades extends Card[Ace, Spades]
sealed trait Pocket
case class BigPair[S1 <: Suit, S2 <: Suit, R <: Rank : Big](c1: Card[R, S1], c2: Card[R, S2])(implicit ev: S1 =:!= S2) extends Pocket
case class MediumPair[S1 <: Suit, S2 <: Suit, R <: Rank : Medium](c1: Card[R, S1], c2: Card[R, S2])(implicit ev: S1 =:!= S2) extends Pocket
case class SmallPair[S1 <: Suit, S2 <: Suit, R <: Rank : Small](c1: Card[R, S1], c2: Card[R, S2])(implicit ev: S1 =:!= S2) extends Pocket
case class SuitedBigCards[S <: Suit, R <: Rank : Big, R1 <: Rank : Big](c1: Card[R, S], c2: Card[R1, S])(implicit ev: R =:!= R1) extends Pocket
case class SuitedMediumCards[S <: Suit, R <: Rank : Medium, R1 <: Rank : Medium](c1: Card[R, S], c2: Card[R1, S])(implicit ev: R =:!= R1) extends Pocket
case class SuitedSmallCards[S <: Suit, R <: Rank : Small, R1 <: Rank : Small](c1: Card[R, S], c2: Card[R1, S])(implicit ev: R =:!= R1) extends Pocket
case class SuitedConnector[S <: Suit, R1 <: Rank, R2 <: Rank](c1: Card[R1, S], c2: Card[R2, S])(implicit ev: ConnectedRanks[R1, R2]) extends Pocket
case class Connector[S1 <: Suit, R1 <: Rank, S2 <: Suit, R2 <: Rank](c1: Card[R1, S1], c2: Card[R2, S2])(implicit ev: ConnectedRanks[R1, R2], ev1: S1 =:!= S2) extends Pocket
case class SuitedAce[S <: Suit, R <: Rank](c1: Card[Ace, S], c2: Card[R, S]) extends Pocket
case class SuitedKing[S <: Suit, R <: Rank](c1: Card[King, S], c2: Card[R, S]) extends Pocket
case class SuitedFaceTrash[S <: Suit, R1 <: Rank : JackOrQueen, R2 <: Rank : MediumOrSmall](c1: Card[R1, S], c2: Card[R2, S]) extends Pocket
case class TwoGap[S1 <: Suit, R1 <: Rank, S2 <: Suit, R2 <: Rank](c1: Card[R1, S1], c2: Card[R2, S2])(implicit ev: TwoGapRank[R1, R2]) extends Pocket
case class ThreeGap[S1 <: Suit, R1 <: Rank, S2 <: Suit, R2 <: Rank](c1: Card[R1, S1], c2: Card[R2, S2])(implicit ev: ThreeGapRank[R1, R2]) extends Pocket
case class PsuedoHigh[S1 <: Suit, R1 <: Rank : High, S2 <: Suit, R2 <: Rank : Low](c1: Card[R1, S1], c2: Card[R2, S2])(implicit ev: R2 <== Ten) extends Pocket
case class RandomSuited[S <: Suit, R1 <: Rank : Low, R2 <: Rank : Low](c1: Card[R1, S], c2: Card[R2, S]) extends Pocket
case class RandomOffsuit[S1 <: Suit, S2 <: Suit, R1 <: Rank : Low, R2 <: Rank : Low](c1: Card[R1, S1], c2: Card[R2, S2])(implicit ev: S1 =:!= S2) extends Pocket
trait JackOrQueen[R1 <: Rank] extends Serializable
object JackOrQueen {
def rankIsJackOrQueen[R1 <: Rank](implicit ev: R1 <== Queen, ev1: R1 >== Jack) = new JackOrQueen[R1] {}
}
trait MediumOrSmall[R1 <: Rank] extends Serializable
object MediumOrSmall{
def rankIsMediumOrSmall[R <: Rank](implicit ev: R <== Ten) = new MediumOrSmall[R] {}
}
@implicitNotFound("Ranks ${R1} and ${R2} are not two-gapped")
trait TwoGapRank[R1 <: Rank, R2 <: Rank] extends Serializable
object TwoGapRank {
implicit def ranksAreTwoGap[R1 <: Rank, R2 <: Rank](implicit ev: Diff.Aux[R1#Val, R2#Val, _3]) = new TwoGapRank[R1, R2] {}
}
@implicitNotFound("Ranks ${R1} and ${R2} are not three-gapped")
trait ThreeGapRank[R1 <: Rank, R2 <: Rank] extends Serializable
object ThreeGapRank {
implicit def ranksAreThreeGap[R1 <: Rank, R2 <: Rank](implicit ev: Diff.Aux[R1#Val, R2#Val, _4]) = new TwoGapRank[R1, R2] {}
}
@implicitNotFound("Rank ${A} is not High")
trait High[A <: Rank] extends Serializable
object High {
implicit def rankIsHigh[R <: Rank](implicit ev: R <== King, ev1: R >== Ten) = new High[R] {}
}
@implicitNotFound("Rank ${A} is not Low")
trait Low[A <: Rank] extends Serializable
object Low {
implicit def rankIsLow[R <: Rank](implicit ev: R <== Nine) = new Low[R] {}
}
@implicitNotFound("Rank ${A} is not Big")
trait Big[A <: Rank] extends Serializable
object Big {
implicit def rankIsBig[R <: Rank](implicit ev: R >== Jack) = new Big[R] {}
}
@implicitNotFound("Rank ${A} is not Medium")
trait Medium[A <: Rank] extends Serializable
object Medium {
implicit def rankIsMedium[R <: Rank](implicit ev1: R >== Seven, ev2: R <== Ten) = new Medium[R] {}
}
@implicitNotFound("Rank ${A} is not Small")
trait Small[A <: Rank] extends Serializable
object Small {
implicit def rankIsSmall[R <: Rank](implicit ev: R <== Six) = new Small[R] {}
}
@implicitNotFound("Rank ${A} is not a face card")
trait Face[A <: Rank] extends Serializable
object Face {
implicit def rankIsFace[R <: Rank](implicit ev: R >== Jack) = new Face[R] {}
}
trait ConnectedRanks[A <: Rank, B <: Rank]
object ConnectedRanks {
type Predecessor[A <: Rank, B <: Rank] = Pred.Aux[A#Val, B#Val]
def apply[A <: Rank, B <: Rank](implicit ev: Predecessor[B, A]) = new ConnectedRanks[A, B] { }
implicit def conn[A <: Rank, B <: Rank](implicit ev: Pred.Aux[A#Val, B#Val]) = new ConnectedRanks[A, B] {}
}
trait GTEq[A <: Nat, B <: Nat] extends Serializable
object GTEq {
def apply[A <: Nat, B <: Nat](implicit gteq: A >= B): GTEq[A, B] = gteq
type >=[A <: Nat, B <: Nat] = GTEq[A, B]
implicit def gtEq1 = new >=[_0, _0] {}
implicit def gtEq2[B <: Nat] = new >=[Succ[B], _0] {}
implicit def gtEq3[A <: Nat, B <: Nat](implicit gteq: A >= B) = new >=[Succ[A], Succ[B]] {}
}
trait NEq[A <: Nat, B <: Nat] extends Serializable
object NEq {
def apply[A <: Nat, B <: Nat](implicit neq: A != B): NEq[A, B] = neq
type !=[A <: Nat, B <: Nat] = NEq[A, B]
implicit def neq1[B <: Nat] = new !=[Succ[B], _0] {}
implicit def neq2[B <: Nat] = new !=[_0, Succ[B]] {}
}
trait RankGTEq[A <: Rank, B <: Rank] extends Serializable
object RankGTEq {
def apply[A <: Rank, B <: Rank](implicit gteq: GTEq[A#Val, B#Val]): RankGTEq[A, B] = new RankGTEq[A, B] {}
type >==[A <: Rank, B <: Rank] = RankGTEq[A, B]
implicit def gtEq3[A <: Rank, B <: Rank](implicit gteq: A#Val >= B#Val): RankGTEq[A, B] = new >==[A, B] {}
}
trait RankLTEq[A <: Rank, B <: Rank] extends Serializable
object RankLTEq {
def apply[A <: Rank, B <: Rank](implicit lteq: LTEq[A#Val, B#Val]): RankLTEq[A, B] = new RankLTEq[A, B] {}
type <==[A <: Rank, B <: Rank] = RankLTEq[A, B]
implicit def gtEq3[A <: Rank, B <: Rank](implicit lteq: A#Val <= B#Val): RankLTEq[A, B] = new <==[A, B] {}
}
object Cards {
val cards = TwoOfClubs ::
ThreeOfClubs ::
FourOfClubs ::
FiveOfClubs ::
SixOfClubs ::
SevenOfClubs ::
EightOfClubs ::
NineOfClubs ::
TenOfClubs ::
JackOfClubs ::
QueenOfClubs ::
KingOfClubs ::
AceOfClubs ::
TwoOfHearts ::
ThreeOfHearts ::
FourOfHearts ::
FiveOfHearts ::
SixOfHearts ::
SevenOfHearts ::
EightOfHearts ::
NineOfHearts ::
TenOfHearts ::
JackOfHearts ::
QueenOfHearts ::
KingOfHearts ::
AceOfHearts ::
TwoOfDiamonds ::
ThreeOfDiamonds ::
FourOfDiamonds ::
FiveOfDiamonds ::
SixOfDiamonds ::
SevenOfDiamonds ::
EightOfDiamonds ::
NineOfDiamonds ::
TenOfDiamonds ::
JackOfDiamonds ::
QueenOfDiamonds ::
KingOfDiamonds ::
AceOfDiamonds ::
TwoOfSpades ::
ThreeOfSpades ::
FourOfSpades ::
FiveOfSpades ::
SixOfSpades ::
SevenOfSpades ::
EightOfSpades ::
NineOfSpades ::
TenOfSpades ::
JackOfSpades ::
QueenOfSpades ::
KingOfSpades ::
AceOfSpades ::
HNil
}
> console
[info] Compiling 1 Scala source to /Users/ryantanner/Programming/showdown/target/scala-2.11/classes...
[info] Starting scala interpreter...
[info]
Welcome to Scala version 2.11.7 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_40).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import org.ryantanner._
import org.ryantanner._
scala> TwoGap(QueenOfHearts, EightOfSpades)
<console>:17: error: Ranks org.ryantanner.Queen and org.ryantanner.Eight are not two-gapped
TwoGap(QueenOfHearts, EightOfSpades)
^
scala> TwoGap(QueenOfHearts, NineOfSpades)
res1: org.ryantanner.TwoGap[org.ryantanner.Hearts,org.ryantanner.Queen,org.ryantanner.Spades,org.ryantanner.Nine] = TwoGap(QueenOfHearts,NineOfSpades)
scala> BigPair(TwoOfClubs, FourOfSpades)
<console>:17: error: type mismatch;
found : org.ryantanner.TwoOfClubs.type
required: org.ryantanner.Card[org.ryantanner.Rank{type Val >: shapeless.Nat._2 with shapeless.Nat._0 <: Serializable with shapeless.Nat{type N >: shapeless.Succ[shapeless.Nat._1] with shapeless._0 <: Serializable with shapeless.Nat}},org.ryantanner.Clubs]
(which expands to) org.ryantanner.Card[org.ryantanner.Rank{type Val >: shapeless.Succ[shapeless.Succ[shapeless._0]] with shapeless._0 <: Serializable with shapeless.Nat{type N >: shapeless.Succ[shapeless.Succ[shapeless._0]] with shapeless._0 <: Serializable with shapeless.Nat}},org.ryantanner.Clubs]
Note: org.ryantanner.Two <: org.ryantanner.Rank{type Val >: shapeless.Nat._2 with shapeless.Nat._0 <: Serializable with shapeless.Nat{type N >: shapeless.Succ[shapeless.Nat._1] with shapeless._0 <: Serializable with shapeless.Nat}} (and org.ryantanner.TwoOfClubs.type <: org.ryantanner.Card[org.ryantanner.Two,org.ryantanner.Clubs]), but class Card is invariant in type R.
You may wish to define R as +R instead. (SLS 4.5)
BigPair(TwoOfClubs, FourOfSpades)
^
<console>:17: error: type mismatch;
found : org.ryantanner.FourOfSpades.type
required: org.ryantanner.Card[org.ryantanner.Rank{type Val >: shapeless.Nat._2 with shapeless.Nat._0 <: Serializable with shapeless.Nat{type N >: shapeless.Succ[shapeless.Nat._1] with shapeless._0 <: Serializable with shapeless.Nat}},org.ryantanner.Spades]
(which expands to) org.ryantanner.Card[org.ryantanner.Rank{type Val >: shapeless.Succ[shapeless.Succ[shapeless._0]] with shapeless._0 <: Serializable with shapeless.Nat{type N >: shapeless.Succ[shapeless.Succ[shapeless._0]] with shapeless._0 <: Serializable with shapeless.Nat}},org.ryantanner.Spades]
Note: org.ryantanner.Four <: org.ryantanner.Rank{type Val >: shapeless.Nat._2 with shapeless.Nat._0 <: Serializable with shapeless.Nat{type N >: shapeless.Succ[shapeless.Nat._1] with shapeless._0 <: Serializable with shapeless.Nat}} (and org.ryantanner.FourOfSpades.type <: org.ryantanner.Card[org.ryantanner.Four,org.ryantanner.Spades]), but class Card is invariant in type R.
You may wish to define R as +R instead. (SLS 4.5)
BigPair(TwoOfClubs, FourOfSpades)
^
<console>:17: error: Rank org.ryantanner.Rank{type Val >: shapeless.Nat._2 with shapeless.Nat._0 <: Serializable with shapeless.Nat{type N >: shapeless.Succ[shapeless.Nat._1] with shapeless._0 <: Serializable with shapeless.Nat}} is not Big
BigPair(TwoOfClubs, FourOfSpades)
^
scala> SuitedConnector(QueenOfHearts, JackOfSpades)
<console>:17: error: type mismatch;
found : org.ryantanner.QueenOfHearts.type
required: org.ryantanner.Card[org.ryantanner.Queen,org.ryantanner.Suit]
Note: org.ryantanner.Hearts <: org.ryantanner.Suit (and org.ryantanner.QueenOfHearts.type <: org.ryantanner.Card[org.ryantanner.Queen,org.ryantanner.Hearts]), but class Card is invariant in type S.
You may wish to define S as +S instead. (SLS 4.5)
SuitedConnector(QueenOfHearts, JackOfSpades)
^
<console>:17: error: type mismatch;
found : org.ryantanner.JackOfSpades.type
required: org.ryantanner.Card[org.ryantanner.Jack,org.ryantanner.Suit]
Note: org.ryantanner.Spades <: org.ryantanner.Suit (and org.ryantanner.JackOfSpades.type <: org.ryantanner.Card[org.ryantanner.Jack,org.ryantanner.Spades]), but class Card is invariant in type S.
You may wish to define S as +S instead. (SLS 4.5)
SuitedConnector(QueenOfHearts, JackOfSpades)
^
scala> SuitedConnector(QueenOfHearts, JackOfHearts)
res6: org.ryantanner.SuitedConnector[org.ryantanner.Hearts,org.ryantanner.Queen,org.ryantanner.Jack] = SuitedConnector(QueenOfHearts,JackOfHearts)
scala> SuitedBigCards(KingOfHearts, QueenOfHearts)
res7: org.ryantanner.SuitedBigCards[org.ryantanner.Hearts,org.ryantanner.King,org.ryantanner.Queen] = SuitedBigCards(KingOfHearts,QueenOfHearts)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment