# Enigmatic Code

Programming Enigma Puzzles

## Enigma 1433: A cribbed deal

From New Scientist #2594, 10th March 2007

I have been introducing my niece and nephew to a simple form of the game of cribbage. I have discarded the “picture” cards from a standard pack of cards, leaving 40 cards. The aces count as ones. I give each of us four of the cards and explain how to work out the score of each hand. Each pair of identical numbers scores two points. Each group of cards adding up to 15 scores another two points. If the four cards have consecutive numbers on them they score a further four points, but if not then any three of the cards which have consecutive numbers on them score another three points. So, for example, a hand comprising 3, 4, 5 and 5 would score eight points and a hand comprising 7, 8, 8, 8 would score 12 points.

In one interesting deal the three of us each had four cards whose score equalled the total of their faces. I then shuffled just those 12 cards and gave us four each again. This time we all had different score from each other, but for each hand the sum of the face values was a multiple (larger than 1) of the score.

What (in increasing order of scores) were the three hands on that last occasion?

[enigma1433]

### One response to “Enigma 1433: A cribbed deal”

1. Jim Randell 7 May 2013 at 7:05 am

The following Python program runs in 60ms. In Python 3 the last line of the recursive solve() function could be replaced with a yield from construct. I left it as a loop so that it works with Python 2 or Python 3.

```from itertools import combinations, combinations_with_replacement
from collections import Counter
from enigma import powerset, irange, flatten, uniq, printf

# determine the score of a hand
def score(cs):
s = 0
# two points for each pair
for (c1, c2) in combinations(cs, 2):
if c1 == c2: s += 2
# two points for each group that sums 15
for c in powerset(cs):
if sum(c) == 15: s += 2
# four points for 4 consecutive values
c = sorted(cs)
if c[0] + 3 == c[1] + 2 == c[2] + 1 == c[3]: s += 4
else:
# otherwise, three points for each 3 consecutive values
for (c1, c2, c3) in combinations(c, 3):
if c1 + 2 == c2 + 1 == c3: s += 3
return s

# check the scores we're given
assert score((3, 4, 5, 5)) == 8
assert score((7, 8, 8, 8)) == 12

# find solution hands with increasing scores
# c - Counter object with the set of remaining cards
# s - solution hands (with increasing scores)
# scs - the scores for the hands
def solve(c, s, scs):
# are we done
if len(s) == 3:
yield (s, scs)
else:
# chose a hand
for h in uniq(combinations(c.elements(), 4)):
(sm, sc) = (sum(h), score(h))
# sum should be a multiple of the score
(d, r) = divmod(sm, sc)
if not(d > 1 and r == 0): continue
# score should be different and increasing
if scs and not(scs[-1] < sc): continue
# try to solve for remaining cards
c1 = c.copy()
c1.subtract(h)
for x in solve(c1, s + [h], scs + [sc]): yield x

# find 4 card hands where the score is the sum of card values
hands = list(c for c in combinations_with_replacement(irange(1, 10), 4) if sum(c) == score(c))

# and choose 3 of these hands
for s in combinations_with_replacement(hands, 3):
# what cards are involved?
cs = flatten(s)
# we can't have more than 4 cards of the same value
c = Counter(cs)
if not all(x < 5 for x in c.values()): continue
# solve this set of cards
for (s, scs) in solve(c, [], []):
printf("hands: {s}, sums: {sms}, scores: {scs}", sms=list(sum(x) for x in s))
```

Solution: The hands were as follows: score = 2, cards = 1, 2, 2, 5; score = 4, cards = 1, 1, 3, 3; score = 8, cards = 1, 5, 5, 5.