Using a “greedy” strategy we can write down a collection of coins that seems like a reasonable maximum.

I also wrote a program that verifies that this is indeed the maximum possible by exhaustive search:

**Run:** [ @repl.it ]

from enigma import Accumulator, printf # generate collections of coins worth more than 100, but can't make 100 # ds = denominations # cs = coins available # ss = change that can be made def solve(ds, cs=[], ss=set([0])): if ds: # try adding an extra coin d = ds[0] s = set(d + x for x in ss) if 100 not in s: cs1 = cs + [d] t = sum(cs1) if t > 100: yield (t, cs1) yield from solve(ds, cs1, ss.union(s)) # try a different denomination yield from solve(ds[1:], cs, ss) # find the maximum amount of change r = Accumulator(fn=max) for (t, cs) in solve([50, 20, 10, 5, 2, 1]): r.accumulate_data(t, cs) printf("max = {r.value} {r.data}")

**Solution:** You have £1.43.

The amount is composed of: 1× 50p, 4× 20p, 1× 5p, 4× 2p.

Although you cannot make £1 exactly you can make £1.01, so you don’t lose out too badly.

]]>There are 26 visible primes in the original arrangement, and we know that the 2 block must be the non visible value. So the smallest possible set of visible primes are those in the range [3, 103], and this includes all the primes were are shown in the diagram.

If we sum the values of each of the faces the grand total is 6× the face sum, but also 3×(corner pieces) + 2×(edge pieces) + 1×(middle pieces).

We can minimise this value by choosing the 8 smallest primes for the corner pieces, the next 12 for the edge pieces and the remaining 6 for the middles:

corners = (3, 5, 7, 11, 13, 17, 19, 23), sum = 98

edges = (29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73), sum = 612

middles = (79, 83, 89, 97, 101, 103), sum = 552

The grand total is then 3×98 + 2×612 + 552 = 2070.

In which case the sum for each individual face is 2070/6 = 345.

So we need to find if it is possible to assemble a cube with these constraints.

I used a *MiniZinc* model to find out. Here it is wrapped using the **minizinc.py** wrapper:

from minizinc import MiniZinc, var from enigma import Primes, first, div, join as _join, printf # odd primes primes = Primes().range(3) # allocate the first 26 odd primes into corners, edges, middles corners = first(primes, 8) edges = first(primes, 12) middles = first(primes, 6) # calculate the target face sum T = div(3 * sum(corners) + 2 * sum(edges) + sum(middles), 6) # allocate the numbers in the following layers: # # [ a b c ] [ j k l ] [ r s t ] # [ d e f ] [ m 2 n ] [ u v w ] # [ g h i ] [ o p q ] [ x y z ] # cs = "acgirtxz" es = "bdfhjloqsuwy" ms = "ekmnpv" # change the default join separator join = lambda s, sep=", ": _join(s, sep=sep) # create the model m = MiniZinc(f""" include "globals.mzn"; % corners set of int: C = {{ {join(corners)} }}; {var("C", cs)}; constraint all_different([ {join(cs)} ]); % edges set of int: E = {{ {join(edges)} }}; {var("E", es)}; constraint all_different([ {join(es)} ]); % middles set of int: M = {{ {join(middles)} }}; {var("M", ms)}; constraint all_different([ {join(ms)} ]); % face sums constraint (a + b + c) + (d + e + f) + (g + h + i) = {T}; % top constraint (r + s + t) + (u + v + w) + (x + y + z) = {T}; % bottom constraint (a + d + g) + (j + m + o) + (r + u + x) = {T}; % left constraint (c + f + i) + (l + n + q) + (t + w + z) = {T}; % right constraint (g + h + i) + (o + p + q) + (x + y + z) = {T}; % front constraint (a + b + c) + (j + k + l) + (r + s + t) = {T}; % back solve satisfy; """) # find a solution for s in m.solve(result=list(cs + es + ms), solver="minizinc"): # output a solution printf("--") printf("[ {s.a:3d} {s.b:3d} {s.c:3d} ]") printf("[ {s.d:3d} {s.e:3d} {s.f:3d} ]") printf("[ {s.g:3d} {s.h:3d} {s.i:3d} ]") printf("") printf("[ {s.j:3d} {s.k:3d} {s.l:3d} ]") printf("[ {s.m:3d} { 2:3d} {s.n:3d} ]") printf("[ {s.o:3d} {s.p:3d} {s.q:3d} ]") printf("") printf("[ {s.r:3d} {s.s:3d} {s.t:3d} ]") printf("[ {s.u:3d} {s.v:3d} {s.w:3d} ]") printf("[ {s.x:3d} {s.y:3d} {s.z:3d} ]") printf("--")

