Cribbage Challenge

For all coding issues - MODers and programmers, HTML and more.

Moderators: Jeff250, fliptw

Post Reply
User avatar
fliptw
DBB DemiGod
DBB DemiGod
Posts: 6458
Joined: Sat Oct 24, 1998 2:01 am
Location: Calgary Alberta Canada

Cribbage Challenge

Post by fliptw »

Well if you want a challenge:

Write something that calculates the score of a cribbage hand(not the crib), and with that, show the hands for the 3 highest scores possible.

this is an example of something that isn't a challenge.
User avatar
Isaac
DBB Artist
DBB Artist
Posts: 7649
Joined: Mon Aug 01, 2005 8:47 am
Location: 🍕

Re: Descentbb.net forum challenge, for all users (proposal)

Post by Isaac »

I think this could also include all possible size of hands.

2, 3, and 4 cards per hands. (I'm looking at the rules)
card values:
K = 10
Q = 10
J = 10
TEN = 10
NINE = 9
EIGHT = 8
...
skip...
...
TWO = 2
ACE = 1
Yeah, I wonder if I could do this in a single elegant python line...
❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉
-⎽__⎽-⎻⎺⎺⎻-⎽__⎽--⎻⎺⎺⎻-★ ·:*¨༺꧁༺ :E ༻꧂༻¨*:·.★-⎽__⎽-⎻⎺⎺⎻-⎽__⎽--⎻⎺⎺⎻-
❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉
User avatar
fliptw
DBB DemiGod
DBB DemiGod
Posts: 6458
Joined: Sat Oct 24, 1998 2:01 am
Location: Calgary Alberta Canada

Re: Descentbb.net forum challenge, for all users (proposal)

Post by fliptw »

just keep it to 4 cards and the turn.
User avatar
Isaac
DBB Artist
DBB Artist
Posts: 7649
Joined: Mon Aug 01, 2005 8:47 am
Location: 🍕

Re: Descentbb.net forum challenge, for all users (proposal)

Post by Isaac »

ok.
edit:
1524 combinations of cards that score between 31 and 29... I know that's not the challenge, but that's a lot!
/edit

I started writing some code, but I misunderstood the procedure of the game. I'll have to start over later after rereading the rules.
❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉
-⎽__⎽-⎻⎺⎺⎻-⎽__⎽--⎻⎺⎺⎻-★ ·:*¨༺꧁༺ :E ༻꧂༻¨*:·.★-⎽__⎽-⎻⎺⎺⎻-⎽__⎽--⎻⎺⎺⎻-
❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉
User avatar
Jeff250
DBB Master
DBB Master
Posts: 6511
Joined: Sun Sep 05, 1999 2:01 am
Location: ❄️❄️❄️

Re: Descentbb.net forum challenge, for all users (proposal)

Post by Jeff250 »

The cribbage challenge looks interesting. I think I'm going to take a suboptimal stab at it tonight, once I understand the scoring rules...
User avatar
Jeff250
DBB Master
DBB Master
Posts: 6511
Joined: Sun Sep 05, 1999 2:01 am
Location: ❄️❄️❄️

Re: Descentbb.net forum challenge, for all users (proposal)

Post by Jeff250 »

To add to the above, Isaac, you don't need me to post challenges. Feel free to post your own and see who bites. ;)

Here's what I *think* is a correct scoring function:

Code: Select all

# coding: UTF-8
from itertools import chain, groupby, combinations

RANKS = u'A23456789TJQK'
SUITS = u'♥♦♣♠'
VALUES = dict((c, min(n + 1, 10)) for c, n in zip(RANKS, range(len(RANKS))))
INDEXES = dict((c, n) for c, n in zip(RANKS, range(len(RANKS))))

def count(iterable):
    return sum(1 for x in iterable)

def powerset(xs, min_len=0):
    return chain.from_iterable(combinations(xs, k)
                               for k in range(len(xs), min_len - 1, -1))

def rank(card):
    return card[0]

def suit(card):
    return card[1]

def score(*hand):
    starter = hand[-1]
    ranks = sorted(rank(card) for card in hand)
    suits = sorted(suit(card) for card in hand)
    values = sorted(VALUES[rank] for rank in ranks)
    indexes = sorted(INDEXES[rank] for rank in ranks)
    # score two points for any combination adding up to 15
    score = sum(2 for v in powerset(values) if sum(v) == 15)
    # score two points for pairs, six for three of a kind, 12 for four
    score += sum(2 for t in combinations(ranks, 2) if t[0] == t[1])
    # score four points for a flush, five for including starter
    if all(x == y for x, y in zip(suits[:-1], suits[1:-1])):
        score += 5 if suit(starter) == suits[0] else 4
    # score one point if hand contains jack of same suit as starter
    score += sum(1 for card in hand[:-1]
                   if rank(card) == 'J' and suit(card) == suit(starter))
    # score n for each disjoint run of n cards, n >= 3
    runss = groupby(count(xs) for xs in powerset(indexes, 3)
                              if all(y - x == 1 for x, y in zip(xs, xs[1:])))
    try: key, runs = runss.next() # try to get set of longest runs
    except StopIteration: pass
    else: score += sum(runs)
    return score

assert(score(u'3♠', u'4♦', u'5♦', u'J♦', u'6♦') == 9)
assert(score(u'5♣', u'5♦', u'5♥', u'J♠', u'5♠') == 29)
assert(score(u'3♠', u'3♦', u'3♣', u'9♦', u'6♦') == 16)
assert(score(u'6♦', u'7♠', u'7♣', u'8♣', u'8♦') == 24)
assert(score(u'2♦', u'3♣', u'4♠', u'4♣', u'4♥') == 17)
User avatar
Isaac
DBB Artist
DBB Artist
Posts: 7649
Joined: Mon Aug 01, 2005 8:47 am
Location: 🍕

Re: Descentbb.net forum challenge, for all users (proposal)

Post by Isaac »

Code: Select all

cards={"K":10,"Q":10,"J":10,"10":10,"9":9,"8":8,"7":7,"6":6,"5":5,"4":4,"3":3,"2":2,"A":1}
hands=[(str((a[0],b[0],c[0],d[0])),(a[1]+b[1]+c[1]+d[1])) for a in cards.items() for b in cards.items() for c in cards.items() for d in cards.items() if a[1]+b[1]+c[1]+d[1]<31 and a[1]+b[1]+c[1]+d[1]>29]
print len(hands)
^---- That isn't anything.
This is how far I've got, but I don't get why there's pegs in the game. I need to find more clear instructions, but I have lots of homework for the next few days (I didn't realize there would be a challenge posted so quickly).
❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉
-⎽__⎽-⎻⎺⎺⎻-⎽__⎽--⎻⎺⎺⎻-★ ·:*¨༺꧁༺ :E ༻꧂༻¨*:·.★-⎽__⎽-⎻⎺⎺⎻-⎽__⎽--⎻⎺⎺⎻-
❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉
User avatar
fliptw
DBB DemiGod
DBB DemiGod
Posts: 6458
Joined: Sat Oct 24, 1998 2:01 am
Location: Calgary Alberta Canada

