Here is a program that calculates the result directly. It runs in 50ms.

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

from enigma import subsets, irange, inf, factorial, div, printf # strategy, take the first amount lower than the first n items def strategy(s, n): t = min(s[:n]) for x in s[n:]: if x < t: break return x # play the game with k items def play(k): # collect total amount t = 0 # consider possible orderings of the items ps = list(1299 + 10 * p for p in irange(1, k)) for s in subsets(ps, size=k, select="P"): t += strategy(s, 1) return t # consider numbers of items for k in irange(2, inf): t = play(k) # calculate the average expected price (in 10th pence) d = factorial(k) p = div(t, d) if p is not None and p % 10 == 0: printf("k={k} -> p={p}") break

**Solution:** There were 5 petrol stations.

And the expected average fuel price was 132.0 pence.

It doesn’t actually matter what the prices actually are, all the petrol stations could adjust their prices by the same whole number of pence, and the expected average price would be adjusted by the same amount.

Analytically:

As determined in **Teaser 2988** we can use the formula:

S(n, k) = ((2n + 1)k – n(n + 1)) (k + 1) / 2(n + 1)k

To determine the mean expected value of choosing from *k* boxes with values from 1..*k*, using the strategy of picking the next box that is better than any of the first *n* boxes (or the last box if there are no boxes better than the first).

In this case *n = 1*:

S(1, k) = (3k – 2) (k + 1) / 4k

If we award ourselves a prize of value *k* for selecting the cheapest fuel, and a prize of value *1* for selecting the most expensive fuel, then we have the same situation as in **Teaser 2988**, and if *p* is expected average prize value, then the corresponding expected average fuel price is *(130.9 + k – p)*.

And *k* is an integer, so in order to make the expected average fuel price a whole number of pence we are looking for expected average prize value that is an integer plus 0.9.

i.e. when the value of *10 S(1, k)* is an integer with a residue of 9 modulo 10.

10 S(1, k) = (15k + 5) / 2 – (5 / k)

When *k* is odd, the first part gives us a whole number, so we would also need the *(5 / k)* part to give a whole number. i.e. *k = 1, 5*.

When *k* is even, the first part gives us an odd number of halves, so we also need *(5 / k)* to give an odd number of halves. i.e. *k = 2, 10*.

And we are only interested in values of *k > 1*, so there are just 3 values to check:

k = 5:10 S(1, k) = 39

k = 2:10 S(1, k) = 15

k = 10:10 S(1, k) = 77

The only value for *k* that gives a residue of 9 modulo 10 is *k = 5*.

And in this case our expected average prize is *p = 3.9* so our expected average fuel price is 132.0 pence.

LikeLike

]]>I’ve updated the diagram with a scale drawing. Including a ball.

LikeLike

]]>@Robert: It’s a limitation of WordPress.com I’m afraid, but if there are any corrections you would like to make, just post a followup comment, and I will use it to correct errors in the original.

LikeLike

]]>Here is the program adapted to just consider the *centre + left/right* values. It finds there is only one segment that must appear in any solution (or its reverse), and this gives the required answer. It runs in 63ms.

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

from enigma import irange, subsets, diff, peek, printf # available holes (points) holes = [ 1, 2, 3, 4, 5, 6, 7, 8 ] # layout for a sequence of holes (in mm) # return a list of: (region size, points scored) pairs def layout(ps): for (i, p) in enumerate(ps): if i > 0: yield (60, 0) # gap between holes yield (110 - 10 * p, p) # hole # generate intervals ((a, b), p) from a layout # where a, b are absolute distances, p is the number of points scored def intervals(ss): a = b = 0 for (d, p) in ss: if b == 0: (a, b) = (0, d) else: (a, b) = (b, b + d) yield ((a, b), p) # analyse the layout (working in 5mm steps) # return list of (d, (v, r)) values, where: # d = absolute target distance # v + r/240 = max average score def analyse(ss): # determine total length t = sum(d for (d, _) in ss) rs = list() # consider target positions (in 5mm steps) for x in irange(120, t - 120, step=5): # consider each zone r = 0 for ((a, b), p) in intervals(ss): # overlap? if b < x - 120: continue if a > x + 120: break d = min(x + 120, b) - max(x - 120, a) r += p * d rs.append((x, r)) # find maximum average value m = max(r for (_, r) in rs) return list((x, divmod(r, 240)) for (x, r) in rs if r == m) # find triples with integer scores max average scores at the centre of the centre hole # choose the centre hole for X in holes: # choose the left/right holes for (L, R) in subsets(diff(holes, [X]), size=2): # create the layout ss = list(layout((L, X, R))) # analyse it rs = analyse(ss) # there should be only one max position if len(rs) != 1: continue (x, (v, r)) = rs[0] # and the max average score should be an integer if r != 0: continue # and it should be centred on X ((a, b), _) = peek(intervals(ss), 2) if a < x < b and b - x == x - a: printf("segment = ({L}, {X}, {R}) -> target = {x} mm, avg pts = {v}")

