This Python program runs in 79ms.

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

from itertools import count, combinations_with_replacement, permutations, combinations from collections import defaultdict from enigma import irange, join, printf # denominations of coins coins = (200, 100, 50, 20, 10, 5, 2, 1) # possible amounts amounts = set(irange(1, 99)) # generate amounts that can be made with increasing minimal numbers of coins # yields (k, r, m) where: # k - number of coins # r - collection of minimal amount -> coins with k coins # m - collection of minimal amount -> coins with fewer than k coins def minimal(coins, amounts=None): # record minimum size combinations m = dict() # consider amounts that can be made with k coins for k in count(1): # collect new amounts that can be made with k coins r = dict() for s in combinations_with_replacement(coins, k): t = sum(s) if t not in m: assert t not in r # check for unique minimal combinations r[t] = s yield (k, r, m) # add in the new minimal amounts m.update(r) # have we considered all possible amounts? if amounts and amounts.issubset(m.keys()): return # consider amounts that can be made with k coins for (k, r, m) in minimal(coins, amounts): # consider possible amounts (x) for the item for (x, coins_x) in r.items(): if x not in amounts: continue # consider possible change amounts (y), made with fewer than k coins # record (coins payed, coins recieved as change) by total number of coins in the transaction s = defaultdict(list) for (y, coins_y) in m.items(): # so we pay an amount (x + y), using fewer than k coins coins_xy = m.get(x + y, None) if coins_xy is None: continue # and the total number of coins used in the exchange must also be less than k t = len(coins_xy) + len(coins_y) if not(t < k): continue s[t].append((coins_xy, coins_y)) # D, T, H transactions each used a minimal number of coins in different ways if not s: continue t = min(s.keys()) # consider possible exchanges (amounts payed and change received) for ((Dp, Dc), (Tp, Tc), (Hp, Hc)) in permutations(s[t], 3): # but D gives 2 coins from his change to T and H for (gT, gH) in combinations(Dc, 2): if gT in Tp and gH in Hp: # output solution fmt = lambda s: join(s, sep='+') printf( "amount={x} [D pays {Dp} change {Dc}; {gT} -> T pays {Tp} change {Tc}; {gH} -> H pays {Hp} change {Hc}]", Dp=fmt(Dp), Dc=fmt(Dc), Tp=fmt(Tp), Tc=fmt(Tc), Hp=fmt(Hp), Hc=fmt(Hc) )

**Solution:** The item cost 83p.

The minimum number of coins to pay for the item exactly is 5 (50p + 20p + 10p + 2p + 1p = 83p).

Dick buys the first item, paying with one 100p coin. He receives change of 17p = 10p + 5p + 2p. So 4 coins are exchanged.

Dick gives the 5p coin to Tom, who pays with 2 coins, 100p + 5p = 105p, and receives 20p + 2p = 22p as change. Again 4 coins are exchanged.

Dick gives the 2p coin to Harry, who pays with 3 coins, 100p + 2p + 1p = 103p, and receives one 20p coin as change. Again 4 coins are exchanged.

(Tom and Harry are indistinguishable, so there is also a solution where Dick gives the 5p coin to Harry and the 2p coin to Tom).

If Dick didn’t need to help out Tom and Harry out using his own change it would be possible for the item to cost 84p, 86p or 87p, each of which takes 5 coins to pay for exactly, but Dick, Tom and Harry could each buy an item paying a different amount with a transaction that uses just 4 coins.

]]>This run file executes in 177ms.

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

#!/usr/bin/env python -m enigma -r SubstitutedSum "YZRM + BRCP + TPRM + BTCP = XLXX"

**Solution:** The sum is: 3754 + 1590 + 2054 + 1290 = 8688.

from collections import namedtuple from enigma import SubstitutedExpression, filter_unique, is_prime, printf # the alphametic sum p = SubstitutedExpression( 'ETA + BETA + THETA = DELTA', answer="(B, (A, B, D, E, H, L, T), (PSI, PHI), THEBES)" ) # find all solutions S = namedtuple('S', 'B letters words answer') ss = list(S(*ans) for (s, ans) in p.solve(verbose=1)) # "if I told you the value of B you could not find all the digits" (_, ss) = filter_unique(ss, (lambda s: s.B), (lambda s: s.letters)) # but we only want solutions where PSI and PHI are prime ss = filter((lambda s: all(is_prime(w) for w in s.words)), ss) # output solutions for s in ss: printf("THEBES={s.answer} [(A, B, D, E, H, L, T) = {s.letters}, (PSI, PHI) = {s.words}]")

