Or we can use the [[ `SubstitutedExpression`

]] solver from the **enigma.py** library (which was not implemented when I originally posted the puzzle).

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

**Run:** [ @replit ]

#! python3 -m enigma -r SubstitutedExpression # upper case symbols must be distinct --distinct="EFGHINORTU" # the squares "is_square_p({ONE})" "is_square_p({FOUR})" "is_square_p({NINE})" # the other statements (evaluate to 0 or 1) "({EIGHT} % 2 == 0) = {a}" "is_square_p({EIGHT} + 1) = {b}" "is_square_p({EIGHT} + {ONE}) = {c}" "is_prime({EIGHT} - 1) = {d}" "is_prime({EIGHT} - {ONE}) = {e}" "(len(factor({EIGHT} + 7)) == 2) = {f}" "({EIGHTEEN} % 3 == 0) = {g}" "({EIGHTEEN} % {THREE} == 0) = {h}" "is_square_p({EIGHTEEN} - 2) = {i}" # at least 2 of them are true "sum([{a}, {b}, {c}, {d}, {e}, {f}, {g}, {h}, {i}]) > 1" --answer="RIGHT" --template="({ONE} {FOUR} {NINE}) ({a} {b} {c} {d} {e} {f} {g} {h} {i}) ({RIGHT})" --solution=""

**Solution:** **RIGHT** = 45798.

The squares are:

ONE= 361

FOUR= 2304

NINE= 6561

And there are two statements which are true:

]]>

EIGHT(= 15798) is even

EIGHT− 1 (= 15797) is prime

And the red and blue buckets must have: **BRG** and **BGG** (in some order).

So we can have the first ball from the red bucket (although either of the non-green buckets will do).

If it is **R**, then we know the red bucket is **BRG**, and we can have the remaining balls from the red bucket to get a set in 3 goes.

If it is **G**, then we can have 2 balls from the green bucket. If we are lucky they will be **BR**, and we have got a set in 3 goes. If we are unlucky they are **RR** and we can have the remaining ball (**B**) from the green bucket to get a set in 4 goes.

If the first ball is **B**, then we can have a second ball from the red bucket, and it must be different from the first ball.

If we get **R**, then we can have the remaining ball from the red bucket (which must be **G**), to get a set in 3 goes.

If we get **G**, then we can have a ball from the green bucket. If it is **R** we have got a set in 3 goes. If it is **B**, then another ball from the green bucket must be **R** and we have got a set in 4 goes.

So we can get a set in 3 or 4 goes.

**Solution:** We require at most 4 balls to get a set.

@Frits: I’m thinking about the *(w, d, l, points)* table listing the teams in order from highest points to lowest points. I should probably have made that clear.

(D, W) = (number of draws, number of wins)

Total points = n*points[n] + 1/2n(n-1)

Total points = 3W + 2D

Number of games = 1/2n(n-1)

Number of games = W + D

leads to D = n(n – 1 – points[n]) and indeed D is a multiple of n in the n=80 case.

With this the program runs slightly faster

# number of draws = n(n - 1 - points[n]) so points[1] <= 2n - 3 #f"array [T] of var 0..{2 * n - 3}: points;", # number of draws = n(n - 1 - T[n]) f"constraint sum (i in T) (draws[i]) = 2 * {n} * ({n} - 1 - points[{n}]);", # number of draws = n(n - 1 - points[n]) so points[1] <= 2n - 3 and points[n] <= n - 2 f"constraint forall (i in T where i < {n}) (points[i] <= 2 * {n} - 2 - i);",

@Jim, Could you please clarify “In between any two of these teams”?

The teams you mentioned before this line had 0 draws.

The wording also implies that the “square”, “palindrome” and “increasing” properties each apply to exactly one of the noted times, and that the actual middle time (which is the mirror of the noted time) does not have the same property as the noted time (and so spoils this pattern).

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

**Run:** [ @replit ]

from enigma import ( Record, irange, cproduct, nconcat, nsplit, is_square, is_palindrome, tuples, subsets, singleton, printf ) # possible mirror digits mirrored = { 0: 0, 1: 1, 2: 5, 3: 3, 5: 2, 8: 8 } # mirror a seq of digits (return the corresponding number or None) def mirror(ds): try: return nconcat(mirrored[d] for d in ds) except KeyError: pass # check for consecutive increasing digits is_increasing = lambda ds: all(y == x + 1 for (x, y) in tuples(ds, 2)) # difference between 2 times def diff(n1, n2): ((h1, m1), (h2, m2)) = (nsplit(n, 2, base=100) for n in (n1, n2)) if h2 < h1 or (h2 == h1 and m2 < m1): h2 += 12 return 60 * (h2 - h1) + (m2 - m1) # collect possible times t = dict() for (h, m) in cproduct([irange(0, 11), irange(0, 59)]): if h == 0: h = 12 # form the number on the display n = nconcat(h, m, base=100) ds = nsplit(n) vs = set() if is_square(n): vs.add('sq') if is_palindrome(ds): vs.add('pal') if is_increasing(ds): vs.add('inc') v = singleton(vs) if v: t[n] = Record(h=h, m=m, ds=ds, v=v) # consider possible times for ((n1, t1), (n2, t2), (n3, t3)) in subsets(t.items(), size=3, select="P"): # t1 and t3 show the same minutes if not (t1.m == t3.m): continue # each property is represented once if len({ t1.v, t2.v, t3.v }) < 3: continue # t2 is between 1 and 2 hours after t1 if not (59 < diff(n1, n2) < 121): continue # the actual time of t2 is the mirror of t2 n2a = mirror(t2.ds) if n2a is None or not (59 < diff(n1, n2a) < 121): continue t2a = t.get(n2a) # and it spoils the pattern if not (t2a is None or t2a.v != t2.v): continue # output solution printf("{n1} -> {n2} ({n2a}) -> {n3}")

**Solution:** The first noted time was 11:56.

The program finds 2 candidate sequences of noted times:

time 1:11:56 (square, 1156 = 34²)

time 2:1:23 (1h23m later; increasing); actual time = 1:53 (1h57m later)

time 3:6:56 (7h later) (palindrome)

time 1:11:56 (square, 1156 = 34²)

time 2:1:51 (1h55m later; palindrome); actual time = 1:21 (1h25m later; both a palindrome and a square)

time 3:4:56 (5h later) (increasing)

But in both cases the start time is the same.

]]>I. “no blue doll contains a doll that has a yellow doll anywhere within it”

II. “there is no doll that contains a pink doll with a red doll anywhere within it”

III. “no yellow doll contains [directly or indirectly] a green doll with a pink doll anywhere within it”

Let’s call the dolls of different colour B, Y, R, P, G, and use the indexes from 5 for the largest to 1 for the smallest doll in a set. Also use “⊃” for “contains”.

1.

B5 must contain Y somewhere within it. If it contains it indirectly, that violates rule I.

Therefore B5⊃Y4.

2.

B5⊃Y4 so Y4 cannot contain B3.

If Y4 contains G3, then G3 contains P2 or P1, which violates rule III.

If Y4 contains P3, then P3 contains R2 or R1, which violates rule II.

Therefore Y4⊃R3.

3.

B5⊃Y4⊃R3, so R3 cannot contain G2 or P2.

If R3 contains G2, then G2 contains the remaining P1, and that violates rule III.

Therefore R3⊃P2, and consequently P2⊃G1.

So the sequence of dolls inside B5 is B5⊃Y4⊃R3⊃P2⊃G1.

4.

Y5 contains R which contains P, in that order. Otherwise if P contains R that violates rule II.

Y5 contains P which contains G in that order. Otherwise if G contains P that violates rule III.

Therefore, Y5 contains R,P,G in that order, and G inside Y5 is not larger than G2.

5. G1 is inside B5, therefore G inside Y5 is not G1, so it’s G2.

That makes the sequence of dolls inside Y5:

Y5⊃R4⊃P3⊃G2⊃B1.

So the wedding ring is inside the largest yellow doll.

]]>@ilya: Originally I had “Y followed directly by G” in the third condition, but this leads to two solutions:

BYRPG, GBYRP, PGBYR, RPGBY, YRPG

B

BYRPG, GRPBY, PGBYR, RPYGB, YBGRP

And we can’t tell where the smallest blue doll it (it is in yellow or red), so I went with the less strict interpretation, which gives a unique solution.

]]>“no yellow doll contains a green doll with a pink doll anywhere within it” ⇒ not(Y.G.*P)

i.e. we reject arrangements that have Y followed *directly* by G followed (directly or indirectly) by P.

Does it still have a single solutin in that case? ]]>

# List of possible aunts' statements statements = [] # Aunts' witness statements W1 = ['Ernest', 'Baggins', 'Mallards', 'Appleton', 'Kent'] W2 = ['Ernest', 'Boggins', 'Halyards', 'Bladon', 'Surrey' ] W3 = ['Edward', 'Biggins', 'Haystacks', 'Cuxham', 'Surrey' ] W4 = ['Edward', 'Boggins', 'Pollards', 'Appleton', 'Sussex'] W5 = ['Ernest', 'Buggins', 'Willows', 'Bladon', 'Surrey' ] # Form lists of all possible witness statements # There are 2 x 4 x 5 x 3 x 3 = 360 no. possible statements # a = first name, b = last name, c = house, d = village, e = county for a in ('Ernest', 'Edward'): for b in ('Baggins', 'Biggins', 'Boggins', 'Buggins'): for c in ('Mallards', 'Halyards', 'Haystacks', 'Pollards', 'Willows'): for d in ('Appleton', 'Bladon', 'Cuxham'): for e in ('Kent', 'Surrey', 'Sussex'): statements.append([a, b, c, d, e]) # Iterate through all statements for each aunt for st in statements: a, b, c, d, e = st # Two statements from five are true for each aunt # test Aunt No.1 statements (Agatha) if sum([a == W1[0], b == W1[1], c == W1[2], \ d == W1[3], e == W1[4]]) == 2: # test Aunt No.2 statements (Maud) if sum([a == W2[0], b == W2[1], c == W2[2], \ d == W2[3], e == W2[4]]) == 2: # test Aunt No.3 statements (Jobiska) if sum([ a == W3[0], b == W3[1], c == W3[2], \ d == W3[3], e == W3[4]]) == 2: # test Aunt No.4 statements (Kate) if sum([a == W4[0], b == W4[1], c == W4[2], \ d == W4[3], e == W4[4]]) == 2: # test Aunt No.5 statements (Tabitha) if sum([ a == W5[0], b == W5[1], c == W5[2], \ d == W5[3], e == W5[4]]) == 2: # print his name and address print(f"His Name was {a} {b}.", f"\nHis address was {c}, {d}, {e}.") # His Name was Ernest Biggins. # His address was Pollards, Appleton, Surrey.]]>

I used *regular expressions* to check the specified constraints.

A sequence of dolls (largest to smallest) is represented by some arrangement of the the string “BGPRY”.

So the following are disallowed:

“no blue doll contains a doll that has a yellow doll anywhere within it” ⇒ not(

`B.+Y`

)

i.e. we reject arrangements that have B indirectly followed by Y.

“there is no doll that contains a pink doll with a red doll anywhere within it” ⇒ not(

`.P.*R`

)

i.e. we reject arrangements that have a character, followed directly by P, followed (directly or indirectly) by R.

“no yellow doll contains a green doll with a pink doll anywhere within it” ⇒ not(

`Y.*G.*P`

)

i.e. we reject arrangements that have Y followed (directly or indirectly) by G followed (directly or indirectly) by P.

For the allowable arrangements we select a set that uses each colour in each size exactly once, and this gives us a unique arrangement of dolls.

The following Python program runs in 77ms. (Internal runtime is 12ms).

**Run:** [ @replit ]

import re from enigma import (subsets, join, group, item, cproduct, unzip, printf) # available colours colours = "BGPRY" # patterns for invalid configurations patterns = ['B.+Y', '.P.*R', 'Y.*G.*P'] # regexps # check for viable arrangements check = lambda ss: not any(re.search(p, ss) for p in patterns) # collect arrangements by largest doll g = group(subsets(colours, size=len, select='P', fn=join), st=check, by=item(0)) # choose orderings for rs in cproduct(g[k] for k in colours): # that use each colour in each size exactly once if not all(len(set(xs)) == 5 for xs in unzip(rs)): continue # output arrangements printf("{rs}", rs=join(rs, sep=", "))

**Solution:** The largest yellow doll contains the smallest blue doll.

The only viable arrangement is:

B > Y > R > P > G

G > B > Y > R > P

P > G > B > Y > R

R > P > G > B > Y

Y > R > P > G >B

Each row is formed from the previous row by moving the rightmost colour to the front.

]]>This Python program runs in 61ms. (Internal runtime is 2.3ms).

**Run:** [ @replit ]

from enigma import (unzip, union, cproduct, seq2str, printf) # statements statements = [ ('Ernest', 'Baggins', 'Mallards', 'Appleton', 'Kent'), ('Ernest', 'Boggins', 'Halyards', 'Bladon', 'Surrey'), ('Edward', 'Biggins', 'Haystacks', 'Cuxham', 'Surrey'), ('Edward', 'Boggins', 'Pollards', 'Appleton', 'Sussex'), ('Ernest', 'Buggins', 'Willows', 'Bladon', 'Surrey'), ] # collect possible values for each attributes attrs = list(union([xs, ['???']]) for xs in unzip(statements)) # count matches correct = lambda xs, ys: sum(x == y for (x, y) in zip(xs, ys)) # consider possible attributes for ss in cproduct(attrs): # each statement is correct in exactly 2 attributes if not all(correct(ss, xs) == 2 for xs in statements): continue printf("{ss}", ss=seq2str(ss, sep=" ", enc=""))

**Solution:** The correct address is:

]]>Ernest Biggins

Pollards

Appleton

Surrey

The season lasts for around 27 weeks, and each team can play up to 3 matches per week. So there is a maximum of around 27 × 3 = 81 matches per team. And each team plays each of the other teams, so there can be no more than around 82 teams in the league.

We can think about the table with the numbers of *wins*, *draws*, *losses* and *points* (= 3× *wins* + *draws*) for each team, starting with the team with the highest points total, and then each subsequent team has a points total one less than the team above it, until we reach the bottom team with the lowest points total.

If more than 1/3 of the teams had 0 draws, then all their points must have come from wins, and so be multiples of 3.

In between any two of these teams there must be at least 2 teams who have at least 1 draw. So in order for more than 1/3 of the teams to have 0 draws, the total number of teams must be of the form *(3k + 1)* or *(3k + 2)*, and every team with a points total divisible by 3 must have got all their points from wins.

Similarly, if more than 1/3 of the teams had exactly 1 draw, then the rest of their points have come from wins, and so their points totals are 1 more than a multiple of 3. So the total number of teams must be of the form *(3k + 2)*, and every team with a points total with residue 1 (mod 3), must have exactly 1 draw.

And if 1/4 of the teams had exactly 2 draws, then the number of teams must be a multiple of 4.

This narrows down *n* to integers of the form *4(3k + 2)* = *(12k + 8)*:

n ∈ {20, 32, 44, 56, 68, 80}

The number of teams with 3+ draws in each of these cases is: 1, 2, 3, 4, 5, 6.

It doesn’t take long to see that it is not possible to assign *(w, d, l)* values in the *n* = 20 case, but the others are more problematic.

I wrote a Python3 program that generates a *MiniZinc* model to attempt to construct a table for specific values of *n*, and then executes the model via the **minizinc.py** library.

For the *n* = 80 case it takes 44s to demonstrate that it is a viable solution (using the `scip`

solver).

For the remaining cases (*n* = 20, 32, 33, 56, 68), it finds no viable solution, but the *n* = 56 case take 12m, and the *n* = 68 case takes 2h17m. So really I need some more analysis, or a better model.

from enigma import (div, arg, join, printf) from minizinc import MiniZinc n = arg(80, 0, int) # number of teams in the league # calculate numbers of teams with 0, 1, 2, 3+ goals (k, r) = divmod(n, 3) assert r == 2 n0 = k + 1 n1 = k + 1 n2 = div(n, 4) assert n2 > 0 n3 = n - n0 - n1 - n2 assert n3 > 0 printf("[n={n}: n0={n0} n1={n1} n2={n2} n3={n3}]") # construct the model model = [ # indices for the teams f"set of int: T = 1..{n};", # x[A, B] = points for A against B; 1 for a draw, 3 for a win "array [T, T] of var {0, 1, 3}: x;", # no team plays themselves "constraint forall (i in T) (x[i, i] = 0);", # symmetry constraints; win <-> lose; draw <-> draw "constraint forall (i, j in T where i < j) ((x[i, j] = 0) -> (x[j, i] = 3));", "constraint forall (i, j in T where i < j) ((x[i, j] = 3) -> (x[j, i] = 0));", "constraint forall (i, j in T where i < j) ((x[i, j] = 1) -> (x[j, i] = 1));", # points, draws for each team f"array [T] of var 0..{3 * (n - 1)}: points;", "constraint forall (i in T) (points[i] = sum (j in T where j != i) (x[i, j]));", f"array [T] of var 0..{n - 1}: draws;", "constraint forall (i in T) (draws[i] = sum (j in T where j != i) (x[i, j] = 1));", # points are in order (team 1 = highest), each is 1 point more than the next f"constraint forall (i in T where i < {n}) (points[i] = points[i + 1] + 1);", # there are n0 teams with 0 draws f"constraint sum (i in T) (draws[i] = 0) = {n0};", # there are n1 teams with 1 draw f"constraint sum (i in T) (draws[i] = 1) = {n1};", # there are n2 teams with 2 draws f"constraint sum (i in T) (draws[i] = 2) = {n2};", # there are n3 teams with >2 draws f"constraint sum (i in T) (draws[i] > 2) = {n3};", # additional constraints to try and speed things up: # points residue 0 -> 0 draws "constraint forall (i in T) ((points[i] mod 3 = 0) -> (draws[i] = 0));", # points residue 1 -> 1 draw "constraint forall (i in T) ((points[i] mod 3 = 1) -> (draws[i] = 1));", # points residue 2 -> >1 draw "constraint forall (i in T) ((points[i] mod 3 = 2) -> (draws[i] > 1));", "solve satisfy;", ] p = MiniZinc(model, verbose=0) for [x] in p.solve(result='x', solver="minizinc --solver scip"): # output the table for (j, r) in enumerate(x, start=1): wdl = (r.count(3), r.count(1), r.count(0) - 1) printf("{j:2d}: [{r}] -> ({wdl}) {t}", r=join(r, sep=" "), wdl=join(wdl, sep=" "), t=sum(r)) printf() break else: printf("[no solution]") printf("[done]") printf()

