If you're interested in functional programming, you might also want to checkout my second blog which i'm actively working on!!

Monday, October 14, 2013

Modeling a poker game in Scala

WORK IN PROGRESS. If I find the time ideally i'd like to develop a PLAY2.x app using AKKA actors to orchestrate the poker game. Would be a very nice exercise. :)
package patterns
object PokerGame {
sealed trait Suit
case object Clubs extends Suit
case object Diamonds extends Suit
case object Hearts extends Suit
case object Spades extends Suit
sealed trait Rank
case object Jack extends Rank
case object Queen extends Rank
case object King extends Rank
case object Ace extends Rank
case class Numeric(value: Int) extends Rank
sealed trait Color
case object Red extends Color
case object Black extends Color
sealed trait Value
case object StraightFlush extends Value
case object FourOfKind extends Value
case object FullHouse extends Value
case object Flush extends Value
case object Straight extends Value
case object ThreeOfKind extends Value
case object TwoPair extends Value
case object Pair extends Value
case class HighCard(value: Int) extends Value
type Card = (Suit, Rank)
type Hand = (Card, Card, Card, Card, Card)
val D1 = (Diamonds, Numeric(1))
val D2 = (Diamonds, Numeric(2))
val D3 = (Diamonds, Numeric(3))
val D4 = (Diamonds, Numeric(4))
val D5 = (Diamonds, Numeric(5))
val D6 = (Diamonds, Numeric(6))
val D7 = (Diamonds, Numeric(7))
val D8 = (Diamonds, Numeric(8))
val D9 = (Diamonds, Numeric(9))
val D10 = (Diamonds, Numeric(10))
val DJ = (Diamonds, Jack)
val DQ = (Diamonds, Queen)
val DK = (Diamonds, King)
val DA = (Diamonds, Ace)
val S1 = (Spades, Numeric(1))
val S2 = (Spades, Numeric(2))
val S3 = (Spades, Numeric(3))
val S4 = (Spades, Numeric(4))
val S5 = (Spades, Numeric(5))
val S6 = (Spades, Numeric(6))
val S7 = (Spades, Numeric(7))
val S8 = (Spades, Numeric(8))
val S9 = (Spades, Numeric(9))
val S10 = (Spades, Numeric(10))
val SJ = (Spades, Jack)
val SQ = (Spades, Queen)
val SK = (Spades, King)
val SA = (Spades, Ace)
val H1 = (Hearts, Numeric(1))
val H2 = (Hearts, Numeric(2))
val H3 = (Hearts, Numeric(3))
val H4 = (Hearts, Numeric(4))
val H5 = (Hearts, Numeric(5))
val H6 = (Hearts, Numeric(6))
val H7 = (Hearts, Numeric(7))
val H8 = (Hearts, Numeric(8))
val H9 = (Hearts, Numeric(9))
val H10 = (Hearts, Numeric(10))
val HJ = (Hearts, Jack)
val HQ = (Hearts, Queen)
val HK = (Hearts, King)
val HA = (Hearts, Ace)
val C1 = (Clubs, Numeric(1))
val C2 = (Clubs, Numeric(2))
val C3 = (Clubs, Numeric(3))
val C4 = (Clubs, Numeric(4))
val C5 = (Clubs, Numeric(5))
val C6 = (Clubs, Numeric(6))
val C7 = (Clubs, Numeric(7))
val C8 = (Clubs, Numeric(8))
val C9 = (Clubs, Numeric(9))
val C10 = (Clubs, Numeric(10))
val CJ = (Clubs, Jack)
val CQ = (Clubs, Queen)
val CK = (Clubs, King)
val CA = (Clubs, Ace)
def valueOf(rank: Rank): Int = rank match {
case Ace => 14
case King => 13
case Queen => 12
case Jack => 11
case Numeric(n) => n
}
def colorOf(suit: Suit): Color = suit match {
case Clubs => Black
case Spades => Black
case _ => Red
}
def toRanks(hand: Hand): List[Rank] = {
val ((suit1, rank1), (suit2, rank2), (suit3, rank3), (suit4, rank4), (suit5, rank5)) = hand
List(rank1, rank2, rank3, rank4, rank5)
}
def toSuites(hand: Hand): List[Suit] = {
val ((suit1, rank1), (suit2, rank2), (suit3, rank3), (suit4, rank4), (suit5, rank5)) = hand
List(suit1, suit2, suit3, suit4, suit5)
}
def toColors(hand: Hand): List[Color] = toSuites(hand).map(colorOf _)
def toRankValues(hand: Hand): List[Int] = toRanks(hand).map(valueOf _)
def toRankSizes(hand: Hand): List[Int] =
toRanks(hand).groupBy(identity).map { case (rank, listofranks) => listofranks.size } .toList
def isSameSuit(hand: Hand): Boolean = toSuites(hand).forall(_ == hand._1._1)
def isStraightFlush(hand: Hand): Boolean = isSameSuit(hand) && isStraight(hand)
def isFourOfKind(hand: Hand): Boolean = toRankSizes(hand).exists(_ >= 4)
def isFullHouse(hand: Hand): Boolean = {
val rankSizes = toRankSizes(hand)
rankSizes.exists(_ == 2) && rankSizes.exists(_ == 3)
}
def isFlush(hand: Hand): Boolean = isSameSuit(hand)
def isStraight(hand: Hand): Boolean = {
val rankValues = toRankValues(hand)
val minimumRankValue = rankValues.min
rankValues.toSet == minimumRankValue.to(minimumRankValue + 4).toSet
}
def isThreeOfKind(hand: Hand): Boolean = toRankSizes(hand).exists(_ >= 3)
def isTwoPair(hand: Hand): Boolean = toRankSizes(hand).filter(_ >= 2).size == 2
def isPair(hand: Hand): Boolean = toRankSizes(hand).exists(_ >= 2)
def evaluate(hand: Hand): Value =
if (isStraightFlush(hand)) StraightFlush
else if (isFourOfKind(hand)) FourOfKind
else if (isFullHouse(hand)) FullHouse
else if (isFlush(hand)) Flush
else if (isStraight(hand)) Straight
else if (isThreeOfKind(hand)) ThreeOfKind
else if (isTwoPair(hand)) TwoPair
else if (isPair(hand)) Pair
else HighCard(toRankValues(hand).sorted.reverse.toList(0))
/** for unit testing
val straightflush = (D10, DJ, DQ, DK, DA)
val fourofkind = (H10, HQ, C10, S10, D10)
val fullhouse = (H10, D10, SJ, C10, CJ)
val flush = (D3, D5, D8, DJ, DA)
val straight = (D6,H4, C3, H5, S7)
val threeofkind = (H10, HQ, CK, S10, D10)
val twopair = (H10, HQ, CK, S10, DQ)
val pair = (H9, HQ, CK, S10, D10)
val highcard = (HK, S5, S2, C7, D9)
val test1 = evaluate(straightflush) == StraightFlush
val test2 = evaluate(fourofkind) == FourOfKind
val test3 = evaluate(fullhouse) == FullHouse
val test4 = evaluate(flush) == Flush
val test5 = evaluate(straight) == Straight
val test6 = evaluate(threeofkind) == ThreeOfKind
val test7 = evaluate(twopair) == TwoPair
val test8 = evaluate(pair) == Pair
val test9 = evaluate(highcard) == HighCard(13)
**/
}
view raw gistfile1.scala hosted with ❤ by GitHub

2 comments:

  1. You entirely go with our expectation and the range of our information.poker online

    ReplyDelete
  2. Wow, absolutely fantastic blog. I am very glad to have such useful information.

    หนังสงคราม

    ReplyDelete