Design a site like this with WordPress.com

Brain-Teaser 252: Blocks

From The Sunday Times, 27th February 1966 [link]

“See these eleven blocks?”, says a so-called friend. “Four of them of 8 inch thickness, two of them of 4 inch thickness, three of 3 inch and two of 1 inch thickness”.

“Pile them in a column 51 inches high with a 3 inch block at the bottom so that, remaining in position, individual blocks or combinations of adjacent blocks can be used to measure every thickness in exact inches from 1 inch to 48 inches”.

In what order do they stand?

This puzzle was included in the book Sunday Times Brain Teasers (1974, edited by Ronald Postill).

[teaser252]

• Jim Randell 8:54 am on 4 December 2022 Permalink | Reply

This Python program performs an exhaustive search of all possible stacks of blocks.

It runs in 268ms.

Run: [ @replit ]

```from enigma import (multiset, subsets, csum, irange, printf)

# the blocks
blocks = multiset.from_dict({8: 4, 4: 2, 3: 3, 1: 2})
assert blocks.sum() == 51

# extract a 3 block
blocks.remove(3)

# and consider possible arrangements of the remaining blocks
for bs in subsets(blocks, size=len, select="mP", fn=list):
bs.insert(0, 3)
# find what thicknesses can be measured
ts = set(b - a for (a, b) in subsets(csum(bs, empty=1), size=2))
# can we measure all values from 1 to 48
if all(x in ts for x in irange(1, 48)):
printf("{bs}")
```

Solution: The pile of blocks (bottom to top) is one of the following two sequences:

(3, 4, 3, 8, 8, 8, 8, 4, 1, 1, 3)
(3, 1, 1, 4, 8, 8, 8, 8, 3, 4, 3)

One being the reverse of the other.

Like

Teaser 3141: Multiple extensions

All the phone extensions at Mick’s work place are four-digit numbers with no zeros or twos, and no digit appears more than once in a number. He can enter all the extension numbers on the keypad by starting at key 2 (but not pressing it) then moving in any direction, including diagonally, to an adjacent key and pressing it; then similarly moving to and pressing adjacent keys until the number is entered. A couple of examples of his extension numbers are 3685 and 5148.

He phoned two different extension numbers this morning and later realised that one was an exact multiple of the other.

What was the larger extension number he dialled?

[teaser3141]

• Jim Randell 4:54 pm on 2 December 2022 Permalink | Reply

The following Python program runs in 58ms. (Internal run time is 6.2ms).

Run: [ @replit ]

```from enigma import (nconcat, div, ordered, printf)

1: [2, 4, 5],
2: [1, 3, 4, 5, 6],
3: [2, 5, 6],
4: [1, 2, 5, 7, 8],
5: [1, 2, 3, 4, 6, 7, 8, 9],
6: [2, 3, 5, 8, 9],
7: [4, 5, 8],
8: [4, 5, 6, 7, 9],
9: [5, 6, 8],
}

# generate k-length numbers with no repeated digits
def solve(k, ds):
if k == 0:
yield ds
else:
if d not in ds:
yield from solve(k - 1, ds + [d])

# start at 2, and dial 4 more digits
ns = list()
for ds in solve(4, [2]):
n = nconcat(ds[1:])
# look for previous numbers that pair with this one
for m in ns:
(x, y) = ordered(m, n)
k = div(y, x)
if k:
printf("{y} = {k} * {x}")
# add in the new number
ns.append(n)
```

(Or a more efficient (but longer) variation on this code [@replit]).

Solution: [To Be Revealed]

Like

Teaser 2689: The right choice

From The Sunday Times, 6th April 2014 [link]

I am organising a tombola for the fete. From a large sheet of card (identical on both sides) I have cut out a lot of triangles of equal area. All of their angles are whole numbers of degrees and no angle exceeds ninety degrees. I have included all possible triangles with those properties and no two of them are identical. At the tombola entrants will pick a triangle at random and they will win if their triangle has a right-angle. The chances of winning turn out to be one in a certain whole number.

What is that whole number?

[teaser2689]

• Jim Randell 8:59 am on 1 December 2022 Permalink | Reply

Once we have chosen the three angles of the triangle (each an integer between 1° and 90°, that together sum 180°), we can form a triangle with the required area by scaling it appropriately.

This Python program counts the number of possible triangles and the number of them that are right angled.

It runs in 53ms. (Internal runtime is 1.0ms).

Run: [ @replit ]

```from enigma import (decompose, fraction, printf)

# generate possible triangles
triangles = lambda: decompose(180, 3, increasing=1, sep=0, min_v=1, max_v=90)

# count:
# t = total number of triangles
# r = number with a right angle
r = t = 0
for (a, b, c) in triangles():
t += 1
if c == 90: r += 1

# output solution
(p, q) = fraction(r, t)
printf("P(win) = {r}/{t} = {p}/{q}")
```

Solution: The chance of winning is 1/16.

There are 720 triangles, and 45 of them are right angled.

I think it would be annoying to choose a triangle with an 89° angle.

Like

Teaser 2685: Not the Gold Cup

From The Sunday Times, 9th March 2014 [link]

Five horses took part in a race, but they all failed to finish, one falling at each of the first five fences. Dave (riding Egg Nog) lasted longer than Bill whose horse fell at the second fence; Big Gun fell at the third, and the jockey wearing mauve lasted the longest. Long Gone lasted longer than the horse ridden by the jockey in yellow, Chris’s horse fell one fence later than the horse ridden by the jockey in green, but Fred and his friend (the jockey in blue) did not fall at adjacent fences. Nig Nag was ridden by Wally and Dragon’s jockey wore red.

Who was the jockey in yellow, and which horse did he ride?

[teaser2685]

• Jim Randell 8:28 am on 29 November 2022 Permalink | Reply

I used the [[ `SubstitutedExpression` ]] solver from the enigma.py library to assign the fence values (1-5) to the 3 groups of jockeys, horses and colours.

The following run file executes in 66ms. (Internal runtime of the generated program is 94µs).

Run: [ @replit ]

```#! python3 -m enigma -r

# assign fence numbers (1-5) to the following groups:
#
#  jockeys = A (Wally), B (Bob), C (Chris), D (Dave), E (Fred)
#  horses  = F (Egg Nog), G (Big Gun), H (Long Gone), I (Nig Nag), J (Dragon)
#  colours = K (mauve), L (yellow), M (green), N (blue), P (red)

SubstitutedExpression

--base="6"
--digits="1-5"
--distinct="ABCDE,FGHIJ,KLMNP"
--template="(A B C D E) (F G H I J) (K L M N P)"
--solution=""

# "Dave (D) riding Egg Nog (F) lasted longer than Bill (B) who fell at the 2nd fence"
"D = F"
"D > B"
"2 = B"

# "Big Gun (G) fell at the 3rd"
"3 = G"

# "mauve (K) lasted the longest"
"5 = K"

# "Long Gone (H) lasted longer than yellow (L)
"H > L"

# "Chris's (C's) horse fell one fence later than the horse ridden by green (M)"
"M + 1 = C"

# "Fred (E) and his friend blue (N) did not fall at adjacent fences"
"abs(E - N) > 1"

# "Nig Nag (I) was ridden by Wally (A)"
"I = A"

# "Dragon's (J's) jockey wore red"
"J = P"
```

We can wrap this in Python code to format the solution in a more friendly form:

Run: [ @replit ]

```from enigma import (SubstitutedExpression, group, printf)

p = SubstitutedExpression.from_file("teaser2685.run")

# map symbols to jockey, horse, colour names
name = dict(
A="Wally", B="Bob", C="Chris", D="Dave", E="Fred",
F="Egg Nog", G="Big Gun", H="Long Gone", I="Nig Nag", J="Dragon",
K="mauve", L="yellow", M="green", N="blue", P="red",
)

# solve the puzzle
for s in p.solve(verbose=0):
# group symbols by value
d = group(s.keys(), by=s.get)
# output solution for each fence
for k in sorted(d.keys()):
# extract jockey, horse, colour
(j, h, c) = (name[s] for s in sorted(d[k]))
printf("{k}: {j} ({c}) on {h}")
printf()
```

Solution: Fred was in yellow, riding Big Gun.

The full solution is:

1st fence: Wally (blue) on Nig Nag
2nd fence: Bob (red) on Dragon
3rd fence: Fred (yellow) on Big Gun
4th fence: Dave (green) on Egg Nog
5th fence: Chris (mauve) on Long Gone

Like

Brain-Teaser 222: British triangles

From The Sunday Times, 25th July 1965 [link]

British Triangles, naturally, stand on horizontal bases with their points upwards. All their sides, never more than a  sensible 60 inches, and their heights measure an exact number of inches. No B.T. is isosceles or right angled.

You can often put more than one B.T. on a common base. On a base of 28 inches 8 B.T.s are erected.

What are their heights?

