This run-file executes in 87ms.

#!/usr/bin/env python -m enigma -r SubstitutedSum "GTKTGPKM + WKXDYPZM = MGMPKPMMT"

**Solution:** The correct sum is 42824581 + 98760531 = 141585112.

See: http://journal.geometryexpressions.com/pdf/feinmansteiner.pdf

The paper examines other ratios of the sides of the triangle, including 1/4, 1/7 and 1/8, which gives a central triangle area of 1/2 of the main triangle area.

There is also an interesting example of construction of the vertices of the inner 1/7 triangle with integer coordinates:

https://math.stackexchange.com/questions/1131161/how-do-i-find-the-area-of-a-triangle-formed-by-cevians ]]>

(I found this at [ https://web.archive.org/web/20060427055758/http://www.randi.org/jr/02-09-2001.html ] where James Randi was sent it by Martin Gardner who attributes it to Hugo Steinhaus).

]]>If k = 1/3 in your formula for R, then the central area XYZ is 1/7 of the main area ABC.

In Routh’s formula , in this case, x = y = z = 2 (ie k = 1/3), so the ratio of the central area to the overall area is (2 * 2 * 2 – 1) ^2 / (4 + 2 + 1) ^ 3

ie 7^2 / 7^3 = 1/7

]]>(xyz – 1)² / ((xz + x + 1)(xy + y + 1)(yz + z + 1))

In this case the ratios are all the same *x = y = z*, which simplifies the formula to:

(x – 1)² / (x² + x + 1) = 1 – 3x / (x² + x + 1)

And for this problem the ratio is equal to 1/37

1 – 3x / (x² + x + 1) = 1/37

12/37 = x / (x² + x + 1)

12x² + 12x + 12 = 37x

12x² – 25x + 12 = 0

(3x – 4)(4x – 3) = 0

So each side is split in the ratio 3:4, hence the value of *k* we are looking for is 3/7.

So here is some analysis, that let me write a program to solve sequence **D** in a reasonable time.

For any of the given sequences we can construct a corresponding sequence of integers. When we encounter a green number we write down its value, when we encounter a red number we write down its negative value.

With this method the example sequence becomes:

[3, −4, 3, −2, 5, −2]

To make a change to a sequence we replace two adjacent elements with different signs with the sum of the two elements, unless the sum is zero, then we simply remove the two elements.

In this way the sequence is reduced until all elements have the same sign. (0 can never appear in a sequence).

If the sequence ends up with 0 or 1 elements, then we have successfully reduced it, if it has 2 or more elements, then we have failed to reduce it.

Every element in a reduced sequence is the sum of one or more adjacent elements from the original sequence, elements are only removed when they have a sum of zero, so the final value of a fully reduced sequence is the sum of the elements of the original sequence, and the sum of the elements in the sequence remains the same throughout the process. (An empty sequence has a sum of 0).

We can derive the following:

The empty sequence is successfully reduced (to a value of 0).

A sequence with only one element is successfully reduced (to a non-zero value equal to the value of the single element).

A sequence with two elements can be successfully reduced if (and only if) the elements have different signs. The value of the sequence is the sum of the elements. If the value is zero, the sequence can be reduced to the empty sequence. Otherwise it can be reduced the a singleton sequence consisting of the value of the original sequence.

A sequence with more than two elements can be reduced if we can find a suitable “split point” for the sequence. For a split point to work we need the subsequence on the left of the split point to be reducible, and the subsequence on the right of the split point to be reducible, and either at least one is reduced to 0, or they are reduced to non-zero values that have different signs. If one of the subsequences reduced to 0, we end up with a sequence of length 0 or 1, which are dealt with above, and if the subsequences reduce to non-zero values with different signs we end up with a sequence of length 2, which is also dealt with above.

The following code uses this approach to solve the puzzle using recursion. We use the `@cached` decorator from the **enigma.py** library to avoid recalculating the result for sequences we have already seen.

We can easilly test to see if two numbers have different signs by evaluating their product. It they have different signs the product will be negative. If at least one of the numbers is zero the product will also be 0. If they have the same sign then the product will be positive.

This program calculates the results for all 4 problem sequences in 94ms.