I suppose really I should demonstrate that we can construct an ordering containing the required segment that satisfies all the requirements, but as my first program finds lots I don’t think it is necessary.

LikeLike

]]>@Robert: I don’t think it is possible for the target area to extend beyond the centre hole and the holes on either side. The smallest holes are 7cm and 8cm and the distance from the centre of one to the edge of the other is always greater than 12cm, so I think we only need to consider centre + left/right configurations. (Which I’m looking at to give a more efficient program).

LikeLike

]]>Both of the above sets of results work, but each post has typos which I cannot correct. An in depth exploration reveals 5 different solutions, all with 3 different L M R values between 1 & 8, and with average values of 3, 4 or 5. In each case the minimum distance from the centre of the middle value (where he aims for) is at least 15.5 cm before going into the next (unknown) slot, plenty of room for the 2cm radius ball to have it’s centre up to 12 cm from that centre. So no need for any of the slots to be the first one on the board.

LikeLike

]]>So there is a solution where the mid value is low, and the adjacent values can take one of two different pairs (they have the same sum), and where the total length measured from the centre of the mid slot is > 12 in each case. Definitely two sets of results, doesn’t matter where they are on the board. Maybe I’m missing something?

LikeLike

]]>LikeLike

]]>To be sure I satisfy all the conditions this Python program constructs all possible orderings for the holes, and then for each ordering looks at possible target positions. It looks for orderings that have a unique maximum targeting point that is at the centre of a hole, and that yields an integer average score per shot. Once an ordering passes these tests we record the hole that the target is in, along with the two holes on either side. This gives a unique *target + left/right* value (although there are many orderings that contain the three holes appropriately positioned).

It runs in 1.58s, but I think this could be improved with some additional analysis.

from enigma import irange, subsets, multiset, ordered, printf # available holes (points) holes = [ 1, 2, 3, 4, 5, 6, 7, 8 ] # layout for a sequence of holes # return a list of: (region size (in mm), points scored) pairs def layout(ps): for (i, p) in enumerate(ps): if i > 0: yield (60, 0) # gap between holes yield (110 - 10 * p, p) # hole size # generate intervals ((a, b), p) from a layout # where a, b are absolute distances, p is number of points scored def intervals(ss): a = b = 0 for (d, p) in ss: if b == 0: (a, b) = (0, d) else: (a, b) = (b, b + d) yield ((a, b), p) # analyse the layout (working in 5mm steps) # return list of (d, (v, r)) values, where: # d = absolute target distance # v + r/240 = max average score def analyse(ss): # determine total length t = sum(d for (d, _) in ss) rs = list() # consider target positions (in 5mm steps) for x in irange(120, t - 120, step=5): # consider each zone r = 0 for ((a, b), p) in intervals(ss): # overlap? if b < x - 120: continue if a > x + 120: break d = min(x + 120, b) - max(x - 120, a) r += p * d rs.append((x, r)) # find maximum average value m = max(r for (_, r) in rs) return list((x, divmod(r, 240)) for (x, r) in rs if r == m) # collect results m = multiset() # choose an order for the holes for ps in subsets(holes, size=len, select="P"): # but ignore the order in the diagram if ps == (6, 3, 8, 7, 2, 5, 1, 4): continue # construct the sequence of (regions, points) ss = list(layout(ps)) # analyse it rs = analyse(ss) # there should only be one max position if len(rs) != 1: continue (x, (v, r)) = rs[0] # and the average score should be an integer if r != 0: continue # find the interval x is in for ((a, b), p) in intervals(ss): # and check it is centred if p > 0 and a < x < b and b - x == x - a: # find the holes on either side i = ps.index(p) z = ps[i - 1:i + 2] printf("[{ps} -> target = {x} mm, avg pts = {v}; segment = {z}]") m.add((p, ordered(ps[i - 1], ps[i + 1]))) # output solution for ((x, (l, r)), n) in m.most_common(): printf("centre = {x}, left/right = {l}/{r} [{n} solutions]")

