Enigmatic Code

Programming Enigma Puzzles

Enigma 1554: Many times better

From New Scientist #2717, 18th July 2009 [link]

My little nephew and I play a simple guessing game using an ordinary pack of cards. In the first round we lay seven cards face down and he has to guess how many are red cards (a number between 0 and 7). Then, likewise, I have to guess how many are black, but I must choose my number so that the two guesses do not add up to 7 (so that at least one of us will be wrong). Then, on turning the cards over, my nephew earns 1 point for each red card plus a bonus of 10 points if his guess was correct and I earn 1 point for each black card plus a bonus of 10 points if my guess was correct. Then in the second round we repeat the exercise with six cards, then in subsequent rounds with five, four, three, two and one card.

In a recent game I recorded cumulative totals throughout and I noticed that after each of six of the seven rounds, my nephew’s total divided by mine was a whole number, and these six whole numbers were all different. Indeed, there were three consecutive rounds after which these three whole numbers were consecutive and decreasing.

Give our cumulative totals after the round(s) when his total divided by mine was an odd number.

[enigma1554]

5 responses to “Enigma 1554: Many times better”

1. Jim Randell 7 March 2012 at 9:49 am

This is the first Enigma problem I tackled in Python (although I had previously coded a solution in Perl, prior to this I attempted Perl solutions for Enigma problems, but I wanted to try and learn Python). This version is a slightly modified version of my original Python code. It runs in 400ms.

```from enigma import irange, is_distinct, printf

def play(c, scores):
"play(<c>, <scores>) - play a game starting with <c> cards, and accumulated scores in <scores>"
# b is the bonus, 0 for no-one, 1 for player 1 (nephew), 2 for player 2 (me)
for b in irange(0, 2):
# if there's only one card then someone has to win the bonus (although this doesn't affect the solution)
if c == 1 and b == 0: continue
# try all the possible scores, i is the number of red cards
for i in irange(0, c):
# compute nephew's and my scores, including possible bonuses
n = (10 if b == 1 else 0) + i
m = (10 if b == 2 else 0) + (c - i)

# analyse the scores to see if the match the puzzle criteria
s = scores + [(n, m)]
if analyse(s):
# and if they do, play the next game with one card less
play(c - 1, s)

def analyse(scores):
"analyse(<scores>) - analyse the scores to see if this game meets the puzzle criteria"
# scores: nephew's, mine and x counts the numbers of games where the quotient of the cumulative scores is non-integral
n = m = x = 0
# qs is a list of the quotients (n/m)
qs = []
for score in scores:
# accumulate the scores for each game
(n, m) = (n + score[0], m + score[1])
# if the quotient is integral...
if m > 0 and n % m == 0:
# ... then record it
q = n // m
else:
# otherwise, increase the non-integral score counter
x = x + 1
# and exit if there is more than 1 non-integral quotient
if x > 1: return 0
q = -1
# all the quotients must be distinct
if not is_distinct(q, *qs): return 0
# if it seems OK then append it to the list of quotients
qs.append(q)

# check to see if we've finished the game, we will have accumulated 7 quotients
if len(qs) == 7:
# and exactly one of them must be non-integral
if not(x == 1): return 0
# and there should be a series of 3 consecutive decreasing integers in the quotient list
if not any(qs[i] == qs[i+1] + 1 and qs[i+1] == qs[i+2] + 1 for i in irange(0, 4)): return 0

# if we get this far we have found a solution, so print it out in a sensible format
n = m = 0
for (i, score) in enumerate(scores):
(n, m, Q) = (n + score[0], m + score[1], qs[i])
printf("[{j}] n={score[0]:2d} m={score[1]:2d} N={n:2d} M={m:2d} Q={Q} {a}", j=7-i, a='[ODD]' if Q > 0 and Q % 2 else '')
printf("")

# so far these scores look OK
return 1

play(7, [])
```

Solution: The cumulative totals divide to give an odd number when you have scored 35 points and your nephew has scored 7 points.

• Jim Randell 7 March 2012 at 9:52 am

Here’s my original Perl 5 solution (which the above Python is based on). It runs in 660ms on the same machine, so it’s faster in Python.