Re: Descentbb.net forum challenge, for all users (proposal)

Post by fliptw »

it has pegs to keep score. The challenge concerns the counting at the end of a round(the show).

basically score according to this:
wikipedia wrote:
  • fifteen-twos
    • two points for each separate combination of two or more cards totalling exactly fifteen
  • runs
    • three points for a run of three consecutive cards (regardless of suit)
    • four points for completing a run of four
    • five points for completing a run of five
  • pairs
    • two points for a pair of cards of a kind
    • six points for three cards of a kind (known as a "pair royal", comprising three distinct pairs)
    • twelve points for four cards of a kind (a "double pair royal", comprising six distinct pairs)
  • flush
    • four points for a flush, where all four cards in the hand are of the same suit, with an additional point if the starter card is also of that suit. It is only a flush in the crib if all five cards, the four in the crib and the starter card, are of the same suit.
  • nobs
    • one point for holding the Jack of the same suit as the starter card
User avatar
Isaac
DBB Artist
DBB Artist
Posts: 7649
Joined: Mon Aug 01, 2005 8:47 am
Location: 🍕

Re: Descentbb.net forum challenge, for all users (proposal)

Post by Isaac »

So these are additional points on top of the points calculated by each card. I see.
❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉
-⎽__⎽-⎻⎺⎺⎻-⎽__⎽--⎻⎺⎺⎻-★ ·:*¨༺꧁༺ :E ༻꧂༻¨*:·.★-⎽__⎽-⎻⎺⎺⎻-⎽__⎽--⎻⎺⎺⎻-
❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉
User avatar
fliptw
DBB DemiGod
DBB DemiGod
Posts: 6458
Joined: Sat Oct 24, 1998 2:01 am
Location: Calgary Alberta Canada

Re: Descentbb.net forum challenge, for all users (proposal)

Post by fliptw »

No, only score using that list. you are over-thinking the problem Issac.
User avatar
Jeff250
DBB Master
DBB Master
Posts: 6511
Joined: Sun Sep 05, 1999 2:01 am
Location: ❄️❄️❄️

Re: Descentbb.net forum challenge, for all users (proposal)

Post by Jeff250 »