**Solution:** There are 80 teams in the league.

Here is a table found for the *n* = 80 case:

]]># <pos>: [<matches>] → (<w> <d> <l>) <points> 1: [0 3 3 0 3 3 3 3 1 3 3 0 0 0 0 3 3 3 3 3 3 0 3 3 3 3 3 0 3 3 3 0 3 3 3 0 3 3 3 0 3 3 3 0 0 3 3 0 3 0 3 3 0 0 3 0 0 3 3 3 3 3 0 0 3 3 0 0 0 3 3 0 0 0 3 3 3 3 3 3] → (52 1 26) 157 2: [0 0 0 3 3 3 0 0 0 3 0 0 3 3 3 3 3 0 3 3 0 3 0 0 3 3 0 3 3 3 0 3 0 3 0 3 0 0 0 3 0 0 3 3 3 3 3 3 3 0 3 3 3 0 3 3 0 3 0 3 3 3 3 3 3 0 3 3 3 3 3 3 3 3 3 0 3 3 0 3] → (52 0 27) 156 3: [0 3 0 3 0 3 0 0 0 3 3 3 3 0 0 3 0 3 3 0 3 0 3 1 0 3 3 0 3 1 3 3 3 3 3 3 3 0 0 3 3 3 3 0 0 3 3 3 0 3 3 3 3 0 3 3 3 0 3 3 3 3 3 3 3 0 3 3 0 0 0 0 3 3 3 3 3 0 0 3] → (51 2 26) 155 4: [3 0 0 0 0 0 3 0 1 3 3 0 3 0 3 3 3 3 3 0 0 0 0 3 3 3 3 3 3 3 3 0 3 3 3 3 3 3 3 0 3 3 3 3 0 3 0 0 0 3 3 0 3 3 3 0 0 0 3 0 3 3 0 3 3 3 3 0 0 0 3 0 3 3 3 3 3 3 3 3] → (51 1 27) 154 5: [0 0 3 3 0 0 3 3 3 3 3 3 0 0 0 3 3 0 0 0 3 0 3 0 3 0 3 0 3 3 0 3 0 3 0 3 3 3 3 3 3 0 3 3 0 3 0 3 3 0 0 3 3 3 0 0 3 3 0 3 3 3 3 3 3 0 0 3 0 3 3 0 3 3 3 3 3 3 3 3] → (51 0 28) 153 6: [0 0 0 3 3 0 3 3 3 3 3 3 3 0 0 3 3 3 0 0 0 3 3 1 0 0 0 0 0 1 3 0 3 3 3 3 0 0 0 3 3 0 0 3 0 3 3 3 0 0 3 0 3 3 3 3 3 3 3 3 3 0 3 3 0 3 0 3 3 3 3 3 0 3 3 3 3 3 3 3] → (50 2 27) 152 7: [0 3 3 0 0 0 0 3 3 3 3 0 3 3 0 3 3 3 0 3 3 0 3 3 0 3 3 0 3 3 3 3 3 3 0 3 3 0 1 3 0 0 0 0 0 3 0 0 0 3 3 3 3 3 3 0 3 3 0 0 3 3 3 0 3 0 0 3 3 3 3 0 3 0 3 3 3 3 3 3] → (50 1 28) 151 8: [0 3 3 3 0 0 0 0 0 3 3 3 3 0 3 0 3 0 3 0 3 0 3 3 0 3 0 3 3 3 3 3 0 0 3 3 3 3 3 3 0 0 3 0 3 3 3 0 0 3 0 0 0 0 3 3 3 0 3 3 3 0 3 3 3 0 0 3 3 0 0 3 3 3 3 3 3 3 3 3] → (50 0 29) 150 9: [1 3 3 1 0 0 0 3 0 3 3 3 3 3 0 0 3 0 3 0 3 0 3 1 0 3 0 0 0 1 0 3 1 3 0 0 3 0 1 3 3 1 3 3 1 1 3 0 3 3 1 0 0 1 3 3 3 0 3 3 0 0 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3] → (46 11 22) 149 10: [0 0 0 0 0 0 0 0 0 0 3 3 0 0 0 0 3 0 0 3 3 0 3 0 3 3 3 3 0 3 3 3 3 0 3 3 3 3 1 3 3 3 0 3 3 3 3 0 3 0 0 0 3 3 3 3 3 0 0 3 3 3 3 0 3 3 3 3 3 3 0 0 3 3 3 3 3 3 3 3] → (49 1 29) 148 11: [0 3 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 0 3 0 0 0 0 0 0 3 0 0 0 3 3 3 3 3 3 3 3 3 0 0 3 0 3 0 3 3 3 0 3 3 3 0 0 3 3 0 3 3 3 3 3 3 3 3 3 3 3 3 0 3 3 0 3 0 3 3 3 3 3] → (49 0 30) 147 12: [3 3 0 3 0 0 3 0 0 0 0 0 3 3 0 0 3 3 3 0 0 0 3 1 3 0 0 3 0 3 0 3 0 0 0 3 3 3 3 3 3 3 0 3 1 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 0 0 0 0 0 0 0 3 3 0 3 3 3 3 0 3 3 3 3] → (48 2 29) 146 13: [3 0 0 0 3 0 0 0 0 3 0 0 0 0 3 0 3 3 0 0 3 0 3 3 3 0 0 0 0 3 0 3 0 0 3 3 3 3 3 3 3 3 0 0 1 0 3 3 0 3 3 0 0 3 3 3 3 0 3 3 3 3 3 0 3 3 0 3 3 3 3 3 3 3 3 3 3 3 3 3] → (48 1 30) 145 14: [3 0 3 3 3 3 0 3 0 3 0 0 3 0 3 3 0 3 0 3 3 0 3 0 3 0 0 0 0 3 3 0 0 0 3 0 3 3 0 0 3 3 3 3 3 3 3 3 0 3 3 3 3 3 3 3 0 0 0 3 0 0 0 0 3 0 3 3 3 0 3 3 3 0 3 0 3 3 3 3] → (48 0 31) 144 15: [3 0 3 0 3 3 3 0 3 3 0 3 0 0 0 3 3 0 0 0 3 3 0 0 0 3 0 0 0 1 0 0 0 0 0 0 3 3 1 3 3 3 3 3 3 0 3 3 3 0 3 3 3 0 3 3 3 0 3 3 3 3 3 3 3 3 3 0 0 3 3 3 3 0 0 3 3 3 0 3] → (47 2 30) 143 16: [0 0 0 0 0 0 0 3 3 3 0 3 3 0 0 0 3 3 3 3 0 3 3 1 0 0 3 3 0 3 0 3 3 3 0 3 3 3 3 0 3 0 3 3 3 0 0 0 0 0 3 0 3 3 3 3 0 3 3 3 0 0 3 3 3 3 3 0 3 3 3 0 0 0 3 3 3 3 3 3] → (47 1 31) 142 17: [0 0 3 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 3 3 0 0 0 3 0 3 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 3 3 3 0 0 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3] → (47 0 32) 141 18: [0 3 0 0 3 0 0 3 3 3 0 0 0 0 3 0 3 0 3 0 0 0 3 1 3 0 3 3 0 1 3 3 3 0 3 0 0 3 0 0 0 3 0 3 0 0 3 0 3 0 3 0 0 3 3 3 3 3 0 3 3 3 3 3 0 0 3 3 3 3 3 3 3 3 3 3 3 3 3 3] → (46 2 31) 140 19: [0 0 0 0 3 3 3 0 0 3 3 0 3 3 3 0 3 0 0 3 3 3 3 1 3 3 0 3 3 3 3 3 3 0 3 3 0 3 3 0 0 3 0 0 3 0 0 0 3 3 0 3 3 0 3 0 3 0 3 3 0 3 0 3 0 0 0 3 0 3 3 0 0 3 3 0 3 3 3 3] → (46 1 32) 139 20: [0 0 3 3 3 3 0 3 3 0 0 3 3 0 3 0 3 3 0 0 3 3 3 3 0 0 3 0 3 3 3 3 3 3 0 0 0 3 0 0 0 0 3 3 0 3 3 0 3 0 0 0 3 0 0 0 0 3 3 0 3 0 0 3 0 0 3 3 3 3 0 3 3 3 3 3 3 3 3 3] → (46 0 33) 138 21: [0 3 0 3 0 3 0 0 0 0 3 3 0 0 0 3 3 3 0 0 0 3 3 0 0 0 3 3 3 3 0 0 3 3 3 3 0 0 1 0 0 3 0 0 1 3 0 3 0 0 0 3 0 0 3 3 3 3 3 3 0 3 3 0 3 3 3 3 3 0 3 3 3 3 3 3 3 3 3 3] → (45 2 32) 137 22: [3 0 3 3 3 0 3 3 3 3 3 3 3 3 0 0 3 3 0 0 0 0 3 3 3 3 3 3 3 3 0 0 3 3 3 0 0 3 3 0 0 0 0 0 1 3 0 0 3 0 0 3 3 3 3 0 0 0 0 0 0 0 3 3 3 3 3 0 3 3 0 3 0 3 3 0 3 3 0 0] → (45 1 33) 136 23: [0 3 0 3 0 0 0 0 0 0 3 0 0 0 3 0 0 0 0 0 0 0 0 0 3 0 3 3 0 0 3 3 3 3 3 0 0 3 3 3 3 3 0 3 3 3 3 3 3 3 3 3 3 3 3 3 3 0 0 0 3 3 3 3 3 3 0 0 3 3 0 3 0 3 0 3 0 3 3 3] → (45 0 34) 135 24: [0 3 1 0 3 1 0 0 1 3 3 1 0 3 3 1 0 1 1 0 3 0 3 0 1 3 3 0 3 1 1 0 1 0 3 1 0 0 1 0 0 0 3 3 1 3 3 3 3 0 3 3 3 0 3 0 1 3 3 1 3 0 1 3 0 3 3 3 1 1 3 3 3 3 3 1 3 3 3 3] → (38 20 21) 134 25: [0 0 3 0 0 3 3 3 3 0 3 0 0 0 3 3 3 0 0 3 3 0 0 1 0 0 3 0 0 0 0 3 0 3 0 0 0 0 3 0 0 0 3 0 0 3 3 0 3 3 3 0 3 3 3 0 3 0 3 0 3 3 3 3 3 3 3 3 3 3 3 3 0 3 3 0 3 3 3 3] → (44 1 34) 133 26: [0 0 0 0 3 3 0 0 0 0 3 3 3 3 0 3 3 3 0 3 3 0 3 0 3 0 0 0 0 3 0 3 0 3 0 0 0 0 0 3 3 3 3 3 0 0 3 3 0 0 0 0 0 3 3 0 0 0 3 0 0 3 0 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3] → (44 0 35) 132 27: [0 3 0 0 0 3 0 3 3 0 0 3 3 3 3 0 3 0 3 0 0 0 0 0 0 3 0 3 3 0 3 3 1 3 0 0 0 3 0 0 0 0 0 3 1 0 0 0 3 3 3 3 0 3 3 3 3 3 0 0 3 3 3 3 3 0 3 3 3 0 3 3 3 3 0 3 3 3 3 0] → (43 2 34) 131 28: [3 0 3 0 3 3 3 0 3 0 3 0 3 3 3 0 0 0 0 3 0 0 0 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 3 0 1 0 0 3 3 3 3 0 0 3 0 3 0 0 3 3 0 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3] → (43 1 35) 130 29: [0 0 0 0 0 3 0 0 3 3 3 3 3 3 3 3 3 3 0 0 0 0 3 0 3 3 0 3 0 0 0 0 0 3 3 3 0 3 3 0 0 3 0 0 0 0 0 3 3 0 0 3 3 3 0 0 3 0 3 0 0 0 3 0 3 0 3 3 3 3 3 3 3 3 3 3 3 0 3 3] → (43 0 36) 129 30: [0 0 1 0 0 1 0 0 1 0 3 0 0 0 1 0 0 1 0 0 0 0 3 1 3 0 3 3 3 0 3 3 1 0 0 0 1 0 1 0 3 3 1 0 1 0 0 1 3 3 3 1 3 3 3 3 3 3 3 3 0 3 3 3 3 3 3 0 1 3 3 3 3 3 3 3 3 3 3 3] → (38 14 27) 128 31: [0 3 0 0 3 0 0 0 3 0 0 3 3 0 3 3 3 0 0 0 3 3 0 1 3 3 0 3 3 0 0 0 0 3 0 3 3 3 3 0 0 0 3 3 0 0 0 0 0 0 3 3 0 3 3 0 3 3 3 3 3 0 3 3 3 0 0 3 0 3 3 3 3 3 0 0 0 3 3 3] → (42 1 36) 127 32: [3 0 0 3 0 3 0 0 0 0 0 0 0 3 3 0 3 0 0 0 3 3 0 3 0 0 0 3 3 0 3 0 3 0 0 0 3 0 0 0 0 3 3 3 0 0 3 3 0 0 3 3 3 0 3 0 0 0 3 3 0 3 3 0 3 3 3 3 3 3 3 3 3 3 3 3 3 0 3 3] → (42 0 37) 126 33: [0 3 0 0 3 0 0 3 1 0 0 3 3 3 3 0 3 0 0 0 0 0 0 1 3 3 1 3 3 1 3 0 0 3 3 0 0 0 1 0 0 3 3 0 3 3 3 3 0 0 3 0 3 0 3 3 3 3 3 3 3 3 3 0 0 3 0 3 3 3 0 0 0 3 0 3 0 0 3 3] → (40 5 34) 125 34: [0 0 0 0 0 0 0 3 0 3 0 3 3 3 3 0 3 3 3 0 0 0 0 3 0 0 0 3 0 3 0 3 0 0 0 0 0 0 0 0 0 3 3 0 1 3 0 3 3 0 3 3 3 0 0 0 3 3 3 0 0 3 3 3 3 3 3 3 0 3 3 3 3 3 0 3 3 3 3 3] → (41 1 37) 124 35: [0 3 0 0 3 0 3 0 3 0 0 3 0 0 3 3 3 0 0 3 0 0 0 0 3 3 3 3 0 3 3 3 0 3 0 3 0 3 0 0 0 0 0 3 0 3 3 0 3 0 3 3 3 0 3 3 3 3 3 0 0 3 3 0 0 3 3 0 0 3 3 0 0 3 0 3 3 3 0 0] → (41 0 38) 123 36: [3 0 0 0 0 0 0 0 3 0 0 0 0 3 3 0 3 3 0 3 0 3 3 1 3 3 3 3 0 3 0 3 3 3 0 0 0 0 1 3 0 0 3 0 0 0 0 3 0 0 3 3 0 3 0 3 3 0 0 3 3 3 3 0 0 3 3 3 3 0 3 0 3 3 3 0 3 0 3 3] → (40 2 37) 122 37: [0 3 0 0 0 3 0 0 0 0 0 0 0 0 0 0 3 3 3 3 3 3 3 3 3 3 3 3 3 1 0 0 3 3 3 3 0 0 0 0 0 0 3 3 3 0 3 0 0 3 3 0 3 3 0 3 0 0 3 3 0 3 3 0 0 0 3 3 3 0 3 0 3 0 3 3 0 0 0 3] → (40 1 38) 121 38: [0 3 3 0 0 3 3 0 3 0 0 0 0 0 0 0 0 0 0 0 3 0 0 3 3 3 0 3 0 3 0 3 3 3 0 3 3 0 0 0 0 0 3 0 0 0 3 0 0 0 3 3 3 3 0 3 3 3 0 3 3 0 3 3 3 3 3 0 3 3 3 3 0 3 0 3 0 0 3 3] → (40 0 39) 120 39: [0 3 3 0 0 3 1 0 1 1 0 0 0 3 1 0 0 3 0 3 1 0 0 1 0 3 3 3 0 1 0 3 1 3 3 1 3 3 0 1 0 1 3 3 1 0 0 0 1 3 3 0 0 3 0 3 3 3 3 3 1 0 1 1 3 3 1 3 3 3 0 1 0 3 3 3 0 1 1 3] → (33 20 26) 119 40: [3 0 0 3 0 0 0 0 0 0 3 0 0 3 0 3 0 3 3 3 3 3 0 3 3 0 3 3 3 3 3 3 3 3 3 0 3 3 1 0 0 0 0 0 0 0 0 3 0 3 3 3 0 0 0 3 3 3 3 0 3 0 0 0 3 0 0 3 3 0 3 0 0 0 3 3 0 0 3 0] → (39 1 39) 118 41: [0 3 0 0 0 0 3 3 0 0 3 0 0 0 0 0 0 3 3 3 3 3 0 3 3 0 3 3 3 0 3 3 3 3 3 3 3 3 3 3 0 0 0 3 3 0 0 0 0 3 0 3 0 0 0 0 3 3 3 0 0 3 0 3 0 0 3 3 0 3 0 0 0 3 0 0 3 0 3 0] → (39 0 40) 117 42: [0 3 0 0 3 3 3 3 1 0 0 0 0 0 0 3 0 0 0 3 0 3 0 3 3 0 3 0 0 0 3 0 0 0 3 3 3 3 1 3 3 0 3 0 3 0 0 0 0 0 3 0 0 3 3 3 3 0 3 3 0 0 0 3 3 0 3 0 0 3 3 3 3 3 3 3 0 0 0 3] → (38 2 39) 116 43: [0 0 0 0 0 3 3 0 0 3 3 3 3 0 0 0 0 3 3 0 3 3 3 0 0 0 3 0 3 1 0 0 0 0 3 0 0 0 0 3 3 0 0 3 3 0 0 3 0 0 0 0 0 3 3 3 3 0 0 3 3 0 3 3 3 0 0 0 0 3 3 3 3 3 3 3 0 3 3 3] → (38 1 40) 115 44: [3 0 3 0 0 0 3 3 0 0 0 0 3 0 0 0 0 0 3 0 3 3 0 0 3 0 0 3 3 3 0 0 3 3 0 3 0 3 0 3 0 3 0 0 0 3 3 3 3 3 3 3 0 3 0 3 3 3 3 3 0 0 3 0 3 0 0 0 0 3 3 0 3 0 0 3 0 3 0 0] → (38 0 41) 114 45: [3 0 3 3 3 3 3 0 1 0 3 1 1 0 0 0 0 3 0 3 1 1 0 1 3 3 1 1 3 1 3 3 0 1 3 3 0 3 1 3 0 0 0 3 0 0 0 1 0 3 1 0 0 1 1 0 1 1 0 1 3 3 3 3 3 1 3 0 3 3 0 1 1 0 1 0 3 1 3 0] → (30 23 26) 113 46: [0 0 0 0 0 0 0 0 1 0 0 0 3 0 3 3 0 3 3 0 0 0 0 0 0 3 3 3 3 3 3 3 0 0 0 3 3 3 3 3 3 3 3 0 3 0 0 0 3 0 3 3 0 3 3 0 0 3 3 3 0 3 0 3 0 3 0 3 0 3 3 0 0 3 3 0 0 0 0 0] → (37 1 41) 112 47: [0 0 0 3 3 0 3 0 0 0 0 0 0 0 0 3 0 0 3 0 3 3 0 0 0 0 3 3 3 3 3 0 0 3 0 3 0 0 3 3 3 3 3 0 3 3 0 0 0 0 0 0 0 0 3 3 0 3 0 3 0 0 3 0 0 3 3 0 3 3 0 0 0 3 3 3 3 3 3 3] → (37 0 42) 111 48: [3 0 0 3 0 0 3 3 3 3 0 0 0 0 0 3 0 3 3 3 0 3 0 0 3 0 3 0 0 1 3 0 0 0 3 0 3 3 3 0 3 3 0 0 1 3 3 0 0 0 0 0 0 0 3 3 0 3 0 3 3 3 0 3 0 0 3 0 0 0 3 0 3 0 0 3 3 0 3 3] → (36 2 41) 110 49: [0 0 3 3 0 3 3 3 0 0 3 0 3 3 0 3 0 0 0 0 3 0 0 0 0 3 0 0 0 0 3 3 3 0 0 3 3 3 1 3 3 3 3 0 3 0 3 3 0 0 0 0 0 0 0 0 0 3 3 0 0 0 0 3 3 0 3 0 0 3 0 0 3 3 0 3 3 3 0 3] → (36 1 42) 109 50: [3 3 0 0 3 3 0 0 0 3 0 0 0 0 3 3 0 3 0 3 3 3 0 3 0 3 0 0 3 0 3 3 3 3 3 3 0 3 0 0 0 3 3 0 0 3 3 3 3 0 3 3 3 0 0 0 0 3 0 3 0 0 0 0 0 3 0 3 3 0 0 0 0 0 3 0 0 0 0 0] → (36 0 43) 108 51: [0 0 0 0 3 0 0 3 1 3 0 0 0 0 0 0 0 0 3 3 3 3 0 0 0 3 0 0 3 0 0 0 0 0 0 0 0 0 0 0 3 0 3 0 1 0 3 3 3 0 0 3 3 0 3 0 0 3 3 0 3 3 0 3 0 3 3 3 3 3 3 3 3 0 3 3 3 3 3 0] → (35 2 42) 107 52: [0 0 0 3 0 3 0 3 3 3 0 0 3 0 0 3 3 3 0 3 0 0 0 0 3 3 0 3 0 1 0 0 3 0 0 0 3 0 3 0 0 3 3 0 3 0 3 3 3 0 0 0 0 0 0 0 3 0 3 3 3 3 3 0 0 3 3 3 0 0 0 0 3 0 0 3 3 0 3 0] → (35 1 43) 106 53: [3 0 0 0 0 0 0 3 3 0 3 0 3 0 0 0 3 3 0 0 3 0 0 0 0 3 3 3 0 0 3 0 0 0 0 3 0 0 3 3 3 3 3 3 3 3 3 3 3 0 0 3 0 0 0 0 0 0 3 3 0 3 0 0 3 0 3 0 3 0 0 3 3 3 3 0 0 0 0 0] → (35 0 44) 105 54: [3 3 3 0 0 0 0 3 1 0 3 0 0 0 3 0 0 0 3 3 3 0 0 3 0 0 0 0 0 0 0 3 3 3 3 0 0 0 0 3 3 0 0 0 1 0 3 3 3 3 3 3 3 0 3 0 0 3 0 0 0 0 3 3 0 3 3 3 0 3 0 3 0 3 0 0 0 3 0 0] → (34 2 43) 104 55: [0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 3 0 0 0 0 3 0 3 3 3 3 3 3 0 0 3 1 0 0 0 3 3 0 3 3 0 0 3 3 0 3 0 3 3 3 3 3 3 0 3 0 3 3 3 3 0 0 3 3 3 0 3] → (34 1 44) 103 56: [3 0 0 3 3 0 3 0 0 0 0 0 0 0 0 0 0 0 3 3 0 3 0 3 3 3 0 0 3 0 3 3 0 3 0 0 0 0 0 0 3 0 0 0 3 3 0 0 3 3 3 3 3 3 0 0 0 3 3 0 3 0 0 3 3 3 0 0 0 0 3 3 3 0 0 0 3 0 3 0] → (34 0 45) 102 57: [3 3 0 3 0 0 0 0 0 0 3 0 0 3 0 3 0 0 0 3 0 3 0 1 0 3 0 3 0 0 0 3 0 0 0 0 3 0 0 0 0 0 0 0 1 3 3 3 3 3 3 0 3 3 0 3 0 3 3 3 3 3 0 0 0 3 3 0 0 0 0 0 3 0 3 0 3 3 0 3] → (33 2 44) 101 58: [0 0 3 3 0 0 0 3 3 3 0 0 3 3 3 0 0 0 3 0 0 3 3 0 3 3 0 3 3 0 0 3 0 0 0 3 3 0 0 0 0 3 3 0 1 0 0 0 0 0 0 3 3 0 3 0 0 0 3 0 0 0 3 3 3 0 0 3 0 3 3 3 3 0 0 3 0 0 0 0] → (33 1 45) 100 59: [0 3 0 0 3 0 3 0 0 3 0 0 0 3 0 0 0 3 0 0 0 3 3 0 0 0 3 0 0 0 0 0 0 0 0 3 0 3 0 0 0 0 3 0 3 0 3 3 0 3 0 0 0 3 0 0 0 0 0 3 3 3 3 3 0 3 3 0 3 3 3 3 0 0 3 0 3 3 3 3] → (33 0 46) 99 60: [0 0 0 3 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 3 0 3 3 1 3 3 3 0 3 0 0 0 0 3 3 0 0 0 0 3 3 0 0 0 1 0 0 0 3 0 3 0 0 3 3 3 0 3 0 0 0 3 3 3 3 3 3 3 3 0 3 0 0 3 3 3 3 0 0 0] → (32 2 45) 98 61: [0 0 0 0 0 0 0 0 3 0 0 0 0 3 0 3 0 0 3 0 3 3 0 0 0 3 0 3 3 3 0 3 0 3 3 0 3 0 1 0 3 3 0 3 0 3 3 0 3 3 0 0 3 3 0 0 0 3 0 3 0 0 0 0 0 3 3 0 0 0 3 3 3 0 0 0 0 3 0 3] → (32 1 46) 97 62: [0 0 0 0 0 3 0 3 3 0 0 3 0 3 0 3 0 0 0 3 0 3 0 3 0 0 0 0 3 0 3 0 0 0 0 0 0 3 3 3 0 3 3 3 0 0 3 0 3 3 0 0 0 3 0 3 0 3 0 0 3 0 3 0 0 0 0 0 0 0 0 3 0 3 3 3 0 3 3 3] → (32 0 47) 96 63: [3 0 0 3 0 0 0 0 0 0 0 3 0 3 0 0 0 0 3 3 0 0 0 1 0 3 0 0 0 0 0 0 0 0 0 0 0 0 1 3 3 3 0 0 0 3 0 3 3 3 3 0 3 0 0 3 3 0 0 0 3 0 0 0 3 3 3 3 0 3 0 3 0 3 3 3 3 3 0 3] → (31 2 46) 95 64: [3 0 0 0 0 0 3 0 0 3 0 3 3 3 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 3 3 0 3 3 3 0 1 3 0 0 0 3 0 0 3 0 0 3 0 3 3 0 0 0 3 0 0 0 3 3 3 0 0 3 0 0 3 0 0 3 3 3 3 3 0 0 3 0] → (31 1 47) 94 65: [0 0 0 0 0 3 0 0 0 0 0 3 0 0 0 0 0 3 3 3 0 0 0 3 0 0 0 0 0 0 0 0 3 0 3 3 3 0 0 0 3 0 0 0 0 3 3 3 0 3 3 3 0 3 0 0 3 0 3 0 3 3 0 3 0 3 3 3 0 0 0 3 3 3 0 3 0 0 3 0] → (31 0 48) 93 66: [0 3 3 0 3 0 3 3 0 0 0 3 0 3 0 0 0 3 3 3 0 0 0 0 0 0 3 0 3 0 3 0 0 0 0 0 3 0 0 3 3 3 3 3 1 0 0 3 3 0 0 0 3 0 0 0 0 3 0 0 0 3 0 0 0 0 0 3 3 0 0 0 0 0 1 3 3 3 3 0] → (30 2 47) 92 67: [3 0 0 0 3 3 3 3 0 0 0 3 3 0 0 0 0 0 3 0 0 0 3 0 0 0 0 0 0 0 3 0 3 0 0 0 0 0 1 3 0 0 3 3 0 3 0 0 0 3 0 0 0 0 3 3 0 3 0 0 0 3 0 3 0 3 0 0 3 3 0 3 3 0 3 3 3 0 0 3] → (30 1 48) 91 68: [3 0 0 3 0 0 0 0 0 0 0 3 0 0 3 3 0 0 0 0 0 3 3 0 0 0 0 0 0 3 0 0 0 0 3 0 0 3 0 0 0 3 3 3 3 0 3 3 3 0 0 0 3 0 0 3 3 0 3 0 3 3 0 3 0 0 3 0 3 0 0 0 3 0 0 3 3 0 3 0] → (30 0 49) 90 69: [3 0 3 3 3 0 0 0 0 0 0 0 0 0 3 0 0 0 3 0 0 0 0 1 0 0 0 0 0 1 3 0 0 3 3 0 0 0 0 0 3 3 3 3 0 3 0 3 3 0 0 3 0 3 3 3 3 3 0 0 3 3 3 0 3 0 0 0 0 0 0 0 0 0 3 0 0 3 0 3] → (29 2 48) 89 70: [0 0 3 3 0 0 0 3 0 0 3 0 0 3 0 0 0 0 0 0 3 0 0 1 0 0 3 0 0 0 0 0 0 0 0 3 3 0 0 3 0 0 0 0 0 0 0 3 0 3 0 3 3 0 0 3 3 0 0 3 3 3 0 3 3 3 0 3 3 0 0 3 3 0 0 0 0 3 3 3] → (29 1 49) 88 71: [0 0 3 0 0 0 0 3 0 3 0 3 0 0 0 0 0 0 0 3 0 3 3 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 3 0 3 0 0 0 3 0 3 0 3 3 0 3 3 3 0 0 3 0 0 0 0 3 3 3 3 3 3 3 3 3 0 3 0 0 0 0 3 0 0 0] → (29 0 50) 87 72: [3 0 3 3 3 0 3 0 0 3 0 0 0 0 0 3 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 3 3 3 0 1 3 3 0 0 3 1 3 3 3 3 3 0 3 0 0 0 0 3 0 0 3 0 0 0 0 0 3 0 3 3 0 0 0 0 0 0 3 0 3 0 0] → (28 2 49) 86 73: [3 0 0 0 0 3 0 0 0 0 3 0 0 0 0 3 0 0 3 0 0 3 3 0 3 0 0 0 0 0 0 0 3 0 3 0 0 3 3 3 3 0 0 0 1 3 3 0 0 3 0 0 0 3 0 0 0 0 3 3 0 3 3 0 0 3 0 0 3 0 3 3 0 3 0 0 3 0 0 0] → (28 1 50) 85 74: [3 0 0 0 0 0 3 0 0 0 0 0 0 3 3 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 3 0 0 0 3 3 0 0 3 0 3 3 3 0 0 3 3 3 3 3 0 3 0 0 0 0 3 3 3 3 3 3 3 0 0 0 0 0 0 3 3] → (28 0 51) 84 75: [0 0 0 0 0 0 0 0 0 0 3 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 3 0 0 0 3 0 3 3 3 0 0 3 0 0 3 0 0 3 1 0 0 3 3 0 0 3 0 3 3 3 0 3 0 0 3 0 0 0 3 1 0 3 0 3 3 3 3 3 0 0 0 0 3 0] → (27 2 50) 83 76: [0 3 0 0 0 0 0 0 0 0 0 3 0 3 0 0 0 0 3 0 0 3 0 1 3 0 0 0 0 0 3 0 0 0 0 3 0 0 0 0 3 0 0 0 3 3 0 0 0 3 0 0 3 3 0 3 3 0 3 0 3 0 0 0 0 0 0 0 3 3 3 0 3 3 3 0 0 3 3 3] → (27 1 51) 82 77: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 3 0 3 0 0 0 3 3 3 3 0 3 3 3 0 3 0 0 0 3 0 0 3 3 0 0 0 3 0 0 3 3 0 3 3 0 0 0 3 3 0 3 0 3 3 3 0 3 0 3] → (27 0 52) 81 78: [0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 3 3 0 0 3 3 3 1 3 3 3 0 0 1 3 0 3 0 3 0 3 3 0 0 3 0 3 0 3 0 0 0 3 3 0 3 3 0 0 3 0 3 3 3 0 0 0 0 0] → (26 2 51) 80 79: [0 3 3 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 3 0 3 0 1 0 0 3 0 3 0 3 0 0 3 3 0 0 3 3 3 0 3 3 0 3 3 0 3 0 0 0 3 0 3 0 3 3 3 0 0 0 3 3 0 0] → (26 1 52) 79 80: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 0 0 3 0 0 0 0 0 0 0 3 0 0 0 0 3 3 0 0 3 3 3 0 0 0 3 3 3 3 3 0 3 0 3 0 3 0 0 0 3 3 3 0 3 0 0 3 3 3 0 3 0 0 3 3 0] → (26 0 53) 78

