Design a site like this with WordPress.com
Get started

Recent Updates Toggle Comment Threads | Keyboard Shortcuts

  • Jim Randell 8:51 am on 4 December 2022 Permalink | Reply
    Tags:   

    Brain-Teaser 252: Blocks 

    From The Sunday Times, 27th February 1966 [link]

    “See these eleven blocks?”, says a so-called friend. “Four of them of 8 inch thickness, two of them of 4 inch thickness, three of 3 inch and two of 1 inch thickness”.

    “Pile them in a column 51 inches high with a 3 inch block at the bottom so that, remaining in position, individual blocks or combinations of adjacent blocks can be used to measure every thickness in exact inches from 1 inch to 48 inches”.

    In what order do they stand?

    This puzzle was included in the book Sunday Times Brain Teasers (1974, edited by Ronald Postill).

    [teaser252]

     
    • Jim Randell 8:54 am on 4 December 2022 Permalink | Reply

      (See also: Teaser 119, Teaser 560).

      This Python program performs an exhaustive search of all possible stacks of blocks.

      It runs in 268ms.

      Run: [ @replit ]

      from enigma import (multiset, subsets, csum, irange, printf)
      
      # the blocks
      blocks = multiset.from_dict({8: 4, 4: 2, 3: 3, 1: 2})
      assert blocks.sum() == 51
      
      # extract a 3 block
      blocks.remove(3)
      
      # and consider possible arrangements of the remaining blocks
      for bs in subsets(blocks, size=len, select="mP", fn=list):
        bs.insert(0, 3)
        # find what thicknesses can be measured
        ts = set(b - a for (a, b) in subsets(csum(bs, empty=1), size=2))
        # can we measure all values from 1 to 48
        if all(x in ts for x in irange(1, 48)):
          printf("{bs}")
      

      Solution: The pile of blocks (bottom to top) is one of the following two sequences:

      (3, 4, 3, 8, 8, 8, 8, 4, 1, 1, 3)
      (3, 1, 1, 4, 8, 8, 8, 8, 3, 4, 3)

      One being the reverse of the other.

      Like

  • Jim Randell 4:35 pm on 2 December 2022 Permalink | Reply
    Tags:   

    Teaser 3141: Multiple extensions 

    From The Sunday Times, 4th December 2022 [link] [link]

    All the phone extensions at Mick’s work place are four-digit numbers with no zeros or twos, and no digit appears more than once in a number. He can enter all the extension numbers on the keypad by starting at key 2 (but not pressing it) then moving in any direction, including diagonally, to an adjacent key and pressing it; then similarly moving to and pressing adjacent keys until the number is entered. A couple of examples of his extension numbers are 3685 and 5148.

    He phoned two different extension numbers this morning and later realised that one was an exact multiple of the other.

    What was the larger extension number he dialled?

    [teaser3141]

     
    • Jim Randell 4:54 pm on 2 December 2022 Permalink | Reply

      The following Python program runs in 58ms. (Internal run time is 6.2ms).

      Run: [ @replit ]

      from enigma import (nconcat, div, ordered, printf)
      
      # adjacency matrix
      adj = {
        1: [2, 4, 5],
        2: [1, 3, 4, 5, 6],
        3: [2, 5, 6],
        4: [1, 2, 5, 7, 8],
        5: [1, 2, 3, 4, 6, 7, 8, 9],
        6: [2, 3, 5, 8, 9],
        7: [4, 5, 8],
        8: [4, 5, 6, 7, 9],
        9: [5, 6, 8],
      }
      
      # generate k-length numbers with no repeated digits
      def solve(k, ds):
        if k == 0:
          yield ds
        else:
          for d in adj[ds[-1]]:
            if d not in ds:
              yield from solve(k - 1, ds + [d])
      
      # start at 2, and dial 4 more digits
      ns = list()
      for ds in solve(4, [2]):
        n = nconcat(ds[1:])
        # look for previous numbers that pair with this one
        for m in ns:
          (x, y) = ordered(m, n)
          k = div(y, x)
          if k:
            printf("{y} = {k} * {x}")
        # add in the new number
        ns.append(n)
      

      (Or a more efficient (but longer) variation on this code [@replit]).

      Solution: [To Be Revealed]

      Like

  • Jim Randell 8:58 am on 1 December 2022 Permalink | Reply
    Tags:   

    Teaser 2689: The right choice 

    From The Sunday Times, 6th April 2014 [link]

    I am organising a tombola for the fete. From a large sheet of card (identical on both sides) I have cut out a lot of triangles of equal area. All of their angles are whole numbers of degrees and no angle exceeds ninety degrees. I have included all possible triangles with those properties and no two of them are identical. At the tombola entrants will pick a triangle at random and they will win if their triangle has a right-angle. The chances of winning turn out to be one in a certain whole number.

    What is that whole number?

    [teaser2689]

     
    • Jim Randell 8:59 am on 1 December 2022 Permalink | Reply

      Once we have chosen the three angles of the triangle (each an integer between 1° and 90°, that together sum 180°), we can form a triangle with the required area by scaling it appropriately.

      This Python program counts the number of possible triangles and the number of them that are right angled.

      It runs in 53ms. (Internal runtime is 1.0ms).

      Run: [ @replit ]

      from enigma import (decompose, fraction, printf)
      
      # generate possible triangles
      triangles = lambda: decompose(180, 3, increasing=1, sep=0, min_v=1, max_v=90)
      
      # count:
      # t = total number of triangles
      # r = number with a right angle
      r = t = 0
      for (a, b, c) in triangles():
        t += 1
        if c == 90: r += 1
      
      # output solution
      (p, q) = fraction(r, t)
      printf("P(win) = {r}/{t} = {p}/{q}")
      

      Solution: The chance of winning is 1/16.

      There are 720 triangles, and 45 of them are right angled.

      I think it would be annoying to choose a triangle with an 89° angle.

      Like

  • Jim Randell 8:28 am on 29 November 2022 Permalink | Reply
    Tags:   

    Teaser 2685: Not the Gold Cup 

    From The Sunday Times, 9th March 2014 [link]

    Five horses took part in a race, but they all failed to finish, one falling at each of the first five fences. Dave (riding Egg Nog) lasted longer than Bill whose horse fell at the second fence; Big Gun fell at the third, and the jockey wearing mauve lasted the longest. Long Gone lasted longer than the horse ridden by the jockey in yellow, Chris’s horse fell one fence later than the horse ridden by the jockey in green, but Fred and his friend (the jockey in blue) did not fall at adjacent fences. Nig Nag was ridden by Wally and Dragon’s jockey wore red.

    Who was the jockey in yellow, and which horse did he ride?

    [teaser2685]

     
    • Jim Randell 8:28 am on 29 November 2022 Permalink | Reply

      I used the [[ SubstitutedExpression ]] solver from the enigma.py library to assign the fence values (1-5) to the 3 groups of jockeys, horses and colours.

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

      Run: [ @replit ]

      #! python3 -m enigma -r
      
      # assign fence numbers (1-5) to the following groups:
      #
      #  jockeys = A (Wally), B (Bob), C (Chris), D (Dave), E (Fred)
      #  horses  = F (Egg Nog), G (Big Gun), H (Long Gone), I (Nig Nag), J (Dragon)
      #  colours = K (mauve), L (yellow), M (green), N (blue), P (red)
      
      SubstitutedExpression
      
      --base="6"
      --digits="1-5"
      --distinct="ABCDE,FGHIJ,KLMNP"
      --template="(A B C D E) (F G H I J) (K L M N P)"
      --solution=""
      
      # "Dave (D) riding Egg Nog (F) lasted longer than Bill (B) who fell at the 2nd fence"
      "D = F"
      "D > B"
      "2 = B"
      
      # "Big Gun (G) fell at the 3rd"
      "3 = G"
      
      # "mauve (K) lasted the longest"
      "5 = K"
      
      # "Long Gone (H) lasted longer than yellow (L)
      "H > L"
      
      # "Chris's (C's) horse fell one fence later than the horse ridden by green (M)"
      "M + 1 = C"
      
      # "Fred (E) and his friend blue (N) did not fall at adjacent fences"
      "abs(E - N) > 1"
      
      # "Nig Nag (I) was ridden by Wally (A)"
      "I = A"
      
      # "Dragon's (J's) jockey wore red"
      "J = P"
      

      We can wrap this in Python code to format the solution in a more friendly form:

      Run: [ @replit ]

      from enigma import (SubstitutedExpression, group, printf)
      
      # load the run file
      p = SubstitutedExpression.from_file("teaser2685.run")
      
      # map symbols to jockey, horse, colour names
      name = dict(
        A="Wally", B="Bob", C="Chris", D="Dave", E="Fred",
        F="Egg Nog", G="Big Gun", H="Long Gone", I="Nig Nag", J="Dragon",
        K="mauve", L="yellow", M="green", N="blue", P="red",
      )
      
      # solve the puzzle
      for s in p.solve(verbose=0):
        # group symbols by value
        d = group(s.keys(), by=s.get)
        # output solution for each fence
        for k in sorted(d.keys()):
          # extract jockey, horse, colour
          (j, h, c) = (name[s] for s in sorted(d[k]))
          printf("{k}: {j} ({c}) on {h}")
        printf()
      

      Solution: Fred was in yellow, riding Big Gun.

      The full solution is:

      1st fence: Wally (blue) on Nig Nag
      2nd fence: Bob (red) on Dragon
      3rd fence: Fred (yellow) on Big Gun
      4th fence: Dave (green) on Egg Nog
      5th fence: Chris (mauve) on Long Gone

      Like

  • Jim Randell 9:47 am on 27 November 2022 Permalink | Reply
    Tags:   

    Brain-Teaser 222: British triangles 

    From The Sunday Times, 25th July 1965 [link]

    British Triangles, naturally, stand on horizontal bases with their points upwards. All their sides, never more than a  sensible 60 inches, and their heights measure an exact number of inches. No B.T. is isosceles or right angled.

    You can often put more than one B.T. on a common base. On a base of 28 inches 8 B.T.s are erected.

    What are their heights?

    This puzzle was included in the book Sunday Times Brain Teasers (1974, edited by Ronald Postill).

    [teaser222]

     
    • Jim Randell 9:47 am on 27 November 2022 Permalink | Reply

      If the 3 sides of a triangle are a, b, c, then the area A is given by Heron’s formula:

      s = (a + b + c) / 2
      A = √(s(s − a)(s − b)(s − c))

      And if the height (from side a) is h, then we also have:

      A = ha / 2

      Hence the height h can be determined from the sides a, b, c:

      h = 2A / a
      h = (2/a)√(s(s − a)(s − b)(s − c))

      This Python program considers possible values for the 2nd and 3rd sides of the triangle, and then looks for values where the height is an integer.

      It runs in 53ms. (Internal runtime is 1.8ms).

      Run: [ @replit ]

      from enigma import (irange, div, is_square, subsets, sq, printf)
      
      # check for a viable triangle
      def is_triangle(a, b, c):
        # check triangle inequalities
        if not (a + b > c and a + c > b and b + c > a): return
        # no triangle is isosceles
        if len({a, b, c}) < 3: return
        # no triangle is right angled
        sqs = (sq(a), sq(b), sq(c))
        if sum(sqs) == 2 * max(sqs): return
        # looks OK
        return (a, b, c)
      
      # calculate integer height from side a
      def height(a, b, c):
        p = a + b + c
        x = div(p * (p - 2 * a) * (p - 2 * b) * (p - 2 * c), 4)
        if not x: return
        x = is_square(x)
        if not x: return
        h = div(x, a)
        return h
      
      # base
      a = 28
      # consider possible integer length for the remaining sides, b, c
      for (b, c) in subsets(irange(1, 60), size=2, select="R"):
        if not is_triangle(a, b, c): continue
        # calculate the height of the triangle
        h = height(a, b, c)
        if not h: continue
        # output viable triangles
        printf("a={a} b={b} c={c} -> h={h}")
      

      Solution: The heights of the triangles are 9″ (2 triangles), 15″ (4 triangles), 24″ (2 triangles).

      The four triangles found by the program are shown below. And they can be mirrored to produce the remaining four triangles.

      Like

    • Hugh Casement 7:41 am on 28 November 2022 Permalink | Reply

      Alternatively we can think of it as two right-angled triangles joined together.
      If their bases are d and e, then d² = b² – h² and e² = c² – h².
      d + e, or |d – e| in the case of the obtuse-angled triangles, must equal a = 28.
      b must not equal c, for then the overall triangle would be isosceles
      (that is the case when h = 48, b = c = 50, and d = e = 14).

      Like

      • Hugh Casement 9:09 am on 28 November 2022 Permalink | Reply

        Joined together along the line of their common height h, of course.
        A base a = 21 also allows eight resultant triangles, including reflections.

        Like

  • Jim Randell 4:12 pm on 25 November 2022 Permalink | Reply
    Tags:   

    Teaser 3140: Enjoy every minute 

    From The Sunday Times, 27th November 2022 [link] [link]

    On rugby international morning, I found myself, along with eight friends, in a pub 5.8 miles from the match ground. We were enjoying ourselves, and so wished to delay our departure for the ground until the last possible minute. The publican, wishing to keep our custom for as long as possible, offered to help us get there by carrying us, one at a time, as pillion passengers on his motorbike.

    We could walk at 2.5mph and the bike would travel at 30mph. We all left the pub together, and arrived at the ground in time for kick-off.

    Ignoring the time taken getting on and off the bike, what was our minimum travelling time in minutes?

    [teaser3140]

     
    • Jim Randell 4:58 pm on 25 November 2022 Permalink | Reply

      (Curiously this week’s New Scientist back page puzzle is a simpler variation on the problem [link]).

      If the friends just walked from pub to the stadium it would take 2.32 hours.

      If the barman ferried each of them individually between the pub and the stadium it would take 3.29 hours.

      But we can do better.

      If the barman takes the first friend on his motorbike, and the rest of the friends start walking towards the stadium. Then the barman drops the first friend off to walk the remainder of the distance to the stadium and returns to the group (now a short distance from the pub) and ferries the next friend to join the first friend, and so on until he collects the final friend and drops him off at the stadium at the same time that all the other friends arrive, then we can achieve a minimum overall time.

      The only thing to work out is how far before the stadium to drop the first friend, then it is just a matter of ferrying friends from the trailing to the leading group.

      If each of the k friends walks a distance x at velocity w, and travels by motorbike a distance (d − x) at a velocity v, then each journey takes:

      t = x/w + (d − x)/v

      And the total time taken for the barman to ferry them all is:

      t = [(2k − 1)d − 2kx]/v

      Everyone arrives at the stadium at the same time, so:

      x/w + (d − x)/v = [(2k − 1)d − 2kx]/v
      vx + (d − x)w = [(2k − 1)d − 2kx]w
      vx + dw − xw = (2k − 1)dw − 2kxw
      x(v + w(2k − 1)) = dw(2k − 2)
      x = 2dw(k − 1) / (v + w(2k − 1))

      or:

      n = 2k − 1
      x = dw(n − 1) / (v + wn)
      t = d(w + vn) / v(v + wn)

      The answer can then be calculated directly.

      Run: [ @replit ]

      from enigma import (fdiv, printf)
      
      k = 9    # number of people in the group
      d = 5.8  # distance between pub and stadium
      w = 2.5  # walking speed
      v = 30   # motorbike speed
      
      # calculate amount of walking per person
      n = 2 * k - 1
      x = fdiv(d * w * (n - 1), v + w * n)
      
      # calculate time taken
      t = fdiv(x, w) + fdiv(d - x, v)
      
      # output solution
      printf("t={t:g} hours (= {m:g} min) [x={x:g} miles]", m=t * 60)
      

      Solution: The minimum travelling time is 82 minutes.

      We calculate:

      x = 16/5 = 32/10
      t = 32/25 + 13/150 = 41/30 = 82/60

      So the first friend is dropped off 3.2 miles from the stadium (and walks the remainder of the way).

      Each friend walks for 76.8 minutes and is on the motorbike for 5.2 minutes. Giving each a total journey time of 82 minutes.

      Like

      • Jim Randell 10:56 pm on 30 November 2022 Permalink | Reply

        Here is a numerical approach, based on the barman dropping the first friend off after a distance x (from the pub) while the remaining friends set off on foot.

        The barman then returns to the trailing group and ferries a single friend from the trailing to the leading group until everyone has been transferred to the leading group. And we record the maximal journey time for the friends to give us a total time to get all the friends to the stadium.

        We then use the [[ find_min() ]] function from the enigma.py library to determine at what distance x the shortest total journey time occurs.

        Unsurprisingly this gives us the same answer as the analytical approach above (but with considerably more effort). But it does show that the logic used in the analysis does indeed produce the minimum time.

        Run: [ @replit ]

        from enigma import (irange, fdiv, find_min, printf)
        
        k = 9    # number of people in the group
        d = 5.8  # distance between pub and stadium
        w = 2.5  # walking speed
        v = 30   # motorbike speed
        
        # if: A starts at a, velocity v; B starts at b, velocity w
        # return: (<position>, <time>) of meeting
        def meet(a, v, b, w, t0=0):
          t = fdiv(b - a, v - w)
          return (b + t * w, t0 + t)
        
        # run a scenario where the first person is dropped off at distance x
        # return the time taken for everyone to arrive
        def run(x):
          ts = list()
          # ferry friend 1 to x and let them walk the remaining distance (d - x)
          d1 = x
          t1 = fdiv(x, v)
          # and so the total time for the first friend is ...
          ts.append(t1 + fdiv(d - d1, w))
        
          # the position of the trailing group at time t is:
          tr = lambda t: min(t * w, d)
          # the position of the leading group at time t >= t1 is:
          ld = lambda t, t1=t1: min(x + (t - t1) * w, d)
        
          # ferry the remaining friends ...
          for _ in irange(2, k):
            # we return from d1 to the trailing group
            (d2, t2) = meet(d1, -v, tr(t1), w, t1)
            # and then back to the leading group
            (d3, t3) = meet(d2, +v, ld(t2), w, t2)
            if d3 < d:
              # they walk the remaining distance
              ts.append(t3 + fdiv(d - d3, w))
            else:
              # they are dropped off at the stadium
              (d3, t3) = (d, t2 + fdiv(d - d2, v))
              ts.append(t3)
            (d1, t1) = (d3, t3)
          # return the maximum time
          return max(ts)
        
        # find the minimal time
        r = find_min(run, 0, d)
        (t, x) = (r.fv, r.v)
        printf("min time = {t:g} hours (= {m:g} min) [drop 1 at {x:g} miles]", m=t * 60)
        

        Here is a graph of the total journey time against the distance x that the first friend is taken from the pub. We see that the minimum time is achieved when x = 2.6 miles.

        Like

      • NigelR 4:29 pm on 1 December 2022 Permalink | Reply

        Hi Jim. I very much enjoyed this puzzle (more for the logic than the Python content!) but I’m intrigued to know how you got to the term 2kx in your second equation. I got to it indirectly by looking at the vector sum of all the motorbike journeys out: [(k)(d-x)] +back: [(k)(d-x)-d] given that he finishes up a distance d from where he started. That then reduces to:
        [(2k-1)d -2kx] but is there a more intuitive way of getting to the second term?

        Like

        • Jim Randell 10:50 pm on 1 December 2022 Permalink | Reply

          @Nigel: The way I thought of it the barman makes a journey towards the stadium for each of the k friends. And in between friends he has to make (k − 1) return journeys towards the pub.

          If he made complete journeys between the pub and the stadium this would be (2k − 1) journeys of distance d for a total of (2k − 1)d.

          But if he made complete journeys he would be travelling over the ground that each friend walks, in both directions, so this amount is overcounting the barmans distance by 2x for each of the k friends.

          So the actual overall distance travelled by the barman is:

          (2k − 1)d − 2kx

          And this actual distance is travelled at velocity v, so we can determine the total time taken for the barman.

          Like

          • NigelR 9:31 am on 3 December 2022 Permalink | Reply

            Thanks Jim. It was the ‘in both directions’ that I was struggling to get my head around. This week’s puzzle is trivial by comparison!

            Like

    • Hugh Casement 9:45 am on 4 December 2022 Permalink | Reply

      There were some early Brain-Teasers of a similar kind by Brigadier A.G.H. Brousson (who died in 1976), involving the Smart brothers who took part in races with one bicycle between them.
      Numbers 640, 663, 686, 722, 741, and 792 would presumably yield to a variant of Jim’s analysis as given here. 792 (at least) is flawed because it doesn’t specify that they all arrived together — nor, for that matter, whether riding pillion on the rear carrier is permitted (I know from experience that it seriously upsets the balance and steering!).

      Like

  • Jim Randell 8:38 am on 24 November 2022 Permalink | Reply
    Tags: by: Dr J C Brown   

    Brain-Teaser 665: … Steady … 

    From The Sunday Times, 7th April 1974 [link]

    There were six starters for the special handicap event for the youngest class at the school sports. All started at the gun, and none fell by the wayside or was disqualified.

    Dave started quicker than Ed and finished before Fred. Colin finished two seconds after he would have finished if he had finished two seconds before Ed. Bob and Dave started quicker than Colin, and Bob was faster than Ed.

    Alf, who won third prize, finished two seconds after he would have finished if he had finished two seconds after Colin.

    Who won second prize?

    This puzzle was included in the book The Sunday Times Book of Brain-Teasers: Book 2 (1981, edited by Victor Bryant and Ronald Postill). The puzzle text above is taken from the book.

    [teaser665]

     
    • Jim Randell 8:38 am on 24 November 2022 Permalink | Reply

      If the total times are A, B, C, D, E, F. Then we derive:

      D < F
      C = (E − 2) + 2 ⇒ C = E
      B < E
      A = (C + 2) + 2 ⇒ A = C + 4 (and A was 3rd)

      From which we get 2 chains (shortest to longest time):

      B < C,E < A
      D < F

      However we are told that A was in 3rd place, but we see there are at least 3 competitors (B, C, E) who finished in a shorter time, which would imply the best A could have placed was 4th.

      So, assuming positions are ranked according to time, either the puzzle is flawed, or the goal of the race is to achieve the longest time, not the shortest.

      In this latter case the finishing positions (longest to shortest time) are:

      1st: Fred
      2nd: Dave
      3rd: Alf
      4th: Colin, Ed (joint)
      6th: Bob

      Solution: Dave won second prize.

      Like

  • Jim Randell 9:04 am on 22 November 2022 Permalink | Reply
    Tags:   

    Teaser 2688: Mother’s Day 

    From The Sunday Times, 30th March 2014 [link]

    Today we are having a family get-together to celebrate Mother’s Day. My maternal grandmother, my mother and I have each written down our date of birth in the form “ddmmyy”. This gives us three six-figure numbers and, surprisingly, both of the ladies’ numbers are multiples of mine. Furthermore, all of the digits from 0 to 9 occur somewhere in the three six-figure numbers.

    What is my mother’s six-figure date of birth?

    [teaser2688]

     
    • Jim Randell 9:05 am on 22 November 2022 Permalink | Reply

      At first I found many possible solutions to this puzzle.

      But if we require that the 6-digit numbers formed from the date cannot have a leading zero, then this narrows down the solution space considerably (and essentially restricts the three dates to the form 10xxxx, 20yyyy, 30zzzz, and the multiples being 1, 2, 3).

      This Python program runs in 129ms.

      Run: [ @replit ]

      from datetime import (date, timedelta)
      from enigma import (
        fdiv, inc, repeat, nconcat, nsplit, catch,
        subsets, append, tuples, union, join, printf
      )
      
      # extract date as a 6-digit number
      def number(d):
        if d.day < 10: return None
        return nconcat(d.day, d.month, d.year % 100, base=100)
      
      # check viable generation gap, a -> b
      def gap(a, b):
        y = fdiv((b - a).days, 365.2422)
        return not (y < 16 or y > 50)
      
      # consider dates for the setters birthdate
      for d in repeat(inc(timedelta(days=-1)), date(2014, 3, 30)):
        if d.year < 1922: break
        # construct the number "ddmmyy"
        n = number(d)
        if n is None: continue
        # look for proper multiples that also give a valid date
        mn = n
        ds = list()
        while True:
          mn += n
          if mn > 311299: break
          (dd, mm, yy) = nsplit(mn, base=100)
          for y in (1900 + yy, 1800 + yy):
            if y < 1892: continue
            md = catch(date, y, mm, dd)
            if md is None or number(d) is None: continue
            ds.append(md)
      
        # look for a set of 3 plausible ages
        for ss in subsets(sorted(ds), size=2):
          ss = append(ss, d)
          if not all(gap(a, b) for (a, b) in tuples(ss, 2)): continue
          # check all digits are used
          if len(union(nsplit(number(d)) for d in ss)) < 10: continue
          # output dates
          printf("{ss}", ss=join(ss, sep=" -> "))
      

      The program works backwards from 2014 to 1922 looking for sets of 3 dates that make a plausible set of birthdates for the three generations.

      It finds 2 possible situations, as below (ages shown are on the date the puzzle was published (2014-03-30)):

      Grandmother = 1919-08-30 (age = 94.6y)
      Mother = 1946-05-20 (age = 67.9y)
      Setter = 1973-02-10 (age = 41.1y)
      gap = 26.7y
      100273 × 2 = 200546
      100273 × 3 = 300819

      Grandmother = 1892-07-30 (age = 121.7y)
      Mother = 1928-05-20 (age = 85.9y)
      Setter = 1964-02-10 (age = 50.1y)
      gap = 35.7y
      100264 × 2 = 200528
      100264 × 3 = 300792

      The second of these is only just plausible, so presumably the first provides the required answer. (I would have preferred the puzzle eliminated one of these solutions by an explicit condition).

      Solution: The mother’s date of birth is: 200546 (i.e. 20th May 1946).

      To see solutions where the 6-digit number formed from the date is permitted to have a leading zero, the check at line 9 can be removed. In this case the program finds 115 solutions.

      Like

  • Jim Randell 11:32 am on 20 November 2022 Permalink | Reply
    Tags:   

    Brain-Teaser 204: Logical will 

    From The Sunday Times, 21st March 1965 [link]

    Uncle George occasionally wasted time on Brain-teasers, and it was expected that his will would take an awkward form. But his five nephews were surprised to learn, after his death, that he had dictated his will to a solicitor who had no use for punctuation. The will ran as follows:

    maurice is not to sing at my funeral service if stephen receives the envelope containing three thousand pounds alec is to have five thousand pounds if thomas receives less than maurice alec is to have exactly twice what nigel has if thomas does not receive the envelope containing a thousand pounds stephen is to have exactly four thousand pounds

    The nephews were confident that Uncle George always uttered complete sentences, none of which contained more than one conditional clause. They also felt sure that what he had said to the solicitor allowed one way, and one way only, of distributing the five envelopes (containing £5000, £4000, £3000, £2000, and £1000), which Uncle George had left for them.

    Who receives each envelope? And may Maurice sing at the funeral service?

    This puzzle was included in the book Sunday Times Brain Teasers (1974, edited by Ronald Postill).

    [teaser204]

     
    • Jim Randell 11:33 am on 20 November 2022 Permalink | Reply

      There are four ways we can parse the will into statements, each consisting of 4 statements, 3 of which are conditional:

      [1]
      (maurice is not to sing at my funeral service)
      (stephen receives £3000) → (alec is to have £5000)
      (thomas receives less than maurice) → (alec is to have exactly twice what nigel has)
      (thomas does not receive £1000) → (stephen is to have exactly £4000)

      [2]
      (maurice is not to sing at my funeral service) ← (stephen receives £3000)
      (alec is to have £5000)
      (thomas receives less than maurice) → (alec is to have exactly twice what nigel has)
      (thomas does not receive £1000) → (stephen is to have exactly £4000)

      [3]
      (maurice is not to sing at my funeral service) ← (stephen receives £3000)
      (alec is to have £5000) ← (thomas receives less than maurice)
      (alec is to have exactly twice what nigel has)
      (thomas does not receive £1000) → (stephen is to have exactly £4000)

      [4]
      (maurice is not to sing at my funeral service) ← (stephen receives £3000)
      (alec is to have £5000) ← (thomas receives less than maurice)
      (alec is to have exactly twice what nigel has) ← (thomas does not receive £1000)
      (stephen is to have exactly £4000)

      This Python program investigates each interpretation, rejecting those that do not have a single way of distributing the money.

      It runs in 54ms. (Internal runtime is 866µs).

      Run: [ @replit ]

      from enigma import (defaultdict, cproduct, subsets, implies, singleton, join, printf)
      
      # evaluate the clauses under interpretation <i>
      def check(i, cs):
        (a, b, c, d, e, f, g) = cs
        # [1] (a, b -> c, d -> e, f -> g)
        if i == 1: return all([a, implies(b, c), implies(d, e), implies(f, g)])
        # [2] (a <- b, c, d -> e, f -> g)
        if i == 2: return all([implies(b, a), c, implies(d, e), implies(f, g)])
        # [3] (a <- b, c <- d, e, f -> g)
        if i == 3: return all([implies(b, a), implies(d, c), e, implies(f, g)])
        # [4] (a <- b, c <- d, e <- f, g)
        if i == 4: return all([implies(b, a), implies(d, c), implies(f, e), g])
      
      # the amounts in the envelopes
      money = [5000, 4000, 3000, 2000, 1000]
      
      # choose an interpretation of the will (1-4)
      for i in (1, 2, 3, 4):
      
        # record outcomes: (A, M, N, S, T) -> sing
        r = defaultdict(list)
      
        # allocate the envelopes, and whether Maurice can sing
        for (k, sing) in cproduct([subsets(money, size=len, select="P"), [0, 1]]):
          (A, M, N, S, T) = k
      
          # the clauses:
          cs = [
            # (a) "M is not to sing ..."
            (not sing),
            # (b) "S gets 3000"
            (S == 3000),
            # (c) "A gets 5000"
            (A == 5000),
            # (d) "T gets less than M"
            (T < M),
            # (e) "A gets twice N"
            (A == 2 * N),
            # (f) "T does not get 1000"
            (T != 1000),
            # (g) "S gets 4000"
            (S == 4000),
          ]
      
          # is this is a valid allocation?
          if check(i, cs):
            r[k].append(sing)
            # do we need to proceed further?
            if len(r.keys()) > 1: break
      
        # there is only one way to distribute the money?
        k = singleton(r.keys())
        if k:
          # output solution
          (A, M, N, S, T) = k
          printf("[{i}] A={A} M={M} N={N} S={S} T={T}; sing={sing}", sing=join(sorted(r[k]), sep=", ", enc="{}"))
      

      Solution: The money is distributed as follows:

      Alec: £2000
      Maurice: £3000
      Nigel: £1000
      Stephen: £4000
      Thomas: £5000

      The solution is provided by interpretation [3] of the will.

      And as Stephen does not get £3000, Maurice is not prohibited from singing at the funeral.

      Like

  • Jim Randell 4:22 pm on 18 November 2022 Permalink | Reply
    Tags:   

    Teaser 3139: Checkmate 

    From The Sunday Times, 20th November 2022 [link] [link]

    Our chess club is divided into sections, with each section having the same number of players. The two oldest members will soon be retiring from playing and we will change the number of sections. The number of sections will change by one and so will the number of players in each section, but all the sections will still have the same number of players. This will result in there being a grand total of 63 fewer matches per year if each member plays all the other members of their section once per year.

    How many players are in each section at the moment?

    [teaser3139]

     
    • Jim Randell 4:56 pm on 18 November 2022 Permalink | Reply

      If the players are split into k sections, each consisting of n players, then the number of matches in each section is C(n, 2), and the total number of matches is m = k.C(n, 2).

      We can use some analysis to simplify the puzzle to two cases, one of which has no solution for positive integers, and the other that gives us the required solution.

      However, here is a constructive Python program that considers the total numbers of players t (up to 2000), and generates the possible (n, k, m) values for each candidate t value. It then looks for two t values that differ by 2, and give n and k values that differ by 1, and m values that differ by 63.

      This Python program runs in 85ms.

      Run: [ @replit ]

      from enigma import (irange, divisors_pairs, tri, cproduct, tuples, printf)
      
      # generate (k, n, m) values for t players
      def generate(t):
        # divide them into k sections of n players each
        for (k, n) in divisors_pairs(t, every=1):
          if n < 2: continue
          # calculate the total number of matches
          m = k * tri(n - 1)
          yield (t, k, n, m)
      
      # solve for numbers of players that differ by 2
      def solve(N):
        for (zs, ys, xs) in tuples((list(generate(t)) for t in irange(1, N)), 3):
          for ((t, k, n, m), (t_, k_, n_, m_)) in cproduct([xs, zs]):
            # check the differences in the corresponding k, n, m values
            if abs(k - k_) == 1 and abs(n - n_) == 1 and m - m_ == 63:
              # output solution
              printf("{k} sections of {n} players (= {m} matches) -> {k_} sections of {n_} players (= {m_} matches)")
      
      # solve the puzzle (up to 2000 players)
      solve(2000)
      

      Solution: There are 10 players in each section.

      The club starts with 110 players, formed into 11 sections of 10 players each. There are 45 matches among the players in each section, and 495 matches in total.

      When 2 players leave there are 108 players remaining. These are formed into 12 sections of 9 players each. There are 36 matches among the players in each section, and 432 matches in total. This is 63 fewer matches.


      Manually from:

      (n ± 1)(k ± 1) = nk − 2

      we can see that (for n + k > 3) there are 2 cases:

      [Case 1] (n, k)(n + 1, k − 1)k = n − 1.

      k C(n, 2) − (k − 1) C(n + 1, 2) = 63
      n[(n − 1)(n − 1) − (n − 2)(n + 1)] = 126
      n(3 − n) = 126
      n² − 3n + 126 = 0

      Which has no solution in positive integers.

      [Case 2] (n, k)(n − 1, k + 1)k = n + 1.

      k C(n, 2) − (k + 1) C(n − 1, 2) = 63
      (n − 1)[(n + 1)n − (n + 2)(n − 2)] = 126
      (n − 1)(n + 4) = 126
      n² + 3n − 130 = 0
      (n − 10)(n + 13) = 0
      n = 10
      k = 11

      And so there are 11 sections, each with 10 players.

      Like

    • GeoffR 3:49 pm on 19 November 2022 Permalink | Reply

      
      % A Solution in MiniZinc
      include "globals.mzn";
      
      % Assumed No. of persons in each section before and after retirement
      var 2..25:persB; var 1..23:persA;
      
      % Assumed No. of sections before and after retirement
      var 2..25:sectB; var 1..25:sectA;
      
      % No of matches before and after retirement
      % UB = 25 * (25 * 24//2)
      var 1..7500: matchesB; var 1..7500: matchesA;
      
      % Change in number of sections is one due to two people retiring
      constraint abs(sectA - sectB) == 1;
      
      % Change in total number of persons is two
      constraint sectB * persB - 2 == sectA * persA
      /\ abs (persB - persA) == 1;
      
      % Find total number of matches before and after two people retire
      constraint 2 * matchesB = sectB * persB * (persB - 1);
      constraint 2 * matchesA = sectA * persA * (persA - 1);
      
      % Change in number of total matches is given as 63
      constraint matchesB - matchesA == 63;
      
      solve satisfy;
      
      output ["Persons per section before two retire = " ++ show(persB)
      ++ "\n" ++ "Number of sections before two retire = " ++ show(sectB)
      ++ "\n" ++ "Persons per section after two retire = " ++ show(persA)
      ++ "\n" ++ "Number of sections after two retire = " ++ show(sectA) ];
      
      
      

      Like

    • GeoffR 6:21 pm on 19 November 2022 Permalink | Reply

      
      # Assumed max no players and sections is 24 for both groups
      # Suffix 'B' for before matches and 'A' for after matches
      for playersB in range(1, 25):
        for sectionsB in range(1, 25):
          before_matches = sectionsB * (playersB * (playersB - 1) // 2)
          for playersA in range(1, 25):
            # The number of players will change by one 
            if abs(playersA - playersB) != 1:
              continue
            for sectionsA in range(1, 25):
              # The number of sections will change by one 
              if abs(sectionsA - sectionsB) != 1:
                continue
              # two players retire
              if sectionsB * playersB - 2 != sectionsA * playersA:
                continue
              after_matches = sectionsA * (playersA * (playersA - 1) // 2)
              
              # Differences in total number of matches
              if before_matches - after_matches != 63:
                continue
              # output player and sections data
              print(f"Players before two retire = {playersB} No.")
              print(f"Sections  before two retire = {sectionsB} No.")
              print(f"Players after two retire = {playersA} No.") 
              print(f"Sections  after two retire = {sectionsA} No.")
      
      

      Like

  • Jim Randell 8:49 am on 17 November 2022 Permalink | Reply
    Tags:   

    Teaser 2680: Yesterday 

    From The Sunday Times, 2nd February 2014 [link]

    In a new design of mobile phone each of the number buttons 1 to 9 is associated with 2 or 3 letters of the alphabet, but not in alphabetical order (and there are no letters on any other buttons). For example: M, T and U are on the same button. Predictive software chooses letters for you as you type. The numbers to type for SUNDAY, TIMES and TEASER are all multiples of 495.

    What number should I type to make SATURDAY?

    [teaser2680]

     
    • Jim Randell 8:52 am on 17 November 2022 Permalink | Reply

      We can solve this puzzle using the [[ SubstitutedExpression ]] solver from the enigma.py library.

      The following run file executes in 67ms. (Internal runtime of the generated program is 1.8ms).

      Run: [ @replit ]

      #! python3 -m enigma -r
      
      SubstitutedExpression
      
      --digits="1-9"
      --distinct=""
      
      # SUNDAY, TIMES, TEASER are all multiples of 495
      "SUNDAY % 495 = 0"
      "TIMES % 495 = 0"
      "TEASER % 495 = 0"
      
      # M, T, U have the same value
      "M = T"
      "T = U"
      
      # no digit appears more than 3 times
      "all(v < 4 for v in multiset.from_seq([A, D, E, I, M, N, R, S, T, U, Y]).values())"
      
      --answer="SATURDAY"
      --template="SUNDAY TIMES TEASER SATURDAY"
      

      Solution: To type SATURDAY use the following keys: 58225185.

      The letters we are given are assigned to the following keys:

      1: D I
      2: M T U
      5: R S Y
      6: N
      8: A E

      So we have:

      SUNDAY = 526185 = 495 × 1063
      TIMES = 21285 = 495 × 43
      TEASER = 288585 = 495 × 583

      Like

    • GeoffR 12:27 pm on 17 November 2022 Permalink | Reply

      # last digit of TIMES, SUNDAY, TEASER
      Y = S = R = 5
      
      digits = set(range(1, 10)).difference({5})
      
      for T in digits:
        M = U = T  # stated condition
        
        # Digits for I and E in TIMES
        for I in digits:
          for E in digits:
            TIMES = 10000*T + 1000*I + 100*M + 10*E + S
            if not (TIMES % 495 == 0):continue
            
            # Add Digit A for TEASER
            for A in digits:
              TEASER = 100000*T + 10000*E + 1000*A + 100*S + 10*E + R
              if not (TEASER % 495 == 0):continue
              
              # Add Digits N and D for SUNDAY
              for N in digits:
                for D in digits:
                  SUNDAY = 100000*S + 10000*U + 1000*N + 100*D + 10*A + Y
                  if not (SUNDAY % 495 == 0):continue
                  
                  print(f"Keys to press for SATURDAY are : ")
                  print(f"{S},{A},{T},{U},{R},{D},{A},{Y}")
                  print(f"SUNDAY = {SUNDAY}, TIMES={TIMES}, TEASER={TEASER}")
                  
      # Keys to press for SATURDAY are : 5,8,2,2,5,1,8,5
      # SUNDAY = 526185, TIMES=21285, TEASER=288585
      
      

      Like

    • GeoffR 1:30 pm on 17 November 2022 Permalink | Reply

      This snippet needs to be added to the output to show no more than three digits were associated with
      each button.

      Digits used with each button as follows:

      [A,D,E,I,M,N,R,S,T,U,Y =
      [8,1,8,1,2,6,5,5,2,2,5]

      Like

  • Jim Randell 9:37 am on 15 November 2022 Permalink | Reply
    Tags:   

    Brain-Teaser 670: A shared legacy 

    From The Sunday Times, 12th May 1974 [link]

    When my neighbour Giles found he could no longer look after his prize herds of cattle and sheep, he planned to divide the lot among his four sons in equal shares.

    But when he started by counting up the cattle he soon found that their total was not exactly divisible by four, so he decided he would juggle with the numbers of beasts and achieve the four shares of equal value by making to the respective recipients quite arbitrary allocations of both cattle and sheep, taking into account that the value per head of the former was four times that of the latter.

    The outcome was that:

    (i) one son received 80% more beasts than another;
    (ii) two sons each received a total of beasts which equalled the aggregate total of two of the other three sons;
    (iii) one son received twice as many of one type of beast as of the other;
    (iv) only one son received over 100 beasts in all.

    How many cattle were included in this last total of over 100 beasts?

    This puzzle was included in the book The Sunday Times Book of Brain-Teasers: Book 2 (1981, edited by Victor Bryant and Ronald Postill). The puzzle text above is taken from the book.

    [teaser670]

     
    • Jim Randell 9:37 am on 15 November 2022 Permalink | Reply

      If the total number of animals received by each brother is: A, B, C, D (in descending order), then (from (iv)) A is the only one to receive more than 100.

      And from (ii) two of the brothers totals are equal to the sum of the totals of two of the remaining three brothers. These two must be A and B, and so B = C + D, and A = C + 2D or 2C + D.

      This Python program starts by finding possible A, B, C, D values, and then tries to split these totals into numbers of cattle and sheep such that the remaining conditions hold.

      It runs in 62ms. (Internal runtime is 11.2ms).

      Run: [ @replit ]

      from enigma import (irange, subsets, ediv, as_int, printf)
      
      # split total <t> into (<cattle>, <sheep>) with value <v>
      def split(t, v):
        c = ediv(v - t, 3)
        return (as_int(c, "0+"), as_int(t - c, "0+"))
      
      # solve puzzle for given totals: A, B, C, D
      def solve(A, B, C, D):
        # consider number of cattle for A
        for Ac in irange(0, A):
          As = A - Ac
          # total value for A (cattle = 4, sheep = 1)
          v = 4 * Ac + As
          # find splits for B, C, D
          try:
            (Bc, Bs) = split(B, v)
            (Cc, Cs) = split(C, v)
            (Dc, Ds) = split(D, v)
          except ValueError:
            continue
      
          # total number of cattle is not divisible by 4
          if (Ac + Bc + Cc + Dc) % 4 == 0: continue
          # someone has twice as many of one type of animal as the other
          if all(2 * x != y and x != 2 * y for (x, y) in [(Ac, As), (Bc, Bs), (Cc, Cs), (Dc, Ds)]): continue
      
          # output scenario
          printf("[v={v}] A: {Ac}c+{As}s = {A}; B: {Bc}c+{Bs}s = {B}; C: {Cc}c+{Cs}s = {C}; D: {Dc}c+{Ds}s = {D}")
      
      # total number of animals for C (not more than 100)
      for C in irange(1, 100):
        # total number of animals for D (not more than C)
        for D in irange(0, C):
          # B = C + D (not more than 100)
          B = C + D
          if B > 100: break
          # A = C + 2D or 2C + D (more than 100)
          for A in (B + D, B + C):
            if not (A > 100): continue
            # one of these values must be 1.8x a lower value
            if not any(5 * x == 9 * y for (x, y) in subsets((A, B, C, D), size=2)): continue
            # solve the puzzle
            solve(A, B, C, D)
      

      Solution: The son receiving over 100 animals received 6 cattle.

      The full solution is:

      A: 6 cattle + 111 sheep = 117 animals; 117 = 81 (B) + 36 (D)
      B: 18 cattle + 63 sheep = 81 animals; 81 = 45 (C) + 36 (D) = 1.8 × 45 (C)
      C: 30 cattle + 15 sheep = 45 animals; 30 is twice 15
      D: 33 cattle + 3 sheep = 36 animals

      Assigning values of cattle = 4, sheep = 1, each brother receives animals to a value of 135.

      In total there are 279 animals = 87 cattle (not a multiple of 4) + 192 sheep.

      Like

  • Jim Randell 4:36 pm on 11 November 2022 Permalink | Reply
    Tags:   

    Teaser 3138: Primus inter impares 

    From The Sunday Times, 13th November 2022 [link] [link]

    Just nine Prime Ministers held office in the Kingdom of Primea during the 20th century. No two Prime Ministers held office at the same time, none had more than one period in office, and the gap between successive Prime Ministers’ terms was never more than a month. Each held office for a period of time in which the number of whole years was a different prime number (e.g. holding office from 1910 to 1915 could cover four or five whole years) and no Prime Minister served for more than 30 years. Appropriately, they all took office in prime years, but there was no change of Prime Minister in 1973.

    In which years during the 20th century did new Prime Ministers in Primea take up office?

    [teaser3138]

     
    • Jim Randell 5:12 pm on 11 November 2022 Permalink | Reply

      This Python program runs in 51ms. (Internal runtime is 554µs).

      Run: [ @replit ]

      from enigma import (primes, append, tuples, printf)
      
      # possible term lengths
      terms = set(primes.between(0, 30))
      
      # select <k> years from <years>
      # return (<start-years>, <term-lengths>)
      def solve(k, years, ys=[], ts=[]):
        # are we done?
        if k == 0:
          # no-one served more than 30 years
          if ys and ys[-1] > 1968:
            yield (ys, ts)
        elif not k > len(years):
          # choose the next year
          for (i, y) in enumerate(years):
            # consider possible term lengths
            g = y - ys[-1]
            for t in terms.intersection({g, g - 1}):
              if t in ts: continue
              # solve for the remaining years
              yield from solve(k - 1, years[i + 1:], append(ys, y), append(ts, t))
      
      # consider the start year of the incumbent at the start of the century
      for y0 in primes.between(1870, 1901):
        # fill out the 8 starting years in the 20th century
        years = list(primes.between(max(y0 + 1, 1901), 2000))
        years.remove(1973)  # but not 1973
        for (ys, ts) in solve(8, years, [y0]):
          # output solution
          for ((y1, y2), t) in zip(tuples(ys, 2), ts):
            printf("{y1} - {y2} = {t} years")
          printf("{y2} - .... = ? years")
          printf()
      

      Solution: The years are: 1901, 1907, 1931, 1949, 1979, 1993, 1997, 1999.

      The incumbent at the start of the 20th century began office in 1889, so we have:

      1. 1889 – 1901 = 11 years
      2. 1901 – 1907 = 5 years
      3. 1907 – 1931 = 23 years
      4. 1931 – 1949 = 17 years
      5. 1949 – 1979 = 29 years
      6. 1979 – 1993 = 13 years
      7. 1993 – 1997 = 3 years
      8. 1997 – 1999 = 2 years
      9. 1999 – …. = (7 or 19 years)

      There are two primes left that could correspond to the length of the term of the incumbent at the end of the 20th century. Note that it is not required that the term of the successor (if any) starts in a prime year.

      Like

      • Frits 1:24 pm on 12 November 2022 Permalink | Reply

        @Jim, as I don’t have access to a PC I can’t publish/test a program myself.

        I think a check is needed to see if the last Prime Minister can serve a prime number of years and which ends after the 20th century (if high prime numbers already have been used this may not be possible anymore).

        Like

        • Hugh Casement 7:17 am on 13 November 2022 Permalink | Reply

          Frits, the wording of the puzzle is vague on that score, but I think if we do allow the last term of office to extend beyond the end of the century then we get multiple solutions. Jim (line 25) would seem to agree with me that we need to start looking before the beginning of the century.

          Like

        • Jim Randell 8:18 am on 13 November 2022 Permalink | Reply

          @Frits: I did wonder about that. I check the final PM of the 20th century does not have a term that is longer than 30 years (line 12), and when I saw that there was only a single possible solution I didn’t worry about the actual length of the term, as it starts very close to the end of the century, and there are 2 unused primes available.

          Here is the code with an extra check to ensure the final term length is possible. (I also include code to specify the first and last years of the 20th century. I am using the “strict” definition 1901-2000, but you get the same answer with the “popular” usage of 1900-1999).

          from enigma import (primes, append, tuples, printf)
          
          # first/last years for 20th century
          (first, last) = (1901, 2000)
          
          # possible term lengths
          terms = set(primes.between(0, 30))
          
          # select <k> years from <years>
          # return (<start-years>, <term-lengths>)
          def solve(k, years, ys=[], ts=[]):
            # are we done?
            if k == 0:
              yield (ys, ts)
            elif not k > len(years):
              # choose the next year
              for (i, y) in enumerate(years):
                # consider possible term lengths
                g = y - ys[-1]
                for t in terms.intersection({g, g - 1}):
                  if t in ts: continue
                  # solve for the remaining years
                  yield from solve(k - 1, years[i + 1:], append(ys, y), append(ts, t))
          
          # consider the start year of the incumbent at the start of the century
          for y0 in primes.between(first - 31, first):
            # fill out the 8 starting years in the 20th century
            years = list(primes.between(max(y0 + 1, first), last))
            years.remove(1973)  # but not 1973
            for (ys, ts) in solve(8, years, [y0]):
              # check possible term lengths for the incumbent at the end of the century
              fs = sorted(t for t in terms.difference(ts) if ys[-1] + t > last)
              if not fs: continue
              # output solution
              for ((y1, y2), t) in zip(tuples(ys, 2), ts):
                printf("{y1} - {y2} = {t} years")
              printf("{y2} - .... = {fs} years")
              printf()
          

          But it seems that it may be possible that the final PM is still in office at the time the puzzle was set (having served less than 30 years so far), so we can’t say what the length of the term will be yet.

          Like

  • Jim Randell 8:40 am on 10 November 2022 Permalink | Reply
    Tags:   

    Teaser 2611: Simple arithmetic 

    From The Sunday Times, 7th October 2012 [link]

    George and Martha are teaching their great-grandchildren some simple arithmetic. “If you add two thirties to four tens you get a hundred”, George was saying, and he wrote it like this:

    “Strangely”, added Martha, there are nine different letters there, and if you allow each letter to stand for a different digit, there is a unique sum which works”.

    Which digit would be missing?

    [teaser2611]

     
    • Jim Randell 8:40 am on 10 November 2022 Permalink | Reply

      We can use the [[ SubstitutedExpression.split_sum() ]] solver from the enigma.py library to solve this puzzle.

      The following run file executes in 58ms. (Internal runtime is 4.74ms).

      Run: [ @replit ]

      from enigma import (SubstitutedExpression, irange, diff, join, printf)
      
      # construct the alphametic sum
      p = SubstitutedExpression.split_sum(
        ["THIRTY"] * 2 + ["TEN"] * 4, "HUNDRED",
        template="(2 * {THIRTY} + 4 * {TEN} = {HUNDRED})",
      )
      
      # solve the puzzle, and output unused digit(s)
      for s in p.solve():
        ds = diff(irange(0, 9), s.values())
        # output solution
        printf("-> unused digits = {ds}", ds=join(ds, sep=", "))
      

      Solution: The missing digit is 7.

      Like

    • GeoffR 11:40 am on 10 November 2022 Permalink | Reply

      
      % A Solution in MiniZinc
      include "globals.mzn";
      
      %          T H I R T Y
      %          T H I R T Y
      %                T E N
      %                T E N
      %                T E N
      %                T E N
      %        -------------
      %        H U N D R E D
      %        -------------
      
      set of int: INT = 0..9;
      var INT: T; var INT: H; var INT: I;
      var INT: R; var INT: Y; var INT: E;
      var INT: N; var INT: U; var INT: D;
      
      constraint T > 0 /\ H > 0;
      constraint all_different( [T,H,I,R,Y,E,N,U,D]);
      
      % Carry digits from RH end
      var 0..6:c1; var 0..6:c2; var 0..6:c3;
      var 0..1:c4; var 0..1:c5; var 0..1:c6;
      
      % Adding digits in columns, with carry digits from RH end of sum
      constraint D == (4*N + 2*Y) mod 10 /\ c1 == (4*N + 2*Y) div 10;
      constraint E == (c1 + 4*E + 2*T) mod 10 /\ c2 == (c1 + 4*E + 2*T) div 10;
      constraint R == (c2 + 4*T + 2*R) mod 10 /\ c3 == (c2 + 4*T + 2*R) div 10;
      constraint D == (c3 + 2*I) mod 10 /\ c4 == (c3 + 2*I) div 10;
      constraint N == (c4 + 2*H) mod 10 /\ c5 == (c4 + 2*H) div 10;
      constraint U == (c5 + 2*T) mod 10 /\ c6 == (c5 + 2*T) div 10;
      constraint H == c6;
      
      solve satisfy;
      
      output ["[T,H,I,R,Y,E,N,U,D] = " ++ show([T,H,I,R,Y,E,N,U,D]) ];
      % [T, H, I, R, Y, E, N, U, D] = 
      % [9, 1, 5, 2, 6, 0, 3, 8, 4]
      % ----------
      % ==========
      % By inspection, missing digit = 7.
      % TEN = 903, THIRTY = 915296, HUNDRED = 1834204.
      
      

      Like

    • GeoffR 10:25 pm on 10 November 2022 Permalink | Reply

      
      % A Solution in MiniZinc
      include "globals.mzn";
       
      %          T H I R T Y
      %          T H I R T Y
      %                T E N
      %                T E N
      %                T E N
      %                T E N
      %        -------------
      %        H U N D R E D
      %        -------------
       
      set of int: INT = 0..9;
      var INT: T; var INT: H; var INT: I;
      var INT: R; var INT: Y; var INT: E;
      var INT: N; var INT: U; var INT: D;
       
      constraint T > 0 /\ H > 0;
      constraint all_different( [T,H,I,R,Y,E,N,U,D]);
       
      var 100..999:TEN = 100*T + 10*E + N;
      var 100000..999999:THIRTY = 100000*T + 10000*H + 1000*I + 100*R + 10*T + Y;
      var 1000000..9999999:HUNDRED = 1000000*H + 100000*U + 10000*N + 1000*D + 100*R + 10*E + D;
      
      constraint 2 * THIRTY + 4 * TEN == HUNDRED;
      
      solve satisfy;
      
      output [ "T,H,I,R,Y,E,N,U,D] = " ++ show( [T,H,I,R,Y,E,N,U,D] ) ];
      
      % [T, H, I, R, Y, E, N ,U, D] = 
      % [9, 1, 5, 2, 6, 0, 3, 8, 4]
      % time elapsed: 0.17 s
      % ----------
      % ==========
      % By inspection, the missing digit is 7.
      
      
      

      Like

  • Jim Randell 9:01 am on 8 November 2022 Permalink | Reply
    Tags:   

    Teaser 2695: Powers behind the thrones 

    From The Sunday Times, 18th May 2014 [link]

    Gold sovereigns were minted in London for most years from the great recoinage in 1817 until Britain left the gold standard in 1917. I have a collection of eight sovereigns from different years during that period, the most recent being an Edward VII sovereign (he reigned from 1902 until 1910). I noticed that the year on one of the coins is a perfect square and this set me thinking about other powers. Surprisingly, it turns out that the product of the eight years on my coins is a perfect cube.

    What (in increasing order) are those eight years?

    [teaser2695]

     
    • Jim Randell 9:02 am on 8 November 2022 Permalink | Reply

      The values were are interested in lie in the interval [1817, 1910].

      And the only square in that range is 1849 (= 43²), so that must be one of the 8 values.

      And the largest value is in the interval [1902, 1910].

      This Python program finds the prime factors for numbers in the required range, and then constructs sets of 8 values whose prime factors, when combined, all appear a multiple of 3 times, and so the product of the values is a cube.

      It runs in 164ms.

      Run: [ @replit ]

      from enigma import (irange, prime_factor, multiset, delete, append, printf)
      
      # find values whose product is a cube
      # k = remaining values for find (int)
      # vs = values so far (list)
      # fs = prime factors so far (multiset)
      # d = map of value -> prime factors (multiset)
      # ks = candidate keys in d (list)
      def solve(n, vs, fs, d, ks):
        if n == 0:
          # check all prime exponents are multiples of 3
          if all(x % 3 == 0 for x in fs.values()):
            yield vs
        elif not len(ks) < n:
          # add in a new candidate
          for (i, k) in enumerate(ks):
            # and solve for the remaining candidates
            yield from solve(n - 1, append(vs, k), fs.combine(d[k]), d, ks[i + 1:])
      
      # collect candidate numbers and their prime factors (as a multiset)
      d = dict((n, multiset.from_pairs(prime_factor(n))) for n in irange(1817, 1910))
      
      # find factors that appear fewer than 3 times in total
      while True:
        # count the factors (by combining values from each of the numbers)
        m = multiset.from_dict(*d.values())
        fs = set(k for (k, v) in m.items() if v < 3)
        if not fs: break
        # and remove any numbers which involve any of these factors
        d = delete(d, (k for (k, v) in d.items() if any(p in fs for p in v)))
      
      # 1849 is one of the values in the set
      (vs1, fs1) = ([1849], d[1849])
      
      # and the max value is between 1902 and 1910
      for v in irange(1902, 1910):
        if v not in d: continue
        vs2 = append(vs1, v)
        fs2 = fs1.union(d[v])
      
        # solve for the remaining 6 values
        ks = sorted(k for k in d.keys() if k < v and k not in vs2)
        for vs in solve(6, vs2, fs2, d, ks):
          # output solution
          printf("years = {vs}", vs=sorted(vs))
      

      Solution: The eight years are: 1820, 1836, 1849, 1859, 1870, 1890, 1892, 1904.

      So we have:

      numbers = (1820, 1836, 1849, 1859, 1870, 1890, 1892, 1904)
      factors = (2^12, 3^6, 5^3, 7^3, 11^3, 13^3, 17^3, 43^3)
      factors = (2^4, 3^2, 5, 7, 11, 13, 17, 43)^3

      And the product of the numbers is: (2^4, 3^2, 5, 7, 11, 13, 17, 43)^3 = 526846320^3.

      Like

    • Hugh Casement 8:31 am on 10 November 2022 Permalink | Reply

      We can get part of the way by analysis.  We need another factor 43, so 1892 must be one of the years.
      The only integer in the range 1902 to 1910 with a small enough largest prime factor to allow us to find two more is 1904 = 2^4 × 7 × 17.
      After that I think trial and error (i.e. by computer) is needed.

      Like

      • Jim Randell 11:03 am on 10 November 2022 Permalink | Reply

        @Hugh: My manual solution proceeded as follows:

        Armed with the prime factorisations of the numbers between 1817 and 1910 (which I did not compute manually), we quickly find 1849, 1892, 1904 are on the list.

        Then we need more factors of 17, and there are only 2 candidates: 1836 and 1870. Both of which must be included. So we now have 5 of the 8 numbers on the list.

        We can eliminate numbers with a factor of 29 (1827, 1856, 1885).

        Considering numbers with factors of 13 (1820, 1859, 1872), if any of these are included it must be 1859 and just one of the others.

        Adding 1859 and 1820 to the list leaves factors of (2, 5, 7) to find, and the only candidate is 1890, and this does indeed give a viable list.

        And I didn’t look for further solutions.

        Like

  • Jim Randell 9:01 am on 6 November 2022 Permalink | Reply
    Tags:   

    Brain-Teaser 195: Common frontier 

    From The Sunday Times, 17th January 1965 [link]

    The adjoining countries of Europhalia and Sopiculia have different standard units of weight and length, but both use the normal units of time. Although both countries use Arabic numerals, neither uses the denary (tens) method of counting, but each has a different integer less than ten as its counting base.

    In reply to my request for more information a Europhalian friend wrote: “Our unit of weight is the Elbo, and there are 42 Elbos to 24 of their Solbos. The length of our common frontier is 21 Emils”. My Sopiculian correspondent replied: “16 Solbos weigh the same as 26 Elbos; the common frontier is 21 Somils long”.

    I later discovered that in both countries there is a speed limit equivalent to our 50 mph. In Sopiculia this is defined by law as 104 Somils per hour.

    What is the Europhalian speed limit?

    This puzzle was included in the book Sunday Times Brain Teasers (1974, edited by Ronald Postill).

    [teaser195]

     
    • Jim Randell 9:02 am on 6 November 2022 Permalink | Reply

      If the bases are E and S (both less than 10).

      Then the ratio of the weights W = (Elbo/Solbo) is (according to to the two correspondents):

      W = (2E + 4) / (4E + 2)
      W = (S + 6) / (2S + 6)
      ⇒ 4ES + 12E + 8S + 24 = 4ES + 24E + 2S + 12
      ⇒ E = S/2 + 1

      And we see from the digits used, E > 4 and S > 6, and S must be even, so:

      S = 8; E = 5

      We can then translate the correspondents statements into decimal to get:

      Eu: “There are 22 Elbos to 14 of their Solbos [W = 7/11]. The common frontier is 11 Emils”.
      So: “14 Solbos weigh the same as 22 Elbos [W = 7/11]. The common frontier is 17 Somils”.

      And:

      “104 Somils/hour” [base 8]
      = 68 Somils/hour [base 10]
      = 4× (17 Somils)/hour [base 10]
      = 4× (11 Emils)/hour [base 10]
      = 44 Emils/hour [base 10]
      = “134 Emils/hour” [base 5]

      Solution: The Europhalian speed-limit would be expressed as: “134 Emils per hour”.

      Like

  • Jim Randell 4:21 pm on 4 November 2022 Permalink | Reply
    Tags:   

    Teaser 3137: Common names 

    From The Sunday Times, 6th November 2022 [link] [link]

    Eight friends met at a party; their ages in whole numbers of years were all different. They were Alan, Cary, James, Lucy, Nick, Ricky, Steve and Victor, with Lucy being the youngest. For each of them the square of their age was a three-figure number consisting of three different digits. Furthermore, for any two of them, the squares of their ages had at least one digit in common precisely when their names had at least one letter in common.

    In alphabetical order of their names, what are the eight ages?

    [teaser3137]

     
    • Jim Randell 4:49 pm on 4 November 2022 Permalink | Reply

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

      Run: [ @replit ]

      from enigma import (irange, sq, nsplit, diff, intersect, append, delete, subsets, printf)
      
      # model a symmetric relation
      class Relation(set):
        # check if x is related to y
        def __call__(self, x, y):
          return (x, y) in self or (y, x) in self
      
      # names
      names = "ALAN CARY JAMES LUCY NICK RICKY STEVE VICTOR".split()
      
      # names are related when they share a letter
      N = Relation((x, y) for (x, y) in subsets(names, size=2) if intersect([x, y]))
      
      # find 3-digits squares with no repeated digits
      sqs = dict()
      for i in irange(10, 31):
        ds = set(nsplit(sq(i)))
        if len(ds) == 3:
          sqs[i] = ds
      
      # values are related when their squares share a digit
      V = Relation((x, y) for ((x, sx), (y, sy)) in subsets(sqs.items(), size=2) if intersect([sx, sy]))
      
      # assign values to remaining names
      # names = remaining names
      # ss = used (name, value) pairs
      # vs = remaining values
      def solve(names, ss, vs):
        if not names:
          yield ss
        elif not len(names) > len(vs):
          # choose a value for the next name
          n = names[0]
          for (i, v) in enumerate(vs):
            # check values have digits in common when names have letters in common
            if all(N(n, n_) == V(v, v_) for (n_, v_) in ss):
              # solve for the remaining names
              yield from solve(names[1:], append(ss, (n, v)), delete(vs, [i]))
      
      # choose an age for LUCY (the youngest)
      n0 = "LUCY"
      ks = sorted(sqs.keys())
      for (i, k) in enumerate(ks):
        # solve for the remaining names
        for ss in solve(diff(names, {n0}), [(n0, k)], ks[i + 1:]):
          # output solution
          for (n, v) in sorted(ss):
            printf("{n} -> {v} [{s}]", s=sq(v))
          printf()
      

      Solution: The ages are: 19, 31, 29, 16, 25, 23, 28, 27.

      With squares in square brackets:

      ALAN = 19 [361]
      CARY = 31 [961]
      JAMES = 29 [841]
      LUCY = 16 [256]
      NICK = 25 [625]
      RICKY = 23 [529]
      STEVE = 28 [784]
      VICTOR = 27 [729]

      Like

    • Paul Byrne 9:54 pm on 14 November 2022 Permalink | Reply

      Hi Jim
      Thanks for all the good work on these Teasers.
      Love the simplicity of your website and your solutions.
      Re 3137 Teaser
      Is 24 instead of 31 also a correct answer? Keep up the good work!

      Like

      • Jim Randell 9:17 am on 15 November 2022 Permalink | Reply

        @Paul: Thanks for the feedback.

        We can’t swap CARY for 24 in the solution I give above, as 24² = 576, and CARY and JAMES share the letter A, so their squares need to share a digit. But 576 and 841 (= 29²) don’t have any digits in common.

        Like

    • Paul Byrne 10:21 am on 16 November 2022 Permalink | Reply

      Hi Jim, thank you very much for your response.

      Forgive me I should’ve made myself clearer.
      If Cary becomes 576, and James 784, and Steve 841, can it then work as an alternative?

      Like

      • Jim Randell 12:14 pm on 16 November 2022 Permalink | Reply

        @Paul: My program performs an exhaustive search, so there is only one solution to the puzzle.

        If we had:

        CARY = 24 [576]
        JAMES = 28 [784]
        STEVE = 29 [841]

        Then {LUCY, NICK, RICKY} must correspond to {16 [256], 23 [529], 25 [625]} in some order.

        LUCY is the youngest, so we have:

        LUCY = 16 [256]

        But then ALAN has to have digits in common with CARY [576], LUCY [256], JAMES [784], but not STEVE [841]

        Which means for ALAN we need to find a square with a 7 and a 5 or a 6. The only candidate is 24 [576], but that is already used by CARY, so it is not possible to find a value for ALAN in this scenario.

        Like

    • Paul Byrne 5:17 pm on 16 November 2022 Permalink | Reply

      Hi Jim
      Alas I’m thwarted!
      Thanks for this and all your efforts.
      They are all appreciated.
      Regards Paul

      Like

  • Jim Randell 7:47 am on 3 November 2022 Permalink | Reply
    Tags:   

    Brain-Teaser 653: Hymn numbers 

    From The Sunday Times, 13th January 1974 [link]

    In Church last Sunday I studied the three numbers on the “service-board”. The first was of the appointed psalm, and the other two of the hymns. They included all the digits from 1 to 9 inclusive and were all prime numbers. (Our service-book contains 666 hymns and the normal 150 psalms).

    What were last Sunday’s numbers?

    This puzzle was included in the book The Sunday Times Book of Brain-Teasers: Book 2 (1981, edited by Victor Bryant and Ronald Postill).

    [teaser653]

     
    • Jim Randell 7:48 am on 3 November 2022 Permalink | Reply

      This puzzle is very similar to Teaser 467 (and the answer is the same), although the conditions are slightly different.

      We can solve this puzzle using the [[ SubstitutedExpression ]] solver from the enigma.py library.

      The following run file executes in 63ms. (Internal runtime of the generated program is 1.2ms).

      Run: [ @replit ]

      #! python3 -m enigma -r
      
      SubstitutedExpression
      
      --digits="1-9"
      
      # the psalm
      "is_prime(ABC)"
      "ABC < 151"
      
      # the hymns
      "is_prime(DEF)"
      "is_prime(GHI)"
      "DEF < GHI < 667"
      
      --answer="(ABC, DEF, GHI)"
      

      Solution: Psalm 149. Hymn 263. Hymn 587.

      Like

    • GeoffR 8:33 am on 3 November 2022 Permalink | Reply

      % A Solution in MiniZinc
      include "globals.mzn";
      
      set of int: INT = 1..9;
      var INT: A; var INT: B; var INT: C; % Psalm
      var INT: D; var INT: E; var INT: F; % Hymn 1
      var INT: G; var INT: H; var INT: I; % Hymn 2
      
      constraint all_different ([A, B, C, D, E, F, G, H, I]);
      constraint ABC < DEF /\ DEF < GHI;
      
      % Specified ranges of psalm and hymn numbers
      var 100..150:ABC = 100*A + 10*B + C;
      var 100..666:DEF = 100*D + 10*E + F;
      var 100..666:GHI = 100*G + 10*H + I;
      
      predicate is_prime(var int: x) = 
      x > 1 /\ forall(i in 2..1 + ceil(sqrt(int2float(ub(x))))) 
      ((i < x) -> (x mod i > 0));
      
      constraint sum([is_prime(ABC), is_prime(DEF), is_prime(GHI)]) == 3;
      
      solve satisfy;
      output["Sunday's numbers were " ++ show(ABC) ++ " , " ++ show(DEF)
      ++ " and " ++ show(GHI) ];
      
      % Sunday's numbers were 149 , 263 and 587
      % ----------
      % ==========
      
      

      There are many solutions without the restricted psalm and hymn number ranges.

      Like

    • GeoffR 1:43 pm on 3 November 2022 Permalink | Reply

      
      from enigma import is_prime, nsplit, all_different
      
      # Find Psalm number
      for P1 in range(100,150):
          if not (is_prime(P1)): continue
          A,B,C = nsplit(P1)
          if 0 in (A,B,C):continue
          if not all_different(A,B,C):continue
          
          # Find 1st Hymn number
          for H1 in range(151,667):
              if not (is_prime(H1)):continue
              D,E,F = nsplit(H1)
              if 0 in (D,E,F): continue
              if not all_different(A,B,C,D,E,F):continue
              
              # Find 2nd Hymn number
              for H2 in range(H1+1, 667):
                  if not is_prime(H2):continue
                  G,H,I = nsplit(H2)
                  if 0 in (G,H,I):continue
                  if not all_different(A,B,C,D,E,F,G,H,I):continue
                  print(f"Sunday's numbers were {P1}, {H1}, {H2}")
      
      # Sundays numbers were 149, 263, 587
      
      
      
      

      Like

  • Jim Randell 8:40 am on 1 November 2022 Permalink | Reply
    Tags:   

    Teaser 2679: Palprimes 

    From The Sunday Times, 26th January 2014 [link]

    My two pals and I have been considering “palprimes” (i.e. palindromic numbers that are also prime). In particular each of us tried to find a five-figure palprime and I managed to come up with 39293. Then each of my two pals found a five-figure palprime. On comparing them we were surprised to find that overall our three palprimes used all the digits from 1 to 9.

    What were the other two five-figure palprimes?

    [teaser2679]

     
    • Jim Randell 8:41 am on 1 November 2022 Permalink | Reply

      A 5-digit palindrome is of the form XYZYX, so consists of 3 digits.

      In order for 3 of them to use all the digits from 1-9 then each digit can only appear in one prime, and X, Y, Z must be different digits.

      The setter has used 3, 9, 2, so we need to find 2 primes that use the digits 1, 4, 5, 6, 7, 8, between them.

      This Python program runs in 59ms. (Internal runtime is 370µs).

      Run: [ @replit ]

      from enigma import (
        irange, nconcat, diff, is_prime, subsets, partitions, cproduct,
        unpack, printf
      )
      
      # construct a 5-digit palindrome from digits X, Y, Z
      pal5 = unpack(lambda X, Y, Z: nconcat(X, Y, Z, Y, X))
      
      # construct palindromic primes from digits <ds>
      def primes(ds):
        for ss in subsets(ds, size=len, select="P"):
          if is_prime(pal5(ss)):
            yield ss
      
      # digits used in the first prime
      p0 = (3, 9, 2)
      assert is_prime(pal5(p0))
      
      # split the remaining digits for the other 2 primes
      for dss in partitions(diff(irange(1, 9), p0), 3):
        for (p1, p2) in cproduct(primes(ds) for ds in dss):
          printf("{p0} {p1} {p2}", p0=pal5(p0), p1=pal5(p1), p2=pal5(p2))
      

      Solution: The other palprimes are: 16561 and 78487.


      In fact as the palprimes must end (and begin) with one of 1, 3, 7, 9, we can see that the two numbers we have to find must be of the form 1???1 and 7???7. And we just need to work out how to arrange the digits 4, 5, 6, 8 in the middle of them.

      And we can make a slightly shorter program based on this observation:

      from enigma import (nconcat, is_prime, subsets, printf)
      
      # construct a 5-digit palindrome from digits X, Y, Z
      pal5 = lambda X, Y, Z: nconcat(X, Y, Z, Y, X)
      
      # digits used in the first prime
      p0 = pal5(3, 9, 2)
      assert is_prime(p0)
      
      # insert digits 4, 5, 6, 8 in 1???1, 7???7
      for (A, B, C, D) in subsets((4, 5, 6, 8), size=len, select="P"):
        (p1, p2) = (pal5(1, A, B), pal5(7, C, D))
        if is_prime(p1) and is_prime(p2):
          printf("{p0} {p1} {p2}")
      

      Like

    • GeoffR 3:59 pm on 1 November 2022 Permalink | Reply

      
      from enigma import is_prime, nsplit
      
      mine = 39293  # given five digit palindromic prime
      mset = {3, 9, 2} # my digit set
      
      #  unused digits are 1, 4, 5, 6, 7, 8 for 2 palprimes
      # range of palindromic primes is from 14841 to 78687
      # find 1st palindromic prime
      for p1 in range(14841, 78687+1):
        if is_prime(p1):
          a, b, c, d, e = nsplit(p1)
          if 0 in (a, b, c, d, e):continue
          if a == e and b == d:
            s2 = set((a, b, c, d, e))
            if len(s2) == 3:  
              if len(mset.union(s2)) == 6:
                  
                # find 2nd palindromic prime 
                for p2 in range(p1+1, 78687+1):
                  if is_prime(p2):
                    f, g, h, i, j = nsplit(p2)
                    if 0 in (f, g, h, i, j):continue
                    if f == j and g == i:
                      s3 = set((f, g, h, i, j))
                      if len(s3) == 3:
                        all_set = mset.union(s2).union(s3)
                        if len(all_set) == 9:
                          print(f"Other two primes are {p1} and {p2}.")
      
      # Other two primes are 16561 and 78487.
      
      

      Like

  • Jim Randell 7:59 am on 30 October 2022 Permalink | Reply
    Tags: by: Comdr. A R Edwards   

    Brain-Teaser 797: Tuesday’s children 

    From The Sunday Times, 24th October 1976 [link]

    Old Andrew, our pensioner neighbour, was telling me about his equally well preserved brother, David.

    “We weren’t twins, but we were both born on a Tuesday and born on the same date in different months. In fact, David was born on the first Tuesday after my birth which occurred on the same monthly date. I am hardier, of course, born in the winter time”.

    “So, with these conditions, the interval between you couldn’t have been long”, I said.

    “Well”, replied Andrew, “it couldn’t have been any longer”.

    When was David born (day, month, year)?

    [teaser797]

     
    • Jim Randell 8:00 am on 30 October 2022 Permalink | Reply

      Assuming both brothers are aged somewhere between 65 and 122, we can start looking for birthdates sometime after 1854.

      This Python program looks for the longest gap between consecutive dates that both occur on Tuesday and the same day of the month (but different months). It runs in 60ms.

      Run: [ @replit ]

      from datetime import (date, timedelta)
      from enigma import (inc, repeat, group, tuples, Accumulator, printf)
      
      # generate possible birthdates
      def generate():
        # start from the first Tuesday in 1854
        for d in repeat(inc(timedelta(days=7)), date(1854, 1, 3)):
          # calculate age in 1976
          a = 1976 - d.year
          if a < 65: break
          yield d
      
      # group candidate birthdates by day of month
      g = group(generate(), by=(lambda d: d.day))
      
      # find maximal distance dates
      r = Accumulator(fn=max, collect=1)
      
      # consider possible days of month
      for (k, ds) in g.items():
        # and possible adjacent dates
        for (A, D) in tuples(ds, 2):
          t = D - A
          r.accumulate_data(t, (A, D))
      
      t = r.value
      printf("max gap = {t} days", t=t.days)
      for (A, D) in r.data:
        # A was born in the winter, say Dec, Jan, Feb
        if A.month in {12, 1, 2} and A.month != D.month:
          printf("-> A={A}; D={D}")
      

      Solution: David was born on Tuesday, 31st August 1880.

      So David is 96 years old at the time the puzzle was set.

      Andrew was born on Tuesday, 31st December 1878.

      So he is 97 years old at the time the puzzle was set.

      The longest possible gap between the birthdates is 609 days, which gives the following candidates:

      A=1855-07-31; D=1857-03-31; ages = 121 & 119
      A=1878-12-31; D=1880-08-31; ages = 97 & 96
      A=1883-07-31; D=1885-03-31; ages = 93 & 91

      But as A is born in the winter only the second of these candidates is viable.

      Other candidates outside the age range considered are:

      A=1850-12-31; D=1852-08-31; ages = 125 & 124
      A=1918-12-31; D=1920-08-31; ages = 57 & 56

      Like

c
Compose new post
j
Next post/Next comment
k
Previous post/Previous comment
r
Reply
e
Edit
o
Show/Hide comments
t
Go to top
l
Go to login
h
Show/Hide help
shift + esc
Cancel
%d bloggers like this: