1

I asked an earlier question to which I received a great answer. In the comments, Travis mentioned that comparing two HandValues wouldn't work directly, but pattern matching could be used to ensure comparing the same class.

  sealed abstract class HandValue[T <: HandValue[T]](val rank: Int) extends Ordered[T]
  case class HighCard(high: Int) extends HandValue[HighCard](0){
    def compare(that: HighCard) = this.high - that.high
  }

  case class TwoPair(high: Int, big: Int, sm: Int) extends HandValue[TwoPair](2) {
    def compare (that: TwoPair) = { ... }
  }

In the attempted pattern matching below, I have a compile-time error that I suspect has to do with using HandValue[_]. val h1: HandValue[T <: HandValue[T]], similar to how the type was declared, isn't valid. Is there a way to resolve these?

  val ans = sessions count {
    hands: (Hand, Hand) => {
      val h1: HandValue[_] = handValue(hands._1)
      val h2: HandValue[_] = handValue(hands._2)
      (h1, h2) match { // <-- Line as source of error
        case _ if h1.rank > h2.rank => true
        case (a: HighCard, b: HighCard) => a > b
        case (a: TwoPair, b: TwoPair) => a > b
        // etc..
      }
    }
  }

Edit: The compile-time error is:

error: type arguments [_$3] do not conform to class HandValue's type parameter bounds [T <: euler.solutions.p54.HandValue[T]]
(h1, h2) match {

Edit 2: As mentioned in this question, using Type[_] won't work.

Community
  • 1
  • 1
Roy
  • 3,574
  • 2
  • 29
  • 39

1 Answers1

2

Can't help with the error, but you could remove a lot of this complexity by allowing any HandValue to be compared to any other HandValue; then you don't have to have that horrendous parameterization and repeated compare methods, followed by the repeated comparison logic in ans.

One way would be to have each one define a strength, which is a Seq[Int] consisting of the hand rank followed by the ranks of the cards within the hand that define its strength. Then you just compare these Seqs by finding which has a larger number coming first, i.e.

sealed abstract class HandValue(val strength: Seq[Int]) extends Ordered[HandValue] {
  import math.Ordering.Implicits.seqDerivedOrdering
  def compare(that: HandValue) = 
    Ordering[Seq[Int]].compare(this.strength, that.strength)
}

case class HighCard(high1: Int, high2: Int, high3: Int, high4: Int, high5: Int ) 
  extends HandValue(Seq(0, high1, high2, high3, high4, high5))

case class TwoPair(high: Int, big: Int, sm: Int) 
  extends HandValue(Seq(2, big, sm, high))

val ans = sessions count { hands => 
  handValue(hands._1) > handValue(hands._2)
}

Note, you need to take all the cards into account when calculating a high card hand strength. Also look out for the Ace-to-5 straight!

You could also just calculate the strength as an Int using a hashing function (as I did when I did this problem: https://gist.github.com/3270831).

Luigi Plinge
  • 50,650
  • 20
  • 113
  • 180