from enigma import irange, cached, arg, printf # represent the red and green numbers (R, G) = (lambda n: -n, lambda n: n) # can sequence <s> be solved? @cached def _solve(s, n): # a sequence of length 0 or 1 is always possible if n < 2: return True # a sequence of length 2 is possible if the numbers have different signs if n == 2: return (s[0] * s[1] < 0) # for longer sequences consider possible split points n -= 1 a = 0 b = sum(s) i = 0 while i < n: x = s[i] a += x b -= x i += 1 if (a * b <= 0) and _solve(s[:i], i) and _solve(s[i:], n - i + 1): return True return False solve = lambda s: _solve(s, len(s)) # helper functions for constructing problem sequences def _alternate(s, f, g): for x in s: yield f(x) (f, g) = (g, f) alternate = lambda s, f, g: tuple(_alternate(s, f, g)) # sequences to check test = { # example sequence 'X': alternate((3, 4, 3, 2, 5, 2), G, R), # puzzle sequences 'A': alternate((9, 4, 1, 4, 1, 7, 1, 3, 5, 4, 2, 6, 1, 4, 8, 3, 2), R, G), 'B': alternate((2, 3, 5, 9, 6, 3, 1, 4, 2, 3, 1), G, R), 'C': alternate(tuple(irange(1, 1000)) + tuple(irange(3, 999, step=2)), G, R), 'D': alternate(( 3, 2, 1, 4, 5, 4, 3, 2, 4, 3, 7, 4, 1, 5, 1, 4, 2, 4, 3, 1, 2, 7, 9, 3, 7, 5, 3, 8, 6, 5, 8, 4, 1, 5, 2, 3, 1, 4, 10, 6, 3, 5, 7, 4, 1, 4 ), R, G) } # we'll be doing some serious recursion import sys sys.setrecursionlimit(4000) # select sequences to check args = arg('ABCD', 0) for k in args: printf("checking sequence {k}...") r = solve(test[k]) printf("{k} = {r}")

**Solutions:** It is possible to successfully reduce sequences **B** and **C**. Sequences **A** and **D** *cannot* be successfully reduced.

Special casing *n = 2* is not strictly necessary, as the general case will handle it, but it is a bit faster.

More compactly (but not necessarily more readably) we could write `solve(s)` as:

def solve(s): return (len(s) < 2) or any(sum(s[:i]) * sum(s[i:]) <= 0 and solve(s[:i]) and solve(s[i:]) for i in irange(1, len(s) - 1))]]>

Instead I would phrase the question using an object being transported at a steady pace by a conveyance that ensures journey times between stations are always exactly the same. Here is a rephrasing on the puzzle:

At the factory there are four workstations which are interlinked by six conveyor belts (one for each pair of stations) that allow items to travel between each of the stations. The time taken for items to travel between stations is an exact number of minutes, and as each of the six belts forms a loop the travel time is exactly the same in both directions. To make life a bit more interesting the workers at the workstations have a fluffy toy which rides the conveyor belts. When the toy arrives at a workstation the worker can move it to one of the other belts or leave it on the belt it is on.

One day the fluffy toy started it’s journey from one workstation at an exact number of minutes past the hour, and so during its entire journey, it arrived at each workstation it visited at an exact number of minutes past the hour. Furthermore during the 30 seconds before or the the 30 seconds after arriving at a workstation the hour and minute hands of the big factory clock were exactly coincident. The toy travelled on each of the six conveyor belts between stations exactly twice during the journey and ended up at the same station it started at. It spent the whole time on the conveyor belts moving between stations. The first shift of the day starts at 6am, and the final shift finishes at midnight.

What time did the toy set out from the first workstation? And what time did it arrive back at the end of its journey?

This has a unique answer that is the same as the published answer for the original puzzle, and doesn’t require any adjustment of the possible time windows involved.

Here is a recursive Python 3 program that finds the solution in 150ms. It’s a bit neater than my original program in that it doesn’t require any analysis or special cases to account for the fact that one of the journeys between stations may take (roughly) twice as long as the others.

from collections import Counter from enigma import irange, update, find, printf # times of exact coincidence between 6am and midnight (to the nearest minute) times = list((1440 * n + 11) // 22 for n in irange(6, 21)) # label the nodes, so that segments can be labelled with n1 + n2 nodes = (1, 2, 4, 8) # find a loop of length 13 that traverses each segment twice # ns - sequence of nodes visited (so far) # ts - sequence of times the nodes are visited (so far) # ss - remaining potential times for visiting nodes # ds - allocated durations for individual segments # ps - sequence of segments traversed (so far) def solve(ns, ts, ss, ds, ps): # are we done? if len(ns) == 13: if ns[0] == ns[-1]: yield (ns, ts) # otherwise, can we complete the itinerary? elif len(ts) + len(ss) > 12: (n0, t0) = (ns[-1], ts[-1]) # move to the next node for n in nodes: # must move to a different node if n == n0: continue # visit new nodes in order if n not in ns and n >> 1 not in ns: break # key for this segment k = n0 + n # don't use segments more than twice if ps.count(k) > 1: continue # does this segment already have a duration d = ds.get(k, None) if d is not None: # would we arrive at a valid time? t = t0 + d i = find(ss, t) if i != -1: yield from solve(ns + [n], ts + [t], ss[i + 1:], ds, ps + [k]) else: # choose an arrival time (which fixes a duration for this segment) for (i, t) in enumerate(ss): yield from solve(ns + [n], ts + [t], ss[i + 1:], update(ds, [(k, t - t0)]), ps + [k]) # record start time and end time r = Counter() # consider possible start times at the first node # (a full itenarary has 13 times in it) for i in irange(0, len(times) - 13): for (ns, ts) in solve([nodes[0]], [times[i]], times[i + 1:], dict(), []): printf("{ns} {ts}") r[(ts[0], ts[-1])] += 1 # output solutions for ((start, end), n) in r.most_common(): (h1, m1) = divmod(start, 60) (h2, m2) = divmod(end, 60) printf("{h1:02d}:{m1:02d} - {h2:02d}:{m2:02d} [{n} solutions]")]]>

This Python program uses the `SubstitutedSum()` solver from the **enigma.py** library. It runs in 530ms.

from enigma import SubstitutedSum, printf # the 10 letters that make up the sum letters = 'BDEHLMPRTX' # the sum as one string text = 'RMLTPTD RMHDTDT RBLXTDD RREPPPPT' # consider each letter of the sum for (i, x) in enumerate(text): if x == ' ': continue # replace the letter with a different one for y in letters: if x == y: continue t0 = text[:i] + y + text[i + 1:] t = t0.split() # solve the sum p = SubstitutedSum(t[:3], t[3]) for s in p.solve(): printf("position {i}, {x} => {y}, {t[0]} + {t[1]} + {t[2]} = {t[3]}") p.solution(s)

**Solution:** One of the R’s that is the first (leftmost) letter of one of the terms in the sum is wrong. It should be an L. The correct sum is (for example): 8689095 + 1625959 + 1384955 = 11700009. The result is always the same but one of the terms starts with an 8 (L) and the other two start with a 1 (R).

% A solution in MiniZinc include "globals.mzn"; var 0..9:O; var 0..9:N; var 0..9:E; var 0..9:F; var 0..9:U; var 0..9:R; var 0..9:I; var 0..9:V; constraint O != 0 /\ F !=0 /\ all_different( [O,N,E,F,U,R,I,V]); var 100..999: ONE = 100*O + 10*N + E; var 1000..9999: FOUR = 1000*F + 100*O + 10*U + R; %var 1000..9999: FIVE = 1000*F + 100*I + 10*V + E; %set of int : sq_pr3 = { (2*n*n*n + 3*n*n + n) div 6 | n in 7..13 }; %set of int : sq_pr4 = { (2*n*n*n + 3*n*n + n) div 6 | n in 14..30 }; set of int: tet3 = { (n*(n+1)*(n+2)) div 6 | n in 8..17}; set of int: tet4 = { (n*(n+1)*(n+2)) div 6 | n in 18..38}; % Statement 1 %constraint ONE in sq_pr3 /\ ONE mod 2 == 1 ; %constraint FIVE in sq_pr4 /\ FIVE mod 2 == 1 ; % Statement 2 constraint ONE in tet3 /\ ONE mod 2 == 1; constraint FOUR in tet4 /\ FOUR mod 2 == 0; solve satisfy; %output [ "ONE, FIVE = " ++ show(ONE) ++ ", " ++ show(FIVE)]; % Statement 1 % ONE, FIVE = 285, 3795 output [ "ONE, FOUR = " ++ show(ONE) ++ ", " ++ show(FOUR)]; % Statement 2 % ONE, FOUR = 165, 7140 % Finished in 56msec]]>

%#! mzn-chuffed -a include "globals.mzn"; % the teams set of int: Teams = 1..6; int: A = 1; int: B = 2; int: C = 3; int: D = 4; int: E = 5; int: F = 6; % the table array[Teams, Teams] of var 0..19: x; % teams don't play themselves constraint forall (i in Teams) (x[i, i] = 0); % figures given in the table constraint x[A, B] = 3; constraint x[A, C] = 3; constraint x[A, D] = 3; constraint x[A, E] = 3; constraint x[A, F] = 10; constraint x[F, A] = 2; % total number of goals scored by team i function var int: goals(var int: i) = sum (j in Teams where j != i) (x[i, j]); % A scored more than half the goals in the match constraint goals(A) > sum (i in Teams where i != A) (goals(i)); % number of matches won by team i function var int: win(var int: i) = sum (j in Teams where j != i) (x[i, j] > x[j, i]); % number of matches drawn by team i function var int: draw(var int: i) = sum (j in Teams where j != i) (x[i, j] = x[j, i]); % points for team i (2 points for a win, 1 for a draw) function var int: points(var int: i) = 2 * win(i) + draw(i); % there are no ties in the points list constraint all_different (i in Teams) (points(i)); % A came bottom constraint forall (i in Teams where i != A) (points(A) < points(i)); % B beat E constraint x[B, E] > x[E, B]; % B drew with F constraint x[B, F] = x[F, B]; % at least one team drew more games than C constraint exists (i in Teams where i != C) (draw(i) > draw(C)); solve satisfy;

The `mzn-chuffed` solver executes this model in 287ms.

And here is a Python program that uses the **minizinc.py** wrapper to format the output from MiniZinc into the appropriate table.

from enigma import compare, printf from minizinc import MiniZinc # map team index to name teams = dict(enumerate("ABCDEF", start=1)) # row format fmt = "{t:>1} {A:>3} {B:>3} {C:>3} {D:>3} {E:>3} {F:>3} {pts:>3}" for (x,) in MiniZinc("tantalizer475.mzn").solve(result="x", solver="mzn-chuffed -a"): # output the header d = dict((x, x) for x in "A B C D E F pts".split()) printf(fmt, t='', **d) for (k, t) in teams.items(): # calculate points pts = sum([0, 1, 2][compare(x[k][i], x[i][k]) + 1] for i in teams.keys() if i != k) # remaining values in the table d = dict((teams[i], s) for (i, s) in x[k].items()) d[t] = '-' # output the row printf(fmt, pts=pts, **d) printf()

**Solution:** The full table is given below:

Assuming 2 points for a win and 1 to each side for a draw. (The published solution gives 1 point for a win and a half point to each side for a draw).

If, however, we were to assume 3 points for a win and 1 for a draw then there would be multiple solutions, so really the puzzle should explicitly state the scoring system.

The scores in the matches are:

AvB = 3-4, AvC = 3-4, AvD = 3-4, AvE = 3-4, AvF = 10-2

BvC = 0-0, BvD = 0-0, BvE = 1-0, BvF = 0-0

CvD = 0-0, CvE = 1-0, CvF = 1-0

DvE = 0-0, DvF = 0-0

EvF = 0-0

As we see, A scored 22 goals, and all the other teams scored 21 goals between them. C drew two matches (BvC, CvD), and B and F drew 3 matches (BvC, BvD, BvF and BvF, DvF, EvF) and D drew four matches (BvD, CvD, DvE, DvF).

]]>from enigma import irange, divisors, is_square, printf # consider the president's number, p for p in irange(1, 80000, step=2): # count the divisors of p n = len(divisors(p)) # output solutions if n % 2 == 1 and n > 10 and is_square(n): printf("p={p} n={n}")

**Solution:** The President’s membership number was 50625.

50625 has 25 divisors (including itself and 1).

There is a straightforward analytical approach to this (see also **Enigma 1226**):

If we consider the prime factorisation of a number *n*:

n = (2^e1)(3^e2)(5^e3)…

Then any number that is formed in the same way, where the each exponent is less than or equal to the corresponding exponent in the prime factorisation of *n* will be a divisor of *n*. And, every divisor of *n* can be expressed in this way.

So by choosing appropriate exponents we can count the divisors of *n* as:

tau(n) = (e1 + 1)(e2 + 1)(e3 + 1)…

(For an exponent *e* we can use factors from *0* to *e*, so there are *(e + 1)* choices of each exponent).

In this problem, the president’s number *p* has a number of divisors equal to an odd square greater than 10.

So it takes the form:

p = (p1^2k)(p2^2k)

where *k* ≥ 2 and *p1* and *p2* are primes, and as *p* is odd *p1* and *p2* must be odd primes.

So the smallest possible value is:

p = (3^4)(5^4) = 50625, with 25 divisors

and, indeed, this is the answer to the problem. Any larger number constructed in this way exceeds the limit of 80,000.

The `tau()` function in the **enigma.py** library counts the number of divisors in this way, and can be used instead of `len(divisors(p))` in the above program to give a shorter execution time.

[diagram showing a rhombus with shorter diagonal equal in length to each of the sides]

>>

At each corner of the forest is a magnificent oak tree. There are six footpaths, one linking each pair of oaks. At the weekend I went on a long hike, starting at an oak and finishing at the same oak, keeping to the paths and going along each one exactly twice (in one direction or the other). Each time I was on the long diagonal I stopped for a while to eat part of my picnic lunch, so that the distance AC (in either direction) took me twice as long as each of the other paths, including BD. Otherwise I kept up a steady pace all day. I always went straight across at the central crossing point.

Whenever I was at an oak I noticed that the minute hand of my watch coincided with the hour hand. I set out soon after 6 in the morning and got home by 22:15.

To the nearest minute, what were my starting and finishing times (at the oaks, I mean)?

<<

So in my version it's AC that takes 131 minutes.

And by the way in English we say turn round, not "around".

Definitely flawed! ]]>

At first I thought there must be multiple solutions to this problem.

We can find the times to the nearest minute when the hour and minute hands of the watch are coincident in the required time period. There are 16 of them:

06:33, 07:38, 08:44, 09:49, 10:55, 12:00, 13:05, 14:11,

15:16, 16:22, 17:27, 18:33, 19:38, 20:44, 21:49, 22:55.

And the walk has 12 legs, so if each leg takes about the same time and we don’t stop anywhere along the way (no stops are mentioned), we could have any of the following start and finish times:

06:33 – 19:38

07:38 – 20:44

08:44 – 21:49

09:49 – 22:55

It’s also possible that one path could take about twice as long to traverse as the other paths, which would mean we could have the following possible start and finish times:

06:33 – 21:49

07:38 – 22:55

One way to reduce the number of possible answers is to assume that the time taken to traverse a path must be *exactly* the same both times it is traversed, even if it is traversed in the opposite direction.

Using this interpretation of the text I was able to write a program to try all possible routes and determine that there was, indeed, a unique start and end time that satisfied the puzzle.

This Python 3 program determines the times (to the nearest minute) when the hands are coincident, and then uses the differences between these times to find routes where paths are always traversed in the same time. It runs in 94 ms.

from collections import Counter from enigma import irange, tuples, update, printf # times of exact coincidence between 6am and midnight (to the nearest minute) ts = list() for n in irange(6, 21): t = (1440 * n + 11) // 22 # = int(720n/11 + 1/2) (h, m) = divmod(t, 60) printf("n={n}, h={h} m={m}") ts.append(t) # compute the differences ds = list(b - a for (a, b) in tuples(ts)) # label the trees, so that paths can be labelled with t1 + t2 trees = (1, 2, 4, 8) # path - record the order the trees are visited in # ds - durations to traverse paths # double - which path take two durations # r - record time taken to travese a path # (0 = not yet traversed, n = traversed once, -n = traversed twice) def solve(path, ds, double, r=dict()): # are we done? if len(path) == 13: yield path else: t0 = path[-1] # move to the next tree for t1 in trees: if t1 == t0: continue k = t0 + t1 v = r.get(k, 0) if v == 0: # first traversal of this path if k == double: if len(ds) > 1: yield from solve(path + [t1], ds[2:], double, update(r, [(k, ds[0] + ds[1])])) else: yield from solve(path + [t1], ds[1:], double, update(r, [(k, ds[0])])) elif v > 0: # second traversal of this path if k == double: if len(ds) > 1 and v == ds[0] + ds[1]: yield from solve(path + [t1], ds[2:], double, update(r, [(k, -v)])) else: if v == ds[0]: yield from solve(path + [t1], ds[1:], double, update(r, [(k, -v)])) # record start time and end time r = Counter() # d = a path that take twice as long to traverse as the rest # (this is either one of the first paths we travel or one of the others) # n = number of duration steps required for (d, n) in ((0, 12), (1 + 2, 14), (2 + 4, 14)): # possible start times for i in irange(0, len(ds) - n): # start from tree 1 for s in solve([1], ds[i:], d): start = ts[i] end = ts[i + n] printf("d={d} i={i} s={s}, start={start} end={end}") r[(start, end)] += 1 # output solutions for ((start, end), n) in r.most_common(): (h1, m1) = divmod(start, 60) (h2, m2) = divmod(end, 60) printf("{h1:02d}:{m1:02d} - {h2:02d}:{m2:02d} [{n} solutions]")