y:m/3 + 5n/12 = 10

r:m/3 + 3n/12 = 8

b:m/3 + 4n/12 = 9

These are easily solved to give: [**y** − **b**] *n* = 12, *m* = 15.

Which can then reduce to lowest terms

**Solution:** The required ratio is 5 parts of dollop 1 to 4 parts of dollop 2.

Solving the equations programatically:

**Run:** [ @replit ]

from enigma import (Rational, Matrix, ratio_q, printf) Q = Rational() # equations for each colour eqs = [ # m n k ((Q(1, 3), Q(5, 12)), 10), # yellow ((Q(1, 3), Q(3, 12)), 8), # red ((Q(1, 3), Q(4, 12)), 9), # blue ] # solve the equations (m, n) = Matrix.linear(eqs, field=Q) # express the ratio using integers (m, n) = ratio_q(m, n) # output solution printf("{m}x dollop 1 + {n}x dollop 2")]]>

The solution given in the magazine the following week was

1, 6, 7, 8, 7, 8, 9, 10, 9, 10, 11, 2, 3, 2, 3, 4, 5, 4, 5, 6, 1, 11, 12, G, 12, G

which is a reflection of most of Jim’s fourth solution.

Similarly his third solution reflects part of the second (path from 1 to 1).

It runs in 232ms.

**Run:** [ @replit]

from enigma import (Accumulator, irange, inf, multiset, remove, printf) # adjacency matrix: s -> t -> cost adj = { 1: { 6: 200, 11: 200 }, 2: { 3: 100, 11: 100 }, 3: { 2: 100, 4: 100 }, 4: { 3: 100, 5: 100 }, 5: { 4: 100, 6: 100 }, 6: { 1: 200, 5: 100, 7: 100 }, 7: { 6: 100, 8: 100 }, 8: { 7: 100, 9: 100 }, 9: { 8: 100, 10: 100 }, 10: { 9: 100, 11: 100 }, 11: { 1: 200, 2: 100, 10: 100, 12: 100 }, 12: { 11: 100, 0: 100 }, 0: { 12: 100 }, } # make a path visiting vertices as specified in <m> # ending at vertex 0 (which has no limit) # return (<path>, <total-cost>) def path(m, ks, t): if not m and ks[-1] == 0: yield (ks, t) else: for (k, v) in adj[ks[-1]].items(): if k == 0: yield from path(m, ks + [k], t + v) elif k in m: yield from path(remove(m, k), ks + [k], t + v) # start at 1, and visit each vertex <k> times for k in irange(1, inf): r = Accumulator(fn=min) m = multiset.from_seq(irange(1, 12), count=k) for (ks, t) in path(remove(m, 1), [1], 0): printf("{t} {ks}") r.accumulate(t) if r.value: printf("min = {r.value}") break

**Solution:** The minimum distance is 2800 yards.

Each vertex is visited twice.

Each solution has a counterpart with (2, 3, 4, 5) swapped for (10, 9, 8 7).

]]>(1, 6, 1, 11, 2, 3, 2, 3, 4, 5, 4, 5, 6, 7, 8, 7, 8, 9, 10, 9, 10, 11, 12, G, 12, G)

(1, 11, 2, 3, 2, 3, 4, 5, 4, 5, 6, 1, 6, 7, 8, 7, 8, 9, 10, 9, 10, 11, 12, G, 12, G)

(1, 6, 5, 4, 5, 4, 3, 2, 3, 2, 11, 1, 6, 7, 8, 7, 8, 9, 10, 9, 10, 11, 12, G, 12, G)

(1, 6, 5, 4, 5, 4, 3, 2, 3, 2, 11, 10, 9, 10, 9, 8, 7, 8, 7, 6, 1, 11, 12, G, 12, G)

If I choose a letter and you choose a letter that comes before mine in the sequence.

Then if your letter is earlier in the alphabet than mine, then if we take one of your α sequences, we can simply add my letter to the end of it to form a longer α sequence for my letter (and there may be even longer ones). So my letter must have a larger α value than yours.

So, your letter must have α < 5.

**Question 1:** Yes.

And if your letter is later in the alphabet than mine, then given any of my ω sequences, we can simply add your letter to the front of it to form a longer ω sequence for your letter.

So in this case the α and ω values for our letters cannot be the same.

Similarly, if your letter comes after mine in the sequence, then if your letter comes after mine in the alphabet, you can form a longer α sequence by adding your letter to the end of any of my α sequences. And if your letter comes before mine in the alphabet, I can form a longer ω sequence by adding my letter to the beginning of any of your ω sequences.

Hence, the letters must have different α or ω values.

**Question 2:** Yes.

The table has 25 cells, and if we were to fill out the table for a sequence and find that all the letters were within the table, then (as there are 26 letters) one of the cells must contain more than 1 letter. (This is an application of the *pigeonhole principle*).

But we have shown above that no two letters in the sequence can have the same α *and* ω values, so this is not possible. So there must be some letters that fall outside the table (i.e. have an α or ω value that is 6 or more).

**Question 3:** No.

And this means that in the sequence *(**)* there must be a subsequence of length 6 that is in either alphabetical order or reverse alphabetical order.

**Question 4:** Yes.

In **Enigma 882** we found:

Any sequence of (k² + 1) distinct integers has an increasing or a decreasing subsequence of length (k + 1).

So, with *k* = 5, when we put the the integers 1 .. 26 into order there must be an increasing or decreasing subsequence of length 6.

And we can map any sequence formed from the letters of the alphabet onto a sequence formed from the integers 1 .. 26 by letting A=1, B=2, …, Z=26.

Which means any sequence of 26 letters must have a letter that has an α or ω value that is at least 6.

In this program I used the *maximal common subsequence* algorithm from **Enigma 882**.

It prints the (α, ω) values for each element of the sequence in the puzzle text, and checks there are no duplicate values.

It will then optionally shuffle the sequence and check again, a specified number of times.

**Run:** [ @replit ]

import random from enigma import (irange, rev, join, first, true, repeat, arg, printf) # given text text = "THEQUICKBROWNFXJMPDVLAZYGS" # alphabetical and reverse alphabetical order az = join(sorted(set(text))) za = rev(az) # find a maximal common subsequence of sequences <xs> and <ys> def mcss1(xs, ys): n = len(ys) zs = list(() for _ in irange(0, n)) for x in xs: ps = list(zs) for (i, y) in enumerate(ys): zs[i + 1] = (ps[i] + (x,) if x == y else max(zs[i], ps[i + 1], key=len)) return zs[n] # calculate alpha, omega values def alpha(text, x): j = text.index(x) # make the subsequence of letters before x ss = list(y for y in first(text, count=j) if y < x) return mcss1(az, ss) + (x,) def omega(text, x): j = text.index(x) # make the subsequence of letters after x ss = list(y for y in first(text, count=true, skip=j + 1) if y < x) return (x,) + mcss1(za, ss) def values(text, x): (a, w) = (alpha(text, x), omega(text, x)) return (len(a), len(w)) # shuffle a sequence def shuffle(ss): ss = list(ss) random.shuffle(ss) return join(ss) # look for duplicate values def check(ss): # look for duplicate (alpha, omega) values seen = dict() for x in ss: vs = values(ss, x) printf("{x} -> {vs}") if vs in seen: printf("--> duplicate value [{k}]", k=seen[vs]) seen[vs] = x # find maximal increasing/decreasing sequences inc = join(mcss1(az, ss)) printf("max inc = {inc} [{n}]", n=len(inc)) dec = join(mcss1(za, ss)) printf("max dec = {dec} [{n}]", n=len(dec)) n = arg(0, 0, int) for ss in repeat(shuffle, text, n): printf("checking: {ss!r}") check(ss) printf()]]>

It’s a well known inequality.

Assume not true:

, which contradicts the assumption. Hence proved.

Then the combined weight *y* of the two weighings is:

y = x + 1/x

If we plot this function we get a graph that looks like:

And this has a minimum value of *y = 2* at *x = 1*, and a higher value for *0 < x < 1*.

**Solution:** She will weigh out more than 2 kg of flour.

However, if the arms are only slightly different lengths (i.e. *x* is only a little less than 1), then the weighed amount will only be a little more than 2 kg.

Yes, Jim, good point. With that constraint I get 32-35 as well.

]]>@Richard: Thanks for your comment.

I was assuming that each country targets a *different* one of the others for their disqualified 10 score, so there would be one **X** in each column.

While it is not explicitly stated in the puzzle text, I think it is implied.

]]>I got 32-36 without zero and 32-37 with zero. Here is a non-zero set with a winner on 36:

A 0 2 2 2 2 2 X 2 B 3 0 3 X 3 3 3 3 C 4 4 0 4 4 4 4 X D X 2 2 0 2 2 2 2 E 1 1 1 1 0 X 1 1 F 7 7 X 7 7 0 7 7 G 9 9 X 9 9 9 0 9 H 9 9 9 9 9 X 9 0 = 33 34 17 32 36 20 26 24]]>

This Python program runs in 60ms. (Internal runtime is 231µs).

**Run:** [ @replit ]

from enigma import (cproduct, join, printf) # possible attributes descs = [ dict(U='unmarried', M='married'), dict(L='left-handed', R='right-handed', A='ambidextrous'), dict(M='man', F='woman'), dict(S='shorter', E='same height', T='taller'), dict(C='communist', A='anti-communist', X='indifferent'), ] # statements statements = [ 'URFS?', 'MA?EC', 'M?MTA', 'ULF?C', '?RMTX' ] # count matches correct = lambda xs, ys: sum(x == y for (x, y) in zip(xs, ys)) # consider possible attributes for ss in cproduct(d.keys() for d in descs): # each statement is correct in exactly two attributes if not all(correct(ss, xs) == 2 for xs in statements): continue printf("{ss}", ss=join((d[x] for (d, x) in zip(descs, ss)), sep="; "))

We see that the culprit is a married right-handed female communist who is taller than the victim. Three of the four suspects are quickly eliminated. So the culprit must be the fourth (assuming the attributes we know nothing about fit, i.e. height, handedness, political persuasion).

**Solution:** The murderer is Mary Hetherington.

There is a simpler solution, which doesn’t require to consider the total number of games and solving equations.

As previously, start by narrowing the variants down to:

– And/orra: 4 won, 0 drawn, 1 lost.

– Booleivia: 3 won, 1 drawn, 1 lost.

– Truenisia: 2 won, 2 drawn, 1 lost.

– Peruf: 1 won, 3 drawn, 1 lost; or 2 won, 0 drawn, 3 lost.

– United Gates: 0 won, 4 drawn, 1 lost; or 1 won, 1 drawn, 3 lost.

– Vennezuela: 0 won, 2 drawn, 3 lost.

The total number of wins is equal to the total number of losses. Apart from Peruf and United Gates, there are 9 wins and 6 losses, or three more wins than losses. Therefore Peruf and United Gates between them have 3 more losses than wins. That narrows it down to:

– Peruf: 2 won, 0 drawn, 3 lost.

– United Gates: 1 won, 1 drawn, 3 lost.

The play proceeds around the table until someone draws a black card. And there is at least 1 black card, so this must eventually happen.

If there are *R* red cards and *B* black cards (such that *R, B* ∈ [1, 26] and *N* = *R* + *B* ≥ 27), then the probability that the process ends on the first draw (i.e. that the first card drawn is the first black card) is:

P(1) = B / N

And the probability that the process ends on subsequent draws is:

P(2) = (R / N) × (B / (N − 1))

P(3) = (R / N) × ((R − 1) / (N − 1)) × (B / (N − 2))

…

P(R + 1) = 0

…

And if there are *n* players (*n* ≤ *R*), then the probability for each player drawing the black card, as play continues around the table, is:

Player 1 = P(1) + P(n + 1) + P(2n + 1) + …

Player 2 = P(2) + P(n + 2) + P(2n + 2) + …

…

