Now, for the moment I want to get back to this other idea
of moving along the elegance direction without changing
the other dimensions, and that's often called "refactoring."
That is, we take a program, and we change it around
not that it does something different but that it's clearer
and easier to maintain.
Now, here's a line from my handrank program
that bothers me a little bit, and what bothers me here
is I'm repeating myself, so I'm asking
do we have 3 of a kind in the ranks, and do we have 2 of a kind in the ranks?
Okay, if we do, that's a full house, and then what are we going to return?
6 is the marker for a full house, and then the 3 of a kind
and the 2 of a kind.
But I'm repeating myself, and so that violates
what's known as the "Don't repeat yourself" principle
or sometimes called "DRY."
I thought to myself is there a different way to do this?
Can I refactor my routine so that I'm not repeating myself,
so that I only have to say this once?
And in doing that, I came up with a different representation for a hand,
for the ranks of a hand.
Consider this hand.
We have a 7, a 10, a 7,
a 9, and another 7.
Now, in the representation we have so far--and note I'm leaving out
the suits here, they don't matter--in the representation we have so far,
we would sort these in order.
We'd have the 10 and the 9 and the three 7s,
and then we'd go through and we'd say is there 3 of a kind,
is there 4 of a kind, is there 2 of a kind, and so on.
But I want to come up now with a representation
that takes into account everything we need to know about this hand,
and I can do that using this function that I'll call "group."
We group this hand, and group is going to return 2 values.
First it's going to return the counts for each of the different kinds
of card ranks, and so here
we have three 7s and one 10 and one 9.
And those counts are going to be sorted biggest first.
And then the second value that groups is going to return
is the card ranks for each of these,
and so what did we have 3 of?
We had three 7s. And what do we have 1 of?
Well, 10s and 9s, and we're going to put those in order of biggest first.
This representation of taking this hand
and turning it into a counts and a list of ranks
is in some ways a better representation of exactly
how a poker hand counts.
Here's the new handrank function using this new representation for hands.
We call it in the same way. We pass in a hand.
And now we create the groups and pull out the counts and the ranks,
and then we do what we did before where we say
we have to deal with the ace-high straight,
and so change the ranks if we have to.
And then similarly to before, we check to see if we have a straight or a flush,
and now we can check for what the results are, and here
we're returning a single number, 0 through 9,
and in every case we return the ranks.
Know that what we're doing here is we're actually
changing the signature of handrank.
This version of handrank is going to return different results
than the previous version of handrank, but that's okay
because it's still going to work in conjunction
with our evaluation in that it's going to return the higher value
for the higher hand, even though it's returning slightly different values.
Why is it slightly different?
Because we're only returning a single number,
and then we always return the set of ranks,
and those ranks are there even when they aren't needed,
so for example, when we have a straight, we don't really need all the cards in the ranks.
And in the previous version of handrank, we only return the high card.
Here we're returning all of them, and what we do
is we go through and we say, "What are the counts?"
If the counts are just 5 of a kind, that's the highest.
Otherwise we check for straight and flush, like we did before.
Otherwise 4 of a kind, and the only way we can have 4 of a kind
is if the counts are 4 and 1.
Otherwise we check for a full house, and the only way we can have a full house
is if the counts are 3 and 2.
Then we look for flush and straight. Those are next in order.
Then we look for 3 of a kind.
The only way to have 3 of a kind is 3, 1, 1.
2 pairs has to be 2, 2, 1.
One pair has to be 2, 1, 1, 1.
And then high card would be 1, 1, 1, 1, 1,
but we don't have to explicitly check for that.
We just have 0 as the final value.
This is simpler. We're not repeating ourselves.
We have a nice representation here.
Also, one thing that I really like about this representation
is it showed me a new fact about poker hands
that I had never realized before, and that if we look at these values,
(5,) (4, 1) (3, 2) (3, 1, 1) (2, 2, 1) (2, 1, 1, 1)
and then here--I haven't written it but it would be 1, 1, 1, 1, 1--
these are all the partitions of the number 5,
so in mathematics, a partition of an integer
is the set of numbers that add up to that integer.
And for the number 5, that partitions into 7 possible ways,
and it turns out that poker recognizes all 7 of those as a different thing.
Poker has a name for all the partitions,
and the even more amazing thing is look,
they're in lexicographic order.
If we sort the 7 partitions, they're in exactly
the same order as the poker hands.
5 comes first, that's the highest.
4, 1 comes next. That's the next highest, and so on.
I never knew that before about the mapping between poker hands
and partitions, but this representation of hand rank makes it clear.