**Solution:** When George bought the blocks the sum on each face was 345.

Here is a diagram of a possible arrangement of the blocks to give a sum of 345 on each face:

]]>`SubstitutedExpression()`

]] solver from the **Run:** [ @repl.it ]

#!/usr/bin/env python -m enigma -r SubstitutedExpression # the common difference d = TWO - ONE # 111th term is THREE "ONE + 110 * (TWO - ONE) = THREE" # common difference is odd "(TWO - ONE) % 2 = 1" # common difference is greater than SIX "TWO - ONE > SIX" # required answer --answer="SENT"]]>

Yes. Each pair of boots allows the wearer to travel the indicated distance in a single step.

]]>Since boot length step length are not directly related, I just assumed that this number alluded to speed. But it seems that ‘x league boots’ really means ‘x league steps’.

]]>@Paul: It’s normal in this type of puzzle to assume that numbers with leading zeros are not permitted. So in this example O, T, S would not be allowed to be zero. (I check this in my program at lines 8, 13, 28).

Assuming these restrictions you should be able to find the required solution (there are two possible values for SIX, but only one for ONE, TWO, THREE, SENT).

]]>@Brian: Assuming they all travelled in a direct line (or at least all took the same route), they must have travelled a different number of steps to end up in the situation described. So if they are travelling together the ones with the shorter step distance must be making more steps to give them all a roughly constant speed.

]]>I found lots of solutions {where 0 is o) and another 4 when o was 1. It’s ugly code ]]>

from enigma import irange, printf # possible distances for Magog (7n + 10) for d in irange(10, 399, step=7): # check distances for Gog and Og are integer steps if (d - 7) % 6 == 0 and (d - 9) % 5 == 0: printf("d={d}")

Or:

>>> [d for d in irange(10, 399, step=7) if d % 6 == 1 and d % 5 == 4] [199]

**Solution:** It is 199 leagues from the Mount to the Pig and Whistle

`SubstitutedExpression()`

]] solver to solve the alphametic sum and the [[ `Football()`

]] helper class to examine the scores. Both are from the It runs in 101ms.

**Run:** [ @repl.it ]

from enigma import SubstitutedExpression, Football, irange, subsets, update # the scoring system football = Football(points=dict(w=2, d=1)) # the alphametic sum (k and p are not used elsewhere, so assume k < p) p = SubstitutedExpression(["k + p = mm", "k < p"], symbols="kmp", verbose=0) # available digits digits = set(irange(0, 9)) # solve the sum (to get: k, p, m) for d in p.solve(): # solve the table (to get: d, x, y) for (ms, d2) in football.substituted_table(dict(played="??x", l="d??", points="y?y"), d=d): # choose values for g, h, r, t from the remaining digits for vs in subsets(digits.difference(d2.values()), size=4, select="P"): d3 = update(d2, "ghrt", vs) # determine the scores in each match for ss in football.substituted_table_goals("tyr", "hgt", ms, d=d3): # output solution football.output_matches(ms, ss, teams="ABC", d=d3)

**Solution:** The scores in the matches are: A vs B = 3-0; A vs C = 4-4; B vs C = 3-5.

The sum is: 5 + 6 = 11 (or: 6 + 5 = 11).

]]>Here is my program modified to allow aiming at any candle (lit or unlit).