The strange thing is that the “even if I told you the value of B, you still could not find all the digits” part of the puzzle is superfluous. As you have found you can just write a program that ignores this part of the puzzle and instead uses the fact that PSI and PHI are prime. This “additional” fact actually narrows the possible solutions to a single candidate anyway, so you can do without line 15 and the call to [[ `filter_unique()` ]].

@Jim: Would your filter_unique library function work OK on this Enigma ?

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

from enigma import SubstitutedDivision, printf # the terms in the original puzzle text original = 'bpkgcx ic chbm mhx smg skp bcc mbi gx ic mi' # choose a position to replace for (i, x) in enumerate(original): if x == ' ': continue # replace the letter with a new symbol X text = original[:i] + 'X' + original[i + 1:] # make a SubstitutedDivision sum from the terms t = text.split() p = SubstitutedDivision( t[0], t[1], t[2], [ (t[0][:3], t[3], t[4][:-1]), (t[4], t[5], t[6][:-1]), (t[6], t[7], t[8][:-1]), (t[8], t[9], t[10]), ], # all symbols, apart from X should be distinct distinct=set(text).difference(' X') ) # solve it for s in p.solve(verbose=0): # reverse mapping of symbols (apart from X) r = dict((v, k) for (k, v) in s.d.items() if k != 'X') # output the incorrect digit (has the same value as X) printf("[@{i}: {x} -> {y}]", y=r.get(s.d['X'], '?')) printf("{p.header}") # output the solution p.output_solution(s)

**Solution:** The incorrect letter is the first letter (*b*) in the *bcc* term. It should be *m* (so, the correct term should be *mcc*). The correct division sum is: 240739 ÷ 63 = 3821 (remainder 16).

The digit that is given an incorrect letter is shown in red.

We can solve the corrected sum directly using the [[ `SubstitutedDivision()` ]] solver:

% python -m enigma SubstitutedDivision "bpkgcx / ic = chbm" "bpk - mhx = sm" "smg - skp = mc" "mcc - mbi = g" "gx - ic = mi" bpkgcx / ic = chbm (rem mi) [bpk - mhx = sm, smg - skp = mc, mcc - mbi = g, gx - ic = mi] 240739 / 63 = 3821 (rem 16) [240 - 189 = 51, 517 - 504 = 13, 133 - 126 = 7, 79 - 63 = 16] / b=2 c=3 g=7 h=8 i=6 k=0 m=1 p=4 s=5 x=9 [1 solution]]]>

It runs in 83ms.

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

from itertools import count, product from enigma import concat, match, printf # patterns to match patterns = list( '*' + t + '*' for t in ( 'G??R?G', 'G?R?R', 'R?G?R', 'RG???G', 'G????R', 'R????R' )) for k in count(6): n = 0 for s in product('RG', repeat=k): s = concat(s) if all(match(s, t) for t in patterns): printf("[{k}] {s}") n += 1 if n: break

**Solution:** Pussicato’s painting consists of 9 squares: GRRGRRRGG.

Here’s a diagram showing how the painting meets all of the requirements.

]]>With the standard board we can get a maximum intended score of 108 (requiring different sectors) with an actual score a third of the intended score.

]]>aim for 14, 20, 14; get 11, 2, 11.

Several more with required score 94 and three different sectors.

And either order allows variant puzzles with a third, a quarter, etc. of the score.

Makes a change from football league tables! ]]>

%#! mzn-gecode -a % board with wraparound at 1 and 22 array [1..22] of int: board = [ 5, 20, 1, 18, 4, 13, 6, 10, 15, 2, 17, 3, 19, 7, 16, 8, 11, 14, 9, 12, 5, 20 ]; % intended sectors var 2..21: i; % single var 2..21: j; % treble var 2..21: k; % double % intended score is more than 100 var int: intended = board[i] + 3 * board[j] + 2 * board[k]; constraint intended > 100; % actual sectors var 1..22: x; % single var 1..22: y; % treble var 1..22: z; % double % actual score is half the intended score var int: actual = board[x] + 3 * board[y] + 2 * board[z]; constraint actual * 2 = intended; % actual darts are all in adjacent sectors to intended darts constraint abs(x - i) = 1 /\ abs(y - j) = 1 /\ abs(z - k) = 1; solve satisfy; output [ "intended = " ++show(intended) ++ " (" ++ show(board[i]) ++ " + 3x " ++ show(board[j]) ++ " + 2x " ++ show(board[k]) ++ "), " ++ "actual = " ++ show(actual) ++ " (" ++ show(board[x]) ++ " + 3x " ++ show(board[y]) ++ " + 2x " ++ show(board[z]) ++ ")" ];]]>

Intended score = 102, t1 = 45, d1 = 40, s1 = 17

Actual score = 51, t2 = 3, d2 = 28, s2 = 20

———-

Intended score = 102, t1 = 45, d1 = 40, s1 = 17