**Solution:** The walk started from the first oak at 6:33am, and returned to it (for the final time), completing the walk, at 9:49pm.

One possible itinerary is:

path AB takes 65m to traverse

path AC takes 66m to traverse

path AD takes 65m to traverse

path BC takes 131m to traverse

path BD takes 66m to traverse

path CD takes 65m to traverse

06:33 – start at tree A

07:38 – arrive at tree B, via path AB (65m)

09:49 – arrive at tree C, via path BC (131m)

10:55 – arrive at tree A, via path AC (66m)

12:00 – arrive at tree D, via path AD (65m)

13:05 – arrive at tree A, via path AD (65m, again, but in the other direction)

14:11 – arrive at tree C, via path AC (66m, again, but in the other direction)

15:16 – arrive at tree D, via path CD (65m)

16:22 – arrive at tree B, via path BD (66m)

18:33 – arrive at tree C, via path BC (131m, again)

19:38 – arrive at tree D, via path CD (65m, again)

20:44 – arrive at tree B, via path BD (66m, again)

21:49 – arrive at tree A, via path AB (65m, again, but in the other direction)

I was close to marking this puzzle as *flawed*, and I still think it could have been worded better.

The following Python code runs in 68ms.

from itertools import permutations from enigma import Football, irange, update, printf # digits digits = set(irange(0, 9)) # scoring system football = Football(points={ 'w': 2, 'd': 1 }) # solve the table for (matches, d) in football.substituted_table({ 'w': '??p', 'points': 'dtx' }): # check the result of the sum (m, t) = divmod(10 * d['t'] + 11 * d['d'] + d['x'], 10) if m > 9 or t != d['t'] or m in d.values(): continue # choose values for h and y for (h, y) in permutations(digits.difference(d.values(), [m]), 2): d2 = update(d, [('m', m), ('h', h), ('y', y)]) # determine the scores in the matches for scores in football.substituted_table_goals('hmp', 'myt', matches, d=d2): # output the matches football.output_matches(matches, scores, teams='ABC', d=d2)

**Solution:** The scores in the football matches are: AvB = 4-5, AvC = 3-0, BvC = 0-0. The addition sum is: 32 + 21 = 53.

Allowing for numbers containing smiley faces to take different values, I found 22 solutions to the three equations in multiple output configuration for MiniZinc.

However, in all case, GAMES = 23785, IN = 10, CHINA = 46103 and the totals of the first and third equations was 92008.

]]>In this case I saved the MiniZinc model to a file and executed it using the `mzn-gecode -a` solver like this:

% time mzn-gecode -a enigma1579geoff.mzn FIFTEEN = 4043551, FIVE = 4085, ELEVEN = 565851 ---------- ========== mzn-gecode -a enigma1579geoff.mzn 0.08s user 0.02s system 112% cpu 0.084 total

I run the command a number of times (usually 16 times for a program that takes less than 1 second), and report the best elapsed time.

So, according to my methodology, the model Geoff posted (7th August 2017 at 4:04pm) executes in 84ms.

My timings are done using a 13″ MacBook Pro (Late 2011 model, with a 2.4 GHz Intel Core i5 processor). This is the same laptop I’ve been using since I started *Enigmatic Code*, so timings should be roughly comparable between my posts (although software has been updated during that time).