# Enigmatic Code

Programming Enigma Puzzles

## Enigma 377: Cricket, lovely cricket

From New Scientist #1526, 18th September 1986 [link]

Three runs were scored in each over and they were all scored in singles.

What was the number of runs scored at the fall of each wicket?

[enigma377]

### 4 responses to “Enigma 377: Cricket, lovely cricket”

1. Jim Randell 30 December 2016 at 8:05 am

I wasn’t sufficiently familiar with the rules of cricket to solve this one without doing a bit of research [ https://en.wikipedia.org/wiki/Cricket#Format_of_the_game ], but I eventually managed to get enough clarification to write this Python 3 program, which runs in 58ms.

```from enigma import update, join, printf

# the score sheet
scores = {
# batsman -> (total, bowler)
'A': (7, 'R'),
'B': (2, 'R'),
'C': (3, 'T'),
'D': (9, 'R'),
'E': (1, 'T'),
'F': (1, 'T'),
'G': (1, 'S'),
'H': (2, 'S'),
'I': (4, 'S'),
'J': (4, '#'), # not out
'K': (2, 'R')
}

# play the cricket match
# n = over number
# over = interesting events in the current over
# batsman = current batsman
# runs = runs for current batsman
# other_batsman = the other batsman
# other_runs = runs for the other batsman
# bowlers = map over number to bowler
# remaining_batsmen = list of remaining batsmen
# overs = previous overs
def play(n, over, batsman, runs, other_batsman, other_runs, bowlers, remaining_batsmen, overs):

# count the number of runs in the over
r = over.count('1')

# can we start a new over?
if r == 3:
# the other batsman faces the first ball of the new over
yield from play(n + 1, '', other_batsman, other_runs, batsman, runs, bowlers, remaining_batsmen, overs + [over])

# can we do more in this over?
if len(over) == 6: return

# extract the total and bowler when the current batsman is dismissed
(total, bowler) = scores[batsman]

# can the batsman score a run?
if runs < total and r < 3:
# the batsman scores a single, and the other batsman faces the next ball
yield from play(n, over + '1', other_batsman, other_runs, batsman, runs + 1, bowlers, remaining_batsmen, overs)

# can the batsman be dismissed?
if runs == total and bowler != '#':
# check the bowler hasn't changed in the over
if bowlers.get(n, bowler) != bowler: return
# check the bowler hasn't bowled two consecutive overs
if n > 1 and bowlers.get(n - 1, '') == bowler: return
# if there are remaining batsmen...
if remaining_batsmen:
# ... the new batsman faces the next ball
yield from play(n, over + 'd', remaining_batsmen[0], 0, other_batsman, other_runs, update(bowlers, [(n, bowler)]), remaining_batsmen[1:], overs)
# ... else check the final batsman has the correct not-out score
# and that three runs have been scored in the final over
elif scores[other_batsman] == (other_runs, '#') and r == 3:
yield overs + [over + 'd']

# start the match at over 1 with batsmen A and B
for overs in play(1, '', 'A', 0, 'B', 0, dict(), 'CDEFGHIJK', []):
# output the overs
overs = join(overs, sep=' ')
printf("overs = {overs}")
# and output the total score at the dismissal of each batsman
(t, n) = (0, 0)
for x in overs:
if x == '1':
# a single is scored
t += 1
elif x == 'd':
# the batsman is dismissed
n += 1
printf("{t} for {n}")
printf()
```

Solution: The total runs scored at the fall of each wicket are: 6 for 1, 11 for 2, 15 for 3, 19 for 4, 21 for 5, 24 for 6, 24 for 7, 30 for 8, 31 for 9, 36 for 10.

2. Hugh Casement 30 December 2016 at 8:32 am

I failed to work out the order in which the batsmen were out (except that, obviously, Johnson was left at the end).  And can we (must we?) assume that the order in which they went in was alphabetic?

• Jim Randell 30 December 2016 at 8:36 am

I assumed the order that the batsmen went in to play was the order given on the score sheet, and that gave me a single solution, so I was happy enough with that.

3. Brian Gladman 1 January 2017 at 10:18 pm
```# the runs made by each player
p_sc = (7, 2, 3, 9, 1, 1, 1, 2, 4, 4, 2)
# the bowler that dismisses each player
p_bw = 'RRTRTTSSS_R'

# p1   - first batsman (facing the bowler)
# p2   - second batman (at the other end)
# pr   - the batsmen still to bat
# s1   - runs so far for batsman 1
# s2   - runs so far for batsman 2
# rns  - total runs so far
# rio  - runs so far in the current over
# nov  - over number
# res  - list of (player, score, over) values at each dismissal
# v    - record of the runs and dismissals in overs
def play(p1, p2, pr, s1=0, s2=0, rns=0, rio=0, nov=0, res=[], v='|'):

# are we at the end of an over?
if rio == 3:
# can the current batsman be dismissed here?
if s1 == p_sc[p1]:
# check for solutions in which this happens
t, u = res + [(p1, rns, nov)], v + chr(ord('a') + p1)
# if there are batsmen yet to bat
if pr:
yield from play(pr[0], p2, pr[1:], 0, s2, rns, rio, nov, t, u)
# is the end of the game valid?
elif p2 == 9 and rns == 36:
yield t, u + '|'
else:
return
# start a new over with a change of ends for the bowlers
nov, rio, v, p1, p2, s1, s2 = nov + 1, 0, v + '|', p2, p1, s2, s1

if s1 < p_sc[p1]:
# the current batman is not out - score a run and continue
yield from play(p2, p1, pr, s2, s1 + 1, rns + 1, rio + 1, nov, res, v + '1')
else:
# he is out and is replaced by the next batsman
t, u = res + [(p1, rns, nov)], v + chr(ord('a') + p1)
if pr:
yield from play(pr[0], p2, pr[1:], 0, s2, rns, rio, nov, t, u)

for s, v in play(0, 1, range(2, 11)):
for (p1, r1, o1), (p2, r2, o2) in zip(s, s[1:]):
# bowlers can't change in an over or bowl consecutive overs
if (o1 == o2 and p_bw[p1] != p_bw[p2]
or p_bw[p1] == p_bw[p2] and o2 - o1 == 1):
break
else:
print('{}\n{}'.format(tuple(x[1] for x in s), v))
```

This site uses Akismet to reduce spam. Learn how your comment data is processed.