This puzzle was included in the book Sunday Times Brain Teasers (1974, edited by Ronald Postill).

[teaser222]

• Jim Randell 9:47 am on 27 November 2022 Permalink | Reply

If the 3 sides of a triangle are a, b, c, then the area A is given by Heron’s formula:

s = (a + b + c) / 2
A = √(s(s − a)(s − b)(s − c))

And if the height (from side a) is h, then we also have:

A = ha / 2

Hence the height h can be determined from the sides a, b, c:

h = 2A / a
h = (2/a)√(s(s − a)(s − b)(s − c))

This Python program considers possible values for the 2nd and 3rd sides of the triangle, and then looks for values where the height is an integer.

It runs in 53ms. (Internal runtime is 1.8ms).

Run: [ @replit ]

```from enigma import (irange, div, is_square, subsets, sq, printf)

# check for a viable triangle
def is_triangle(a, b, c):
# check triangle inequalities
if not (a + b > c and a + c > b and b + c > a): return
# no triangle is isosceles
if len({a, b, c}) < 3: return
# no triangle is right angled
sqs = (sq(a), sq(b), sq(c))
if sum(sqs) == 2 * max(sqs): return
# looks OK
return (a, b, c)

# calculate integer height from side a
def height(a, b, c):
p = a + b + c
x = div(p * (p - 2 * a) * (p - 2 * b) * (p - 2 * c), 4)
if not x: return
x = is_square(x)
if not x: return
h = div(x, a)
return h

# base
a = 28
# consider possible integer length for the remaining sides, b, c
for (b, c) in subsets(irange(1, 60), size=2, select="R"):
if not is_triangle(a, b, c): continue
# calculate the height of the triangle
h = height(a, b, c)
if not h: continue
# output viable triangles
printf("a={a} b={b} c={c} -> h={h}")
```

Solution: The heights of the triangles are 9″ (2 triangles), 15″ (4 triangles), 24″ (2 triangles).

The four triangles found by the program are shown below. And they can be mirrored to produce the remaining four triangles.

Like

• Hugh Casement 7:41 am on 28 November 2022 Permalink | Reply

Alternatively we can think of it as two right-angled triangles joined together.
If their bases are d and e, then d² = b² – h² and e² = c² – h².
d + e, or |d – e| in the case of the obtuse-angled triangles, must equal a = 28.
b must not equal c, for then the overall triangle would be isosceles
(that is the case when h = 48, b = c = 50, and d = e = 14).

Like

• Hugh Casement 9:09 am on 28 November 2022 Permalink | Reply

Joined together along the line of their common height h, of course.
A base a = 21 also allows eight resultant triangles, including reflections.

Like

Teaser 3140: Enjoy every minute

On rugby international morning, I found myself, along with eight friends, in a pub 5.8 miles from the match ground. We were enjoying ourselves, and so wished to delay our departure for the ground until the last possible minute. The publican, wishing to keep our custom for as long as possible, offered to help us get there by carrying us, one at a time, as pillion passengers on his motorbike.

We could walk at 2.5mph and the bike would travel at 30mph. We all left the pub together, and arrived at the ground in time for kick-off.

Ignoring the time taken getting on and off the bike, what was our minimum travelling time in minutes?

[teaser3140]

• Jim Randell 4:58 pm on 25 November 2022 Permalink | Reply

(Curiously this week’s New Scientist back page puzzle is a simpler variation on the problem [link]).

If the friends just walked from pub to the stadium it would take 2.32 hours.

If the barman ferried each of them individually between the pub and the stadium it would take 3.29 hours.

But we can do better.

If the barman takes the first friend on his motorbike, and the rest of the friends start walking towards the stadium. Then the barman drops the first friend off to walk the remainder of the distance to the stadium and returns to the group (now a short distance from the pub) and ferries the next friend to join the first friend, and so on until he collects the final friend and drops him off at the stadium at the same time that all the other friends arrive, then we can achieve a minimum overall time.

The only thing to work out is how far before the stadium to drop the first friend, then it is just a matter of ferrying friends from the trailing to the leading group.

If each of the k friends walks a distance x at velocity w, and travels by motorbike a distance (d − x) at a velocity v, then each journey takes:

t = x/w + (d − x)/v

And the total time taken for the barman to ferry them all is:

t = [(2k − 1)d − 2kx]/v

Everyone arrives at the stadium at the same time, so:

x/w + (d − x)/v = [(2k − 1)d − 2kx]/v
vx + (d − x)w = [(2k − 1)d − 2kx]w
vx + dw − xw = (2k − 1)dw − 2kxw
x(v + w(2k − 1)) = dw(2k − 2)
x = 2dw(k − 1) / (v + w(2k − 1))

or:

n = 2k − 1
x = dw(n − 1) / (v + wn)
t = d(w + vn) / v(v + wn)

The answer can then be calculated directly.

Run: [ @replit ]

```from enigma import (fdiv, printf)

k = 9    # number of people in the group
d = 5.8  # distance between pub and stadium
w = 2.5  # walking speed
v = 30   # motorbike speed

# calculate amount of walking per person
n = 2 * k - 1
x = fdiv(d * w * (n - 1), v + w * n)

# calculate time taken
t = fdiv(x, w) + fdiv(d - x, v)

# output solution
printf("t={t:g} hours (= {m:g} min) [x={x:g} miles]", m=t * 60)
```

Solution: The minimum travelling time is 82 minutes.

We calculate:

x = 16/5 = 32/10
t = 32/25 + 13/150 = 41/30 = 82/60

So the first friend is dropped off 3.2 miles from the stadium (and walks the remainder of the way).

Each friend walks for 76.8 minutes and is on the motorbike for 5.2 minutes. Giving each a total journey time of 82 minutes.

Like

• Jim Randell 10:56 pm on 30 November 2022 Permalink | Reply

Here is a numerical approach, based on the barman dropping the first friend off after a distance x (from the pub) while the remaining friends set off on foot.

The barman then returns to the trailing group and ferries a single friend from the trailing to the leading group until everyone has been transferred to the leading group. And we record the maximal journey time for the friends to give us a total time to get all the friends to the stadium.

We then use the [[ `find_min()` ]] function from the enigma.py library to determine at what distance x the shortest total journey time occurs.

Unsurprisingly this gives us the same answer as the analytical approach above (but with considerably more effort). But it does show that the logic used in the analysis does indeed produce the minimum time.

Run: [ @replit ]

```from enigma import (irange, fdiv, find_min, printf)

k = 9    # number of people in the group
d = 5.8  # distance between pub and stadium
w = 2.5  # walking speed
v = 30   # motorbike speed

# if: A starts at a, velocity v; B starts at b, velocity w
# return: (<position>, <time>) of meeting
def meet(a, v, b, w, t0=0):
t = fdiv(b - a, v - w)
return (b + t * w, t0 + t)

# run a scenario where the first person is dropped off at distance x
# return the time taken for everyone to arrive
def run(x):
ts = list()
# ferry friend 1 to x and let them walk the remaining distance (d - x)
d1 = x
t1 = fdiv(x, v)
# and so the total time for the first friend is ...
ts.append(t1 + fdiv(d - d1, w))

# the position of the trailing group at time t is:
tr = lambda t: min(t * w, d)
# the position of the leading group at time t >= t1 is:
ld = lambda t, t1=t1: min(x + (t - t1) * w, d)

# ferry the remaining friends ...
for _ in irange(2, k):
# we return from d1 to the trailing group
(d2, t2) = meet(d1, -v, tr(t1), w, t1)
# and then back to the leading group
(d3, t3) = meet(d2, +v, ld(t2), w, t2)
if d3 < d:
# they walk the remaining distance
ts.append(t3 + fdiv(d - d3, w))
else:
# they are dropped off at the stadium
(d3, t3) = (d, t2 + fdiv(d - d2, v))
ts.append(t3)
(d1, t1) = (d3, t3)
# return the maximum time
return max(ts)

# find the minimal time
r = find_min(run, 0, d)
(t, x) = (r.fv, r.v)
printf("min time = {t:g} hours (= {m:g} min) [drop 1 at {x:g} miles]", m=t * 60)
```

Here is a graph of the total journey time against the distance x that the first friend is taken from the pub. We see that the minimum time is achieved when x = 2.6 miles.

Like

Hi Jim. I very much enjoyed this puzzle (more for the logic than the Python content!) but I’m intrigued to know how you got to the term 2kx in your second equation. I got to it indirectly by looking at the vector sum of all the motorbike journeys out: [(k)(d-x)] +back: [(k)(d-x)-d] given that he finishes up a distance d from where he started. That then reduces to:
[(2k-1)d -2kx] but is there a more intuitive way of getting to the second term?

Like

• Jim Randell 10:50 pm on 1 December 2022 Permalink | Reply

@Nigel: The way I thought of it the barman makes a journey towards the stadium for each of the k friends. And in between friends he has to make (k − 1) return journeys towards the pub.