**Solution:** *[To Be Revealed]*

LikeLike

]]>Easy to check the digits in TIME give the digits in LITTLE

little, cnt = 0, 0 # check value of LITTLE using TIME'S digits of (3,5,7,8) from itertools import permutations for p in permutations((3,5,7,8)): t, i, m, e = p time = 1000*t + 100*i + 10*m + e # Add current <time> total little += time # increase permutation count cnt += 1 print(f"LITTLE = {little} in {cnt} permutations") # LITTLE = 153318 in 24 permutations

LikeLike

]]>So this Python program considers all 4 digit values for **TIME**, and totals only those rearrangements corresponding to 4 digit numbers. It runs in 135ms.

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

from enigma import irange, nsplit, nconcat, subsets, ordered, cached, printf # update a map m consistently with (k, v) pairs in ps def update(m, ps): m = m.copy() for (k, v) in ps: x = m.get(k) if x is None: m[k] = v elif x != v: return None return m # sum the rearrangements that give 4 digit numbers @cached def total(ds): t = 0 for s in subsets(ds, size=len, select="mP"): if s[0] != 0: t += nconcat(s) return t # consider 4 digit numbers for TIME for TIME in irange(1000, 9999): # this maps the letters T, I, M, E to digits ds = nsplit(TIME, 4) # sum the rearrangements of TIME that give 4 digit numbers t = total(ordered(*ds)) # the total is a 6 digit number ts = nsplit(t) if len(ts) != 6: continue # map letters to digits m = update(dict(zip("TIME", ds)), zip("LITTLE", ts)) if m is None: continue # output solution printf("TIME={TIME} LITTLE={t}")

**Solution:** **TIME** = 3578.

And so **LITTLE** = 153318.

It turns out that using a standard alphametic interpretation, and not worrying about whether the rearrangements always give 4 digit numbers will also give this answer. So:

If we write down the sum of the 24 permutations of **TIME**, each letter appears in each column 6 times, the result of the sum is thus:

6666 × (T + I + M + E) = LITTLE

Which we can solve as an alphametic expression using the [[ `SubstitutedExpression()`

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

The following run file gives the same solution in 92ms.

SubstitutedExpression --answer="(TIME, LITTLE)" "6666 * (T + I + M + E) = LITTLE"

LikeLike

]]>It runs in 50ms (on my new laptop).

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

from enigma import subsets, printf # check a statement (p -> q, "p implies q", "if p then q") check = lambda p, q: not(p) or q # choose days for the 8 items in question for (CC, CT, CH, CB, CS, PM, GB, LE) in subsets((1, 2), size=8, select="M"): # check the statements: # R: "if we have ham today we'll have beef tomorrow" if not check(CH == 1, CB == 2): continue # R: "if we have potted meat today we'll have cress sandwiches tomorrow" if not check(PM == 1, CS == 2): continue # R: "if we have tongue today we'll have lemonade tomorrow" if not check(CT == 1, LE == 2): continue # M: "if we save the cress sandwiches for tomorrow we'll have the beef today" if not check(CS == 2, CB == 1): continue # M: "if we keep the potted meat for tomorrow we'll have the ginger beer today" if not check(PM == 2, GB == 1): continue # M: "if we keep the lemonade for tomorrow we'll have the ham today" if not check(LE == 2, CH == 1): continue # R: "we'll have the lemonade and ginger beer on different days ..." if not(LE != GB): continue # R: "... and likewise the beef and the chicken" if not(CB != CC): continue # M: "if we have the chicken and cress sandwiches together, we'll # have the potted meat the day after we have the tongue" if not check(CC == CS, PM == CT + 1): continue # output solution printf("CC={CC} CT={CT} CH={CH} CB={CB} CS={CS} PM={PM} GB={GB} LE={LE}")