Actual score = 51, t2 = 3, d2 = 30, s2 = 18

% A Solution in MiniZinc include "globals.mzn"; var 8..120: int_score; % intended total score var 8..60: act_score; % actual total score % treble (t1,t2), double(d1,d2) and single(s1,s2) dart scores var 1..60: t1; var 1..60: t2; var 1..40: d1; var 1..40: d2; var 1..20: s1; var 1..20: s2; % different trebles, double and singles for both throws constraint t1 != t2 /\ d1 != d2 /\ s1 != s2; % treble, double and single darts must not be in the same sector constraint t1 mod d1 != 0 /\ t1 mod s1 != 0 /\ d1 mod s1 != 0 ; constraint t2 mod d2 != 0 /\ t2 mod s2 != 0 /\ d2 mod s1 != 0 ; set of int: trebles = {3 * n | n in 1..20}; set of int: doubles = {2 * n | n in 1..20}; set of int: singles = {n | n in 1..20}; constraint int_score = t1 + d1 + s1; constraint int_score > 100 /\ t1 in trebles /\ d1 in doubles /\ s1 in singles; % intended score must be even to divisible by 2 constraint int_score mod 2 == 0; constraint act_score = t2 + d2 + s2; constraint act_score = int_score div 2 /\ t2 in trebles /\ d2 in doubles /\ s2 in singles; solve satisfy; output [ "Intended score = " ++ show(int_score) ] ++ [ ", t1 = " ++ show(t1) ++ ", " ++ "d1 = " ++ show(d1) ++ ", " ++ "s1 = " ++ show(s1)] ++ [ "\nActual score = " ++ show(act_score) ] ++ [ ", t2 = " ++ show(t2) ++ ", " ++ "d2 = " ++ show(d2) ++ ", " ++ "s2 = " ++ show(s2)];]]>

I think it was a letter to *New Scientist* in 1995 that pointed out that the sectors on a darts board are numbered to ‘punish’ poorly aimed darts, but a better order to that end would be

1, 19, 3, 17, 5, 15, 9, 12, 7, 10, 13, 8, 11, 14, 6, 16, 4, 18, 2, 20.

I’ve not checked to see whether that could lead to a halving of the intended score.

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

from itertools import product from enigma import printf # implement a circular list class CircularList(list): def __getitem__(self, i): return list.__getitem__(self, i % len(self)) # the numbers on a dartboard board = CircularList([20, 1, 18, 4, 13, 6, 10, 15, 2, 17, 3, 19, 7, 16, 8, 11, 14, 9, 12, 5]) # consider numbers aimed for x, y, z (at indices i, j, k) for ((i, x), (j, y), (k, z)) in product(enumerate(board), repeat=3): # the total desired score t = x + 3 * y + 2 * z if not(t > 100): continue # the actual score is half this (s, r) = divmod(t, 2) if r !=0: continue # each dart went into the adjacent number for (di, dj, dk) in product((-1, +1), repeat=3): # does this make half the score? (dx, dy, dz) = (board[i + di], board[j + dj], board[k + dk]) if dx + 3 * dy + 2 * dz == s: printf("t = {t} = {x} + 3x {y} + 2x {z} -> s = {s} = {dx} + 3x {dy} + 2x {dz}")

**Solution:** The three darts scored a total of 51.

There are 4 ways to achieve this:

aim for: single(15) + treble(19) + double(15) = 102, get: single(10) + treble(7) + double(10) = 51

aim for: single(19) + treble(15) + double(19) = 102, get: single(7) + treble(10) + double(7) = 51

aim for: single(7) + treble(19) + double(19) = 102, get: single(16) + treble(7) + double(7) = 51

aim for: single(5) + treble(19) + double(20) = 102, get: single(20) + treble(7) + double(5) = 51

Only the final one of these involves aiming for three *different* numbered sectors of the board.

d = (q – p²) / 3

Then we have equations:

bc = d

b – c = p

Solving for *c* gives the following quadratic:

c² + pc – d = 0

Which, using the quadratic formula has a solution at:

c = (√(p² + 4d) – p) / 2

and substituting for *d*:

c = (√((4q – p²) / 3) – p) / 2

b = p + c

Which gives a similar approach to Arthur’s method above – factorising *N* and then solving a quadratic equation.

from enigma import arg, divisors_pairs, is_square, printf N = arg(3185, 0, int) for (p, q) in divisors_pairs(N): (d, r) = divmod(4 * q - p * p, 3) if d < 0: break if r != 0: continue x = is_square(d) if x is None: continue (c, r) = divmod(x - p, 2) if c < 1 or r != 0: continue b = c + p printf("{N} = {b3} - {c3} = {b}^3 - {c}^3", c3=c ** 3, b3=b ** 3)]]>