If he made complete journeys between the pub and the stadium this would be (2k − 1) journeys of distance d for a total of (2k − 1)d.

But if he made complete journeys he would be travelling over the ground that each friend walks, in both directions, so this amount is overcounting the barmans distance by 2x for each of the k friends.

So the actual overall distance travelled by the barman is:

(2k − 1)d − 2kx

And this actual distance is travelled at velocity v, so we can determine the total time taken for the barman.

Like

Thanks Jim. It was the ‘in both directions’ that I was struggling to get my head around. This week’s puzzle is trivial by comparison!

Like

• Hugh Casement 9:45 am on 4 December 2022 Permalink | Reply

There were some early Brain-Teasers of a similar kind by Brigadier A.G.H. Brousson (who died in 1976), involving the Smart brothers who took part in races with one bicycle between them.
Numbers 640, 663, 686, 722, 741, and 792 would presumably yield to a variant of Jim’s analysis as given here. 792 (at least) is flawed because it doesn’t specify that they all arrived together — nor, for that matter, whether riding pillion on the rear carrier is permitted (I know from experience that it seriously upsets the balance and steering!).

Like

• Jim Randell 8:38 am on 24 November 2022 Permalink | Reply Tags: by: Dr J C Brown

From The Sunday Times, 7th April 1974 [link]

There were six starters for the special handicap event for the youngest class at the school sports. All started at the gun, and none fell by the wayside or was disqualified.

Dave started quicker than Ed and finished before Fred. Colin finished two seconds after he would have finished if he had finished two seconds before Ed. Bob and Dave started quicker than Colin, and Bob was faster than Ed.

Alf, who won third prize, finished two seconds after he would have finished if he had finished two seconds after Colin.

Who won second prize?

This puzzle was included in the book The Sunday Times Book of Brain-Teasers: Book 2 (1981, edited by Victor Bryant and Ronald Postill). The puzzle text above is taken from the book.

[teaser665]

• Jim Randell 8:38 am on 24 November 2022 Permalink | Reply

If the total times are A, B, C, D, E, F. Then we derive:

D < F
C = (E − 2) + 2 ⇒ C = E
B < E
A = (C + 2) + 2 ⇒ A = C + 4 (and A was 3rd)

From which we get 2 chains (shortest to longest time):

B < C,E < A
D < F

However we are told that A was in 3rd place, but we see there are at least 3 competitors (B, C, E) who finished in a shorter time, which would imply the best A could have placed was 4th.

So, assuming positions are ranked according to time, either the puzzle is flawed, or the goal of the race is to achieve the longest time, not the shortest.

In this latter case the finishing positions (longest to shortest time) are:

1st: Fred
2nd: Dave
3rd: Alf
4th: Colin, Ed (joint)
6th: Bob

Solution: Dave won second prize.

Like

Teaser 2688: Mother’s Day

From The Sunday Times, 30th March 2014 [link]

Today we are having a family get-together to celebrate Mother’s Day. My maternal grandmother, my mother and I have each written down our date of birth in the form “ddmmyy”. This gives us three six-figure numbers and, surprisingly, both of the ladies’ numbers are multiples of mine. Furthermore, all of the digits from 0 to 9 occur somewhere in the three six-figure numbers.

What is my mother’s six-figure date of birth?

[teaser2688]

• Jim Randell 9:05 am on 22 November 2022 Permalink | Reply

At first I found many possible solutions to this puzzle.

But if we require that the 6-digit numbers formed from the date cannot have a leading zero, then this narrows down the solution space considerably (and essentially restricts the three dates to the form 10xxxx, 20yyyy, 30zzzz, and the multiples being 1, 2, 3).

This Python program runs in 129ms.

Run: [ @replit ]

```from datetime import (date, timedelta)
from enigma import (
fdiv, inc, repeat, nconcat, nsplit, catch,
subsets, append, tuples, union, join, printf
)

# extract date as a 6-digit number
def number(d):
if d.day < 10: return None
return nconcat(d.day, d.month, d.year % 100, base=100)

# check viable generation gap, a -> b
def gap(a, b):
y = fdiv((b - a).days, 365.2422)
return not (y < 16 or y > 50)

# consider dates for the setters birthdate
for d in repeat(inc(timedelta(days=-1)), date(2014, 3, 30)):
if d.year < 1922: break
# construct the number "ddmmyy"
n = number(d)
if n is None: continue
# look for proper multiples that also give a valid date
mn = n
ds = list()
while True:
mn += n
if mn > 311299: break
(dd, mm, yy) = nsplit(mn, base=100)
for y in (1900 + yy, 1800 + yy):
if y < 1892: continue
md = catch(date, y, mm, dd)
if md is None or number(d) is None: continue
ds.append(md)

# look for a set of 3 plausible ages
for ss in subsets(sorted(ds), size=2):
ss = append(ss, d)
if not all(gap(a, b) for (a, b) in tuples(ss, 2)): continue
# check all digits are used
if len(union(nsplit(number(d)) for d in ss)) < 10: continue
# output dates
printf("{ss}", ss=join(ss, sep=" -> "))
```

The program works backwards from 2014 to 1922 looking for sets of 3 dates that make a plausible set of birthdates for the three generations.

It finds 2 possible situations, as below (ages shown are on the date the puzzle was published (2014-03-30)):

Grandmother = 1919-08-30 (age = 94.6y)
Mother = 1946-05-20 (age = 67.9y)
Setter = 1973-02-10 (age = 41.1y)
gap = 26.7y
100273 × 2 = 200546
100273 × 3 = 300819

Grandmother = 1892-07-30 (age = 121.7y)
Mother = 1928-05-20 (age = 85.9y)
Setter = 1964-02-10 (age = 50.1y)
gap = 35.7y
100264 × 2 = 200528
100264 × 3 = 300792

The second of these is only just plausible, so presumably the first provides the required answer. (I would have preferred the puzzle eliminated one of these solutions by an explicit condition).

Solution: The mother’s date of birth is: 200546 (i.e. 20th May 1946).

To see solutions where the 6-digit number formed from the date is permitted to have a leading zero, the check at line 9 can be removed. In this case the program finds 115 solutions.

Like

Brain-Teaser 204: Logical will

From The Sunday Times, 21st March 1965 [link]

Uncle George occasionally wasted time on Brain-teasers, and it was expected that his will would take an awkward form. But his five nephews were surprised to learn, after his death, that he had dictated his will to a solicitor who had no use for punctuation. The will ran as follows:

maurice is not to sing at my funeral service if stephen receives the envelope containing three thousand pounds alec is to have five thousand pounds if thomas receives less than maurice alec is to have exactly twice what nigel has if thomas does not receive the envelope containing a thousand pounds stephen is to have exactly four thousand pounds

The nephews were confident that Uncle George always uttered complete sentences, none of which contained more than one conditional clause. They also felt sure that what he had said to the solicitor allowed one way, and one way only, of distributing the five envelopes (containing £5000, £4000, £3000, £2000, and £1000), which Uncle George had left for them.

Who receives each envelope? And may Maurice sing at the funeral service?

This puzzle was included in the book Sunday Times Brain Teasers (1974, edited by Ronald Postill).

[teaser204]

• Jim Randell 11:33 am on 20 November 2022 Permalink | Reply

There are four ways we can parse the will into statements, each consisting of 4 statements, 3 of which are conditional:

[1]
(maurice is not to sing at my funeral service)
(stephen receives £3000) → (alec is to have £5000)
(thomas receives less than maurice) → (alec is to have exactly twice what nigel has)
(thomas does not receive £1000) → (stephen is to have exactly £4000)

[2]
(maurice is not to sing at my funeral service) ← (stephen receives £3000)
(alec is to have £5000)
(thomas receives less than maurice) → (alec is to have exactly twice what nigel has)
(thomas does not receive £1000) → (stephen is to have exactly £4000)

[3]
(maurice is not to sing at my funeral service) ← (stephen receives £3000)
(alec is to have £5000) ← (thomas receives less than maurice)
(alec is to have exactly twice what nigel has)
(thomas does not receive £1000) → (stephen is to have exactly £4000)

[4]
(maurice is not to sing at my funeral service) ← (stephen receives £3000)
(alec is to have £5000) ← (thomas receives less than maurice)
(alec is to have exactly twice what nigel has) ← (thomas does not receive £1000)
(stephen is to have exactly £4000)

This Python program investigates each interpretation, rejecting those that do not have a single way of distributing the money.

It runs in 54ms. (Internal runtime is 866µs).

Run: [ @replit ]