**Solution:** The cold beef, potted meat and lemonade was saved for the second day.

LikeLike

]]>Need to find 4 sections that end in reversible numbers, so just look for reversible pairs where the sum of the pair has the same last digit. Only works for 4 sections, QED.

LikeLike

]]>I wrote a recursive function that keeps track of all the conditions as it goes along.

The following Python 3 program runs in 320ms.

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

from itertools import product from enigma import irange, nsplit, join, cached, printf # does A mirror B? mirror = cached(lambda A, B: nsplit(A) == nsplit(B)[::-1]) # play the game starting with a round of k coins, # where A plays heads, B plays tails, and B is always ahead # ms = number of points B is ahead of A # s = index in ms when B = 2A # rv = count number of scores that are reverse of each other def play(k, tA=0, tB=0, ms=[], s=None, rv=0, ss=[]): # are we done? if k == 0: if s is not None and rv > 3: # there must be exactly 1 round after s where B is further ahead if sum(x > ms[s] for x in ms[s + 1:]) == 1: yield ss else: # consider the number of heads, and predictions for heads and tails for (n, h, t) in product(irange(0, k), (0, 1), (0, 1)): # calculate the points for each player a = n + h * 10 b = k - n + t * 10 # and the total points A = tA + a B = tB + b m = B - A # B is always ahead if not(m > 0): continue # look for cases where B = 2A s_ = s if B == 2 * A: # it only happens once if s is not None: continue # there must be exactly 1 previous round where B is further ahead if not(sum(x > m for x in ms) == 1): continue s_ = len(ms) # are A, B mirrored scores? rv_ = rv + mirror(A, B) # in the final 4 rounds we must have encountered some mirrored scores if k < 5 and rv_ < 5 - k: continue # play the remaining rounds yield from play(k - 1, A, B, ms + [m], s_, rv_, ss + [(n, h, t, A, B)]) # play the game, starting with 7 coins for ss in play(7): # output the rounds (pA, pB) = (0, 0) s = list(i for (i, (n, h, t, A, B)) in enumerate(ss) if B == 2 * A)[0] for (i, (n, h, t, A, B)) in enumerate(ss): k = 7 - i fs = [ f"lead = {B - A}" ] if i == s: fs.append("double") if mirror(A, B): fs.append("mirror") printf( "{k} coins: heads={n}; predictions = ({h}, {t}); points = ({a}, {b}); totals = ({A}, {B}); {fs}", a=A - pA, b=B - pB, fs=join(fs, sep="; "), ) (pA, pB) = (A, B) printf()

**Solution:** The number of heads in each of the rounds was: 0, 2, 4, 4, 3, 1, 1.

The full description of the rounds is:

k h t | H T | a b | A B 7: 0 7 | - 10 | 0 17 | 0 17 [lead >16] 6: 2 4 | 10 - | 12 4 | 12 21 [mirror] 5: 4 1 | - 10 | 4 11 | 16 32 [double, lead =16] 4: 4 0 | - - | 4 0 | 20 32 3: 3 0 | - - | 3 0 | 23 32 [mirror] 2: 1 1 | 10 10 | 11 11 | 34 43 [mirror] 1: 1 0 | - 10 | 1 10 | 35 53 [mirror, lead >16]

(k = number of coins; h, t = number of heads/tails; H, T = bonus points; a, b = points in round; A, B = cumulative totals)

However, keeping the cumulative totals always using 2 digits gives us three further solutions where the totals 03 and 30 are used as mirrored pairs:

k h t | H T | a b | A B 7: 1 6 | - 10 | 01 16 | 01 16 6: 2 4 | - 10 | 02 14 | 03 30 [mirror, lead >16] 5: 3 2 | 10 - | 13 02 | 16 32 [double, lead =16] 4: 4 0 | - - | 04 00 | 20 32 3: 3 0 | - - | 03 00 | 23 32 [mirror] 2: 1 1 | 10 10 | 11 11 | 34 43 [mirror] 1: 1 0 | - 10 | 01 10 | 35 53 [mirror, lead >16] k h t | H T | a b | A B 7: 2 5 | - 10 | 02 15 | 02 15 6: 1 5 | - 10 | 01 15 | 03 30 [mirror, lead >16] 5: 3 2 | 10 - | 13 02 | 16 32 [double, lead =16] 4: 4 0 | - - | 04 00 | 20 32 3: 3 0 | - - | 03 00 | 23 32 [mirror] 2: 1 1 | 10 10 | 11 11 | 34 43 [mirror] 1: 1 0 | - 10 | 01 10 | 35 53 [mirror, lead >16] k h t | H T | a b | A B 7: 3 4 | - 10 | 03 14 | 03 14 6: 0 6 | - 10 | 00 16 | 03 30 [mirror, lead >16] 5: 3 2 | 10 - | 13 02 | 16 32 [double, lead =16] 4: 4 0 | - - | 04 00 | 20 32 3: 3 0 | - - | 03 00 | 23 32 [mirror] 2: 1 1 | 10 10 | 11 11 | 34 43 [mirror] 1: 1 0 | - 10 | 01 10 | 35 53 [mirror, lead >16]

The program will find all 4 solutions if we replace the calls to [[ `nsplit(x)`

]] with [[ `nsplit(x, 2)`

]] in the function [[ `mirror()`

]] (line 5).

LikeLike

]]>1, 1, 2, 3, 5, 8, 13, 21, …

i.e. a Fibonacci sequence. [ @Wikipedia ]

So we can start with the two 1×1 cm squares and build up the original rectangle square by square, until find one where the mean area of the squares is a two digit integer as required.

This Python program runs in 82ms.

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

from enigma import printf # initial a x b rectangle, n = number of squares, A = total Area (a, b, n, A) = (1, 1, 2, 2) while True: # calculate the mean area of the squares (m, r) = divmod(A, n) if m > 99: break # construct the rectangle (a, b) = (b, a + b) if r == 0 and m > 9: # output solution, when m is a 2 digit integer printf("[n={n}] rectangle = {a} x {b}, mean area = {m}") # move on to the next square A += b * b n += 1

**Solution:** The original rectangle was 13 cm × 21 cm.

So in total 6 cuts were made, producing 7 squares.

The total area of the 7 squares is 273 sq cm, so the mean area is 39 sq cm.

Manually:

If:

F(n) = nth Fibonacci number

S(n) = sum of squares of F(n) = F(n) F(n + 1)

M(n) = mean of squares of F(n) = F(n) F(n + 1) / n

Then we can calculate:

n F(n) S(n) M(n) 1 1 1 1 2 1 2 1 3 2 6 2 4 3 15 3.75 5 5 40 8 6 8 104 17.3... 7 13 273 39 8 21 714 89.25 9 34 1870 207.7... 10 55 ...

And the answer is apparent.

If we draw a quarter circle through each square we can make a *Fibonacci Spiral*:

LikeLike

]]>This Python 3 program runs in 87ms.

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

from fractions import Fraction as F from enigma import divisors, div, irange, inf, join, printf # decompose t into numbers between 2 and 9 def decompose(t, m=2, M=9, s=[]): if not(t < m or t > M): yield s + [t] for x in irange(m, min(t - m, M)): yield from decompose(t - x, x + 1, M, s + [x]) # each wheel is divided into n equal sized divisions # each spanning d degrees for n in divisors(360): d = div(360, n) if d < 10: break if d > 99: continue # probability of 3 cherries p = F(1, n) ** 3 # consider the number of other fruits (all different and between 2 and 9) for ns in decompose(n - 1): # calculate the probabilities of getting 3 of each of the other fruits ps = list(F(x, n) ** 3 for x in ns) # probabilities are all 1/N if not all(x.numerator == 1 for x in ps): continue # and more than one N is odd if sum(x.denominator % 2 == 1 for x in ps) < 2: continue # output solution printf("{n} divisions, {d} degrees -> 1 + {ns}; p={p}, ps=[{ps}]", ps=join(ps, sep=", "))