```use Enigma qw/distinct/;

sub play {
my (\$c, @scores) = @_;

my (\$b, \$i, \$n, \$m);

for \$b (0..2) {
next if \$c == 1 and \$b == 0; # someone always wins the bonus in the last game (although it doesn't matter if you don't realise this)
for \$i (0..\$c) {
\$n = (\$b == 1 ? 10 : 0) + \$i;
\$m = (\$b == 2 ? 10 : 0) + (\$c - \$i);

if (analyse(@scores, [\$n, \$m])) {
play(\$c - 1, @scores, [\$n, \$m]);
}
}
}
}

sub analyse {
my \$x = 0; # count the non-integer quotients
my @q = (); # list of quotients
my (\$N, \$M, \$i) = (0, 0);
my \$q;
for (@_) {
\$N += \$_->[0];
\$M += \$_->[1];
if (\$M > 0 and \$N % \$M == 0) {
\$q = \$N / \$M;
} else {
\$x++;
return 0 if \$x > 1; # reject if there's more than one non-integer quotient
\$q = -1;
}
return 0 unless distinct(\$q, @q); # all the quotients are distinct
push @q, \$q;
}
if (@_ == 7) {
# we have a full complement of scores
return 0 unless \$x == 1; # one of them shouldn't be an integer
# there should be a descending consecutive sequence
return 0 unless
(\$q[0] == \$q[1] + 1 and \$q[1] == \$q[2] + 1) or
(\$q[1] == \$q[2] + 1 and \$q[2] == \$q[3] + 1) or
(\$q[2] == \$q[3] + 1 and \$q[3] == \$q[4] + 1) or
(\$q[3] == \$q[4] + 1 and \$q[4] == \$q[5] + 1) or
(\$q[4] == \$q[5] + 1 and \$q[5] == \$q[6] + 1);
# output the game
(\$N, \$M) = (0, 0);
for (\$i = 0; \$i < @_; \$i++) {
\$N += \$_[\$i]->[0];
\$M += \$_[\$i]->[1];
printf "[%d] n=%2d m=%2d N=%2d M=%2d Q=%d\n", 7 - \$i, \$_[\$i]->[0], \$_[\$i]->[1], \$N, \$M, \$q[\$i];
}
print "\n";
return 0;
}
return 1;
}

play(7);
```
2. Hugh Casement 24 February 2016 at 6:05 pm

I found a solution in which the cumulative scores in the third, fourth, and fifth rounds were 24 & 4, 35 & 7, 36 & 9 respectively.  But I also found several where the cumulative scores in the fourth, fifth, and sixth rounds were 28 & 4, 30 & 5, 30 & 6, or else 30 & 2, 42 & 3, 52 & 4.  Are those precluded by the terms of the puzzle?

• Jim Randell 25 February 2016 at 8:23 am

In a round with n cards the total number of points handed out is n (if no-one gets the bonus) or n + 10 (if someone does win the bonus).

So in the sixth round (with 2 cards) the points awarded must be 2 or 12.

Going from (30, 5) in round 5 to (30, 6) in round 6 the points are (0, 1), so this can’t be a sixth round score. Similarly, going from (42, 3) in round 5 to (52, 4) in round 6 the points are (10, 1), so this can’t be a sixth round score either.

The only possible scores (for the first six rounds) my program came up with are:

```                  scores     cumulative   ratio
round  cards  nephew  mine  nephew  mine   n/m
1      7      16      1     16      1     16  [even]
2      6       6      0     22      1     22  [even]
3      5       2      3     24      4      6  [even, seq]
4      4      11      3     35      7      5  [odd, seq]
5      3       1      2     36      9      4  [even, seq]
6      2       2     10     38     19      2  [even]```

There are four possible scores in the final round with 1 card (0, 11), (1, 10), (10, 1), (11, 0) (someone always gets the bonus in the last round), so there are four possible final scores, but only in the fourth round is the n/m ratio odd.

• Hugh Casement 26 February 2016 at 6:23 am

Thanks, Jim.  BASICally I was doing it right, but there was a wee fault in my program — easy to overlook but it made all the difference.  I now get the same result as you.