```from enigma import (defaultdict, cproduct, subsets, implies, singleton, join, printf)

# evaluate the clauses under interpretation <i>
def check(i, cs):
(a, b, c, d, e, f, g) = cs
# [1] (a, b -> c, d -> e, f -> g)
if i == 1: return all([a, implies(b, c), implies(d, e), implies(f, g)])
# [2] (a <- b, c, d -> e, f -> g)
if i == 2: return all([implies(b, a), c, implies(d, e), implies(f, g)])
# [3] (a <- b, c <- d, e, f -> g)
if i == 3: return all([implies(b, a), implies(d, c), e, implies(f, g)])
# [4] (a <- b, c <- d, e <- f, g)
if i == 4: return all([implies(b, a), implies(d, c), implies(f, e), g])

# the amounts in the envelopes
money = [5000, 4000, 3000, 2000, 1000]

# choose an interpretation of the will (1-4)
for i in (1, 2, 3, 4):

# record outcomes: (A, M, N, S, T) -> sing
r = defaultdict(list)

# allocate the envelopes, and whether Maurice can sing
for (k, sing) in cproduct([subsets(money, size=len, select="P"), [0, 1]]):
(A, M, N, S, T) = k

# the clauses:
cs = [
# (a) "M is not to sing ..."
(not sing),
# (b) "S gets 3000"
(S == 3000),
# (c) "A gets 5000"
(A == 5000),
# (d) "T gets less than M"
(T < M),
# (e) "A gets twice N"
(A == 2 * N),
# (f) "T does not get 1000"
(T != 1000),
# (g) "S gets 4000"
(S == 4000),
]

# is this is a valid allocation?
if check(i, cs):
r[k].append(sing)
# do we need to proceed further?
if len(r.keys()) > 1: break

# there is only one way to distribute the money?
k = singleton(r.keys())
if k:
# output solution
(A, M, N, S, T) = k
printf("[{i}] A={A} M={M} N={N} S={S} T={T}; sing={sing}", sing=join(sorted(r[k]), sep=", ", enc="{}"))
```

Solution: The money is distributed as follows:

Alec: £2000
Maurice: £3000
Nigel: £1000
Stephen: £4000
Thomas: £5000

The solution is provided by interpretation [3] of the will.

And as Stephen does not get £3000, Maurice is not prohibited from singing at the funeral.

Like

Teaser 3139: Checkmate

Our chess club is divided into sections, with each section having the same number of players. The two oldest members will soon be retiring from playing and we will change the number of sections. The number of sections will change by one and so will the number of players in each section, but all the sections will still have the same number of players. This will result in there being a grand total of 63 fewer matches per year if each member plays all the other members of their section once per year.

How many players are in each section at the moment?

[teaser3139]

• Jim Randell 4:56 pm on 18 November 2022 Permalink | Reply

If the players are split into k sections, each consisting of n players, then the number of matches in each section is C(n, 2), and the total number of matches is m = k.C(n, 2).

We can use some analysis to simplify the puzzle to two cases, one of which has no solution for positive integers, and the other that gives us the required solution.

However, here is a constructive Python program that considers the total numbers of players t (up to 2000), and generates the possible (n, k, m) values for each candidate t value. It then looks for two t values that differ by 2, and give n and k values that differ by 1, and m values that differ by 63.

This Python program runs in 85ms.

Run: [ @replit ]

```from enigma import (irange, divisors_pairs, tri, cproduct, tuples, printf)

# generate (k, n, m) values for t players
def generate(t):
# divide them into k sections of n players each
for (k, n) in divisors_pairs(t, every=1):
if n < 2: continue
# calculate the total number of matches
m = k * tri(n - 1)
yield (t, k, n, m)

# solve for numbers of players that differ by 2
def solve(N):
for (zs, ys, xs) in tuples((list(generate(t)) for t in irange(1, N)), 3):
for ((t, k, n, m), (t_, k_, n_, m_)) in cproduct([xs, zs]):
# check the differences in the corresponding k, n, m values
if abs(k - k_) == 1 and abs(n - n_) == 1 and m - m_ == 63:
# output solution
printf("{k} sections of {n} players (= {m} matches) -> {k_} sections of {n_} players (= {m_} matches)")

# solve the puzzle (up to 2000 players)
solve(2000)
```

Solution: There are 10 players in each section.

The club starts with 110 players, formed into 11 sections of 10 players each. There are 45 matches among the players in each section, and 495 matches in total.

When 2 players leave there are 108 players remaining. These are formed into 12 sections of 9 players each. There are 36 matches among the players in each section, and 432 matches in total. This is 63 fewer matches.

Manually from:

(n ± 1)(k ± 1) = nk − 2

we can see that (for n + k > 3) there are 2 cases:

[Case 1] (n, k)(n + 1, k − 1)k = n − 1.

k C(n, 2) − (k − 1) C(n + 1, 2) = 63
n[(n − 1)(n − 1) − (n − 2)(n + 1)] = 126
n(3 − n) = 126
n² − 3n + 126 = 0

Which has no solution in positive integers.

[Case 2] (n, k)(n − 1, k + 1)k = n + 1.

k C(n, 2) − (k + 1) C(n − 1, 2) = 63
(n − 1)[(n + 1)n − (n + 2)(n − 2)] = 126
(n − 1)(n + 4) = 126
n² + 3n − 130 = 0
(n − 10)(n + 13) = 0
n = 10
k = 11

And so there are 11 sections, each with 10 players.

Like

```
% A Solution in MiniZinc
include "globals.mzn";

% Assumed No. of persons in each section before and after retirement
var 2..25:persB; var 1..23:persA;

% Assumed No. of sections before and after retirement
var 2..25:sectB; var 1..25:sectA;

% No of matches before and after retirement
% UB = 25 * (25 * 24//2)
var 1..7500: matchesB; var 1..7500: matchesA;

% Change in number of sections is one due to two people retiring
constraint abs(sectA - sectB) == 1;

% Change in total number of persons is two
constraint sectB * persB - 2 == sectA * persA
/\ abs (persB - persA) == 1;

% Find total number of matches before and after two people retire
constraint 2 * matchesB = sectB * persB * (persB - 1);
constraint 2 * matchesA = sectA * persA * (persA - 1);

% Change in number of total matches is given as 63
constraint matchesB - matchesA == 63;

solve satisfy;

output ["Persons per section before two retire = " ++ show(persB)
++ "\n" ++ "Number of sections before two retire = " ++ show(sectB)
++ "\n" ++ "Persons per section after two retire = " ++ show(persA)
++ "\n" ++ "Number of sections after two retire = " ++ show(sectA) ];

```

Like

```
# Assumed max no players and sections is 24 for both groups
# Suffix 'B' for before matches and 'A' for after matches
for playersB in range(1, 25):
for sectionsB in range(1, 25):
before_matches = sectionsB * (playersB * (playersB - 1) // 2)
for playersA in range(1, 25):
# The number of players will change by one
if abs(playersA - playersB) != 1:
continue
for sectionsA in range(1, 25):
# The number of sections will change by one
if abs(sectionsA - sectionsB) != 1:
continue
# two players retire
if sectionsB * playersB - 2 != sectionsA * playersA:
continue
after_matches = sectionsA * (playersA * (playersA - 1) // 2)

# Differences in total number of matches
if before_matches - after_matches != 63:
continue
# output player and sections data
print(f"Players before two retire = {playersB} No.")
print(f"Sections  before two retire = {sectionsB} No.")
print(f"Players after two retire = {playersA} No.")
print(f"Sections  after two retire = {sectionsA} No.")

```

Like

Teaser 2680: Yesterday

From The Sunday Times, 2nd February 2014 [link]

In a new design of mobile phone each of the number buttons 1 to 9 is associated with 2 or 3 letters of the alphabet, but not in alphabetical order (and there are no letters on any other buttons). For example: M, T and U are on the same button. Predictive software chooses letters for you as you type. The numbers to type for SUNDAY, TIMES and TEASER are all multiples of 495.

What number should I type to make SATURDAY?

[teaser2680]

• Jim Randell 8:52 am on 17 November 2022 Permalink | Reply

We can solve this puzzle using the [[ `SubstitutedExpression` ]] solver from the enigma.py library.

The following run file executes in 67ms. (Internal runtime of the generated program is 1.8ms).

Run: [ @replit ]

```#! python3 -m enigma -r

SubstitutedExpression

--digits="1-9"
--distinct=""

# SUNDAY, TIMES, TEASER are all multiples of 495
"SUNDAY % 495 = 0"
"TIMES % 495 = 0"
"TEASER % 495 = 0"

# M, T, U have the same value
"M = T"
"T = U"

# no digit appears more than 3 times
"all(v < 4 for v in multiset.from_seq([A, D, E, I, M, N, R, S, T, U, Y]).values())"

--template="SUNDAY TIMES TEASER SATURDAY"
```

Solution: To type SATURDAY use the following keys: 58225185.

The letters we are given are assigned to the following keys:

1: D I
2: M T U
5: R S Y
6: N
8: A E

So we have:

SUNDAY = 526185 = 495 × 1063
TIMES = 21285 = 495 × 43
TEASER = 288585 = 495 × 583

Like