**Solution:** There is a 1 / 5832 chance of getting 3 cherries.

Each wheel is divided into 18 sectors. Each sector subtends 20°.

There are 4 fruits, each is allocated 1, 2, 6, 9 sectors on each wheel.

The probabilities for each of the 4 fruits are: 1/5832 (= 1/18³), 1/729 (= 1/9³), 1/27 (= 1/3³), 1/8 (= 1/2³).

LikeLike

]]>The generalisation of this puzzle is known as **Routh’s Theorem** [ @wikipedia ], which states that the ratio of the area of the central triangle to the original triangle, where the sides are divided in the ratios *1:x, 1:y, 1:z* is given by the formula:

R = (xyz – 1)² / ((xz + x + 1)(xy + y + 1)(yz + z + 1))

I made a note giving the areas of the various subdivisions here [ **rouths-theorem.pdf** ].

For this puzzle we have: *x = y = z = 6*, which gives the ratio as:

R = (x – 1)² / (x² + x + 1) = 25/43

The smaller triangle has an area of 100, so the larger triangle has an area of: 100 × 43/25 = 172.

**Solution:** The area of the green triangle is 172 sq cm.

Or using a program:

from fractions import Fraction from enigma import printf # ratio ABC/XYZ in Routh's theorem def routh(x, y, z): a = x * y * z - 1 b = (x * y + y + 1) * (y * z + z + 1) * (z * x + x + 1) return Fraction(a * a, b) # compute the ratio of the area of the inner and outer triangles R = routh(6, 6, 6) # output the solution, given the inner triangle has area 100 printf("outer triangle = {x} [R={R}]", x=100 / R)

LikeLike

]]>This gives us a simpler, and slightly shorter, program.

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

from enigma import irange, chunk, printf # number of blocks in outer band n = 402 # record Red, Grey, Yellow blocks required R = G = Y = 0 # work inwards in chunks of 8 bands # each band has 8 less blocks than the previous band for s in chunk(irange(n, 1, step=-8), 8): if len(s) < 8: break (r1, r2, r3, r4, g1, g2, g3, y) = s R += r1 + r2 + r3 + r4 G += g1 + g2 + g3 # the middle is a single row m = 1 + y // 2 if 5 * (Y + m) == R: printf("R={R} G={G} Y={Y}", Y=Y + m) # otherwise, carry on Y += y

LikeLike

]]>LikeLike

]]>If there are *k* repeats of the (red, grey yellow) bands, then *y = 16k – 1*.

And the first band of red stones requires *2x + 2y – 4 = 402* stones, so *x + y = 203*.

Here is a constructive program that counts the number of stones in each band. It runs in 78ms.

from enigma import irange, inf, printf # calculate the number of stones with <k> repeats # and the initial band being <x> by <y> def stones(k, y, x): d = dict(R=0, G=0, Y=0) for i in ("RRRRGGGY" * k): if y < 2: d[i] += x * y break d[i] += 2 * (x + y - 2) x -= 2 y -= 2 return (d['R'], d['G'], d['Y']) # consider the number of repeats of the bands for k in irange(1, inf): y = 16 * k - 1 x = 203 - y if not(x > y): break # calculate the number of stones needed (R, G, Y) = stones(k, y, x) # output solution if 5 * Y == R: printf("k={k}, y={y} x={x}; R={R} G={G} Y={Y}")

**Solution:** James requires 5520 red stones.

The patio consists of 6 red/grey/yellow layers, finishing with a single row of 14 yellow stones:

The number of stones required is: red = 5520, grey = 3636, yellow = 1104; total = 10260.

The outer band measures 108×95 stones.

LikeLike

]]>