まず手札を同じ数でまとめます。その際、ソートしておくとあとで便利です。枚数で比較して同じなら数で比較します。
5H 5C 6S 7S KD -> List((2, 5), (1, 13), (1, 7), (1, 6))
次に同じ数系の役になっていないか調べます。Scalaならパターンマッチで簡単に調べられます。
def rank() :(eHand.Value,List[Int]) = collect match { case List((4,n),(1,m)) => (eHand.FourOfAKind, List(n, m)) case List((3,n),(2,m)) => (eHand.FullHouse, List(n, m)) case List((3,n),(1,m),(1,p)) => (eHand.ThreeOfAKind, List(n, m, p)) ...
第2要素は同じ役だったときの判定用です。元からソートされているので簡単に判定できます。
ここで役にひっかからなかったら、ストレートかフラッシュかを判定します。
役は列挙型にします。
object eHand extends Enumeration { val HighCard, OnePair, TwoPairs, ThreeOfAKind, Straight, Flush, FullHouse, FourOfAKind, StrightFlush, RoyalFlush = Value }
型は、
eHand.Value
となります。
val a :eHand.Value = eHand.FourOfAKind
大小の比較もふつうにできます。先に書かれた方が小です。
def greater(a :List[Int], b :List[Int]) :Boolean = (a, b) match { case (Nil, Nil) => false case (_, Nil) => true case (Nil, _) => false case (h1 :: t1, h2 :: t2) if h1 == h2 => greater(t1, t2) case (h1 :: t1, h2 :: t2) => h1 > h2 } object eHand extends Enumeration { val HighCard, OnePair, TwoPairs, ThreeOfAKind, Straight, Flush, FullHouse, FourOfAKind, StrightFlush, RoyalFlush = Value } class cHand(s :String) { val hs :List[(Int,Char)] = init(s) def init(s :String) = s.split(' ').toList.map(x => (number(x(0)), x(1))) def number(c :Char) :Int = c match { case c if '2' <= c && c <= '9' => c.toString.toInt case 'T' => 10 case 'J' => 11 case 'Q' => 12 case 'K' => 13 case 'A' => 14 } def wins(h :cHand) :Boolean = { val (eh1, a1) = rank val (eh2, a2) = h.rank if(eh1 != eh2) eh1 > eh2 else { greater(a1, a2) } } def rank() :(eHand.Value,List[Int]) = collect match { case List((4,n),(1,m)) => (eHand.FourOfAKind, List(n, m)) case List((3,n),(2,m)) => (eHand.FullHouse, List(n, m)) case List((3,n),(1,m),(1,p)) => (eHand.ThreeOfAKind, List(n, m, p)) case List((2,n),(2,m),(1,p)) => (eHand.TwoPairs, List(n, m, p)) case List((2,n),(1,m),(1,p),(1,q)) => (eHand.OnePair, List(n, m, p, q)) case a => if(is_straight(a)) if(is_flush) if(is_royal(a)) (eHand.RoyalFlush, Nil) else (eHand.StrightFlush, a.map(_._2)) else (eHand.Straight, a.map(_._2)) else if(is_flush) (eHand.Flush, a.map(_._2)) else (eHand.HighCard, a.map(_._2)) } def collect() :List[(Int,Int)] = { def greater(p :(Int,Int), q :(Int,Int)) :Boolean = if(p._1 != q._1) p._1 > q._1 else p._2 > q._2 val a = new Array[Int](13) for((n, s) <- hs) a(n-2) += 1 a.toList.zip(List.range(2, 15)).filter(_._1 > 0).sortWith(greater) } def is_straight(a :List[(Int,Int)]) :Boolean = a match { case (_,n) :: (_,m) :: b if n == m + 1 => is_straight(a.tail) case (_,n) :: (_,m) :: b => false case _ => true } def is_flush() :Boolean = hs.tail.forall(x => x._2 == hs.head._2) def is_royal(a :List[(Int,Int)]) :Boolean = a.head._2 == 14 } def line_to_hands(line :String) :(cHand,cHand) = (new cHand(line.take(14)), new cHand(line.drop(15))) val s = io.Source.fromFile("poker.txt") val hands = s.getLines.map(line_to_hands) println (hands.count(x => x._1.wins(x._2)))