from enigma import irange, inf, arg, printf N = arg(7, 0, int) printf("[N={N}]") # flip the bits at position (j - 1, j, j + 1) def flip(bs, j): bs = list(bs) for i in (j, (j - 1) % N, (j + 1) % N): bs[i] ^= 1 return bs # clear the bits in <bs> in <k> moves (or less) def clear(bs, k, ms=[]): if not any(bs): yield ms elif k > 0: for (j, _) in enumerate(bs): if not(ms) or j != ms[-1]: yield from clear(flip(bs, j), k - 1, ms + [j]) # solutions for <n> bits, by shortest number of moves def solve(n): for k in irange(1, inf): yield from clear([1] * n, k) # find the smallest number of moves for ms in solve(N): printf("{n} -> {ms}", n=len(ms)) break

It confirms that the candles can be blown out with only 7 puffs.

Aiming for each candle (in any order) means that each candle’s state will be flipped 3 times (once as the intended target, once as the intended target + 1, and once as the intended target – 1), so they will all end up extinguished. This works for any number of candles, but isn’t always the minimum number (e.g. when the number of candles is a multiple of 3, they can just be blown out in groups of 3).

]]>@Julian: I see. I was only allowing blowing on candles that were lit. It seems that I was assuming a behaviour of 7 year old boys that isn’t specified in the puzzle text.

I expect your interpretation is the correct one.

]]>This Python program runs in 155ms.

**Run:** [ @repl.it ]

from enigma import irange, inf, arg, printf N = arg(7, 0, int) printf("[N={N}]") # flip the bits at position (j - 1, j, j + 1) def flip(bs, j): bs = list(bs) for i in (j, (j - 1) % N, (j + 1) % N): bs[i] ^= 1 return bs # clear the bits in <bs> in <k> moves (or less) def clear(bs, k, ms=[]): if not any(bs): yield ms elif k > 0: for (j, x) in enumerate(bs): if x: yield from clear(flip(bs, j), k - 1, ms + [j]) # solutions for <n> bits, by shortest number of moves def solve(n): for k in irange(1, inf): yield from clear([1] * n, k) # find the smallest number of moves for ms in solve(N): printf("{n} -> {ms}", n=len(ms)) break

**Solution:** Tom can blow out the candles with 9 puffs.

Here is a diagram:

We start with all the candles alight (indicated by 1) and then in each row the state of the highlighted candles is flipped, until after 9 operations all the candles are out (indicate by 0).

]]>**Run:** [ @repl.it ]

from enigma import subsets, irange, filter_unique, map2str, printf # possible points awarded per match outcomes = dict(w=(3, 0), d=(1, 1), l=(0, 3)) # calculate the points: # - there must be at least one win (= 3 points) # - there must be at least one loss (= 0 points) def points(ms, ts): ps = list(outcomes[m][t] for (m, t) in zip(ms, ts)) if not(3 in ps and 0 in ps): return None return sum(ps) # record possible matches ms = list() # choose outcomes for U's matches for (AU, BU, CU, RU) in subsets("wdl", size=4, select="M"): U = points([AU, BU, CU, RU], [1, 1, 1, 1]) if U is None: continue # choose coutcomes for R's remaining matches for (AR, BR, CR) in subsets("wdl", size=3, select="M"): R = points([AR, BR, CR, RU], [1, 1, 1, 0]) if R is None or not(R > U): continue # choose outcomes for C's remaining matches for (AC, BC) in subsets("wdl", size=2, select="M"): C = points([AC, BC, CR, CU], [1, 1, 0, 0]) if C is None or not(C > R): continue # choose outcome for the remaining match for AB in "wdl": B = points([AB, BC, BR, BU], [1, 0, 0, 0]) if B is None or not(B > C): continue A = points([AB, AC, AR, AU], [0, 0, 0, 0]) if A is None or not(A > B): continue ms.append((AB, AC, AR, AU, BC, BR, BU, CR, CU, RU)) # find which match fixes all the others labels = "AB AC AR AU BC BR BU CR CU RU".split() for i in irange(0, 9): (ss, _) = filter_unique(ms, (lambda m: m[i])) for s in ss: printf("{k}={v} -> {s}", k=labels[i], v=s[i], s=map2str(zip(labels, s)))