```# last digit of TIMES, SUNDAY, TEASER
Y = S = R = 5

digits = set(range(1, 10)).difference({5})

for T in digits:
M = U = T  # stated condition

# Digits for I and E in TIMES
for I in digits:
for E in digits:
TIMES = 10000*T + 1000*I + 100*M + 10*E + S
if not (TIMES % 495 == 0):continue

# Add Digit A for TEASER
for A in digits:
TEASER = 100000*T + 10000*E + 1000*A + 100*S + 10*E + R
if not (TEASER % 495 == 0):continue

# Add Digits N and D for SUNDAY
for N in digits:
for D in digits:
SUNDAY = 100000*S + 10000*U + 1000*N + 100*D + 10*A + Y
if not (SUNDAY % 495 == 0):continue

print(f"Keys to press for SATURDAY are : ")
print(f"{S},{A},{T},{U},{R},{D},{A},{Y}")
print(f"SUNDAY = {SUNDAY}, TIMES={TIMES}, TEASER={TEASER}")

# Keys to press for SATURDAY are : 5,8,2,2,5,1,8,5
# SUNDAY = 526185, TIMES=21285, TEASER=288585

```

Like

This snippet needs to be added to the output to show no more than three digits were associated with
each button.

Digits used with each button as follows:

[A,D,E,I,M,N,R,S,T,U,Y =
[8,1,8,1,2,6,5,5,2,2,5]

Like

Brain-Teaser 670: A shared legacy

From The Sunday Times, 12th May 1974 [link]

When my neighbour Giles found he could no longer look after his prize herds of cattle and sheep, he planned to divide the lot among his four sons in equal shares.

But when he started by counting up the cattle he soon found that their total was not exactly divisible by four, so he decided he would juggle with the numbers of beasts and achieve the four shares of equal value by making to the respective recipients quite arbitrary allocations of both cattle and sheep, taking into account that the value per head of the former was four times that of the latter.

The outcome was that:

(i) one son received 80% more beasts than another;
(ii) two sons each received a total of beasts which equalled the aggregate total of two of the other three sons;
(iii) one son received twice as many of one type of beast as of the other;
(iv) only one son received over 100 beasts in all.

How many cattle were included in this last total of over 100 beasts?

This puzzle was included in the book The Sunday Times Book of Brain-Teasers: Book 2 (1981, edited by Victor Bryant and Ronald Postill). The puzzle text above is taken from the book.

[teaser670]

• Jim Randell 9:37 am on 15 November 2022 Permalink | Reply

If the total number of animals received by each brother is: A, B, C, D (in descending order), then (from (iv)) A is the only one to receive more than 100.

And from (ii) two of the brothers totals are equal to the sum of the totals of two of the remaining three brothers. These two must be A and B, and so B = C + D, and A = C + 2D or 2C + D.

This Python program starts by finding possible A, B, C, D values, and then tries to split these totals into numbers of cattle and sheep such that the remaining conditions hold.

It runs in 62ms. (Internal runtime is 11.2ms).

Run: [ @replit ]

```from enigma import (irange, subsets, ediv, as_int, printf)

# split total <t> into (<cattle>, <sheep>) with value <v>
def split(t, v):
c = ediv(v - t, 3)
return (as_int(c, "0+"), as_int(t - c, "0+"))

# solve puzzle for given totals: A, B, C, D
def solve(A, B, C, D):
# consider number of cattle for A
for Ac in irange(0, A):
As = A - Ac
# total value for A (cattle = 4, sheep = 1)
v = 4 * Ac + As
# find splits for B, C, D
try:
(Bc, Bs) = split(B, v)
(Cc, Cs) = split(C, v)
(Dc, Ds) = split(D, v)
except ValueError:
continue

# total number of cattle is not divisible by 4
if (Ac + Bc + Cc + Dc) % 4 == 0: continue
# someone has twice as many of one type of animal as the other
if all(2 * x != y and x != 2 * y for (x, y) in [(Ac, As), (Bc, Bs), (Cc, Cs), (Dc, Ds)]): continue

# output scenario
printf("[v={v}] A: {Ac}c+{As}s = {A}; B: {Bc}c+{Bs}s = {B}; C: {Cc}c+{Cs}s = {C}; D: {Dc}c+{Ds}s = {D}")

# total number of animals for C (not more than 100)
for C in irange(1, 100):
# total number of animals for D (not more than C)
for D in irange(0, C):
# B = C + D (not more than 100)
B = C + D
if B > 100: break
# A = C + 2D or 2C + D (more than 100)
for A in (B + D, B + C):
if not (A > 100): continue
# one of these values must be 1.8x a lower value
if not any(5 * x == 9 * y for (x, y) in subsets((A, B, C, D), size=2)): continue
# solve the puzzle
solve(A, B, C, D)
```

Solution: The son receiving over 100 animals received 6 cattle.

The full solution is:

A: 6 cattle + 111 sheep = 117 animals; 117 = 81 (B) + 36 (D)
B: 18 cattle + 63 sheep = 81 animals; 81 = 45 (C) + 36 (D) = 1.8 × 45 (C)
C: 30 cattle + 15 sheep = 45 animals; 30 is twice 15
D: 33 cattle + 3 sheep = 36 animals

Assigning values of cattle = 4, sheep = 1, each brother receives animals to a value of 135.

In total there are 279 animals = 87 cattle (not a multiple of 4) + 192 sheep.

Like

Teaser 3138: Primus inter impares

Just nine Prime Ministers held office in the Kingdom of Primea during the 20th century. No two Prime Ministers held office at the same time, none had more than one period in office, and the gap between successive Prime Ministers’ terms was never more than a month. Each held office for a period of time in which the number of whole years was a different prime number (e.g. holding office from 1910 to 1915 could cover four or five whole years) and no Prime Minister served for more than 30 years. Appropriately, they all took office in prime years, but there was no change of Prime Minister in 1973.

In which years during the 20th century did new Prime Ministers in Primea take up office?

[teaser3138]

• Jim Randell 5:12 pm on 11 November 2022 Permalink | Reply

This Python program runs in 51ms. (Internal runtime is 554µs).

Run: [ @replit ]

```from enigma import (primes, append, tuples, printf)

# possible term lengths
terms = set(primes.between(0, 30))

# select <k> years from <years>
# return (<start-years>, <term-lengths>)
def solve(k, years, ys=[], ts=[]):
# are we done?
if k == 0:
# no-one served more than 30 years
if ys and ys[-1] > 1968:
yield (ys, ts)
elif not k > len(years):
# choose the next year
for (i, y) in enumerate(years):
# consider possible term lengths
g = y - ys[-1]
for t in terms.intersection({g, g - 1}):
if t in ts: continue
# solve for the remaining years
yield from solve(k - 1, years[i + 1:], append(ys, y), append(ts, t))

# consider the start year of the incumbent at the start of the century
for y0 in primes.between(1870, 1901):
# fill out the 8 starting years in the 20th century
years = list(primes.between(max(y0 + 1, 1901), 2000))
years.remove(1973)  # but not 1973
for (ys, ts) in solve(8, years, [y0]):
# output solution
for ((y1, y2), t) in zip(tuples(ys, 2), ts):
printf("{y1} - {y2} = {t} years")
printf("{y2} - .... = ? years")
printf()
```

Solution: The years are: 1901, 1907, 1931, 1949, 1979, 1993, 1997, 1999.

The incumbent at the start of the 20th century began office in 1889, so we have:

1. 1889 – 1901 = 11 years
2. 1901 – 1907 = 5 years
3. 1907 – 1931 = 23 years
4. 1931 – 1949 = 17 years
5. 1949 – 1979 = 29 years
6. 1979 – 1993 = 13 years
7. 1993 – 1997 = 3 years
8. 1997 – 1999 = 2 years
9. 1999 – …. = (7 or 19 years)

There are two primes left that could correspond to the length of the term of the incumbent at the end of the 20th century. Note that it is not required that the term of the successor (if any) starts in a prime year.

Like

@Jim, as I don’t have access to a PC I can’t publish/test a program myself.

I think a check is needed to see if the last Prime Minister can serve a prime number of years and which ends after the 20th century (if high prime numbers already have been used this may not be possible anymore).

Like

• Hugh Casement 7:17 am on 13 November 2022 Permalink | Reply

Frits, the wording of the puzzle is vague on that score, but I think if we do allow the last term of office to extend beyond the end of the century then we get multiple solutions. Jim (line 25) would seem to agree with me that we need to start looking before the beginning of the century.

Like

• Jim Randell 8:18 am on 13 November 2022 Permalink | Reply

@Frits: I did wonder about that. I check the final PM of the 20th century does not have a term that is longer than 30 years (line 12), and when I saw that there was only a single possible solution I didn’t worry about the actual length of the term, as it starts very close to the end of the century, and there are 2 unused primes available.

Here is the code with an extra check to ensure the final term length is possible. (I also include code to specify the first and last years of the 20th century. I am using the “strict” definition 1901-2000, but you get the same answer with the “popular” usage of 1900-1999).

```from enigma import (primes, append, tuples, printf)

# first/last years for 20th century
(first, last) = (1901, 2000)

# possible term lengths
terms = set(primes.between(0, 30))

# select <k> years from <years>
# return (<start-years>, <term-lengths>)
def solve(k, years, ys=[], ts=[]):
# are we done?
if k == 0:
yield (ys, ts)
elif not k > len(years):
# choose the next year
for (i, y) in enumerate(years):
# consider possible term lengths
g = y - ys[-1]
for t in terms.intersection({g, g - 1}):
if t in ts: continue
# solve for the remaining years
yield from solve(k - 1, years[i + 1:], append(ys, y), append(ts, t))

# consider the start year of the incumbent at the start of the century
for y0 in primes.between(first - 31, first):
# fill out the 8 starting years in the 20th century
years = list(primes.between(max(y0 + 1, first), last))
years.remove(1973)  # but not 1973
for (ys, ts) in solve(8, years, [y0]):
# check possible term lengths for the incumbent at the end of the century
fs = sorted(t for t in terms.difference(ts) if ys[-1] + t > last)
if not fs: continue
# output solution
for ((y1, y2), t) in zip(tuples(ys, 2), ts):
printf("{y1} - {y2} = {t} years")
printf("{y2} - .... = {fs} years")
printf()
```

But it seems that it may be possible that the final PM is still in office at the time the puzzle was set (having served less than 30 years so far), so we can’t say what the length of the term will be yet.

Like

Teaser 2611: Simple arithmetic

From The Sunday Times, 7th October 2012 [link]

George and Martha are teaching their great-grandchildren some simple arithmetic. “If you add two thirties to four tens you get a hundred”, George was saying, and he wrote it like this:

“Strangely”, added Martha, there are nine different letters there, and if you allow each letter to stand for a different digit, there is a unique sum which works”.

Which digit would be missing?

[teaser2611]

• Jim Randell 8:40 am on 10 November 2022 Permalink | Reply

We can use the [[ `SubstitutedExpression.split_sum()` ]] solver from the enigma.py library to solve this puzzle.

The following run file executes in 58ms. (Internal runtime is 4.74ms).

Run: [ @replit ]

```from enigma import (SubstitutedExpression, irange, diff, join, printf)

# construct the alphametic sum
p = SubstitutedExpression.split_sum(
["THIRTY"] * 2 + ["TEN"] * 4, "HUNDRED",
template="(2 * {THIRTY} + 4 * {TEN} = {HUNDRED})",
)

# solve the puzzle, and output unused digit(s)
for s in p.solve():
ds = diff(irange(0, 9), s.values())
# output solution
printf("-> unused digits = {ds}", ds=join(ds, sep=", "))
```

Solution: The missing digit is 7.

Like

```
% A Solution in MiniZinc
include "globals.mzn";

%          T H I R T Y
%          T H I R T Y
%                T E N
%                T E N
%                T E N
%                T E N
%        -------------
%        H U N D R E D
%        -------------

set of int: INT = 0..9;
var INT: T; var INT: H; var INT: I;
var INT: R; var INT: Y; var INT: E;
var INT: N; var INT: U; var INT: D;

constraint T > 0 /\ H > 0;
constraint all_different( [T,H,I,R,Y,E,N,U,D]);

% Carry digits from RH end
var 0..6:c1; var 0..6:c2; var 0..6:c3;
var 0..1:c4; var 0..1:c5; var 0..1:c6;

% Adding digits in columns, with carry digits from RH end of sum
constraint D == (4*N + 2*Y) mod 10 /\ c1 == (4*N + 2*Y) div 10;
constraint E == (c1 + 4*E + 2*T) mod 10 /\ c2 == (c1 + 4*E + 2*T) div 10;
constraint R == (c2 + 4*T + 2*R) mod 10 /\ c3 == (c2 + 4*T + 2*R) div 10;
constraint D == (c3 + 2*I) mod 10 /\ c4 == (c3 + 2*I) div 10;
constraint N == (c4 + 2*H) mod 10 /\ c5 == (c4 + 2*H) div 10;
constraint U == (c5 + 2*T) mod 10 /\ c6 == (c5 + 2*T) div 10;
constraint H == c6;

solve satisfy;

output ["[T,H,I,R,Y,E,N,U,D] = " ++ show([T,H,I,R,Y,E,N,U,D]) ];
% [T, H, I, R, Y, E, N, U, D] =
% [9, 1, 5, 2, 6, 0, 3, 8, 4]
% ----------
% ==========
% By inspection, missing digit = 7.
% TEN = 903, THIRTY = 915296, HUNDRED = 1834204.

```

Like

```
% A Solution in MiniZinc
include "globals.mzn";

%          T H I R T Y
%          T H I R T Y
%                T E N
%                T E N
%                T E N
%                T E N
%        -------------
%        H U N D R E D
%        -------------

set of int: INT = 0..9;
var INT: T; var INT: H; var INT: I;
var INT: R; var INT: Y; var INT: E;
var INT: N; var INT: U; var INT: D;

constraint T > 0 /\ H > 0;
constraint all_different( [T,H,I,R,Y,E,N,U,D]);

var 100..999:TEN = 100*T + 10*E + N;
var 100000..999999:THIRTY = 100000*T + 10000*H + 1000*I + 100*R + 10*T + Y;
var 1000000..9999999:HUNDRED = 1000000*H + 100000*U + 10000*N + 1000*D + 100*R + 10*E + D;

constraint 2 * THIRTY + 4 * TEN == HUNDRED;

solve satisfy;

output [ "T,H,I,R,Y,E,N,U,D] = " ++ show( [T,H,I,R,Y,E,N,U,D] ) ];

% [T, H, I, R, Y, E, N ,U, D] =
% [9, 1, 5, 2, 6, 0, 3, 8, 4]
% time elapsed: 0.17 s
% ----------
% ==========
% By inspection, the missing digit is 7.

```

Like

Teaser 2695: Powers behind the thrones

From The Sunday Times, 18th May 2014 [link]

Gold sovereigns were minted in London for most years from the great recoinage in 1817 until Britain left the gold standard in 1917. I have a collection of eight sovereigns from different years during that period, the most recent being an Edward VII sovereign (he reigned from 1902 until 1910). I noticed that the year on one of the coins is a perfect square and this set me thinking about other powers. Surprisingly, it turns out that the product of the eight years on my coins is a perfect cube.

What (in increasing order) are those eight years?

[teaser2695]

• Jim Randell 9:02 am on 8 November 2022 Permalink | Reply

The values were are interested in lie in the interval [1817, 1910].

And the only square in that range is 1849 (= 43²), so that must be one of the 8 values.

And the largest value is in the interval [1902, 1910].

This Python program finds the prime factors for numbers in the required range, and then constructs sets of 8 values whose prime factors, when combined, all appear a multiple of 3 times, and so the product of the values is a cube.

It runs in 164ms.

Run: [ @replit ]

```from enigma import (irange, prime_factor, multiset, delete, append, printf)

# find values whose product is a cube
# k = remaining values for find (int)
# vs = values so far (list)
# fs = prime factors so far (multiset)
# d = map of value -> prime factors (multiset)
# ks = candidate keys in d (list)
def solve(n, vs, fs, d, ks):
if n == 0:
# check all prime exponents are multiples of 3
if all(x % 3 == 0 for x in fs.values()):
yield vs
elif not len(ks) < n:
# add in a new candidate
for (i, k) in enumerate(ks):
# and solve for the remaining candidates
yield from solve(n - 1, append(vs, k), fs.combine(d[k]), d, ks[i + 1:])

# collect candidate numbers and their prime factors (as a multiset)
d = dict((n, multiset.from_pairs(prime_factor(n))) for n in irange(1817, 1910))

# find factors that appear fewer than 3 times in total
while True:
# count the factors (by combining values from each of the numbers)
m = multiset.from_dict(*d.values())
fs = set(k for (k, v) in m.items() if v < 3)
if not fs: break
# and remove any numbers which involve any of these factors
d = delete(d, (k for (k, v) in d.items() if any(p in fs for p in v)))

# 1849 is one of the values in the set
(vs1, fs1) = ([1849], d[1849])

# and the max value is between 1902 and 1910
for v in irange(1902, 1910):
if v not in d: continue
vs2 = append(vs1, v)
fs2 = fs1.union(d[v])

# solve for the remaining 6 values
ks = sorted(k for k in d.keys() if k < v and k not in vs2)
for vs in solve(6, vs2, fs2, d, ks):
# output solution
printf("years = {vs}", vs=sorted(vs))
```

Solution: The eight years are: 1820, 1836, 1849, 1859, 1870, 1890, 1892, 1904.

So we have:

numbers = (1820, 1836, 1849, 1859, 1870, 1890, 1892, 1904)
factors = (2^12, 3^6, 5^3, 7^3, 11^3, 13^3, 17^3, 43^3)
factors = (2^4, 3^2, 5, 7, 11, 13, 17, 43)^3

And the product of the numbers is: (2^4, 3^2, 5, 7, 11, 13, 17, 43)^3 = 526846320^3.

Like

• Hugh Casement 8:31 am on 10 November 2022 Permalink | Reply

We can get part of the way by analysis.  We need another factor 43, so 1892 must be one of the years.
The only integer in the range 1902 to 1910 with a small enough largest prime factor to allow us to find two more is 1904 = 2^4 × 7 × 17.
After that I think trial and error (i.e. by computer) is needed.

Like

• Jim Randell 11:03 am on 10 November 2022 Permalink | Reply

@Hugh: My manual solution proceeded as follows:

Armed with the prime factorisations of the numbers between 1817 and 1910 (which I did not compute manually), we quickly find 1849, 1892, 1904 are on the list.

Then we need more factors of 17, and there are only 2 candidates: 1836 and 1870. Both of which must be included. So we now have 5 of the 8 numbers on the list.

We can eliminate numbers with a factor of 29 (1827, 1856, 1885).

Considering numbers with factors of 13 (1820, 1859, 1872), if any of these are included it must be 1859 and just one of the others.

Adding 1859 and 1820 to the list leaves factors of (2, 5, 7) to find, and the only candidate is 1890, and this does indeed give a viable list.

And I didn’t look for further solutions.

Like

Brain-Teaser 195: Common frontier

From The Sunday Times, 17th January 1965 [link]

The adjoining countries of Europhalia and Sopiculia have different standard units of weight and length, but both use the normal units of time. Although both countries use Arabic numerals, neither uses the denary (tens) method of counting, but each has a different integer less than ten as its counting base.

In reply to my request for more information a Europhalian friend wrote: “Our unit of weight is the Elbo, and there are 42 Elbos to 24 of their Solbos. The length of our common frontier is 21 Emils”. My Sopiculian correspondent replied: “16 Solbos weigh the same as 26 Elbos; the common frontier is 21 Somils long”.

I later discovered that in both countries there is a speed limit equivalent to our 50 mph. In Sopiculia this is defined by law as 104 Somils per hour.

What is the Europhalian speed limit?

This puzzle was included in the book Sunday Times Brain Teasers (1974, edited by Ronald Postill).

[teaser195]

• Jim Randell 9:02 am on 6 November 2022 Permalink | Reply

If the bases are E and S (both less than 10).

Then the ratio of the weights W = (Elbo/Solbo) is (according to to the two correspondents):

W = (2E + 4) / (4E + 2)
W = (S + 6) / (2S + 6)
⇒ 4ES + 12E + 8S + 24 = 4ES + 24E + 2S + 12
⇒ E = S/2 + 1

And we see from the digits used, E > 4 and S > 6, and S must be even, so:

S = 8; E = 5

We can then translate the correspondents statements into decimal to get:

Eu: “There are 22 Elbos to 14 of their Solbos [W = 7/11]. The common frontier is 11 Emils”.
So: “14 Solbos weigh the same as 22 Elbos [W = 7/11]. The common frontier is 17 Somils”.

And:

“104 Somils/hour” [base 8]
= 68 Somils/hour [base 10]
= 4× (17 Somils)/hour [base 10]
= 4× (11 Emils)/hour [base 10]
= 44 Emils/hour [base 10]
= “134 Emils/hour” [base 5]

Solution: The Europhalian speed-limit would be expressed as: “134 Emils per hour”.

Like

Teaser 3137: Common names

Eight friends met at a party; their ages in whole numbers of years were all different. They were Alan, Cary, James, Lucy, Nick, Ricky, Steve and Victor, with Lucy being the youngest. For each of them the square of their age was a three-figure number consisting of three different digits. Furthermore, for any two of them, the squares of their ages had at least one digit in common precisely when their names had at least one letter in common.

In alphabetical order of their names, what are the eight ages?

[teaser3137]

• Jim Randell 4:49 pm on 4 November 2022 Permalink | Reply

This Python program runs in 61ms. (Internal runtime is 9.2ms).

Run: [ @replit ]

```from enigma import (irange, sq, nsplit, diff, intersect, append, delete, subsets, printf)

# model a symmetric relation
class Relation(set):
# check if x is related to y
def __call__(self, x, y):
return (x, y) in self or (y, x) in self

# names
names = "ALAN CARY JAMES LUCY NICK RICKY STEVE VICTOR".split()

# names are related when they share a letter
N = Relation((x, y) for (x, y) in subsets(names, size=2) if intersect([x, y]))

# find 3-digits squares with no repeated digits
sqs = dict()
for i in irange(10, 31):
ds = set(nsplit(sq(i)))
if len(ds) == 3:
sqs[i] = ds

# values are related when their squares share a digit
V = Relation((x, y) for ((x, sx), (y, sy)) in subsets(sqs.items(), size=2) if intersect([sx, sy]))

# assign values to remaining names
# names = remaining names
# ss = used (name, value) pairs
# vs = remaining values
def solve(names, ss, vs):
if not names:
yield ss
elif not len(names) > len(vs):
# choose a value for the next name
n = names[0]
for (i, v) in enumerate(vs):
# check values have digits in common when names have letters in common
if all(N(n, n_) == V(v, v_) for (n_, v_) in ss):
# solve for the remaining names
yield from solve(names[1:], append(ss, (n, v)), delete(vs, [i]))

# choose an age for LUCY (the youngest)
n0 = "LUCY"
ks = sorted(sqs.keys())
for (i, k) in enumerate(ks):
# solve for the remaining names
for ss in solve(diff(names, {n0}), [(n0, k)], ks[i + 1:]):
# output solution
for (n, v) in sorted(ss):
printf("{n} -> {v} [{s}]", s=sq(v))
printf()
```

Solution: The ages are: 19, 31, 29, 16, 25, 23, 28, 27.

With squares in square brackets:

ALAN = 19 [361]
CARY = 31 [961]
JAMES = 29 [841]
LUCY = 16 [256]
NICK = 25 [625]
RICKY = 23 [529]
STEVE = 28 [784]
VICTOR = 27 [729]

Like

• Paul Byrne 9:54 pm on 14 November 2022 Permalink | Reply

Hi Jim
Thanks for all the good work on these Teasers.
Re 3137 Teaser
Is 24 instead of 31 also a correct answer? Keep up the good work!

Like

• Jim Randell 9:17 am on 15 November 2022 Permalink | Reply

@Paul: Thanks for the feedback.

We can’t swap CARY for 24 in the solution I give above, as 24² = 576, and CARY and JAMES share the letter A, so their squares need to share a digit. But 576 and 841 (= 29²) don’t have any digits in common.

Like

• Paul Byrne 10:21 am on 16 November 2022 Permalink | Reply

Hi Jim, thank you very much for your response.

Forgive me I should’ve made myself clearer.
If Cary becomes 576, and James 784, and Steve 841, can it then work as an alternative?

Like

• Jim Randell 12:14 pm on 16 November 2022 Permalink | Reply

@Paul: My program performs an exhaustive search, so there is only one solution to the puzzle.

CARY = 24 [576]
JAMES = 28 [784]
STEVE = 29 [841]

Then {LUCY, NICK, RICKY} must correspond to {16 [256], 23 [529], 25 [625]} in some order.

LUCY is the youngest, so we have:

LUCY = 16 [256]

But then ALAN has to have digits in common with CARY [576], LUCY [256], JAMES [784], but not STEVE [841]

Which means for ALAN we need to find a square with a 7 and a 5 or a 6. The only candidate is 24 [576], but that is already used by CARY, so it is not possible to find a value for ALAN in this scenario.

Like

• Paul Byrne 5:17 pm on 16 November 2022 Permalink | Reply

Hi Jim
Alas I’m thwarted!
Thanks for this and all your efforts.
They are all appreciated.
Regards Paul

Like

Brain-Teaser 653: Hymn numbers

From The Sunday Times, 13th January 1974 [link]

In Church last Sunday I studied the three numbers on the “service-board”. The first was of the appointed psalm, and the other two of the hymns. They included all the digits from 1 to 9 inclusive and were all prime numbers. (Our service-book contains 666 hymns and the normal 150 psalms).

What were last Sunday’s numbers?

This puzzle was included in the book The Sunday Times Book of Brain-Teasers: Book 2 (1981, edited by Victor Bryant and Ronald Postill).

[teaser653]

• Jim Randell 7:48 am on 3 November 2022 Permalink | Reply

This puzzle is very similar to Teaser 467 (and the answer is the same), although the conditions are slightly different.

We can solve this puzzle using the [[ `SubstitutedExpression` ]] solver from the enigma.py library.

The following run file executes in 63ms. (Internal runtime of the generated program is 1.2ms).

Run: [ @replit ]

```#! python3 -m enigma -r

SubstitutedExpression

--digits="1-9"

# the psalm
"is_prime(ABC)"
"ABC < 151"

# the hymns
"is_prime(DEF)"
"is_prime(GHI)"
"DEF < GHI < 667"

```

Solution: Psalm 149. Hymn 263. Hymn 587.

Like

```% A Solution in MiniZinc
include "globals.mzn";

set of int: INT = 1..9;
var INT: A; var INT: B; var INT: C; % Psalm
var INT: D; var INT: E; var INT: F; % Hymn 1
var INT: G; var INT: H; var INT: I; % Hymn 2

constraint all_different ([A, B, C, D, E, F, G, H, I]);
constraint ABC < DEF /\ DEF < GHI;

% Specified ranges of psalm and hymn numbers
var 100..150:ABC = 100*A + 10*B + C;
var 100..666:DEF = 100*D + 10*E + F;
var 100..666:GHI = 100*G + 10*H + I;

predicate is_prime(var int: x) =
x > 1 /\ forall(i in 2..1 + ceil(sqrt(int2float(ub(x)))))
((i < x) -> (x mod i > 0));

constraint sum([is_prime(ABC), is_prime(DEF), is_prime(GHI)]) == 3;

solve satisfy;
output["Sunday's numbers were " ++ show(ABC) ++ " , " ++ show(DEF)
++ " and " ++ show(GHI) ];

% Sunday's numbers were 149 , 263 and 587
% ----------
% ==========

```

There are many solutions without the restricted psalm and hymn number ranges.

Like

```
from enigma import is_prime, nsplit, all_different

# Find Psalm number
for P1 in range(100,150):
if not (is_prime(P1)): continue
A,B,C = nsplit(P1)
if 0 in (A,B,C):continue
if not all_different(A,B,C):continue

# Find 1st Hymn number
for H1 in range(151,667):
if not (is_prime(H1)):continue
D,E,F = nsplit(H1)
if 0 in (D,E,F): continue
if not all_different(A,B,C,D,E,F):continue

# Find 2nd Hymn number
for H2 in range(H1+1, 667):
if not is_prime(H2):continue
G,H,I = nsplit(H2)
if 0 in (G,H,I):continue
if not all_different(A,B,C,D,E,F,G,H,I):continue
print(f"Sunday's numbers were {P1}, {H1}, {H2}")

# Sundays numbers were 149, 263, 587

```

Like

Teaser 2679: Palprimes

From The Sunday Times, 26th January 2014 [link]

My two pals and I have been considering “palprimes” (i.e. palindromic numbers that are also prime). In particular each of us tried to find a five-figure palprime and I managed to come up with 39293. Then each of my two pals found a five-figure palprime. On comparing them we were surprised to find that overall our three palprimes used all the digits from 1 to 9.

What were the other two five-figure palprimes?

[teaser2679]

• Jim Randell 8:41 am on 1 November 2022 Permalink | Reply

A 5-digit palindrome is of the form XYZYX, so consists of 3 digits.

In order for 3 of them to use all the digits from 1-9 then each digit can only appear in one prime, and X, Y, Z must be different digits.

The setter has used 3, 9, 2, so we need to find 2 primes that use the digits 1, 4, 5, 6, 7, 8, between them.

This Python program runs in 59ms. (Internal runtime is 370µs).

Run: [ @replit ]

```from enigma import (
irange, nconcat, diff, is_prime, subsets, partitions, cproduct,
unpack, printf
)

# construct a 5-digit palindrome from digits X, Y, Z
pal5 = unpack(lambda X, Y, Z: nconcat(X, Y, Z, Y, X))

# construct palindromic primes from digits <ds>
def primes(ds):
for ss in subsets(ds, size=len, select="P"):
if is_prime(pal5(ss)):
yield ss

# digits used in the first prime
p0 = (3, 9, 2)
assert is_prime(pal5(p0))

# split the remaining digits for the other 2 primes
for dss in partitions(diff(irange(1, 9), p0), 3):
for (p1, p2) in cproduct(primes(ds) for ds in dss):
printf("{p0} {p1} {p2}", p0=pal5(p0), p1=pal5(p1), p2=pal5(p2))
```

Solution: The other palprimes are: 16561 and 78487.

In fact as the palprimes must end (and begin) with one of 1, 3, 7, 9, we can see that the two numbers we have to find must be of the form 1???1 and 7???7. And we just need to work out how to arrange the digits 4, 5, 6, 8 in the middle of them.

And we can make a slightly shorter program based on this observation:

```from enigma import (nconcat, is_prime, subsets, printf)

# construct a 5-digit palindrome from digits X, Y, Z
pal5 = lambda X, Y, Z: nconcat(X, Y, Z, Y, X)

# digits used in the first prime
p0 = pal5(3, 9, 2)
assert is_prime(p0)

# insert digits 4, 5, 6, 8 in 1???1, 7???7
for (A, B, C, D) in subsets((4, 5, 6, 8), size=len, select="P"):
(p1, p2) = (pal5(1, A, B), pal5(7, C, D))
if is_prime(p1) and is_prime(p2):
printf("{p0} {p1} {p2}")
```

Like

```
from enigma import is_prime, nsplit

mine = 39293  # given five digit palindromic prime
mset = {3, 9, 2} # my digit set

#  unused digits are 1, 4, 5, 6, 7, 8 for 2 palprimes
# range of palindromic primes is from 14841 to 78687
# find 1st palindromic prime
for p1 in range(14841, 78687+1):
if is_prime(p1):
a, b, c, d, e = nsplit(p1)
if 0 in (a, b, c, d, e):continue
if a == e and b == d:
s2 = set((a, b, c, d, e))
if len(s2) == 3:
if len(mset.union(s2)) == 6:

# find 2nd palindromic prime
for p2 in range(p1+1, 78687+1):
if is_prime(p2):
f, g, h, i, j = nsplit(p2)
if 0 in (f, g, h, i, j):continue
if f == j and g == i:
s3 = set((f, g, h, i, j))
if len(s3) == 3:
all_set = mset.union(s2).union(s3)
if len(all_set) == 9:
print(f"Other two primes are {p1} and {p2}.")

# Other two primes are 16561 and 78487.

```

Like

Brain-Teaser 797: Tuesday’s children

From The Sunday Times, 24th October 1976 [link]

Old Andrew, our pensioner neighbour, was telling me about his equally well preserved brother, David.

“We weren’t twins, but we were both born on a Tuesday and born on the same date in different months. In fact, David was born on the first Tuesday after my birth which occurred on the same monthly date. I am hardier, of course, born in the winter time”.

“So, with these conditions, the interval between you couldn’t have been long”, I said.

“Well”, replied Andrew, “it couldn’t have been any longer”.

When was David born (day, month, year)?

[teaser797]

• Jim Randell 8:00 am on 30 October 2022 Permalink | Reply

Assuming both brothers are aged somewhere between 65 and 122, we can start looking for birthdates sometime after 1854.

This Python program looks for the longest gap between consecutive dates that both occur on Tuesday and the same day of the month (but different months). It runs in 60ms.

Run: [ @replit ]

```from datetime import (date, timedelta)
from enigma import (inc, repeat, group, tuples, Accumulator, printf)

# generate possible birthdates
def generate():
# start from the first Tuesday in 1854
for d in repeat(inc(timedelta(days=7)), date(1854, 1, 3)):
# calculate age in 1976
a = 1976 - d.year
if a < 65: break
yield d

# group candidate birthdates by day of month
g = group(generate(), by=(lambda d: d.day))

# find maximal distance dates
r = Accumulator(fn=max, collect=1)

# consider possible days of month
for (k, ds) in g.items():
for (A, D) in tuples(ds, 2):
t = D - A
r.accumulate_data(t, (A, D))

t = r.value
printf("max gap = {t} days", t=t.days)
for (A, D) in r.data:
# A was born in the winter, say Dec, Jan, Feb
if A.month in {12, 1, 2} and A.month != D.month:
printf("-> A={A}; D={D}")
```

Solution: David was born on Tuesday, 31st August 1880.

So David is 96 years old at the time the puzzle was set.

Andrew was born on Tuesday, 31st December 1878.

So he is 97 years old at the time the puzzle was set.

The longest possible gap between the birthdates is 609 days, which gives the following candidates:

A=1855-07-31; D=1857-03-31; ages = 121 & 119
A=1878-12-31; D=1880-08-31; ages = 97 & 96
A=1883-07-31; D=1885-03-31; ages = 93 & 91

But as A is born in the winter only the second of these candidates is viable.

Other candidates outside the age range considered are:

A=1850-12-31; D=1852-08-31; ages = 125 & 124
A=1918-12-31; D=1920-08-31; ages = 57 & 56

Like

c
Compose new post
j
Next post/Next comment
k
Previous post/Previous comment
r