-
Notifications
You must be signed in to change notification settings - Fork 0
/
Hand.scala
67 lines (45 loc) · 2.03 KB
/
Hand.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package poker.core
import poker.Utils
/** Container for five poker cards */
final class Hand private (cs: Vector[Card]) {
def hasConsecutiveCards: Boolean = hasConsecutiveCardsStartingWith(lowestRank)
def hasConsecutiveCardsStartingWith(start: Char): Boolean = {
hasConsecutiveCardsStartingWith(Utils.rankAsInt(start))
}
def hasConsecutiveCardsStartingWith(start: Int): Boolean = {
ranksSorted == Vector.tabulate(length)(_ + start)
}
def isSameAs(that: Hand): Boolean = this.cards == that.cards
def isNotSameAs(that: Hand): Boolean = !isSameAs(that)
def existsNCardsBySameRank(n: Int): Boolean = cardsByRank.exists(_._2.size == n)
def findNCardsBySameRank(n: Int): Option[Traversable[Card]] = cardsByRank.find(_._2.size == n).map(_._2)
override def toString: String = s"[${cards.mkString(", ")}]"
lazy val cards: Traversable[Card] = cs
lazy val cardsByRank: Map[Rank, Traversable[Card]] = Hand.byRank(cards)
lazy val hasSameSuit: Boolean = suits.toSet.size == 1
lazy val length: Int = cs.length
lazy val sorted: Hand = Hand(cs.sorted)
lazy val suits: Vector[Suit] = cs.map(_.suit)
lazy val ranks: Vector[Int] = cs.map(_.rankAsInt)
lazy val ranksSorted: Vector[Int] = ranks.sorted
lazy val lowestRank: Int = ranksSorted.head
lazy val highestRank: Int = ranksSorted.last
lazy val lowestRankCard: Card = sorted.cards.head
lazy val highestRankCard: Card = sorted.cards.last
}
object Hand {
def apply(cards: Traversable[Card]): Hand = {
validate(cards)
new Hand(cards.toVector)
}
def apply(strings: String*): Hand = apply(strings.map(Card(_)))
def existsNCardsBySameRank(cards: Traversable[Card], n: Int): Boolean = byRank(cards).exists(_._2.size == n)
private def byRank(cards: Traversable[Card]): Map[Rank, Traversable[Card]] = cards.groupBy(_.rank)
private def validate(cards: Traversable[Card]): Unit = {
val handSize = cards.toSet.size
require(
handSize == 5,
s"Invalid hand: Expected 5 distinct cards but found $handSize: [${cards.mkString(", ")}]"
)
}
}