One observation that I made for my solution is that the six points for the three of a kind can be counted as just two points for each of the three pairs in the three of a kind. A similar observation can be made for four of a kind. So if it simplifies, you only need to count distinct pairs.

My code for scoring runs though is pretty messy. I think I'm failing to see some kind of elegant simplification.
User avatar
fliptw
DBB DemiGod
DBB DemiGod
Posts: 6458
Joined: Sat Oct 24, 1998 2:01 am
Location: Calgary Alberta Canada

Re: Descentbb.net forum challenge, for all users (proposal)

Post by fliptw »

you can use the number of pairs to limit the length of a given run. That would technically not simplify the solution.
User avatar
Jeff250
DBB Master
DBB Master
Posts: 6511
Joined: Sun Sep 05, 1999 2:01 am
Location: ❄️❄️❄️

Re: Descentbb.net forum challenge, for all users (proposal)

Post by Jeff250 »

OK, I had some time to optimize the "n-of-a-kind" scoring, and I think that the "runs" scoring is faster and easier to read, although I still think it could somehow be simpler:

Code: Select all

# coding: UTF-8
from itertools import count, izip, chain, groupby, combinations

RANKS = u'A23456789TJQK'
SUITS = u'♥♦♣♠'
VALUES = dict((c, min(n + 1, 10)) for c, n in izip(RANKS, range(len(RANKS))))
INDEXES = dict((c, n) for c, n in izip(RANKS, range(len(RANKS))))

def powerset(xs, min_len=0):
    return chain.from_iterable(
            combinations(xs, k) for k in range(len(xs), min_len - 1, -1))

def product(xs):
    return reduce(lambda x, y: x * y, xs, 1)

def rank(card):
    return card[0]

def suit(card):
    return card[1]

def score(*hand):
    starter = hand[-1]
    ranks = sorted(rank(card) for card in hand)
    suits = sorted(suit(card) for card in hand)
    values = sorted(VALUES[rank] for rank in ranks)
    indexes = sorted(INDEXES[rank] for rank in ranks)
    # score two points for any combination adding up to 15
    score = sum(2 for xs in powerset(values) if sum(xs) == 15)
    # score two points for pairs, six for three of a kind, 12 for four
    score += sum((0, 0, 2, 6, 12)[len(list(xs))] for k, xs in groupby(ranks))
    # score four points for a flush, five for including starter
    if all(x == y for x, y in izip(suits[:-1], suits[1:-1])):
        score += 5 if suit(starter) == suits[0] else 4
    # score one point if hand contains jack of same suit as starter
    score += sum(1 for card in hand[:-1]
                   if rank(card) == 'J' and suit(card) == suit(starter))
    # score n for each disjoint run of n cards, n >= 3
    gs = ((i - j, list(xs)) for (i, xs), j in izip(groupby(indexes), count()))
    runs = filter(lambda xs: len(xs) >= 3, # keep only a run of size >= 3
                  (list(xs) for i, xs in groupby(gs, lambda xs: xs[0])))
    score += sum(len(r) * product(len(rank) for i, rank in r) for r in runs)
    return score

assert(score(u'3♠', u'4♦', u'5♦', u'J♦', u'6♦') == 9)
assert(score(u'5♣', u'5♦', u'5♥', u'J♠', u'5♠') == 29)
assert(score(u'3♠', u'3♦', u'3♣', u'9♦', u'6♦') == 16)
assert(score(u'6♦', u'7♠', u'7♣', u'8♣', u'8♦') == 24)
assert(score(u'2♦', u'3♣', u'4♠', u'4♣', u'4♥') == 17)
edit: Simplified "runs" scoring by another line.
User avatar
Isaac
DBB Artist
DBB Artist
Posts: 7649
Joined: Mon Aug 01, 2005 8:47 am
Location: 🍕

Re: Descentbb.net forum challenge, for all users (proposal)

Post by Isaac »

I think I finally understand the instructions of the challenge, now that I've watched a few games and read different versions of the instructions.
(remember Isaac is slow)

I'm going to first do the UI (click the cards to change them):
http://testing.isaacg.net/crib/cirb.html <-- the first sprite sheet I ever used in a program. :E
It will allow the user to not only declare what hand he/she has, but there will be another way (not yet added) of checking off cards that have been eliminated from the probability of being obtained by the holder.

1: Show the value and type of hand the holder has.
2: Show the 3 highest possible hands of the cards remaining in the deck, less the eliminated cards.


Am I on track? I assume I finally am.
❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉
-⎽__⎽-⎻⎺⎺⎻-⎽__⎽--⎻⎺⎺⎻-★ ·:*¨༺꧁༺ :E ༻꧂༻¨*:·.★-⎽__⎽-⎻⎺⎺⎻-⎽__⎽--⎻⎺⎺⎻-
❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉
User avatar
Jeff250
DBB Master
DBB Master
Posts: 6511
Joined: Sun Sep 05, 1999 2:01 am
Location: ❄️❄️❄️