And these probabilities must be equal (= 1/*n*).

This Python program considers all possible *R, **B* values.

It runs in 95ms. (Internal runtime is 30ms).

**Run:** [ @replit ]

from enigma import (Rational, irange, decompose, seq_all_same, printf) Q = Rational() # solve the puzzle for N cards (R red, B black) def solve(N, R, B): p = dict() # calculate the probability of player n drawing the first black pR = 1 # probability all previous players have drawn red for k in irange(0, R): # probability of drawing one of B blacks from (N - k) cards pB = Q(B, N - k) # probability of player (k + 1) drawing the first black p[k + 1] = pR * pB # move on to the next player pR *= Q(R - k, N - k) # look for n players with the same probability for n in irange(5, min(R + 1, 26)): if seq_all_same(sum(p[j] for j in irange(i, R + 1, step=n)) for i in irange(1, n)): printf("N={N}: R={R} B={B} -> n={n}") # consider total number of cards (more than half the pack) for N in irange(27, 52): # split into red and black for (R, B) in decompose(N, 2, increasing=0, sep=0, min_v=1, max_v=26): solve(N, R, B)

**Solution:** The initial of the man who bought the drinks is I.

There were 26 red cards and 1 black card, and the process lasted as long as possible. i.e. the first 26 cards that were drawn were red, leaving the black card to be drawn as the 27th card.

The probabilities are:

P(1) = 1/27

P(2) = (26/27)×(1/26) = 1/27

P(3) = (26/27)×(25/26)×(1/25) = 1/27

P(4) = (26/27)×(25/26)×(24/25)×(1/24) = 1/27

…

P(27) = 1/27

i.e. the probabilities of the black card being drawn on any particular draw are all equal.

There are more than 4 friends, and less than 27, so the only way these probabilities can be divided to give an equal overall probability for each friend is with 9 players:

Player 1 = P(1) + P(10) + P(19) = 1/9

Player 2 = P(2) + P(11) + P(20) = 1/9

…

Player 9 = P(9) + P(18) + P(27) = 1/9

Hence there are 9 players, A – I, and each draws 3 cards, until I is left to draw his third and final card, which is black.

This scenario can be arrived at directly by equating *P(1)* and *P(2)*, which immediately gives *B* = 1 and *R* = 26.

– And/orra: 4 won, 0 drawn.

– Booleivia: 3 won, 1 drawn.

– Truenisia: 2 won, 2 drawn.

– Vennezuela: 0 won, 2 drawn.

For each of the remaining 2 teams, there are two possible variants:

– Peruf: 2 won, 0 drawn; or 1 won, 3 drawn.

– United Gates: 0 won, 4 drawn; or 1 won, 1 drawn.

In this 6-team round robin tournament the total number of games is 6*5/2=15. The grand total score is 42. Let the number of the games which ended up in a draw be d, and the number of decisive games be w. Then we can write two equations, one for the total number of games and another for the grand total score:

d + w = 15

2*d + 3*w = 42

Solving these simultaneous equations, we get d = 3, w = 12.

So there were total 6 points awarded for draws, of which 5 were scored by Booleivia, Truenisia and Vennesuela, so only 1 left to share between Peruf and United gates. That further narrows down the number of won and drawn for both of them:

– Peruf: 2 won, 0 drawn.

– United Gates: 1 won, 1 drawn.

So the answer is

– And/orra: 4 won, 0 drawn, 1 lost.

– Booleivia: 3 won, 1 drawn, 1 lost.

– Truenisia: 2 won, 2 drawn, 1 lost.

– Peruf: 2 won, 0 drawn, 3 lost.

– United Gates: 1 won, 1 drawn, 3 lost.

– Vennezuela: 0 won, 2 drawn, 3 lost.

This reasoning is not just wrong, but also sloppy and strange for two reasons:

1. “Since the factors of 222 are 2, 3, and 37, there must have been eight scores” that should be “the *prime* factors of 222”, and it doesn’t really explain how they got eight. Factors we really care about are 6 for (N-2), and 37 for the sum, but all factors have to be considered, not just primes.

2. “We know one score was 7 points” is irrelevant/unnecessary. The only way to choose 8 different numbers from 1 to 9, which add up to 37, is {1,2,3,4,5,6,7,9}.

If we don’t know that the numbers are all different, then knowing that one of the scores was 7 doesn’t help either.

“The reasoning given does work if instead of the 10 point score from each panel being discarded, it is reduced to be the same as the other scores given by that panel.”

No, I don’t think it works in that case either, because the grand total then would be (N-1)*37=222, hence N=7, not 8; and 37 would then be the sum of 7 scores, not 8. The reasoning in that case would be similar to my solution above, with the same results.

`Football()`

]] helper class from the It runs in 75ms. (Internal runtime is 13ms).

**Run:** [ @replit ]

from enigma import (Football, digit_map, map2str, printf) # scoring system football = Football(games='wdl', points=dict(w=3, d=1)) # labels for the teams teams = "ABTPUV" # collect (w, d, l) results for each team ss = set() # the table uses values up to 12 (A=10, C=12) d = digit_map(0, 12) table = dict(played='555555', points='CA8642') # find possible match outcomes for (ms, _) in football.substituted_table(table, d=d): # form the table rows rs = list() for (i, t) in enumerate(teams): r = football.extract_table(ms, i) rs.append((r.w, r.d, r.l)) ss.add(tuple(rs)) # output the results for rs in ss: printf("(w, d, l) = {rs}", rs=map2str(zip(teams, rs), enc="", sort=0))

**Solution:** The complete table is:

There are 8 ways to allocate match outcomes that result in this table.

]]>Still reasonably fast, twice as long as Jim’s program.

from enigma import SubstitutedExpression from itertools import product # form the set of possible three dart scores single = set(range(21)) | {25} double = set(2 * x for x in single) treble = set(3 * x for x in single if x != 25) darts = single | double | treble scores = set(sum(x) for x in product(darts, repeat=3)) # invalid digit / symbol assignments d2i = dict() for d in range(0, 17): vs = set() if d == 0: vs.update('FGUVW') # position first sequence count letter 1-3 if d > 3: vs.update('F') if d < 3 or d > 7: vs.update('G') if d < 5 or d > 11: vs.update('U') if d < 7 or d > 14: vs.update('V') if d < 9: vs.update('W') if 0 < d < 11: vs.update('X') if 0 < d < 13: vs.update('Y') if 0 < d < 15: vs.update('Z') # don't use S and D as it will cause an unnecessary check if d > 9: vs.update('TREBLOPA') d2i[d] = vs word = "TREBLETOPSATDARTS" # 17 letters # positions of sequence count letter = [F, G, U, V, W, X, Y, Z] # we have at least 5 sequence count letters (at most 8) # the alphametic puzzle p = SubstitutedExpression( [ # generate scores of 1, 2 or 3 letters by partitioning "TREBLETOPSATDARTS" "F + 1 < G < F + 5", "G + 1 < U < G + 5", "U + 1 < V < U + 5", "V + 1 < W < V + 5", "not X or W + 1 < X < W + 5", "not Y or (X and X + 1 < Y < X + 5)", "not Z or (Y and Y + 1 < Z < Y + 5)", # last sequence count letter position must be 16 "(pos := [x for x in @seq if x])[-1] == len(word) - 1", # last sequence count letter "len(pos) == S", # make sure all sequence count letters are different letters "len(set(ltrs := [word[x] for x in pos])) == S", # for 3 digits scores the hundreds digit must equal ltrs[0] (having value 1) "all(word[x + 1] == ltrs[0] for x, y in zip([-1] + pos[:-1], pos) if y - x == 4)", # give sequence count letters a value # try to do a check early, it will postpone the introduction of a new letter "pos[0] > 2 or [T,R,E][pos[0]] == 1", "pos[0] < 3 or [T,R,E,B][pos[0]] == 1", "pos[1] > 6 or [T,R,E,B,L,E,T][pos[1]] == 2", "pos[1] < 7 or [T,R,E,B,L,E,T,O][pos[1]] == 2", "pos[2] > 8 or [T,R,E,B,L,E,T,O,P][pos[2]] == 3", "pos[2] < 9 or [T,R,E,B,L,E,T,O,P,S,A,T][pos[2]] == 3", "pos[3] > 11 or [T,R,E,B,L,E,T,O,P,S,A,T][pos[3]] == 4", # D is digit not used yet "peek(set(range(10)).difference([T,R,E,B,L,O,P,S,A])) = D", "pos[3] < 12 or @wrd[pos[3]] == 4", "all(@wrd[pos[i]] == i + 1 for i in range(4, S - 1))", # my total score was a prime number "is_prime(sum(scs := [nconcat(@wrd[x + 1:y]) for x, y in zip([-1] + pos[:-1], pos)]))", # avoid leading zero digits in scores "all(@wrd[x + 1] for x, y in zip([-1] + pos[:-1], pos) if y > x + 2)", # check for valid scores "all(s in scores for s in scs)", ], answer="[word[x + 1: y] for x, y in zip([-1] + pos[:-1], pos)], scs, \ ''.join(str(x) for x in [P,L,E,A,S,E])", base=len(word), # don't use D as it will cause an unnecessary check distinct="TREBLOPSA", d2i=d2i, env=dict(word=word, scores=scores), macro=dict([("seq", "[F, G, U, V, W, X, Y, Z]")] + [("wrd", "[T,R,E,B,L,E,T,O,P,S,A,T,D,A,R,T,S]")]), reorder=0, verbose=0, # use 256 to see the generated code ) # print answers for (_, ans) in p.solve(): print(f"{ans[:2]}, PLEASE = {ans[2]}")]]>

Eight countries took part and the winning song scored 36 points.

If there are

Ncountries, each judging panel gave scores toN−1 songs, and the score of 10 was then deducted, so the 222 total points = (number of countries in the final round − 2) × the sum of each different number that the panels chose. No countries tied, so there are at most nine different countries. Since the factors of 222 are 2, 3, and 37, there must have been eight scores (from eight countries) that added to 37.We know one score was 7 points, and the only combination that adds to 37 is (9, 7, 6, 5, 4, 3, 2, 1). The best musical act must have scored 37−1 = 36.

The start of this seems to follow my initial reasoning, that each panel ends up awarding the same number of points to all but 2 of the participants.

But then it seems to go awry. Because while the different scores sum to 37, the total for each song is the sum of 6 of the 8 possible scores. So with the set of scores given a total of 36 is not possible.

The reasoning given does work if instead of the 10 point score from each panel being discarded, it is reduced to be the same as the other scores given by that panel. Then the total for each song is missing just one of the 8 possible scores, and so the maximum total *is* 36.

And this is equivalent to each panel give the same score to all but one of the songs.

]]>@Jim, thank you.

I might use it if a list of variables is frequently used:

–macro=”@AtoZ = [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z]”

]]>I recently added code to the [[ `SubstitutedExpression`

]] solver, in the **enigma.py** library, that allows you to specify macros. These are strings, introduced with the @ character, that are replaced verbatim in the expressions to be evaluated.

This puzzle provides an example, whereby the symbols for the subjects may be referred to by more meaningful names (but a macro could be used to give a shortcut for any string, not just individual symbols).

You can see the expressions after macro substitution by passing the ‘P’ verbose flag to the [[ `SubstitutedExpression`

]] solver.

The following run file executes in 68ms. (Internal runtime is 86µs).

**Run:** [ @replit ]

#! python3 -m enigma -r SubstitutedExpression # year/subject: # # En Fr Ge Hi La # 1: A B C D E # 2: F G H I J # # binary variables --base=2 --distinct="" # let's refer to them with macros for convenience: --macro="@1En = A" --macro="@1Fr = B" --macro="@1Ge = C" --macro="@1Hi = D" --macro="@1La = E" --macro="@2En = F" --macro="@2Fr = G" --macro="@2Ge = H" --macro="@2Hi = I" --macro="@2La = J" # exactly 3 subjects per year "@1En + @1Fr + @1Ge + @1Hi + @1La == 3" "@2En + @2Fr + @2Ge + @2Hi + @2La == 3" # Ge for at least 1 year "@1Ge + @2Ge >= 1" # En for exactly 1 year "@1En + @2En == 1" # 2En -> 2Fr "implies(@2En, @2Fr)" # 1En -> 1Ge "implies(@1En, @1Ge)" # not(2Fr) -> not(1Ge) "implies(not @2Fr, not @1Ge)" # not(1Hi) -> not(2Ge) "implies(not @1Hi, not @2Ge)" # not(1Fr) -> 2Hi "implies(not @1Fr, @2Hi)" # not(1Fr and 1Ge) "not (@1Fr and @1Ge)" # not(2Fr and 2Hi) "not (@2Fr and @2Hi)" --header="(En Fr Ge Hi La) (En Fr Ge Hi La)" --template="( @1En @1Fr @1Ge @1Hi @1La) ( @2En @2Fr @2Ge @2Hi @2La)" --solution=""

**Solution:** 1st Year = French, History, Latin; 2nd Year = English, French, Geography.

@Frits: I’m not quite sure what you are getting at here.

But I can see that any 3-digit score must begin with 1 (as the highest possible score in darts is 180), and as we have allocated 1 as an index to one of the symbols we can reject any collection of terms that has a 3-digit term with a leading symbol that is not allocated to the digit 1.

And this does indeed reduce the number of collections to be considered to 6 sets.

We can easily perform this check by adding the following between lines 29 and 30:

# any 3-digit score must start with 1 if any(len(t) == 3 and s2d.get(t[0], -1) != 1 for t in terms): return]]>

With

# check for 3 digit scores hplus = {t[0] for t in terms if len(t) > 2} if len(hplus) > 1: return if hplus: if peek(hplus) not in s2d or s2d[peek(hplus)] != 1: return

only 6 calls SubstitutedExpression() will be made to instead of 76.

]]>Each turn is represented by 2, 3, or 4 characters from the string.

This Python program chops the strings into possible chunks, and then uses those chunks to construct an alphametic puzzle which is then solved using the [[ `SubstitutedExpression()`

]] solver from the **enigma.py** library.

It runs in 236ms.

**Run:** [ @replit ]

from enigma import (SubstitutedExpression, irange, union, subsets, sprintf as f, join, printf) # possible scores with 3 darts single = union([irange(1, 20), [25]]) double = set(2 * x for x in single) treble = set(3 * x for x in single if x != 25) darts = union([single, double, treble]) scores = set(subsets(darts, min_size=0, max_size=3, select='R', fn=sum)) # cut <text> into chunks with lengths from <ks> def decompose(text, ks, ss=[]): n = len(text) if n == 0: yield ss elif n > 1: for k in ks: if k > n: break yield from decompose(text[k:], ks, ss + [text[:k]]) # construct an alphametic puzzle using the terms <ts> def solve(ts): # collect initial allocation and score terms (terms, s2d) = (list(), dict()) for (i, t) in enumerate(ts, start=1): s2d[t[-1]] = i terms.append(t[:-1]) if len(s2d) != len(ts): return # construct the alphametic puzzle exprs = list(f("{t} in scores") for t in terms) exprs.append(f("is_prime({ts})", ts=join(terms, sep=" + "))) p = SubstitutedExpression( exprs, s2d=s2d, env=dict(scores=scores), answer=f("(PLEASE, ({ts}))", ts=join(terms, sep=", ")), verbose=0 ) # solve it for (ans, ss) in p.answers(): printf("PLEASE = {ans} [scores = {ss} -> {t}]", t=sum(ss)) # decompose the text into chunks of length 2, 3, 4 for ts in decompose("TREBLETOPSATDARTS", [2, 3, 4]): # use these chunks to solve the puzzle alphametically solve(ts)

**Solution:** **PLEASE** = 321561.

The scores are: 48 (1); *a* (2); 14*b* (3); 65 (4); *c* (5); 84 (6)

where *(a, b, c)* are the digits (0, 7, 9) in some order.

So the total scored is: 343.

We might suppose the setter did not score 0 on any turn, which sets *b* = 0, but still gives two possible sequences:

]]>TR (E); B (L); ETO (P); SA (T); D (A); RT (S) 48 (1); 9 (2); 140 (3); 65 (4); 7 (5); 84 (6) 48 (1); 7 (2); 140 (3); 65 (4); 9 (5); 84 (6)

**Run:** [ @replit ]

from enigma import (divisors_pairs, decompose, subsets, printf) # number of "missing" scores m = 1 # consider possible (k, t) pairs for (k, t) in divisors_pairs(222, every=1): if t < 7: continue n = k + m ws = set() # decompose t into n scores, one of which is 7 for ss in decompose(t - 7, n - 1, increasing=1, sep=0, min_v=1, max_v=9, fn=list): ss.append(7) ss.sort() # possible total scores are the total t, less m of the panels ps = set(t - sum(xs) for xs in subsets(ss, size=m, select="mC")) # find an n-subset of these scores that sum to 222 for ts in subsets(ps, size=n): if sum(ts) != 222: continue printf("[n={n}; k={k} t={t}] -> scores={ss} totals={ts}", ts=sorted(ts, reverse=1)) ws.add(max(ts)) if ws: printf("n={n}: winner = {ws}", ws=sorted(ws))

To allow for 2 “missing” scores for each song (from the favourite panel, and the home panel) you can change `m`

at line 4. To allow scores of 0 (“nul points!”), you can set `min_v=0`

at line 13.

@ilya: I think you are right. That is the puzzle the setter intended to set. It is a shame the sloppy wording spoils it.

Although I think we also need to be told that there wasn’t a country that awarded 0 points to all its non-favourite songs (including its own!), otherwise we could have a situation such as:

A → (C, 4)

B → (F, 8)

C → (D, 6)

D → (A, 0)

E → (G, 9)

F → (E, 7)

G → (B, 3)

which gives total scores of:

A=37, B=34, C=33, D=31, E=30, F=29, G=28

total = 222

and the highest score is 37.

In my original analysis of the puzzle I found that with 8 participants the highest score was between 32 and 37 (if 0 was allowed – otherwise between 32 and 35).

]]>If the panel doesn’t judge its own country’s song, we cannot even rule out that two countries gave a score of 1, so the winning score could be as high as 35.

E.g.

A → (D, 1), total 37-1-1=35

B → (A, 1), total 37-1-2=34

C → (B, 2), total 37-2-4=31

D → (C, 4), total 37-4-1=32

E → (G, 5), total 37-5-6=26

F → (E, 6), total 37-6-8=23

G → (H, 7), total 37-7-5=25

H → (F, 8), total 37-8-7=22

I think that rather paradoxically, the panel could judge its own country’s song, and judged it below the favourite. I know it says “Every nation … gave a score to each of the *others*”, and your interpretation makes perfect sense from any perspective. But if we assume that they judged their own song, the problem can be solved.

Lets number countries from 1 to n, and let a_1, a_2, … a_n be the lower score given by each country. The grand total of all scores would be

(a_1 + a_2 + … + a_n)(n − 1) = 222

Considering all the factors of 222: 1, 2, 3, 6, 37, 74, 101, 222, we easily rule out all possibilities for n-1 except 6. So there were 7 countries, and the sum of all 7 lower scores is 37.

Each country was favoured by only one another country (which they tailored their song for). So we know that for each country, it received a lower score from all countries except one which favoured them (and gave 10 which was later deducted). So for each country A, the total score is 37−a_B, where B is the country which favoured A.

There were no ties for any position, so all totals were different, and therefore all a_1, a_2, … , a_7 were different.

So how the scores were distributed?

We need to find 7 different numbers from 1 to 9, which sum up to 37. All numbers from 1 to 9 sum up to 45, so two excluded numbers sum up to 45-37=8. We cannot exclude 1 and 7, because we know that Transylvania panel gave 7 to everybody except Ruritania. So the two excluded numbers are either 2 and 6, or 3 and 5. Either way, the highest total score is 37-1=36.

If I understand this puzzle correctly there seem to be multiple solutions.

For example, if there are 8 participating countries, A – H, and each country targets a different one of the others for their disqualified 10 score, so that each panel ends up awarding the same number of points to each of 6 participants (excluding their own entry, and that of the favourite).

The following scenario: *(favourite, score)*:

A → (C, 1)

B → (F, 2)

C → (H, 7)

D → (B, 5)

E → (D, 4)

F → (G, 9)

G → (A, 3)

H → (E, 6)

gives the following totals:

A=33, B=30, C=29, D=28, E=27, F=26, G=25, H=24

total = 222

However here is another scenario, which seems to be equally viable:

A → (F, 2)

B → (C, 1)

C → (H, 7)

D → (B, 5)

E → (D, 4)

F → (G, 9)

G → (A, 3)

H → (E, 6)

which gives the following totals:

A=32, B=31, C=29, D=28, E=27, F=26, G=25, H=24

total = 222

So there are multiple possibilities for the winning score.

]]>@Bob: Certainly. I’ve put the code up on [@replit].

It uses my **enigma.py** library, and **plot.py** (which is a Tk graphics library). Both are available via GitHub [@github].

Nice. Can you include your code, or some description of how you did the simulation?

]]>**Run:** [ @replit ]

from enigma import (subsets, map2str, printf) # hats bishops = "ABC" naval = "DEFGH" hats = bishops + naval # multiple lookups on dict <d> def nget(d, k, n): while n > 0: k = d[k] n -= 1 return k # map each person to a hat (not their own) for hs in subsets(hats, size=len, select='D'): # m maps person -> hat m = dict(zip(hats, hs)) # H is wearing a bishops hat if m['H'] not in bishops: continue # the bishops are wearing naval hats if not all(m[k] in naval for k in bishops): continue # check the statements for A, B, C, H if not nget(m, 'D', 2) == 'A': continue if not nget(m, 'E', 3) == 'B': continue if not nget(m, 'F', 4) == 'C': continue if not nget(m, 'H', 5) == 'H': continue # output solution printf("{m}", m=map2str(m))

**Solution:** The wearers and hats are:

Armuth is wearing Hornpipe’s

Bangor is wearing Drake’s

Cone is wearing Grogg’s

Drake is wearing Easy’s

Easy is wearing Armuth’s

Fish is wearing Cone’s

Grogg is wearing Fish’s

Hornpipe is wearing Bangor’s

Which give the following cycles (*x* → *y* = “*x* is wearing *y*‘s”):

]]>A → H → B → D → E → A

C → G → F → C

`SubstitutedExpression`

]] solver from the The following run file executes in 70ms. (Internal runtime of the generated code is 4ms).

**Run:** [ @replit ]

#! python3 -m enigma -r SubstitutedExpression --distinct="" --code="f = is_square_p" # the six non-3-digit numbers are perfect squares "f(THREE)" "f(FOUR)" "f(FIVE)" "f(SEVEN)" "f(EIGHT)" # exactly one of the 3-digit numbers is _not_ a square "f(TWO) != f(SIX)" --answer="ROOTS" --solution=""

**Solution:** **ROOTS** = 96641.

There are 10 ways to assign digits to the letters, but in each of them we have:

THREE=EIGHT= 44944 = 212²

FOUR= 8649 = 93²

FIVE= 8464 = 92²

SIX= 144 = 12²

SEVEN= 14641 = 121²

1 →NS

4 →EHITUX

6 →OV

8 →F

9 →GR

And **W** can take on any value (0 – 9), so:

]]>

TWO= 406, 416, 426, 436, 446, 456, 466, 476, 486, 496

@Frits: Some interesting stuff there.

Before I came up with my explanation for how Neville can escape I did run some simulations to see if it was possible.

This is one where the Monster’s strategy is to move 1 step (of 4 units) in whatever direction (clockwise or anticlockwise) brings it closest to Neville. And Neville’s strategy is to move 1 step (of 1 unit) towards whichever point on the moat gives him the greatest time advantage over the Monster.

Initially the time advantage is negative (i.e. Neville is heading for a point where he will get caught), but as the chase progresses his greater angular velocity close to the centre allows him to reach a point with a positive advantage.

]]>The probability of a red queen appearing in the 2nd position is, the probability of a red queen appearing in position 1 (= 2/52), multiplied by the probability of a red queen appearing in position 2 (= 1/51):

P(2) = (2/52) × (1/51) = 1 / 1326

And the probability of a red queen appearing in the 3rd position is, the probability of a red queen appearing in positions 1 or 2 (= 2 × (2×50)/(52×51)), multiplied by the probability of a red queen appearing in position 3 (= 1/50):

P(3) = 2 × (2×50)/(52×51) × (1/50) = 2 / 1326

Similarly:

P(4) = 3 × (2×50×49)/(52×51×50) × (1/49) = 3 / 1326

P(5) = 4 × (2×50×49×48)/(52×51×50×49) × (1/48) = 4 / 1326

…

P(k + 1) = k / 1326

**Solution:** The best choice is position 52.

And we would expect to see position 52 occur 51/1326 ≈ 3.85% of the time.

And we can run a simulation to verify the situation is what we expect:

import random from enigma import (irange, multiset, fdiv, printf) # the pack pack = ['Q'] * 2 + ['X'] * 50 # run N random trials N = 1000000 p = multiset() for _ in irange(N): # shuffle the pack random.shuffle(pack) # record the position of the second queen p.add(52 - pack.index('Q')) for (r, n) in p.most_common(1): printf("position {r} = {n} / {N} = {f:.3%}", f=fdiv(n, N))

(To see more results you can increase the argument to [[ `multiset.most_common()`

]] at line 16).

% run -ipypy -t puzzle-219x.py position 52 = 38467 / 1000000 = 3.847% [puzzle-219x.py] elapsed time: 0.6448800s (644.88ms)]]>

I don’t yet understand the “J” shape diagram (swimming east from P to Q). I would think if the bear notices the bear swimming from P to Q the bear would run clockwise towards Q and catch the swimmer (if swimmer stays on course).

]]>`SubstitutedExpression()`

]] solver from the The first time to allocate points for positions (1st = 3 points; 2nd = 2 points; 3rd = 1 point), and then to allocate appropriate “knot values” to the positions. In the first instance we want to examine all possible allocations of points, but in the second instance we only need to find one way to allocate the values for a valid solution.

This Python program runs in 75ms. (Internal runtime is 17ms).

**Run:** [ @replit ]

from enigma import (SubstitutedExpression, subsets, sprintf, printf) # allocate first places: # # 3 = best, 2 = middle, 1 = worst # # G H I # ----- # row: A B C # steer: D E F # cook: G H I p = SubstitutedExpression( [ # each is best and worst at something "{3, 1}.issubset({A, D, G})", # George "{3, 1}.issubset({B, E, H})", # Harris "{3, 1}.issubset({C, F, I})", # I # George is best at help, or worst at oar (or both) "D == 3 or A == 1", ], digits=[1, 2, 3], distinct=["ABC", "DEF", "GHI"], answer="((A, B, C), (D, E, F), (G, H, I))", ) for (rs, ss, cs) in p.answers(verbose=0): # try to allocate knot scores (between 1 and 9) given the values # # G H I # ----- # row: U V W # steer: X Y Z exprs = ["W + X < U + Y", "U + Y < V + Z"] # ensure position order is maintained for vs in [(rs, "UVW"), (ss, "XYZ")]: for ((a, x), (b, y)) in subsets(zip(*vs), size=2, select='P'): if a < b: exprs.append(sprintf("{x} < {y}")) q = SubstitutedExpression( exprs, digits=[1, 2, 3, 4, 5, 6, 7, 8, 9], distinct=[], answer="((U, V, W), (X, Y, Z))", ) for (kr, ks) in q.answers(first=1, verbose=0): # output solution ((G, H, I), (kG, kH, kI)) = (rs, kr) printf("row: G = {G} ({kG}k); H = {H} ({kH}k); I = {I} ({kI}k)") ((G, H, I), (kG, kH, kI)) = (ss, ks) printf("steer: G = {G} ({kG}k); H = {H} ({kH}k); I = {I} ({kI}k)") (G, H, I) = cs printf("cook: G = {G}; H = {H}; I = {I}") printf()

**Solution:** “I” is (am) the best cook.

The ratings can be given as follows (with example knot values):

Rowing:1st = Harris (5 kt); 2nd = George (4 kt); 3rd = I (1 kt)

Steering:1st = George (3 kt); 2nd = I (2 kt); 3rd = Harris (1 kt)

Cooking:1st = I; 2nd = Harris; 3rd = George

And the combined knot values are:

]]>I rows + G steers = 4 < G rows + H steers = 5 < H rows + I steers = 7

I found the Nahin book was available via the Internet Archive [link], and it is neat that the earliest reference brings us back to *New Scientist*.

Also interesting that the earlier versions of the puzzle have the water in the disc, and the running around the circumference.

]]>If Anna’s tokens have a total value not more than £126, then at least one of the values must be duplicated. (This is known as the *Pigeonhole Principle* [wikipedia]).

**Solution:** **(a)** Yes. Anna must be be able to find two different combinations with the same value.

Wesley has the additional possibility of having tokens with a value of £127. In this case it would be possible for the values of all subsets to be different (from 1 to 127). And we can construct a set of tokens that give 127 different values using powers of 2. If the tokens have value (1, 2, 4, 8, 16, 32, 64), then we can make each of the values from 1 to 127 in just one way, and the tokens involved in each amount may be determined by writing the number out in binary.

**Solution:** **(b)** No. It is possible that Wesley cannot find two combinations with the same value.

If we take two different combinations that Anna has found that have the same value, then if they are disjoint we have found two sets of equal value that can be given away.

If they are not disjoint Anna can just keep the tokens that the sets have in common, and that produces two non-empty disjoint subsets with equal value.

**Solution:** **(c)** Yes. Anna can give away tokens with equal value to her two cousins.

As we have seen Wesley might might not be able to construct two combinations with the same value at all. In this case he would also be unable to construct two disjoint sets of tokens with the same value. With the (1, 2, 4, 8, 16, 32, 64) set of tokens any of the amounts between 1 and 127 that can be made correspond to a unique collection of tokens.

**Solution:** **(d)** No. It is possible that Wesley cannot give away tokens with equal value to his two cousins.

In the book, Nahin also refers to:

Schuurman,W., and Lodder, J., “The Beauty, the Beast, and the Pond”, Mathematics

Magazine, March–April 1974, pp. 93–95.

But apparently there is an even earlier version:

T. H. O’Beirne, “Christmas Puzzles and Paradoxes”, New Scientist, 266, Dec 21, 1961 p. 751–753. [link]

]]>(We first met this in NABLA, the Bulletin of the Malayan Mathematical Society: we have since received another version from a correspondent). Some robbers have stolen the green eye of a little yellow god from a temple on a small island in the middle of a circular lake. As they embark in their boat, they are observed by a solitary guard on the shore, who can run four times as fast as they can row the boat. Can they be sure of reaching the shore and escaping with their loot? If so, how? And what if the guard could move four and a half times as fast as the robbers?

I don’t know how I get to this nonsense about 7°. The optimal path after reaching the circle of 1/4 radius would be to keep going along the tangential line to that circle. That gives sqrt(15/16)≈0.9682 distance for Neville and pi+arccos(1/4)≈4.4597 distance for the monster.

Generally, if monster’s speed to Neville’s is k:1, then Neville’s best time to monster’s time is:

sqrt(k^2 – 1) : pi+arccos(1/k)

Equating these times and solving numerically for k, I get k≈4.603339. That’s the minimum (monster speed : Neville’s speed) to avoid any escape, as Brian Gladman mentioned.

If there are *x* children on the swings and *y* children on the climbing frame, then the second statement becomes:

x − k = y + k

⇒ x = y + 2k

And the first statement becomes:

x + k = 2(y − k)

⇒ y + 3k = 2y − 2k

⇒ y = 5k

⇒ x = 7k

⇒ x + y = 12k

**Solution:** The total number of children needs to be a multiple of 12 (or any of its divisors), and a multiple of the size of the contingent that moves between the groups.

And the transitions are:

5k + 7k → 4k + 8k

5k + 7k → 6k + 6k

In the given example we have *k* = 2.

So: *x** = 14, **y* = 10.

2 children moving from 10 → 14 give groups of size 8 and 16.

2 children moving from 14 → 10 give groups of size 12 and 12.

]]>Now a tricky bit: he can further improve his time gain by a factor of about 3.6 if instead of taking a shortest path to the edge, he deviates by about 7° clockwise. That slightly increases the distance he needs to run, but this is justified as the monster’s path increases by a factor greater than 4. ]]>

It is used exacly for that: to minimise the number of switchings when cycling through all possible states.

Reminds me Duke Nukem 3D game which has switch operated doors (https://infosuite.duke4.net/index.php?page=ae_doors_d8) on some levels, where you need to cycle through different switch combinations to open it. ]]>

Instead of a greedy algorithm we can use the minimum hitting set implementation in *MiniZinc* written for **Enigma 82** via **utils_mzn.py**:

from utils_mzn import hitting_set # map cells to { "<row>", "<col>" } sets ss = list({sprintf("r{r:02d}"), sprintf("c{c:02d}")} for (r, c) in cells) # find a minimum hitting set of rows/cols that hits all cells hs = hitting_set(ss) printf("(2) min rows/cols = {n} {hs}", n=len(hs), hs=join(sorted(hs), sep=", ", enc="[]"))

This verifies that 9 rows/cols is the minimum required.

]]>The positions are symmetrical, so we can examine what happens when the player in cell 1 moves first.

This Python program considers games with increasing numbers of moves (as defensive play could continue indefinitely), analysing all possible positions.

It runs in 61ms. (Internal runtime is 601µs).

**Run:** [ @replit ]

from enigma import (irange, inf, cache, printf) # adjacency matrix (for clockwise directions 0-5) X = 0 adj = { # [ 0 1 2 3 4 5 ] 1: [ X, 2, 12, X, X, X ], 2: [ X, 3, 13, 12, 1, X ], 3: [ X, 4, 14, 13, 2, X ], 4: [ X, X, 5, 14, 3, X ], 5: [ X, X, 6, 15, 14, 4 ], 6: [ X, X, 7, 8, 15, 5 ], 7: [ X, X, X, X, 8, 6 ], 8: [ 6, 7, X, X, 9, 15 ], 9: [ 15, 8, X, X, 10, 16 ], 10: [ 16, 9, X, X, X, 11 ], 11: [ 13, 16, 10, X, X, 12 ], 12: [ 2, 13, 11, X, X, 1 ], 13: [ 3, 14, 16, 11, 12, 2 ], 14: [ 4, 5, 15, 16, 13, 3 ], 15: [ 5, 6, 8, 9, 16, 14 ], 16: [ 14, 15, 9, 10, 11, 13 ], } @cache # find cells commanded by <k> # map cell -> direction def commands(k): r = dict() # add in cells in a particular direction for d in (0, 1, 2, 3, 4, 5): x = k while True: x = adj[x][d] if not x: break r[x] = d return r # play a game with up to n moves # return 1 = player 1 win; -1 = player 1 loss; 0 = draw @cache def play(n, X, Y): if n == 0: return 0 # find cells commanded by each (cX, cY) = map(commands, (X, Y)) # consider possible moves for X r = -1 # worst case is a loss for (t, d) in cX.items(): x = X while True: # move in the required direction x = adj[x][d] # no further moves in this direction if (not x) or x in cY: break if x == t: # reached the target cell # what is the outcome for the rest of the game? k = play(n - 1, Y, x) if k == -1: return 1 # a win is best if k == 0: r = 0 # otherwise a draw break # return best outcome return r # consider possible games of length n for n in irange(1, inf): r = play(n, 1, 7) if r != 0: printf("[n={n}] (1, 7) -> win for player {w}", w=(1 if r == 1 else 2)) break

**Solution:** X should let Y move first. And then X can force Y back to position 7 with X on 15 and Y is unable to move.

We can fully describe the game (modulo reflections):

[1] Y→5, X→3, Y→7, X→15 #

[2] Y→5, X→3, Y→6, X→14, Y→7, X→15 #

[3] Y→6, X→2, Y→5, X→3 = [1]

[4] Y→6, X→2, Y→15, X→13, Y→6, X→14 = [2]

[5] Y→6, X→2, Y→8, X→16 = [2]

The puzzle in the book **Tantalizers** (1970) is the same except the game is played on a board 5 hexagons high, but play proceeds in the same way.

@Frits: This could be satisfied by 1 pet with 0 legs and 1 pet with 6 legs.

]]>The condition “dogs and cats are the only quadrupeds” isn’t easy to implement.

You seem to allow the situation with xpets = 2 and xpairs = 3.

The same model can be used with SubstitutedExpression.

As we must have at least 5 cats or dogs we can use sum(xpairs) in {1, 3, 5}. With a specific order of constraints (reorder=0) the program runs in 100ms.

]]>If Uncle started with a taxable income of 1, then in the alternative system he receives a single non-taxable rebate:

income = 1

tax = 1

income after tax = 0

non-taxable rebate = r

So the net amount received is simply:

N = r

The actual process continues indefinitely, in the following Python program we stop the process when the amount of income to be taxed has become ridiculously small.

This Python program runs in 61ms. (Internal runtime is 141µs).

**Run:** [ @replit ]

from enigma import (find_zero, printf) # process the tax on a given amount def process(X, r): # net amount received N = 0 while X > 1e-6: # calculate tax on X t = r * X N += (X - t) # and a rebate is returned X = r * t # return net amount, and any remaining income return N + X # return the difference between the systems fn = lambda r: process(1, r) - r # find a rate when the amounts are the same r = find_zero(fn, 0.0, 1.0) printf("tax rate = {r:.1%}", r=r.v)

**Solution:** The tax rate is: 61.8%.

Analytically, we can calculate the effective tax rate of the indefinite procedure, as follows:

income = 1

tax = r

income after tax = (1 − r)

taxable rebate = r^2income = r^2

tax = r^3

income after tax = (r^2 − r^3)

taxable rebate = r^4income = r^4

tax = r^5

income after tax = (r^4 − r^5)

taxable rebate = r^6…

So the net amount Uncle receives is:

N = (1 − r) + (r^2 − r^3) + (r^4 − r^5) + …

N = 1 + (−r) + (−r)^2 + (−r)^3 + …

N = 1 / (1 + r)

And equating the two net amounts:

r = 1 / (1 + r)

r(r + 1) = 1

r² + r − 1 = 0

r = (−1 ± √5) / 2; r ∈ [0, 1]

So the exact tax rate is: *r* = (−1 + √5) / 2 = 0.6180339887498949… = *φ* − 1 = 1 / *φ*

where *φ* is the *Golden Ratio* [@wikipedia].

In fact Neville would need to start at a point less than *π/4* ≈ 0.785 times the radius of the circle away from the edge, with the monster directly behind him to get to the moat before the monster arrives.

So, initially, it seems like Neville *is* doomed. Which makes me think that there must be a way he can avoid a grisly death (otherwise why set the puzzle?).

Now, if Neville were to run around a circle, concentric with the moat, but inside it, then if the circle has a radius 1/4 the radius of the moat, then he could keep (angular) pace with the monster as it swims around the moat. If the circle was smaller, he would be able to outpace the monster.

So if he were to run around a circle that was, say, 0.23 times the radius of the moat, that is less than 1/4, so he can outpace the monster, and will eventually reach a situation where the monster is directly opposite him (i.e. exactly on the other side of the centre).

At this point he can make a break for the point on the moat opposite from the monster. He needs to travel a distance of 0.77 times the radius, and so will get to the moat just before the monster arrives, and can safely jump.

**Solution:** It is possible for Neville to escape.

Except if Neville really is Not That Bright he might not be able to work out a strategy to escape.

]]>I wrote a *MiniZinc* model to express the constraints, and then ran it using the **minizinc.py** library so I could format the output using Python.

The whole thing runs in 344ms.

from enigma import printf from minizinc import (MiniZinc, enum) # the minizinc model p = MiniZinc(f""" {enum("ABCDE", "Name")}; {enum(["dogs", "cats", "xpets", "xpairs"], "Col")}; % decision matrix array [Name, Col] of var 0..5: x; % no extra legs without extra pets constraint forall (i in Name) ((x[i, xpairs] > 0) -> (x[i, xpets] > 0)); % totals (total pets = 10; total legs = 15 pairs) constraint sum (i in Name) (x[i, dogs] + x[i, cats] + x[i, xpets]) = 10; constraint sum (i in Name) (2 * (x[i, dogs] + x[i, cats]) + x[i, xpairs]) = 15; % dogs and cats are the only quadrupeds constraint forall (i in Name) (not (x[i, xpets] = 1 /\ x[i, xpairs] = 2)); % there are more dogs than cats constraint sum (i in Name) (x[i, dogs]) > sum (i in Name) (x[i, cats]); % there are exactly 2 dog owners constraint sum (i in Name) (x[i, dogs] > 0) = 2; % each dog owner has at least 1 cat constraint forall (i in Name) ((x[i, dogs] > 0) -> (x[i, cats] > 0)); % A has 1 budgie & no dogs constraint x[A, xpets] >= 1 /\ x[A, xpairs] >= 1 /\ x[A, dogs] = 0; % B has 2 extra pairs of legs constraint 2 * (x[B, dogs] + x[B, cats]) + x[B, xpairs] = 2; % C & D have the same number of pets; and the same number of legs constraint x[C, dogs] + x[C, cats] + x[C, xpets] = x[D, dogs] + x[D, cats] + x[D, xpets]; constraint 2 * (x[C, dogs] + x[C, cats]) + x[C, xpairs] = 2 * (x[D, dogs] + x[D, cats]) + x[D, xpairs]; % E has multiple pets constraint x[E, dogs] + x[E, cats] + x[E, xpets] >= 2; solve satisfy; """) # solve the model for [x] in p.solve(result='x'): for (name, (dogs, cats, xpets, xpairs)) in zip("ABCDE", x): n = dogs + cats + xpets xlegs = 2 * xpairs legs = 4 * (dogs + cats) + xlegs printf("{name}: {n} pets, {legs} legs [{dogs} dogs; {cats} cats; {xpets} other pets; {xlegs} other legs]") printf()

**Solution:**

A has 1 budgie (= 1 pet; 2 legs)

B has 1 cat (= 1 pet; 4 legs)

C has 2 dogs, 1 cat (= 3 pets; 12 legs)

D has 2 dogs, 1 cat (= 3 pets; 12 legs)

E has 2 pets with no legs (= 2 pets, 0 legs)

So we can’t say for sure what pets E has, but they have no legs and are attempting to following him upstairs. So probably not fish, but they could be snakes.

]]>Hi Jim

I note the puzzle does say they sketched the lines on the diagram, not on the plot, which is what I was thinking. So I agree that makes the problem fairly simple.

I should have tried to solve the puzzle in NS and not the one in my head.

]]>@Mike: The puzzle says they sketched the lines *on the diagram*, so I think that would be fairly easy to do.

Although equipped with some string and pegs I think it would also be relatively straightforward to do on the ground too.

]]>I haven’t seen the official solution. I have to confess this puzzle totally defeated me.

The problem with the above solution is determining the positions of the posts. Practically, if you stand at one corner of the plot and look along to the opposite corner, you could get someone to mark a short line along that line about where the centre is, by calling out instructions. Then repeat that with other pair of corners. Where the 2 lines cross is where the post goes.

That works for Laura’s solution. For Kate’s you would have to mark the points on the edge of the lawn where the edges of the vegetable plot extended meet the edges of the lawn and use those as the ‘corner points’ as above.

]]>**Run:** [ @replit ]

from enigma import (is_square_p, is_prime, printf) def solve(k=1, ds=[], ws=[]): (D, W) = (len(ds), len(ws)) # are we done? if D > W and sum(ds) == sum(ws) and ds[-1] > ws[-1]: yield (ds, ws) if D < 16 and W < 16: # consider winners of this frame if not is_square_p(k): yield from solve(k + 1, ds, ws + [k]) if not is_prime(k): yield from solve(k + 1, ds + [k], ws) for (ds, ws) in solve(): (D, W) = (len(ds), len(ws)) printf("D = {D} {ds}; W = {W} {ws}")

**Solution:** D won 14 frames. W won 13 frames. The penultimate frame was won by W.

Here are the frame numbers won in the 2 possible scenarios:

D = [1, 4, 6, 8, 9, 10, 12, 14, 15, 16, 20, 22, 25, 27]; W = [2, 3, 5, 7, 11, 13, 17, 18, 19, 21, 23, 24, 26]

D = [1, 4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 24, 25, 27]; W = [2, 3, 5, 7, 11, 13, 17, 19, 20, 21, 22, 23, 26]

Which are the same except the winners of frames 18 & 24 and 20 & 22 are swapped.

In each case each players frames sum to 189.

]]>The following Python program plays the game with each player preferring to make a move that guarantees a win (if possible).

This Python program runs in 64ms. (Internal runtime is 150µs).

from enigma import (irange, cache, printf) # play a game with gaps a, b (such that a <= b) @cache def play(a, b, v=0): if a == 1 and b == 1: # lose return -1 else: r = -1 # worst case is a loss # divide one of the gaps for g in {a, b}: g -= 1 for x in irange(0, g // 2): k = play(x, g - x) if k == -1: if v: printf("({a}, {b}) -> ({x}, {y})", y=g - x) return 1 # a win if k == 0: r = 0 # draw return r play(19, 19, v=1)

**Solution:** The first player can guarantee a win by moving one of the outer stones next to one of the other stones. i.e. (19, 19) → (0, 18).

The second player must then divide the remaining (even) 18 gap by inserting a stone into it, leaving 17 spaces. However these 17 spaces are divided, either a single gap of 17 or an odd + even gap, the first player can then move a stone to produce a single even gap, which will eventually reach 0 giving a win for the first player.

For the longest possible game, each player reduces the single gap by 1, but the player that is always producing even gaps will win.

]]>The size 6 grid is solved in 5.3 seconds, the size 7 grid in 22 seconds, the size 8 grid in 44 seconds, the size 9 grid in 4 minutes, and the size 10 grid in 12 hours (using the `highs`

solver).

from enigma import (namedtuple, irange, subsets, ordered, cproduct, repeat, union, arg, printf) from utils_mzn import hitting_set # edge length of the triangular grid N = arg(6, 0, int) # a point has x and y values P = namedtuple("P", "x y") # points are non-negative (x, y) s.t. x + y <= N pts = set() for y in irange(0, N): pts.update(P(x, y) for x in irange(0, N - y)) # make a set of matchsticks from quad edges # each matchstick is of the form ((ax, ay), (bx, by)) def sticks(edges): ss = list() for (a, b) in edges: if a.x == b.x: ss.extend((P(a.x, y), P(a.x, y + 1)) for y in irange(a.y, b.y - 1)) elif a.y == b.y: ss.extend((P(x, a.y), P(x + 1, a.y)) for x in irange(a.x, b.x - 1)) elif a.x + a.y == b.x + b.y: ss.extend((P(a.x - k - 1, a.y + k + 1), P(a.x - k, a.y + k)) for k in irange(0, a.x - b.x - 1)) return ss # rotate a tuple of sticks rot = lambda ss: tuple(ordered(P(a.y, N - a.y - a.x), P(b.y, N - b.y - b.x)) for (a, b) in ss) # find quads quads = set() # choose a base level for the quadrilateral for y1 in irange(0, N - 2): # choose positions for the base points for (ax, bx) in subsets(irange(0, N - y1), size=2): # choose a top level for y2 in irange(y1 + 1, N - 1): k = y2 - y1 # choose position for the top points for (px, qx) in cproduct([[ax - k, ax], [bx - k, bx]]): if px < qx and P(px, y2) in pts and P(qx, y2) in pts: # find the matchsticks involved from the edges of the quadrilateral quad = sticks([ (P(ax, y1), P(bx, y1)), # base (P(px, y2), P(qx, y2)), # top (P(ax, y1), P(px, y2)), # left (P(bx, y1), P(qx, y2)), # right ]) # record all 3 rotations of the quadrilateral for qs in repeat(rot, quad, 2): quads.add(ordered(*qs)) # find triangles tris = set() # choose a base level for the triangle for y in irange(0, N - 1): # choose positions for the base points for (ax, bx) in subsets(irange(0, N - y), size=2): k = bx - ax # find matchsticks involved from the edges of the triangle tri = sticks([ (P(ax, y), P(bx, y)), # base (P(ax, y), P(ax, y + k)), # left (P(bx, y), P(bx - k, y + k)), # right ]) tris.add(ordered(*tri)) if not (k > y): # and the inverted triangle tri = sticks([ (P(ax, y), P(bx, y)), # top (P(ax + k, y - k), P(ax, y)), # left (P(bx, y - k), P(bx, y)), # right ]) tris.add(ordered(*tri)) printf("[N={N} -> {t} tris, {q} quads]", t=len(tris), q=len(quads)) # find a minimum hitting set hs = hitting_set(union([tris, quads]), solver="minizinc --solver highs") printf("minimum hitting set size {n}", n=len(hs))

**Solution:** The smallest number of matches required to spoil all quadrilaterals and triangles is 29.

]]>t = tris; q = quads; s = spoilers N t q s [highs ] 1: 1 0 1 [ 188ms] 2: 5 6 4 [ 194ms] 3: 13 33 8 [ 222ms] 4: 27 102 13 [ 259ms] 5: 48 243 20 [ 454ms] 6: 78 492 29 [ 3.45s] 7: 118 894 39 [ 12.6s] 8: 170 1500 50 [ 31.8s] 9: 235 2370 63 [ 3m23s] 10: 315 3570 78 [11h42m]

I put the following code in the file **utils_mzn.py**:

from enigma import (union, sprintf as f, join) from minizinc import MiniZinc # find a minimum hitting set def hitting_set(ss, solver="minizinc", verbose=0): # find elements vs = sorted(union(ss)) # map elements to indices (1-indexed) m = dict((v, j) for (j, v) in enumerate(vs, start=1)) # construct the model model = [ # decision variables: x[j] = 1 if element j is in the hitting set f("array [1..{n}] of var 0..1: x;", n=len(vs)) ] + [ # each set must be hit f("constraint {sum} > 0;", sum=join((f("x[{j}]", j=m[v]) for v in s), sep=" + ")) for s in ss ] + [ # minimise the size of the hitting set "solve minimize(sum(x));" ] # execute the model (with additional arguments) for s in MiniZinc(model, solver=solver, verbose=verbose).solve(): xs = s['x'] # return the elements of the hitting set return set(vs[j] for (j, x) in enumerate(xs) if x == 1)

And I wrote neater code to generate the quadrilaterals.

So here is a complete program to solve the puzzle using *MiniZinc*.

I found the `highs`

solver performed well (although it will only produce single answers, but in this case we only need one example of a minimum hitting set). For the size 6 grid it finds a solution in 3.8 seconds, and is able to run the size 7 grid in 23 seconds, the size 8 grid in 3 minutes, and the size 9 grid in 40 minutes.

The `scip`

solver performs better though. For the size 6 grid it finds a solution in 2.3 seconds, the size 7 grid takes 17.9 seconds, the size 8 grid takes 1 minute 39 seconds, the size 9 grid takes 11 minutes, and the size 10 grid takes 6 hours, 37 minutes.

from enigma import (namedtuple, irange, subsets, ordered, cproduct, repeat, arg, printf) from utils_mzn import hitting_set # edge length of the triangular grid N = arg(6, 0, int) # a point has x and y values P = namedtuple("P", "x y") # points are non-negative (x, y) s.t. x + y <= N pts = set() for y in irange(0, N): pts.update(P(x, y) for x in irange(0, N - y)) # make a set of matchsticks from quad edges # each matchstick is of the form ((ax, ay), (bx, by)) def sticks(edges): ss = list() for (a, b) in edges: if a.x == b.x: ss.extend((P(a.x, y), P(a.x, y + 1)) for y in irange(a.y, b.y - 1)) elif a.y == b.y: ss.extend((P(x, a.y), P(x + 1, a.y)) for x in irange(a.x, b.x - 1)) elif a.x + a.y == b.x + b.y: ss.extend((P(a.x - k - 1, a.y + k + 1), P(a.x - k, a.y + k)) for k in irange(0, a.x - b.x - 1)) return ss # rotate a tuple of sticks rot = lambda ss: tuple(ordered(P(a.y, N - a.y - a.x), P(b.y, N - b.y - b.x)) for (a, b) in ss) # find quads quads = set() # choose a base level for the quadrilateral for y1 in irange(0, N - 2): # choose positions for the base points for (ax, bx) in subsets(irange(0, N - y1), size=2): # choose a top level for y2 in irange(y1 + 1, N - 1): k = y2 - y1 # choose position for the top points for (px, qx) in cproduct([[ax - k, ax], [bx - k, bx]]): if px < qx and P(px, y2) in pts and P(qx, y2) in pts: # find the matchsticks involved from the edges of the quadrilateral quad = sticks([ (P(ax, y1), P(bx, y1)), # base (P(px, y2), P(qx, y2)), # top (P(ax, y1), P(px, y2)), # left (P(bx, y1), P(qx, y2)), # right ]) # record all 3 rotations of the quadrilateral for qs in repeat(rot, quad, 2): quads.add(ordered(*qs)) printf("[N={N} -> {q} quads]", q=len(quads)) # find a minimum hitting set hs = hitting_set(quads, solver="minizinc --solver scip") printf("minimum hitting set size {n}", n=len(hs))

**Solution:** The smallest number of matches that can be removed to spoil all quadrilaterals is 20.

]]>q = quads; s = spoilers N q s [scip ] [highs ] 1: 0 0 [ 187ms] 2: 6 2 [ 191ms] 3: 33 5 [ 205ms] 4: 102 9 [ 253ms] 5: 243 14 [ 691ms] [ 703ms] 6: 492 20 [ 2.32s] [ 3.84s] 7: 894 27 [ 17.9s] [ 22.8s] 8: 1500 35 [ 1m39s] [ 2m48s] 9: 2370 44 [10m53s] [40m31s] 10: 3570 54 [ 6h37m]

Nice unicode skills!

]]>So, assuming Mabel does not think the town she lives in is a horrible dump, we are looking for the second case with 2 vertices of odd degree.

We can start at one of these vertices, and look for other vertices that have have exactly possible paths that don’t involve travel N, E, or NE.

This Python program runs in 62ms. (Internal runtime is 1.2ms).

**Run:** [ @replit ]

from enigma import (cproduct, icount_exactly, printf) # the adjacency matrix adj = dict( A=dict(E='B', S='F'), B=dict(W='A', E='C', S='G', SW='F'), C=dict(W='B', E='D', S='H', SW='G'), D=dict(W='C', E='E', S='I'), E=dict(W='D', S='J'), F=dict(N='A', E='G', S='K', NE='B'), G=dict(N='B', W='F', S='L', NE='C'), H=dict(N='C', E='I', S='M', SW='L'), I=dict(N='D', W='H', E='J', S='N'), J=dict(N='E', W='I', S='O', SW='N'), K=dict(N='F', S='P'), L=dict(N='G', E='M', S='Q', NE='H'), M=dict(N='H', W='L', E='N', S='R'), N=dict(N='I', W='M', E='O', S='S', NE='J', SW='R'), O=dict(N='J', W='N', S='T'), P=dict(N='K', E='Q'), Q=dict(N='L', W='P', E='R', S='U'), R=dict(N='M', W='Q', S='V', NE='N'), S=dict(N='N', E='T', S='W', SW='V'), T=dict(N='O', W='S', S='X', SW='W'), U=dict(N='Q', E='V'), V=dict(N='R', W='U', E='W', NE='S'), W=dict(N='S', W='V', E='X', NE='T'), X=dict(N='T', W='W'), ) # find nodes of odd order odds = list(k for (k, vs) in adj.items() if len(vs.keys()) % 2 == 1) assert len(odds) == 2 # generate paths from <x> to <y> excluding directions <xs> def paths(x, y, xs, ss=[]): # are we there yet? if x == y: yield ss else: # move in one of the permitted directions for (k, z) in adj[x].items(): if k not in xs and z not in ss: yield from paths(z, y, xs, ss + [z]) # consider possible start/end points for (s, t) in cproduct([odds, adj.keys()]): if icount_exactly(paths(s, t, {'N', 'E', 'NE'}, [s]), n=8): printf("{s} -> {t}")

**Solution:** They live at **O**, and plan to holiday at **V**.

**O** and **D** are the only vertices with odd degree, so **D** must the “horrible **D**ump”.

⬜️⬜️🟥⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️

⬜️⬜️🟥⬜️⬜️⬜️⬜️⬜️⬜️🟥🟥🟥⬜️⬜️

⬜️🟩🟥🟥⬜️⬜️⬜️⬜️🟩🟥⬜️🟦⬜️⬜️

⬜️🟩⬜️🟦🟦🟦⬜️⬜️🟩⬜️⬜️🟦⬜️⬜️

⬜️🟩🟩🟦⬜️⬜️⬜️⬜️🟩🟩🟦🟦⬜️⬜️

⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️⬜️ ]]>

Assuming that the house number has several digits and using Πx to represent the product of all the digits and ∑x to represent the sum of all the digits, we have:

Πx = 5∑x

Since each digit can take a natural number value between 0 and 9, we can derive:

– ① There can be no digit that is equal to 0.

If a digit were equal to 0, then 5∑x would be equal to 0, and all the digits would have to be 0, which would be a contradiction.

– ② There must be a digit that is equal to 5.

Since the right-hand side of the equation has a factor of 5, therefore, there must be a digit on the left-hand side that is a multiple of 5, which implies that this digit must be equal to 5.

– ③ The number of digits must be greater than 1.

If there were a single-digit house number that satisfies the equation, denoted by a, we would have:

a = 5a → a = 0

which contradicts statement ①.

– ④ The number of digits must be greater than 2.

If there were a two-digit house number that satisfies the equation, by statement ②, one digit would be equal to 5. Assuming the other digit is a, we have:

5a = 5(5 + a) → 0 = 5

which is a contradiction.

– ⑤ Assuming there is a three-digit house number that satisfies the equation, by statement ②, one digit would be equal to 5. Assuming the other two digits are a and b, we have:

5ab = 5(5 + a + b) → a = (5 + b)/(b – 1)

Trying values of b starting from 1, the smallest solution is `b = 2`, which gives `a = 7`.

Therefore, the smallest house number that satisfies the equation is: `257`.

– ⑥ Since only one house number on the street satisfies the equation, it must be the smallest possible solution, which we found to be `257` in statement ⑤.

]]>In any case, liquid-crystal displays are not illuminated: when a segment is activated it goes dark. It’s clear that ‘Susan Denham’ has never seen one of these new-fangled devices but knows of them only by hearsay. ]]>

The sets of digits were are interested in form a number that is not divisible by any of constituent digits, so we could simply exclude 1 from the possible set of digits, as it can not appear in any answer. It is also mentioned that at least 3 different digits appear, so we exclude any shorter sequences.

This Python program runs in 60ms. (Internal runtime is 196µs).

**Run:** [ @replit ]

from enigma import (nconcat, is_prime, printf) # map digits to illuminated segments, arranged as: # 0 # 1 2 # 3 # 4 5 # 6 segments = dict((k, frozenset(v)) for (k, v) in enumerate([ (0, 1, 2, 4, 5, 6), # 0 (2, 5), # 1 (0, 2, 3, 4, 6), # 2 (0, 2, 3, 5, 6), # 3 (1, 2, 3, 5), # 4 (0, 1, 3, 5, 6), # 5 (1, 3, 4, 5, 6), # 6 - note: doesn't use 0 (0, 2, 5), # 7 (0, 1, 2, 3, 4, 5, 6), # 8 (0, 1, 2, 3, 5, 6), # 9 ])) # check for subsets (is x a subset of y) issubset = lambda x, y, strict=0: (x < y if strict else x <= y) # find chains of digits where each is a subset of the previous def solve(ds): yield ds segs = segments[ds[-1]] for (k, vs) in segments.items(): if issubset(vs, segs, strict=1): yield from solve(ds + [k]) # choose a start digit for k in segments.keys(): for ds in solve([k]): n = nconcat(ds) if len(ds) > 2 and 1 not in ds and is_prime(n): printf("{ds} -> {n}")

**Solution:** The number was: 937.

If we just require the resulting number to be prime there are many solutions, including the 5-digit number: 89371.

]]>produced a program which ran correctly, It stated on its

blog, however, that it found three answers (all of which

were incorrect) Perhaps it is the briefing line with

five asterisks which is causing the ambiguity in the original

teaser description.

The code ChatGPT produces code with very long variable

names and it was produced by ChatGPT exactly as shown

below.

''' AMENDED BRIEF FOR PROGRAM ABCD is exactly divisible by 7. All four digits are distinct. The 3-digit numbers formed as ABC and BCD are also exactly divisible by 7. The sum of the digits (A + B + C + D) is not divisible by 7. The sum of (A + B + C + D) is a two digit number. ***** The sum of these two digits of the two digit number is exactly divisible by 7. ***** Produce a Python program and show the output of this program ''' for A in range(1, 10): for B in range(0, 10): if B == A: continue for C in range(0, 10): if C == A or C == B: continue for D in range(0, 10): if D == A or D == B or D == C: continue ABC = A * 100 + B * 10 + C BCD = B * 100 + C * 10 + D ABC_divisible_by_7 = ABC % 7 == 0 BCD_divisible_by_7 = BCD % 7 == 0 ABCD_divisible_by_7 = (ABC * 10 + D) % 7 == 0 sum_ABCD_not_divisible_by_7 = (A + B + C + D) % 7 != 0 sum_ABCD_two_digits = 10 <= A + B + C + D <= 99 sum_ABCD_two_digits_divisible_by_7 = (A + B + C + D) // 10 + (A + B + C + D) % 10 == 7 if (ABC_divisible_by_7 and BCD_divisible_by_7 and ABCD_divisible_by_7 and sum_ABCD_not_divisible_by_7 and sum_ABCD_two_digits and sum_ABCD_two_digits_divisible_by_7): print(f"{A}{B}{C}{D}") # Actual output from its own Python code is correct # 7630 ''' ChatGPT outputs three incorrect answers when asked to output its own code: 1963 7852 9873 ''']]>

@GeoffR: You obviously had more luck (or patience) with ChatGPT than I did.

When I presented it with the problem (as originally worded) and asked it to write a Python program to solve the puzzle, then it did produce viable code.

But when I asked it what the answer to the puzzle was, it produced a set of fourteen 4-digit numbers that it claimed were solutions, but none of them were correct.

]]>It took some effort to clarify the exact brief (having the benefit of Jim’s answer).

]]>

Brief to ChatGPT for Puzzle 215For months between April 2023 and December 2023, tell me when days and months have the same numerical value. The April day should be a Tuesday and all other months with the same day and date numerical values should be a Tuesday. List the numerical day, the descriptive month and the descriptive day of all days in 2023 which satisfy the specified conditions.

ChatGPT answer (after some clarifications)Sure, here is the list of all days in the months between April 2023 and December 2023 when the day and month have the same numerical value, with the additional condition that the April day should be a Tuesday and all other months with the same day and date numerical values should be a Tuesday:

April 4th, 2023 (Tuesday)

June 6th, 2023 (Tuesday)

August 8th, 2023 (Tuesday)

October 10th, 2023 (Tuesday)

December 12th, 2023 (Tuesday)I hope this list is helpful.

Let me know if you have any further questions.

If we remember the number of days in a month without looking at a calendar (Apr = 30, May = 31, Jun = 30, Jul = 31, Aug = 31, Sep = 30, Oct = 31, Nov = 30), then we can calculate the day of the week for the dates we are interested in:

4th Apr = Tuesday

+(30+1) days, 31 mod 7 = 3

⇒ 5th May = Friday

+(31+1) days, 32 mod 7 = 4

⇒ 6th June = Tuesday [*]

+(30+1) days, 31 mod 7 = 3

⇒ 7th July = Friday

+(31+1) days, 32 mod 7 = 4

⇒ 8th August = Tuesday [*]

+(31+1) days, 32 mod 7 = 4

⇒ 9th September = Saturday

+(30+1) days, 31 mod 7 = 3

⇒ 10th October = Tuesday [*]

+(31+1) days, 32 mod 7 = 4

⇒ 11th November = Saturday

+(30+1) days, 31 mod 7 = 3

⇒ 12th December = Tuesday [*]

**Solution:** There are 4 more Trivia Tuesdays in 2023 where the day and month number are the same.

They are: 6th June; 8th August; 10th October; 12th December.

]]>It looks like the published answer is 7630 [link].

]]>**FINAL SOLUTION BY ChatGPT**

Given:

ABCD is exactly divisible by 7.

All four digits are distinct.

The 3-digit numbers formed as ABC and BCD are also exactly divisible by 7.

The sum of the digits (A + B + C + D) is not divisible by 7.

The sum of (A + B + C + D) is a two digit number.

The sum of these two digits of the two digit number is exactly divisible by 7.

]]>To solve this problem, we will use the following steps:

Step 1: Find all possible values of ABCD that are divisible by 7.

We know that ABCD is divisible by 7, and all four digits are distinct. Since there are only 5040 possible four-digit numbers with distinct digits, we can generate all of them and check for divisibility by 7.

After generating all possible four-digit numbers with distinct digits, we find that there are only two possible values of ABCD that are divisible by 7: 2590 and 7630.

Step 2: Check which of the two possible values of ABCD satisfy the other given conditions.

For each of the two possible values of ABCD, we check if the 3-digit numbers formed as ABC and BCD are also divisible by 7.

For 2590, we have ABC = 259 and BCD = 590. Both ABC and BCD are divisible by 7, so this value of ABCD satisfies the second condition.

For 7630, we have ABC = 763 and BCD = 630. Both ABC and BCD are divisible by 7, so this value of ABCD also satisfies the second condition.

Step 3: Check which of the two possible values of ABCD satisfy the remaining conditions.

For each of the two possible values of ABCD, we check if the sum of the digits (A + B + C + D) is not divisible by 7, and if it is a two-digit number whose digits sum to a multiple of 7.

For 2590, we have A + B + C + D = 16, which is not divisible by 7. The digits of the two-digit number (A + B + C + D) sum to 7, which is a multiple of 7.

For 7630, we have A + B + C + D = 16, which is not divisible by 7. The digits of the two-digit number (A + B + C + D) sum to 7, which is a multiple of 7.

Step 4: Check if all four digits are distinct for the solution(s) that satisfy all conditions.

For the value of ABCD = 2590, we have A = 2, B = 5, C = 9, and D = 0, which are all distinct digits.

For the value of ABCD = 7630, we have A = 7, B = 6, C = 3, and D = 0, which are all distinct digits.

Therefore, the solutions to the puzzle are ABCD = 2590 and ABCD = 7630.

We can identify the players by the number of steps they take (+3 and +4). I look at games with an increasing number of moves, as defensive play could continue indefinitely, with the players just moving back and forth between two positions.

This Python program runs in 61ms. (Internal runtime is 768µs).

**Run:** [ @replit ]

from enigma import (grid_adjacency, irange, inf, union, cache, printf) # we can construct the adjacency matrix from the following grid: # # [00] [01] [02] 03 04 [05] [06] [07] # [08] [09] 10 11 12 13 [14] [15] # [16] 17 18 19 20 21 22 [23] # 24 25 26 27 28 29 30 31 # [32] 33 34 35 36 37 38 [39] # [40] [41] 42 43 44 45 [46] [47] # [48] [49] [50] 51 52 [53] [54] [55] # # the original positions 1 and 32 become 24 and 31 (p1, p32) = (24, 31) xs = {0, 1, 2, 5, 6, 7, 8, 9, 14, 15, 16, 23, 32, 39, 40, 41, 46, 47, 48, 49, 50, 53, 54, 55} adj = dict((k, vs.difference(xs)) for (k, vs) in enumerate(grid_adjacency(8, 7, fn=set)) if k not in xs) # find nodes that can be reached in <k> moves from <src> @cache def move(k, src): if k == 0: return {src} if k > 0: return union(adj[x] for x in move(k - 1, src)) # play a game of (up to) n moves; p1, p2 = position 1, 2; k1, k2 = moves 1, 2 def play(n, p1, p2, k1, k2): if n == 0: return 0 # moves for player 1 p1s = move(k1, p1) # can p1 land on p2? if p2 in p1s: return k1 # consider up to n-1 more moves r = k2 # worst case is a loss for p in p1s: x = play(n - 1, p2, p, k2, k1) if x == k1: return k1 # a win is best if x == 0: r = 0 # then a draw return r # look for a number of moves that guarantee a win for one of the players def check(p1, p2, k1, k2): for n in irange(1, inf): r = play(n, p1, p2, k1, k2) if r != 0: printf("({k1:+}, {k2:+}) -> win for {r:+}") break # Gladiator (32, +3) vs Retiarius (1, +4) check(p32, p1, +3, +4) # Gladiator moves first check(p1, p32, +4, +3) # Retiarius moves first

**Solution:** Whichever player takes the first turn can guarantee a win.

If +4 moves first from 1 to 12 (or 14), then +3 can only move from 32 to one of (20, 25, 27, 30), and all of these are +4 moves from 12.

And if +3 moves first from 32 to 25 (or 27) and then to 13, then the squares reachable from 13 in +3 moves are exactly those squares reachable from 1 in +8 moves (and 25 is not reachable from 1 in +4 moves).

]]>I see what you mean. Fortunately each interpretation gives rise to a unique answer (although different in each case), so when the solution is published we should be able to determine what the setter had in mind.

To find the answer using this interpretation we can replace line 17 with:

"div7(dsum(ABCD) + dsum(dsum(ABCD)))"]]>

The digit sum of 7630 is 16, and if we add to it 1 + 6 we get 23,

which is not an integer multiple of 7.

The solution based on my understanding of the phrase is 7350:

digit sum 15, which when increased by 1 + 5 gives 21.

Puzzle setters should say what they mean! ]]>

This Python program runs in 63ms. (Internal runtime is 3.1ms).

**Run:** [ @replit ]

from enigma import (cproduct, intersect, diff, unzip, uniq, printf) # the 10 envelopes envs = [ ("David", "Davis", "Rose Cottage", "Ely"), ("Brian", "Clark", "The Meadow", "Carlisle"), ("Ed.", "Andrews", "Riverside", "Bradford"), ("Alan", "Eyres", "Waters' Edge", "Altrincham"), ("Ed.", "Clark", "Belle View", "Carlisle"), ("David", "Andrews", "Waters' Edge", "Ely"), ("Clive", "Brown", "Belle View", "Doncaster"), ("Brian", "Eyres", "Riverside", "Doncaster"), ("Clive", "Clark", "Riverside", "Ely"), ("Ed.", "Davis", "Rose Cottage", "Carlisle"), ] # solve envs for the remaining groups gs def solve(envs, gs, ss=[]): # are we done? if not gs[0]: yield ss else: # find the first component n = gs[0][0] # choose the remaining components for rs in cproduct(gs[1:]): cs = (n,) + rs # check each envelope contains at most one of these components if all(len(intersect([cs, xs])) < 2 for xs in envs): # solve for the remaining components yield from solve(envs, list(diff(xs, {x}) for (xs, x) in zip(gs, cs)), ss + [cs]) # group the components together gs = list(list(uniq(xs)) for xs in unzip(envs)) # find solutions for ss in solve(envs, gs): for (i, (f, s, h, t)) in enumerate(ss, start=1): printf("{i}: {f} {s}, {h}, {t}") printf()

**Solution:** Brian Andrews, Belle View, Altrincham.

The correct addresses are:

]]>Brian Andrews, Belle View, Altrincham

David Brown, Riverside, Carlisle

Alan Clark, Rose Cottage, Doncaster

Clive Davis, Waters’ Edge, Bradford

Ed. Eyres, The Meadow, Ely

I found there were 11 candidate solutions before the digit sum conditions are applied (all of the form 7xx0). None of them have a digit sum divisible by 7, so only the final condition narrows these down to a single value.

]]>`SubstitutedExpression`

]] solver from the The following run file executes in 68ms. (Internal run time of the generated program is 329µs).

**Run:** [ @replit ]

#! python3 -m enigma -r SubstitutedExpression # check a number is divisible by 7 --code="div7 = lambda n: n % 7 == 0" # the entire number is divisible by 7 "div7(ABCD)" # as are just the first 3 and last 3 digits "div7(ABC)" "div7(BCD)" # the digit sum is not, but digit sum of the digit sum is "not div7(dsum(ABCD))" "div7(dsum(dsum(ABCD)))"

**Solution:** The code is: 7630.

This Python program constructs possible meals (one dish from each course) by price, and then allocates appropriate meals to each of the three participants, such that P and G has no dish in common, and there is a single candidate poisonous dish that is eaten by J alone.

We then look for situations where if we knew which dishes were eaten by P and G (although not necessarily who ate what), we could deduce the poisoned dish. From these candidates we select those that include the dish BE.

This Python program runs in 64ms. (Internal runtime is 470µs).

**Run:** [ @replit ]

from enigma import (group, cproduct, union, diff, singleton, ordered, filter_unique, item, joinf, printf) # courses and prices courses = [ dict(PT=1, HT=2, CC=3), dict(BC=4, CT=5, TC=6), dict(FS=2, MG=3, BE=4) ] # group a full meal by its price price = lambda ks: sum(d[k] for (d, k) in zip(courses, ks)) g = group(cproduct(d.keys() for d in courses), by=price) # generate candidate dishes, and potential poisonous dishes # return (P+G, poisoned, J, P, G) def generate(): # choose the meals for (J, P, G) in cproduct([g[8], g[9], g[10]]): # P and G had no dishes in common PG = union([P, G]) if len(PG) != 6: continue # can we identify the poisonous dish? # (i.e. a dish eaten by J alone) xxx = singleton(diff(J, PG)) if xxx: yield (ordered(*PG), xxx, J, P, G) # if we knew what P and G had eaten (item 0) we could deduce the poisoned dish (item 1) ss = filter_unique(generate(), item(0), item(1)).unique # now we can identify the poisoned dish knowing that someone had BE fmt = joinf(sep=" ", enc="()") for (_, xxx, J, P, G) in ss: if 'BE' in union([J, P, G]): printf("{xxx} -> J={J} P={P} G={G}", J=fmt(J), P=fmt(P), G=fmt(G))

**Solution:** The poison dish was: Fromage Souriciere.

We have the following possible orders:

Jones = PT, CT, FS / HT, BC, FS [8s]

→ Polly = PT, BC, BE [9s]; Gladys = HT, CT, MG [10s]

→ Polly = PT, CT, MG [9s]; Gladys = HT, BC, BE [10s]

→ Polly = HT, BC, MG [9s]; Gladys = PT, CT, BE [10s]

The dishes are (thanks to Hugh Casement for the translations):

]]>PT = tepid soup

HT = beans on toast

CC = prawn cocktailBC = bubble and squeak

CT = toad in the hole

TC = pig trottersFS = mousetrap cheese

MG = Welsh rarebit (“rare bit” = “singular piece”)

BE = Scotch woodcock

We first note that the puzzle contains the digits 4, 7, 8, so these cannot be the misbehaving digit.

The larger number (containing digits 7 and 8) has at least 2 digits, so the misbehaving digit must be 3 or more.

So the possibilities for the misbehaving digit are narrowed down to: 3, 5, 6, 9.

This Python program runs in 59ms. (Internal runtime is 679us).

**Run:** [ @replit ]

from enigma import (irange, nconcat, subsets, update, sq, cb, nsplit, printf) # does number n contain digit d? contains = lambda n, d: d in nsplit(n) # construct numbers of length a .. b by inserting extra digits d into ds # return (k, n), where n is a k-length number def number(a, b, d, ds, i=0): for k in irange(a, b): # construct the k-length number rs = [d] * k # and replace the existing digits for js in subsets(irange(k), size=len(ds)): yield (k, nconcat(update(rs, js, ds))) # consider the misbehaving digit for d in [3, 5, 6, 9]: # consider the number of digits in the larger number (containing 7 and 8) for (k, n) in number(2, d - 1, d, [7, 8]): # the square and cube cannot contain d if contains(sq(n), d) or contains(cb(n), d): continue # there is a smaller number that contains the digit 4 for (k_, n_) in number(1, k, d, [4]): if not (n_ < n): continue # whose square cannot be typed correctly, but whose cube can if not (contains(sq(n_), d) and not contains(cb(n_), d)): continue # output solution printf("d={d} -> {n_}, {n}")

**Solution:** The misbehaving digit is 6.

The first number (“4”) is actually 664:

The cube of 664 is 292754944, which *does not* contain the digit 6, so can be typed correctly.

And the square of 664 is 440896, which *does* contain the digit 6, so cannot be typed correctly.

The second (larger) number (“78”) is actually 768:

The cube of 768 is 452984832, which *does not* contain the digit 6, so can be typed correctly.

The square of 768 is 589824, which also *does not* contain the digit 6, so can also be typed correctly.

Apparently the setter intended the three devices may be in any mute state (apart from all unmuted).

We can adapt the program to solve this scenario by changing line 11:

# possible sources (some of the devices are muted) srcs = [(0, 0, 0), (0, 0, 1), (0, 1, 0), (1, 0, 0), (0, 1, 1), (1, 0, 1), (1, 1, 0)]

We then find a minimal sequence of length 7 that will resolve these situations in 1-7 presses:

% python3 puzzle-212.py (0, 1, 0, 2, 0, 1, 0) -> [5, 2, 6, 4, 1, 3, 7]]]>

If we place a point in the centre of a rectangular area, then any straight line passing through that point will divide the rectangle in half.

So this gives us a way to find a candidate for Laura’s fence. We place one post in the centre of the vegetable plot, and another in the centre of the entire plot, and then run the fence through both of them.

As the line goes through the centre of the entire plot each daughter gets an area that is half of the entire plot, and as it also goes through the centre of the vegetable plot each daughter gets an area that is half of the vegetable plot. As the area of the lawn is the area of the entire plot minus the area of the vegetable plot, each daughter gets half of the lawn.

For Kate we can divide just the lawn into 2 rectangular plots, and make line joining their centres. One obvious way is to use the small rectangle above the vegetable plot and the remaining large rectangle of lawn, but this will create a narrow “pinch point”. Another way is to extend the small rectangle horizontally to give a strip the full width of the plot, and have a narrower rectangular plot below.

]]>Hi Jim. You win! The two I missed were 2048 (2^11) and 8192 (2^13) I stopped at tenth powers. 4096 is 2^12, but also 4^6, 8^4, 16^3 and 64^2.

]]>It allocates scores for the won matches such that A and F tie for last place, and then determines the winners (and checks there are two of them). It then constructs pairings for each round, such that the given conditions apply.

It runs in 76ms. (Internal runtime is 11ms).

**Run:** [ @replit ]

from enigma import (subsets, union, tuples, singleton, map2str, join, sprintf, printf) # form the matches players = "ABCDEF" matches = set(x + y for (x, y) in subsets(players, size=2)) # fill out the semi-points draws = "AB AF BC BE CF DE DF EF".split() points = dict((k, 1) for k in draws) def get_points(a, b): if a == b: return 0 if a > b: return 2 - points[b + a] return points[a + b] # generate rounds for matches ms def rounds(ms, ps, ws, ss=[]): # are we done? if not ms: # everyone drew in at least 2 consecutive rounds for x in players: ds = list(i for (i, rs) in enumerate(ss) if any(x in m and ps[m] == 1 for m in rs)) if all(b - a > 1 for (a, b) in tuples(ds, 2)): break else: yield ss else: k = len(ss) + 1 # choose 3 disjoint matches for rs in subsets(ms, size=3): if len(union(rs)) != 6: continue # round 1: contains AF if k == 1 and 'AF' not in rs: continue # round 2: does not contain the winners if k == 2 and ws in rs: continue # every round had at least 1 draw if all(ps[x] != 1 for x in rs): continue # complete the following rounds yield from rounds(ms.difference(rs), ps, ws, ss + [sorted(rs)]) # fill out the remaining matches remaining = matches.difference(draws) for vs in subsets((0, 2), size=len(remaining), select='M'): points.update(zip(remaining, vs)) # calculate total points for each player t = dict((k, sum(get_points(k, x) for x in players)) for k in players) # A and F tied for bottom place z = min(t.values()) if not all((v == z) == (k in 'AF') for (k, v) in t.items()): continue # determine the winners a = max(t.values()) ws = join(k for k in players if t[k] == a) assert len(ws) == 2 # find rounds for ss in rounds(matches, points, ws): # output solution printf("matches = {ms}; winners = {ws}", ms=map2str(points), ws=join(ws, sep=" ")) for (i, rs) in enumerate(ss, start=1): printf(" round {i} = {rs}", rs=join((sprintf("{k} ({p})", p=points[k]) for k in rs), sep="; ")) # who did the winners play in the final round? for w in ws: x = singleton(m for m in ss[-1] if w in m).replace(w, '') printf("final round {w} played {x}") printf()

**Solution:** The winners are Colle and Dragon. In the final round Colle played French, and Dragon played Bishop.

There are 3 scenarios for the results of the matches, but they all lead to the same final results, and the pairings in each round.

The final results are:

C & D = 3 points

B & E = 2.5 points

A & F = 2 points

So the winners are C & D.

And the the rounds are:

]]>

Round 1:AF, BE, CD

Round 2:AB, CE, DF

Round 3:AC, BF, DE

Round 4:AD, BC, EF

Round 5:AE, BD, CF