Teaser 3317: Hitting all the spots
From The Sunday Times, 19th April 2026 [link] [link]
A board game uses three coloured tetrahedral dice (red, green and blue) to determine which numbers are hit when the three dice are rolled. The 12 faces of the three dice each have different numbers, comprising a 1 and the primes from 2 to 31. A hit is made when it is the number rolled on any of the dice, the sum of any two numbers rolled or the sum of all three numbers rolled.
The arrangement of the numbers on each die made it possible to hit every number in a range and this range was as large as it could be. The green die has numbers 2, 5, 7, 11 and the blue die also has three consecutive primes.
In ascending order, what are the numbers on the red die?
[teaser3317]


Jim Randell 6:32 am on 19 April 2026 Permalink |
The most interesting part was writing the [[
maxcss()]] function to find the maximum continuous subsequence of consecutive integers contained in the parent sequence.This Python program runs in 70ms. (Internal runtime is 3.3ms).
from enigma import ( Accumulator, primes, irange, tuples, trim, diff, cproduct, union, subsets, printf ) # calculate the hits for a set of dice def hits(ds): # sum of any (non-empty) subset of a throw hs = union(subsets(vs, min_size=1, fn=sum) for vs in cproduct(ds)) # return as a sorted list return sorted(hs) # generate possible sets of dice def generate(): # numbers used on the dice ns = list(primes.between(2, 31)) ns.insert(0, 1) # green die G = {2, 5, 7, 11} # choose 3 consecutive primes for the blue die for b3 in tuples(trim(ns, head=6), 3, fn=set): rs = diff(ns, G, b3) # and one of the remaining numbers for bx in subsets(rs, size=1, fn=set): B = b3.union(bx) # red die is what's left R = diff(rs, bx, fn=set) yield (G, B, R) # find the largest continuous subsequence (length >= m) # in the list of integers <vs>, the list should be strictly increasing # return (<max-length>, (<lowest-value>, <highest-value>)) def maxcss(vs, m=0): r = Accumulator(fn=max, value=m) # consider possible starts n = len(vs) for (i, v) in enumerate(vs): if i + r.value > n: break for j in irange(n - 1, i + r.value, step=-1): if vs[j] - v == j - i: r.accumulate_data(j - i + 1, i) break if r.data is None: return (k, i) = (r.value, r.data) return (k, (vs[i], vs[i + k - 1])) # find maximal length range of hits r = Accumulator(fn=max, value=1, collect=1) for ds in generate(): hs = hits(ds) z = maxcss(hs, r.value) if z is None: continue (n, (a, b)) = z r.accumulate_data(n, ds) # output solution printf("max range = {r.value}") for (G, B, R) in r.data: printf("-> G={G} B={B} R={R}", G=sorted(G), B=sorted(B), R=sorted(R))Solution: The numbers on the red die are: 1, 13, 17, 31.
The dice are:
All hits from 1 – 57 can be made. (58 is the first number that cannot be hit using these dice).
In fact, using these dice we can make: [1 – 57; 59 – 62; 65; 67; 71].
LikeLike
Jim Randell 4:51 pm on 19 April 2026 Permalink |
Here is a simpler implementation of [[
maxcss()]], that just returns the length of a maximal subsequence:We calculate a derived sequence by subtracting the index of each element of the original sequence from the value of that element. We then look for a maximal length run of equal values in the derived sequence, and this corresponds to a maximal length continuous subsequence of consecutive integers in the original sequence.
[I am posting this code because although I have seen several other solutions posted for this puzzle, none of them have managed to implement this logic correctly].
LikeLike
Ruud 5:10 am on 20 April 2026 Permalink |
@Frits
Now, I see what you mean. i had interpreted the problem wrongly.
Here’s a revised version:
import itertools max_max_length = 0 faces = [n for n in range(1, 32) if all(n % i for i in range(2, int(n**0.5) + 1))] # 1, 2, 3, ...,31 green = {2, 5, 7, 11} for primes3 in zip(faces[0:], faces[1:], faces[2:]): if not any(x in green for x in primes3): for prime4 in set(faces) - green - {primes3}: blue = {*primes3, prime4} red = set(faces) - green - blue hits = sorted({sum(x) for a, b, c in itertools.product(green, blue, red) for x in itertools.combinations((0, 0, a, b, c), 3)}) max_length = 0 length = 1 for d0, d1 in zip(hits, hits[1:] + [0]): if d1 - d0 == 1: length += 1 else: max_length = max(max_length, length) length = 1 if max_length >= max_max_length: if max_length > max_max_length: solutions = [] max_max_length = max_length solutions.append((green, blue, red)) print("maximum range = ", max_max_length) for solution in solutions: for i, color in enumerate("green blue red".split()): print(color, sorted(solution[i]))LikeLike
Ruud 10:14 am on 19 April 2026 Permalink |
import itertools max_max_hit = 0 faces = [n for n in range(1, 32) if all(n % i for i in range(2, int(n**0.5) + 1))] # 1, 2, 3, ...,31 green = {2, 5, 7, 11} for primes3 in zip(faces[0:], faces[1:], faces[2:]): if not any(x in green for x in primes3): for prime4 in set(faces) - green - {primes3}: blue = {*primes3, prime4} red = set(faces) - green - blue hits = {sum(x) for a, b, c in itertools.product(green, blue, red) for x in itertools.combinations((0, 0, a, b, c), 3)} for max_hit in itertools.count(): if max_hit + 1 not in hits: break if max_hit >= max_max_hit: if max_hit > max_max_hit: solutions = [] max_max_hit = max_hit solutions.append((green, blue, red)) print("maximum range = ", max_max_hit) for solution in solutions: for i, color in enumerate("green blue red".split()): print(color, sorted(solution[i]))LikeLike
Frits 11:26 am on 19 April 2026 Permalink |
@Ruud, why do you assume the range has to start with 1?
LikeLike
Ruud 3:18 pm on 19 April 2026 Permalink |
Because 1 is also one of the numbers on the dice. So faces is really 1, 2, 3, …, 31 .
LikeLike
Frits 9:32 pm on 19 April 2026 Permalink |
@Ruud,
The collection of hits might be (if 1 and 3 belong to the same colour):
In this case the biggest range isn’t 3 but 37 (17-53) and number 1 isn’t included in this range.
LikeLike
Ellen Napier 1:21 pm on 20 April 2026 Permalink |
I found two different answers to this puzzle.
LikeLike
Jim Randell 6:53 am on 21 April 2026 Permalink |
@Ellen: I found there were 20 possible sets of dice. And one of them gave the single longest continuous subsequence of consecutive hits.
However there are two sets which give the second longest continuous subsequence of consecutive hits.
LikeLike
Ellen Napier 11:13 pm on 21 April 2026 Permalink |
Got it, thanks. Had a sorting error.
LikeLike