Re: Descentbb.net forum challenge, for all users (proposal)

Post by Jeff250 »

I think it's far outside the scope of the challenge as stated, but if that seems interesting to you, why not.
User avatar
Jeff250
DBB Master
DBB Master
Posts: 6511
Joined: Sun Sep 05, 1999 2:01 am
Location: ❄️❄️❄️

Re: Descentbb.net forum challenge, for all users (proposal)

Post by Jeff250 »

Also, looking over your code, to create an iterator for every possible hand, simply:

Code: Select all

from itertools import combinations
hands = combinations(cards.items(), 5)
Substitute 5 with 4 to not include the starter. This also handles the problem of getting duplicate cards, but you'll also need to distinguish cards by their suit for this to work right. Something like this should work (untested):

Code: Select all

from itertools import product
cards = list(product(ranks, suits))
User avatar
Isaac
DBB Artist
DBB Artist
Posts: 7649
Joined: Mon Aug 01, 2005 8:47 am
Location: 🍕

Re: Descentbb.net forum challenge, for all users (proposal)

Post by Isaac »

interesting. I have not yet tried product() or combinations() before. I ended up having to add list() around each of those to make them work. Very cool stuff in itertools! Thanks.
❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉
-⎽__⎽-⎻⎺⎺⎻-⎽__⎽--⎻⎺⎺⎻-★ ·:*¨༺꧁༺ :E ༻꧂༻¨*:·.★-⎽__⎽-⎻⎺⎺⎻-⎽__⎽--⎻⎺⎺⎻-
❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉
User avatar
Jeff250
DBB Master
DBB Master
Posts: 6511
Joined: Sun Sep 05, 1999 2:01 am
Location: ❄️❄️❄️

Re: Descentbb.net forum challenge, for all users (proposal)

Post by Jeff250 »

So list() will put everything into memory all at once, as opposed to just being an iterator generating the items lazily. This is fine for small sequences like a list of all possible cards that you'll be using over and over again, but you should think twice for using list() with all 52 choose 5 possible hands. Iterators don't support all of the operations that a list does (like len()), but this shouldn't be a problem.
User avatar
Isaac
DBB Artist
DBB Artist
Posts: 7649
Joined: Mon Aug 01, 2005 8:47 am
Location: 🍕

Re: Descentbb.net forum challenge, for all users (proposal)

Post by Isaac »

But with out list() it only can return <itertools.combinations object at 0xb76aaa04> .

Maybe I'm not following the pydoc correctly...
❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉
-⎽__⎽-⎻⎺⎺⎻-⎽__⎽--⎻⎺⎺⎻-★ ·:*¨༺꧁༺ :E ༻꧂༻¨*:·.★-⎽__⎽-⎻⎺⎺⎻-⎽__⎽--⎻⎺⎺⎻-
❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉❉⊱•═•⊰❉⊱•═•⊰❉⊱•═•⊰❉
User avatar
Jeff250
DBB Master
DBB Master
Posts: 6511
Joined: Sun Sep 05, 1999 2:01 am
Location: ❄️❄️❄️

Re: Descentbb.net forum challenge, for all users (proposal)

Post by Jeff250 »

That's normal. It can't print out the elements because doing so would exhaust the iterator, making it useless thereafter. Also, iterators can be infinite, which can take a while to print. You don't ever want to call list() on an infinite iterator either unless you're prepared for some thrashing. In the past, I might have done this once or twice on accident. ;)

A common way to use an iterator is something like:

Code: Select all

for hand in hands:
    pass # your code here
Or in this case, maybe (but probably not):

Code: Select all

for a, b, c, d, e in hands:
    pass # your code here
Just remember, whenever you want to reiterate freshly over all the hands, you'll need to recreate the iterator by calling combinations(). This might seem like a disadvantage, but it's really not--unlike lists, iterators are cheap to create, since all of the work is done lazily while iterating.

Most library functions that you might think take lists are actually taking iterators, lists being iterable.
User avatar
snoopy
DBB Benefactor
DBB Benefactor
Posts: 4435
Joined: Thu Sep 02, 1999 2:01 am

Re: Descentbb.net forum challenge, for all users (proposal)

Post by snoopy »

I'd take a stab at challenges, when I had time.

I'd also fall relatively short of the coding prowess present in the forums here.
Arch Linux x86-64, Openbox
"We'll just set a new course for that empty region over there, near that blackish, holeish thing. " Zapp Brannigan
Post Reply