**Solution:** If we are told that Rangers beat Borough then we can deduce the outcomes of all the other matches.

The outcomes of all the matches are:

A vs B = win for B

A vs C = win for A

A vs R = win for A

A vs U = win for A

B vs C = draw

B vs R = win for R

B vs U = win for B

C vs R = draw

C vs U = win for C

R vs U = win for U

And the points are:

]]>A = 9

B = 7

C = 5

R = 4

U = 3

`SubstitutedDivision()`

]] solver from the The following run file executes in 145ms.

**Run:** [ @repl.it ]

#!/usr/bin/env python -m enigma -r # writing the long division sum as: # # ? B # ------- # ? A ) ? ? ? # ? ? # --- # ? C ? # ? ? D # ===== SubstitutedDivision --distinct="" "??? / ?A = ?B" "?? - ?? = ?C" "?C? - ??D = 0" # exactly one of the following inequalities holds --extra="sum([A != 6, B != 4, C != 2, D != 3]) = 1"

**Solution:** The given 3 digit is wrong (it should be 4). The correct sum is: 784 ÷ 56 = 14.

**Run:** [ @repl.it ]

from itertools import product from enigma import irange, subsets, icount_exactly, unpack, printf # indices and labels for the exits (A, B, C, D, E) = indices = irange(0, 4) exits = "ABCDE" # labels for the people people = ("Adam", "Brian", "Clive", "David", "Edward") # labels for the destinations dests = ("Aberdeen", "Berwick", "Carlisle", "Dundee", "Edinburgh") # collect potential solutions ss = list() # choose the person for each exit for p in subsets(people, size=len, select="P"): # no-one uses an exit with their own initial if any(p[i][0] == x for (i, x) in enumerate(exits)): continue # check conditions involving only p: # 1. "David leaves at an exit labelled with a vowel" (i.e. A or E) if not("David" in (p[A], p[E])): continue # 2. "Adam leaves the roundabout at the exit before Edward if not(p.index("Edward") == p.index("Adam") + 1): continue # choose a destination for each exit for d in subsets(dests, size=len, select="P"): # no destination's initial matches the exit or person if any(d[i][0] in (x, p[i][0]) for (i, x) in enumerate(exits)): continue # check conditions involving p and d: # 3. "the man going to Edinburgh drives past Clive's exit and leaves # three exits later" if not(d.index("Edinburgh") == p.index("Clive") + 3): continue # output potential solution for (x, person, dest) in zip(exits, p, d): printf("{x}: {person} -> {dest}") printf() ss.append((p, d)) printf("{n} potential solutions\n", n=len(ss)) # now look for a clue for the form: "exit x does not lead to y" # and see if it gives a unique solution for (x, y) in product(indices, dests): f = unpack(lambda p, d: d[x] != y) if icount_exactly(ss, f, 1): printf("extra clue = \"exit {x} does not lead to {y}\"", x=exits[x])

**Solution:** The additional clue was: “Exit B does not lead to Carlisle”.

And the unique solution is:

A: Clive → Berwick

B: Adam → Dundee

C: Edward → Aberdeen

D: Brian → Edinburgh

E: David → Carlisle

Without the extra clue there are three more solutions to the original puzzle (where exit B *does* lead to Carlisle):

A: Clive → Berwick

B: Adam → Carlisle

C: Edward → Dundee

D: Brian → Edinburgh

E: David → Aberdeen

A: Clive → Dundee

B: Adam → Carlisle

C: Edward → Aberdeen

D: Brian → Edinburgh

E: David → Berwick

]]>A: Clive → Dundee

B: Adam → Carlisle

C: Edward → Berwick

D: Brian → Edinburgh

E: David → Aberdeen