Updates from October, 2023 Toggle Comment Threads | Keyboard Shortcuts

  • Unknown's avatar

    Jim Randell 7:46 am on 15 October 2023 Permalink | Reply
    Tags:   

    Teaser 2644: Route canal 

    From The Sunday Times, 26th May 2013 [link] [link]

    Stephen is planning a 70-mile canal trip from the lock at Aytown to the lock at Beeswick, stopping at a pub at a lock over half way along the route. He has listed the number of miles from each lock to the next, the largest being the stretch from the pub to the next lock. He has also noted the distances from Aytown to the pub and from the pub to Beeswick. All the numbers that he has written down are different primes.

    Stephen can use his figures to work out the number of miles from any lock to any other. He’s found that, whenever that number of miles between locks is odd, then it is also a prime.

    What (in order) are the numbers of miles between consecutive locks?

    [teaser2644]

     
    • Jim Randell's avatar

      Jim Randell 7:46 am on 15 October 2023 Permalink | Reply

      This Python program runs in 55ms. (Internal runtime is 806µs).

      Run: [ @replit ]

      from enigma import (irange, primes, express, diff, cproduct, subsets, flatten, printf)
      
      # decompose total <t> into different values from <ns>
      def decompose(t, ns):
        if not ns: return
        for qs in express(t, ns, qs=(0, 1)):
          yield list(n for (n, q) in zip(ns, qs) if q > 0)
      
      # check all odd distances are prime
      def check(ds):
        for (i, j) in subsets(irange(len(ds)), size=2):
          d = sum(ds[i:j + 1])
          if d % 2 == 1 and d not in primes: return False
        return True
      
      # consider possible distances from P to B (prime, < 35)
      for d2 in primes.between(2, 34):
        # distance from A to P (prime, > 35)
        d1 = 70 - d2
        if d1 not in primes: continue
      
        # decompose the distances into individual sections
        for d2s in decompose(d2, list(primes.between(2, d2 - 1))):
          max_d = d2s[-1]
          for d1s in decompose(d1, list(diff(primes.between(2, max_d - 1), d2s))):
      
            # construct possible ordered sequences
            for (s1, s2) in cproduct(subsets(s, size=len, select='P') for s in (d1s, d2s[:-1])):
              ds = flatten([s1, [max_d], s2])
              if check(ds):
                # output solution
                printf("{ds}")
      

      Solution: The distances between consecutive locks (from A to B) are (in miles): 17, 13, 11, 19, 7, 3.

      Like

  • Unknown's avatar

    Jim Randell 4:25 pm on 13 October 2023 Permalink | Reply
    Tags:   

    Teaser 3186: Contemporary classmates 

    From The Sunday Times, 15th October 2023 [link] [link]

    In our local school, the year begins on September 1 and ends on August 31, and class one contains all the children who reach the age of five during the school year. I was looking back at the school records and discovered that one year during the 1980s, it so happened that the birthdays of a group of children in class one fell on the same-numbered day of different months and also on the same day of the week. The size of this group was the largest possible for these circumstances, and by coincidence the number of classmates in the group was also the number of the day in the month for their birthday.

    The oldest member of that group, whose birthday was in January, was born in the 1980s.

    What was the full date of birth of the youngest member of that group?

    [teaser3186]

     
    • Jim Randell's avatar

      Jim Randell 4:54 pm on 13 October 2023 Permalink | Reply

      This Python program finds maximal groups of birthdays sharing day-of-month and day-of-week for academic years starting in the 1980s, and then looks for maximal groups satisfying the remaining conditions.

      It runs in 76ms. (Internal runtime is 4.6ms).

      Run: [ @replit ]

      from datetime import (date, timedelta)
      from enigma import (defaultdict, Accumulator, irange, repeat, inc, seq2str, printf)
      
      # collect all maximal groups
      gs = Accumulator(fn=max, collect=1)
      
      # consider school years that start in the 80s
      for y in irange(1980, 1989):
      
        # record (day-of-month, day-of-week) -> [date, ...]
        g = defaultdict(list)
        for d in repeat(inc(timedelta(days=1)), date(y, 9, 1)):
          if d.year > y and d.month > 8: break
          g[(d.day, d.isoweekday())].append(d)
      
        # look for the longest lists
        r = Accumulator(fn=max, collect=1)
        for (k, vs) in g.items():
          r.accumulate_data(len(vs), k)
      
        # record them
        for k in r.data:
          gs.accumulate_data(r.value, g[k])
      
      # maximal group size
      n = gs.value
      printf("max group = {n}")
      
      # look for maximal groups where day-of-month = n
      # and the oldest member of the group has a birthday in January
      for ds in gs.data:
        d = ds[0]
        if not (d.day == n and d.month == 1): continue
        # calculate the dates of birth
        bs = list(d.replace(year=d.year - 5) for d in ds)
        # check the eldest is born in the 80s
        if not bs[0].year // 10 == 198: continue
        # output solution
        printf("birthdates = {bs}", bs=seq2str(bs))
      

      Solution: The youngest member of the group was born on: 3rd July 1983.

      The largest group of dates in a year that share the same day of the week and day of the month is 3.

      The relevant school year starts on 1st September 1987, and the 3 birthdays are:

      Sunday, 3rd January 1988 (DOB: Monday, 3rd January 1983)
      Sunday, 3rd April 1988 (DOB: Sunday, 3rd April 1983)
      Sunday, 3rd July 1988 (DOB: Sunday, 3rd July 1983)

      Like

  • Unknown's avatar

    Jim Randell 12:31 pm on 12 October 2023 Permalink | Reply
    Tags:   

    Teaser 2656: Wrong adding 

    From The Sunday Times, 18th August 2013 [link] [link]

    Here is an addition sum in which digits have consistently been replaced by letters, with different letters used for different digits. The six-figure total is even:

    Unfortunately, once again I have made a mistake. In just one place in the display I have written an incorrect letter.

    What is the correct numerical value of the six-figure total?

    [teaser2656]

     
    • Jim Randell's avatar

      Jim Randell 12:31 pm on 12 October 2023 Permalink | Reply

      I’ve added the [[ bungled_sum() ]] solver (from Puzzle 56 etc.) to the enigma.py library as a class method on [[ SubstitutedSum ]], and also allowed it to be called from the command line.

      Using this solver we find there are two possibilities for as single letter mistake in the translation.

      The following command line executes in 270ms.

      Run: [ @replit ]

      % python3 -m enigma -r SubstitutedSum.bungled_sum "AGAIN + WRONG = ADDING"
      
                  G
      AGAIN + WRONI = ADDING / @[1,4] G -> I
      14195 + 86759 = 100954 / A=1 D=0 G=4 I=9 N=5 O=7 R=6 W=8
      
                           G
      AGAIN + WRONG = ADDINA / @[2,5] G -> A
      16195 + 84756 = 100951 / A=1 D=0 G=6 I=9 N=5 O=7 R=4 W=8
      

      But we are told that in the original numerical sum the result is even, so we are looking at the first possibility.

      Solution: The result of the sum is 100954.

      The original sum was: 14195 + 86759 = 100954.

      And it should have been encoded as: AGAIN + WRONI = ADDING.

      Like

  • Unknown's avatar

    Jim Randell 1:24 pm on 10 October 2023 Permalink | Reply
    Tags:   

    Brainteaser 1702: And now not one is… 

    From The Sunday Times, 30th April 1995 [link]

    In what follows, digits have been replaced by letters, a different letter being used consistently for each different digit. There are no zeros.

    Each of the recurring decimals:

    .ANDANDAND
    .NOWNOWNOW
    .NOTNOTNOT
    .ONEONEONE
    .ISISISIS

    equals a fraction with a denominator less than 50. And now not one is easy to find.

    Please find what is DONE.

    [teaser1702]

     
    • Jim Randell's avatar

      Jim Randell 1:25 pm on 10 October 2023 Permalink | Reply

      We have:

      0.(ab)… = ab / 99
      0.(abc)… = abc / 999

      Here is a run file that uses the [[ SubstitutedExpression ]] solver from the enigma.py library to solve the puzzle.

      It runs in 86ms. (Internal runtime of the generated program is 14ms).

      Run: [ @replit ]

      #! python3 -m enigma -rr
      
      SubstitutedExpression
      
      --digits="1-9"
      
      # valid fractions have denominators less than 50
      --code="valid = lambda a, b: Fraction(a, b).den < 50"
      
      "valid(AND, 999)"
      "valid(NOW, 999)"
      "valid(NOT, 999)"
      "valid(ONE, 999)"
      "valid(IS, 99)"
      
      --answer="DONE"
      

      Solution: DONE = 4925.

      The fractions are:

      0.(AND)… = 324/999 = 12/37
      0.(NOW)… = 296/999 = 8/27 [*]
      0.(NOT)… = 297/999 = 11/37 [*]
      0.(ONE)… = 925/999 = 25/27
      0.(IS)… = 81/99 = 9/11 [*]
      0.(IS)… = 18/99 = 2/11 [*]

      [*] NOW and NOT can be interchanged, and the digits of IS can appear in either order, which accounts for the four solutions found by the program.

      Like

  • Unknown's avatar

    Jim Randell 12:28 pm on 8 October 2023 Permalink | Reply
    Tags:   

    Teaser 1866: Which Sunday paper? 

    From The Sunday Times, 21st June 1998 [link]

    Today you have to do a usual digits-for-letters substitution to make sense of the sum:

    SUN + DAYS = ?????

    I have not yet decided which Sunday paper the right-hand side is going to be. It will be one of GRAPH, MATCH, SCENE, SEEDY, SPORT, TIMES, TODAY, WORLD and WYNDY.

    But I must choose it so that the five-figure total is uniquely determined.

    Which word should be the right-hand side, and then what would the numerical total be?

    [teaser1866]

     
    • Jim Randell's avatar

      Jim Randell 12:29 pm on 8 October 2023 Permalink | Reply

      This Python program uses the [[ SubstitutedExpression.split_sum() ]] solver from the enigma.py library to try each of the candidate alphametic sums, and looks for ones that have a single solution.

      It runs in 82ms.

      Run: [ @replit ]

      from enigma import (SubstitutedExpression, singleton, sprintf, printf)
      
      # possible words
      words = "GRAPH MATCH SCENE SEEDY SPORT TIMES TODAY WORLD WYNDY".split()
      
      # choose a result
      for w in words:
        # construct a puzzle using the word
        expr = sprintf("SUN + DAYS = {w}")
        p = SubstitutedExpression.split_sum(expr).solver()
        # that has a single solution
        s = singleton(p.solve(verbose=0))
        if s is None: continue
        # output solution
        printf("{expr} / {s}", s=p.substitute(s, expr))
      

      Solution: The alphametic total is: WYNDY, and the numerical total is: 10390.

      So we have:

      SUN + DAYS = WYNDY → 783 + 9607 = 10390

      The remaining result words have no solutions, apart from WORLD, which has 6.

      Like

  • Unknown's avatar

    Jim Randell 4:42 pm on 6 October 2023 Permalink | Reply
    Tags:   

    Teaser 3185: Multiple squares 

    From The Sunday Times, 8th October 2023 [link] [link]

    My grandson likes to compile 3×3 magic squares, where each of the three rows of numbers, each of the three columns of numbers and both of the straight diagonals, add up to the same total. This he did without repeating any of the nine numbers in the square.

    He has now progressed to compiling similar 3×3 squares, which instead of the eight rows, columns and diagonals of numbers adding to the same total, they instead multiply to produce the same product.

    In his first such square this product was 32,768. He was able to find every square of nine different whole numbers that gives this product, excluding identical rotational and mirrored squares.

    What, in ascending order, were the totals of the nine numbers in each of his different squares?

    [teaser3185]

     
    • Jim Randell's avatar

      Jim Randell 5:09 pm on 6 October 2023 Permalink | Reply

      32768 = 2^15, so each multiplicative square is filled with numbers that are powers of 2. And we can treat it as an additive magic square of the corresponding exponents.

      So we just need to find how many essentially different additive magic squares there are (modulo rotation and reflection) with a magic constant of 15. And we can then transform the exponents back to powers of 2 to give the required answers. (Note we allow an exponent of 0 to give a corresponding value of 2^0 = 1).

      This Python program uses the [[ SubstitutedExpression() ]] solver from the enigma.py library to generate all possible additive magic squares of exponents, and then collects those that are different, and we then transform the exponents back to powers of two and sum the numbers in the corresponding multiplicative magic square to give the required total.

      It runs in 77ms.

      Run: [ @replit ]

      from enigma import (SubstitutedExpression, irange, uniq, printf)
      
      # orientations of a square
      squares = [
        # rotations
        (0, 1, 2, 3, 4, 5, 6, 7, 8),
        (2, 5, 8, 1, 4, 7, 0, 3, 6),
        (8, 7, 6, 5, 4, 3, 2, 1, 0),
        (6, 3, 0, 7, 4, 1, 8, 5, 2),
        # reflections
        (2, 1, 0, 5, 4, 3, 8, 7, 6),
        (8, 5, 2, 7, 4, 1, 6, 3, 0),
        (6, 7, 8, 3, 4, 5, 0, 1, 2),
        (0, 3, 6, 1, 4, 7, 2, 5, 8),
      ]
      
      # find the canonical form of a square
      def canonical(sq):
        return min(tuple(sq[j] for j in js) for js in squares)
      
      # find possible squares
      p = SubstitutedExpression(
        [
          # rows
          "A + B + C == 15",
          "D + E + F == 15",
          "G + H + I == 15",
          # columns
          "A + D + G == 15",
          "B + E + H == 15",
          "C + F + I == 15",
          # diagonals
          "A + E + I == 15",
          "C + E + G == 15",
        ],
        base=11,
        answer="(A, B, C, D, E, F, G, H, I)"
      )
      
      # collect results
      ts = list()
      
      # find different squares
      for sq in uniq(canonical(sq) for sq in p.answers(verbose=0)):
        # transform the powers to numbers, and sum them
        t = sum(2**n for n in sq)
        printf("[{sq} -> {t}]")
        ts.append(t)
      
      # output solution
      printf("totals = {ts}", ts=sorted(ts))
      

      Solution: The totals of the numbers in the different squares are: 1022, 1533, 1911.

      And the corresponding squares are:

      Like

    • Hugo's avatar

      Hugo 9:26 am on 15 October 2023 Permalink | Reply

      If we halve each number in the first of those squares, we get one with magic product 4096.
      But that’s certainly not the smallest possible value, as Dudeney showed:
      see the solution and comments to Puzzle no. 203.

      Like

  • Unknown's avatar

    Jim Randell 8:59 am on 4 October 2023 Permalink | Reply
    Tags:   

    Teaser 2496: [Letter values] 

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

    I have chosen 10 different letters of the alphabet before U to represent the digits 0 to 9. I can tell you that 0’s letter is in the word NOUGHT, 1’s letter is in the word ONE, 2’s letter is in TWO, and so on up to 9’s letter being in the word NINE.

    Furthermore, I can write down a particular five-figure number that is divisible by 8, and replacing the digits by their letters I get EIGHT. Similarly, a four-figure number divisible by 9 translates to NINE.

    What number is represented by TEN?

    This puzzle was originally published with no title.

    [teaser2496]

     
    • Jim Randell's avatar

      Jim Randell 9:00 am on 4 October 2023 Permalink | Reply

      We only need to consider the letters AT, and of these only ten of them appear in the words mentioned. So we can assign the digits 0-9 to the letters EFGHINORST (in some order).

      We can use the [[ SubstitutedExpression ]] solver from the enigma.py library to do this, subject to the necessary conditions.

      The following run file executes in 126ms. (Internal runtime is 949µs).

      #! python3 -m enigma -rr
      
      SubstitutedExpression
      
      "EIGHT % 8 = 0"
      "NINE % 9 = 0"
      
      "0 in {N, O, G, H, T}"
      "1 in {O, N, E}"
      "2 in {T, O}"
      "3 in {T, H, R, E}"
      "4 in {F, O, R}"
      "5 in {F, I, E}"
      "6 in {S, I}"
      "7 in {S, E, N}"
      "8 in {E, I, G, H, T}"
      "9 in {N, I, E}"
      
      --answer="TEN"
      --template=""
      

      Solution: TEN = 271.

      The assignment of digits to (bold) letters is:

      0 → (N) O (UGHT)
      1 → (O) N (E)
      2 → T (WO)
      3 → (T) H (REE)
      4 → (FOU) R
      5 → F (IVE)
      6 → S (IX)
      7 → (S) E (V) E (N)
      8 → (EI) G (HT)
      9 → (N) I (NE)

      And:

      EIGHT = 79832 = 8 × 9979
      NINE = 1917 = 9 × 213

      Like

  • Unknown's avatar

    Jim Randell 4:19 pm on 29 September 2023 Permalink | Reply
    Tags:   

    Teaser 3184: Four away 

    From The Sunday Times, 1st October 2023 [link] [link]

    The rectangular snooker table had four corner pockets and two centre pockets (one each in the middle of the left and right sides, which were 12ft long). A ball always left the cushions at the same angle as it struck them. The cue ball was by the bottom right corner pocket and Joe hit it off the left cushion; it bounced off another seven cushions without hitting a ball or entering a pocket, then entered the right centre pocket. Four away!

    Joe replayed the shot but the cue ball hit the left cushion further up the table than before, bounced another ten times without hitting a ball or entering a pocket, then entered the right centre pocket. Four away!

    How much further up the table did the second shot hit the left cushion?

    [teaser3184]

     
    • Jim Randell's avatar

      Jim Randell 5:02 pm on 29 September 2023 Permalink | Reply

      (See also: Teaser 1917 and Teaser 3129).

      Fairly straightforward with some graph paper to find paths between the bottom right and centre right pockets that hit exactly 8 and 11 cushions.

      These give the angle of the shot, from which we can calculate the distance between the respective first bounces, and this gives the answer to the puzzle.

      Run: [ @replit ]

      from enigma import (Rational, irange, is_coprime, printf)
      
      Q = Rational()
      
      # g: bounce -> [((x, y), angle), ...]
      g = { 8: [], 11: [] }
      
      # consider bounces between (0, 0) and (x, y)
      for y in irange(1, 24, step=2):
        for x in irange(2, 12, step=2):
          # check ball doesn't hit a pocket early
          if not is_coprime(x, y): continue
          # calculate number of bounces from (0, 0)
          b = (x - 1) + y // 2
          if b not in g: continue
          # calculate the angle
          t = Q(y, x)
          if t < 2:
            g[b].append(((x, y), t))
      
      # look for 8 bounces
      for ((x1, y1), t1) in g[8]:
        # look for 11 bounces, with a higher angle
        for ((x2, y2), t2) in g[11]:
          if not (t2 > t1): continue
          printf("(0, 0) -> ({x1}, {y1}) = 8 bounces [t = {t1}]")
          printf("-> (0, 0) -> ({x2}, {y2}) = 11 bounces [t = {t2}]")
          # calculate distance between first bounces
          d = 6 * (t2 - t1)
          printf("--> answer = {d:.2f} ft", d=float(d))
      

      Solution: The second shot hit the left cushion 4.5 feet further up the table than the first shot.

      In the following diagram the original table is in the bottom right corner, and the other rectangles are reflections of the table. We want to find paths between the red pocket in the extreme bottom right and a green pocket, that cross the boundaries of the table (the black lines) 8 and 11 times, but do not hit any intermediate pockets.

      The two paths are shown as dotted lines.

      We can denote the 8-bounce path is (8, 3) (i.e. 8 units horizontally, and 3 units vertically), and the 11-bounce path is (8, 9).

      There is a further 8-bounce path at (6, 7) and further 11-bounce path at (12, 1), but these are not involved in the answer to the puzzle.

      And here are the two paths (8-bounce = red, 11-bounce = green) plotted on the table:

      Like

  • Unknown's avatar

    Jim Randell 9:48 am on 28 September 2023 Permalink | Reply
    Tags:   

    Teaser 2641: Exchange rate 

    From The Sunday Times, 5th May 2013 [link] [link]

    I am going on holiday to Tezarland. So at our local Bureau de Change I exchanged a three-figure number of pounds for Tezar dollars. From the pounds I paid a £12 fee and received a whole number of Tezar dollars for each remaining pound.

    This was an unremarkable transaction except that it was an exchange in more ways than one: the number of Tezar dollars I received was like the number of pounds that I started with but with the digits in the reverse order.

    How many Tezar dollars did I receive?

    [teaser2641]

     
    • Jim Randell's avatar

      Jim Randell 9:49 am on 28 September 2023 Permalink | Reply

      Here is a solution using the [[ SubstitutedExpression ]] solver from the enigma.py library.

      The following run files executes in 68ms. (Internal runtime of the generated program is 703µs).

      Run: [ @replit ]

      #! python3 -m enigma -rr
      
      # (ABC - 12) * rate = CBA
      
      SubstitutedExpression
      
      --distinct=""
      
      # rate is a whole number
      "div(CBA, ABC - 12) > 0"
      
      # answer is the number of dollars received
      --answer="CBA"
      

      Solution: You received 612 Tezar dollars.

      Like

  • Unknown's avatar

    Jim Randell 12:12 pm on 26 September 2023 Permalink | Reply
    Tags: ,   

    Teaser 2653: Tough guys 

    From The Sunday Times, 28th July 2013 [link] [link]

    The SS Thomas More has two identical vertical masts mounted on the centre line of the deck, the masts being a whole number of feet tall and seven feet apart. Two straight guy ropes secure the top of each mast to a single anchor point on the centre line of the deck some distance forward of the masts. The total length of the two ropes is a whole number of feet, with one rope being two feet longer than the other.

    What is the height of the masts?

    [teaser2653]

     
    • Jim Randell's avatar

      Jim Randell 12:13 pm on 26 September 2023 Permalink | Reply

      If the ropes are length x and (x + 2), then the total length (= 2x + 2) is a whole number of feet, so x is a whole number of semi-feet (i.e. units of 6 inches).

      So let’s do everything in semi-feet.

      From the 2 right-angled triangles we have:

      r² = d² + h²
      (r + 4)² = (d + 14)² + h²

      r = (7d + 45) / 2

      And as r is an integer, d must be an odd integer.

      This Python program looks for the smallest viable solution:

      It runs in 58ms. (Internal runtime is 200µs)

      Run: [ @replit ]

      from enigma import (irange, inf, div, ircs, printf)
      
      # generate candidate solutions
      def generate():
        # consider d values
        for d in irange(1, inf, step=2):
          r = div(7 * d + 45, 2)
          h = ircs(r, -d)
          x = div(h, 2)
          if h is None or x is None: continue
          # return solution
          yield (d, r, h, x)
      
      # find the first solution
      for (d, r, h, x) in generate():
        printf("height = {x} ft [d={d} r={r} -> h={h}]")
        break
      

      Solution: The masts are 30 ft tall.

      The ropes are 30.5 ft and 32.5 ft long (giving a total rope length of 63 ft), and they are anchored 5.5 ft away from the nearest mast.

      The next solution is found when the masts are 540 ft tall, which seems a bit impractical.


      Analytically we are looking for integer solutions to the equation:

      h² = [(7d + 45) / 2]² − d²

      where h is an even integer, say h = 2z (so z is the mast height in feet):

      (2z)² = (45/4)(d + 7)² − 45
      16z² − 45(d + 7)² = −180

      writing X = 4z (= 2h), Y = d + 7 we get a form of Pell’s equation:

      X² − 45 Y² = −180

      And we can use the pells.py module (from the py-enigma-plus repository – see: Teaser 2994) to quickly find larger solutions to the original equation:

      from enigma import (div, arg, ifirst, printf)
      import pells
      
      # generate (h, d, r, height) values
      def solve():
        # find solutions to: 16z^2 - 45(d + 7)^2 = -180
        for (z, d) in pells.diop_quad(16, -45, -180):
          d -= 7
          r = div(7 * d + 45, 2)
          if r and r > 0 and d > 0 and z > 0:
            yield (2 * z, d, r, z)
      
      # find the first N solutions
      N = arg(8, 0, int)
      for (i, (h, d, r, height)) in enumerate(ifirst(solve(), N), start=1):
        printf("[{i}] h={h} d={d} r={r} -> height = {height} ft")
      
      % time python3 teaser2653pells.py 8
      [1] h=60 d=11 r=61 -> height = 30 ft
      [2] h=1080 d=315 r=1125 -> height = 540 ft
      [3] h=19380 d=5771 r=20221 -> height = 9690 ft
      [4] h=347760 d=103675 r=362885 -> height = 173880 ft
      [5] h=6240300 d=1860491 r=6511741 -> height = 3120150 ft
      [6] h=111977640 d=33385275 r=116848485 -> height = 55988820 ft
      [7] h=2009357220 d=599074571 r=2096761021 -> height = 1004678610 ft
      [8] h=36056452320 d=10749957115 r=37624849925 -> height = 18028226160 ft
      python3 teaser2653pells.py 8  0.06s user 0.03s system 89% cpu 0.098 total
      

      Like

    • Frits's avatar

      Frits 7:49 pm on 26 September 2023 Permalink | Reply

       
      # 16z^2 - 45(d + 7)^2 = -180 
      # with X = 4z (= 2h), Y = d + 7 we get a form of Pell's equation:
      # X^2 - 45 Y^2 = -180 
      # the first soltion being the trivial one, X=0, Y=2 
      
      # Using Brian's method: https://brg.me.uk/?page_id=1468
      #
      # These solutions can also be generated recursively using:
      # x(n+1) = 9 x(n) + 60 y(n)
      # y(n+1) = 4/3 x(n) + 9 y(n)
      
      x, y = 0, 2
      for n in range(8):
        x, y = 9 * x + 60 * y, (4 * x) // 3 + 9 * y
        print(f"[{n + 1}] h={x // 2} d={y - 7} r={(7 * (y - 7) + 45 ) // 2} "
              f"-> height = {x // 4} ft")  
      

      Like

  • Unknown's avatar

    Jim Randell 12:50 pm on 24 September 2023 Permalink | Reply
    Tags:   

    Brainteaser 1095: “Seven anagrams” 

    From The Sunday Times, 31st July 1983 [link]

    Members of TOPIQ (the society with membership limited to those with a tested I.Q. above a specified figure), are required to test one another’s mental quickness with suitable problems from time to time. Once, when I was asked to set a problem, I recalled an old verse which holds several anagrams of the same six letters. The verse went something like this:

    Hushed was the RUSTLE of leaves in the breeze,
    Faded, the LUSTRE of light on the trees,
    As the SUTLER sat in his ULSTER grey,
    Quaffing his ale at the close of the day.
    Then he came to the end of his drinking song:
    “Thou RULEST the weak; thou LUREST the strong,
    John Barleycorn, my Jo!”

    In my problem the six anagrams were omitted. Members firstly had to find these. They were told that, if each of the six letters in the anagrams represented a different one of digits 1 to 6, then the sum of all the six-digit numbers of the anagrams was a 7-digit figure starting with LS and ending with UT. They were then asked the following question, solved by most members in under 10 minutes:

    Having, from the sum, solved the number-letter relationship, what number do you get for RESULT?

    What do you get?

    [teaser1095]

     
    • Jim Randell's avatar

      Jim Randell 12:51 pm on 24 September 2023 Permalink | Reply

      I used the [[ SubstitutedExpression ]] solver from the enigma.py library to solve this puzzle.

      I introduced additional symbols x, y, z, which can take on any value (not just 1-6) for the result of the sum.

      This run file executes in 71ms. (Internal runtime of the generated program is 1.4ms – or 467µs if you use [[ SubstitutedExpression.split_sum() ]]).

      Run: [ @replit ]

      #! python3 -m enigma -rr
      
      SubstitutedExpression
      
      --symbols="ELRSTUxyz"
      --distinct="ELRSTU"
      --invalid="0|7|8|9,ELRSTU"
      
      "RUSTLE + LUSTRE + SUTLER + ULSTER + RULEST + LUREST = LSxyzUT"
      
      --answer="RESULT"
      

      Solution: RESULT = 254316.

      The numbers (in the order given) give the following sum:

      234615 + 134625 + 436152 + 314652 + 231546 + 132546 = 1484136

      Like

  • Unknown's avatar

    Jim Randell 4:27 pm on 22 September 2023 Permalink | Reply
    Tags:   

    Teaser 3183: Partial eclipse 

    From The Sunday Times, 24th September 2023 [link] [link]

    Alf, Bert and Charlie were comparing their experiences of the eclipse from different locations. The moon appeared to be exactly the same size as the sun as it passed in front of part of the sun’s disc. The magnitude of an eclipse measures the maximum part of the diameter of the sun’s disc that is obscured. Taking the apparent diameter of the sun as 100, they noted the following:

    Alf: “My magnitude was a whole number”.
    Bert: “If I took the part of the sun’s circumference that was obscured, multiplied it by the radius and then subtracted the area of the sun’s disc that was obscured, I also got a whole number”.
    Charlie: “Both of those statements are true for all of us, but we all saw different magnitudes greater than 10”.

    In increasing order, what were those three magnitudes?

    As well as this puzzle being Teaser 3183 there are now 3183 puzzles posted in total between the Enigmatic Code and S2T2 sites.

    [teaser3183]

     
    • Jim Randell's avatar

      Jim Randell 4:55 pm on 22 September 2023 Permalink | Reply

      If we suppose the apparent radius of the two discs is R, and we consider the part of the circumference of the sun that is obscured, then it forms the arc of a circular sector that subtends an angle of at the centre of the sun’s disc. The length of the obscured circumference is then: 2Rθ.

      The area of the part of the sun’s disc that is obscured A can be calculated as the sum of two equal obscured segments, each being the area of the circular sector less the area of the triangle formed by replacing the arc of the sector with a chord.

      A = 4 [(𝛑R²)(θ/2𝛑) − (R cos(θ))(R sin(θ))/2)
      A = 2R²θ − 2R²sin(θ)cos(θ)
      A = R²(2θ − sin(2θ))

      (See also: [@wikipedia])

      And so B’s measure is:

      B = 2R²θ − A

      B = 2R²sin(θ)cos(θ)
      B = R²sin(2θ)

      And A’s measure (the magnitude) m is given by:

      m = 2R(1 − cos(θ))

      So given an integer magnitude, we can calculate a rational value for cos(θ), and using the identity cos²(θ) + sin²(θ) = 1 we can calculate a value for sin(θ), which must also be rational if B is to have an integer value.

      This Python program runs in 61ms. (Internal runtime is 413µs).

      from enigma import (Rational, irange, is_square_q, sq, as_int, printf)
      
      Q = Rational()
      
      # apparent radius
      R = 50
      
      # consider possible magnitudes from 11 to 99
      for m in irange(11, 99):
        # calculate cos(theta), sin(theta)
        cost = 1 - Q(m, 2 * R)
        sint = is_square_q(1 - sq(cost), F=Q)
        if sint is None: continue
        # calculate B's measure
        B = 2 * sq(R) * sint * cost
        # is it an integer?
        B = as_int(B, default=None)
        if B is None: continue
        # output solution
        printf("m={m} -> B={B}")
      

      Solution: The magnitudes are: 20, 40, 72.

      And we have:

      m = 20 → B = 2400
      m = 40 → B = 2400
      m = 72 → B = 1344

      There are only 3 values because the “partner” value for m = 72 (which also gives B = 1344) is m = 4.

      Like

      • Frits's avatar

        Frits 8:47 pm on 22 September 2023 Permalink | Reply

        I had to look up some formula and came to the same formula for B.

           
        # apparent radius
        R = 50
        
        # consider possible magnitudes from 11 to 99
        for m in range(11, 100):
          # calculate cos(theta)
          c = 1.0 - m / (2 * R)
          # calculate sin(theta), c^2 + s^2 = 1
          s = (1 - c**2)**.5
          # B = r^2.sin(2 * theta), sin(2x) = 2.sin(x).cos(x) 
          B = 2 * R * R * s * c
          
          # is it close to an integer?
          if abs(B - round(B)) > 1e-6: continue
         
          # output solution
          print(f"m={m} -> B={B:.2f}")
        

        Like

      • Jim Randell's avatar

        Jim Randell 2:38 pm on 23 September 2023 Permalink | Reply

        With a bit more work we can simplify the calculation of B to:

        B = (1/2)(2R − m)√(m(4R − m))

        Which gives a simpler program, that only uses integers:

        Run: [ @replit ]

        from enigma import (irange, is_square, div, printf)
        
        # apparent radius
        R = 50
        
        # consider possible magnitudes from 11 to 99
        for m in irange(11, 99):
          r = is_square(m * (4 * R - m))
          if r is None: continue
          B = div((2 * R - m) * r, 2)
          if B is None: continue
          # output solution
          printf("m={m} -> B={B}")
        

        Like

  • Unknown's avatar

    Jim Randell 9:32 am on 21 September 2023 Permalink | Reply
    Tags: by: A. H. R. Grimsey   

    Brainteaser 1485: Safe depository 

    From The Sunday Times, 24th February 1991 [link]

    The number of my safe deposit box in the Norsex Bank has four different digits, decreasing from left to right. Curiously, that of my fiancée has the same figures but in the reverse order. The bank manager, Mr K. Aprekar, has said that when we are married next month, he will give us a presently-vacant box number which not only contains the four digits we now share, but is in fact the difference between our two numbers.

    What is it?

    [teaser1485]

     
    • Jim Randell's avatar

      Jim Randell 9:32 am on 21 September 2023 Permalink | Reply

      Here is a solution using the [[ SubstitutedExpression ]] solver from the enigma.py library.

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

      Run: [ @replit ]

      #! python3 -m enigma -rr
      
      SubstitutedExpression
      
      # suppose the current numbers are: ABCD and DCBA
      
      # numbers are decreasing
      "A > B" "B > C" "C > D"
      
      # the new number (= the difference between the original two numbers)
      --macro="@new = ABCD - DCBA"
      # is composed of the same digits
      "set(nsplit(@new, 4)) == {A, B, C, D}"
      
      --answer="@new"
      

      Solution: The new box number is 6174.

      We have:

      7641 − 1467 = 6174

      Like

  • Unknown's avatar

    Jim Randell 12:33 pm on 19 September 2023 Permalink | Reply
    Tags: ,   

    Teaser 2642: New world order 

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

    In maths class Pat has been learning about progressions from his “New World” text book. The book has three sections, namely “Arithmetic”, “Algebra” and “Geometry” which overall run from page 1 to page 500 inclusive — with each section starting on a new page. The geometry section is over twice as long as the arithmetic section.

    As an exercise Pat calculated the sum of the page numbers in each section and he was surprised to find that the sum of the page numbers in “Algebra” was double that of the sum of the page numbers in “Geometry”.

    How many pages are there in the “Arithmetic” section?

    [teaser2642]

     
    • Jim Randell's avatar

      Jim Randell 12:34 pm on 19 September 2023 Permalink | Reply

      The total sum of all the page numbers = T = tri(500).

      If the Arithmetic section is pages 1 .. x, the Algebra section pages (x + 1) .. y, and the Geometry section pages (y + 1) .. 500, then the sums of the page numbers in each section are:

      Ar = tri(x)
      Al = tri(y) − tri(x)
      Ge = T − tri(y)

      tri(y) = T − Ge

      and:

      Al = 2 Ge

      Ge = (T − Ar) / 3

      So, by choosing a value for x, we can calculate the values of Ar, Al, Ge and hence y.

      This Python program runs in 55ms. (Internal runtime is 267µs).

      Run: [ @replit ]

      from enigma import (irange, tri, div, is_triangular, printf)
      
      # Ar: sum(1 .. x) = tri(x)
      # Al: sum(x + 1 .. y) = tri(y) - tri(x)
      # Ge: sum(y + 1 .. 500) = tri(500) - tri(y)
      #
      # Al = 2 * Ge
      
      # total sum of all pages
      T = tri(500)
      
      # consider the end page for arithmetic = x
      for x in irange(2, 165):
        Ar = tri(x)
        Ge = div(T - Ar, 3)
        if Ge is None: continue
        # calculate y
        y = is_triangular(T - Ge)
        if y is None or not x < y < 500: continue
        if not (500 - y > 2 * x): continue
        # output solution
        printf("Ar = 1..{x}; Al = {x1}..{y}; Ge = {y1}..500", x1=x + 1, y1=y + 1)
      

      Solution: There are 45 pages in the Arithmetic section.

      So the sections are:

      Arithmetic: pages 1 – 45 (= 45 pages); sum = 1035
      Algebra: pages 46 – 409 (= 364 pages); sum = 82810 (= Geometry × 2)
      Geometry: pages 410 – 500 (= 91 pages); sum = 41405

      Like

  • Unknown's avatar

    Jim Randell 9:32 am on 17 September 2023 Permalink | Reply
    Tags:   

    Brain-Teaser 919: Golden age of steam 

    From The Sunday Times, 2nd March 1980 [link]

    Ever since the dawn of history, mankind has looked back to a Golden Age when everybody and everything was so much better.

    As far as our railway system is concerned, the Golden Age was the prewar era of the great steam locomotives. In spite of their noise, steam, and smoke pollution, (or perhaps even because of these characteristics), the older generation look back with nostalgia to that golden era. Let us therefore pose a not-too-difficult problem concerning those wonderful days.

    Two steam locomotives, each travelling at 50 mph, are driven by Tom and Dick. They are approaching Harry’s signal box from opposite directions.

    Tom sounds his whistle. Immediately upon hearing it, Dick replies. Harry hears both whistles with an interval of seven seconds between them. The two engines later pass the signal box at the same instant.

    You may assume that the speed of sound was 1100 feet per second relative to the ground. One mile has 5280 feet.

    How far (in feet) was Tom from the box when he sounded his whistle?

    This puzzle is included in the book The Sunday Times Book of Brainteasers (1994). The puzzle text above is taken from the book.

    [teaser919]

     
    • Jim Randell's avatar

      Jim Randell 9:33 am on 17 September 2023 Permalink | Reply

      The trains are travelling at the same speed, and (presumably on different tracks) pass the signal box at the same time, so they must start the same distance from the signal box.

      Working in feet per second, a speed of 50 mph = 220/3 ft/s.

      Suppose at time t = 0 both T and D are a distance x feet from H, and T sounds his whistle.

      At a time t = x / 1100 H hears T’s whistle.

      And if D hears the whistle when he is a distance y from H, then he hears T’s whistle at time t = (x + y) / 1100.

      D instantaneously responds (still at distance y), and H hears D’s whistle at time t = (x + 2y) / 1100.

      H hears the whistles 7 seconds apart, so:

      (x + 2y) / 1100 = 7 + x / 1100
      y = (7/2)1100 = 3850

      So D sounds his whistle when he is 3850 ft from H at time t = (x + 3850) / 1100.

      And at this time T must also be 3850 ft from H.

      Hence:

      x = 3850 + (220/3)(x + 3850) / 1100
      ⇒ x = 4400

      Solution: Tom was 4400 ft from the signal box when he sounded his whistle.

      Like

    • Hugo's avatar

      Hugo 9:49 am on 17 September 2023 Permalink | Reply

      It must have been a cold day: the speed of sound is about 1100 ft/s at 5°C and 60% relative humidity
      (about 3 ft/s less in dry air at that temperature).

      Like

  • Unknown's avatar

    Jim Randell 4:45 pm on 15 September 2023 Permalink | Reply
    Tags:   

    Teaser 3182: Stand and be counted 

    From The Sunday Times, 17th September 2023 [link] [link]

    When bad light ended the first day’s play, the total score was 182 with three batters having been “out” during the day.

    In the successive stands, the lower-numbered and the higher-numbered batters scored in the ratios 7:3, 10:7, 1:11 and 11:19, in that order. The total score was the sum of the scores of the five batters.

    The third batter was the highest scorer.

    [In cricket the batting team starts with batters 1 and 2 together, and each is able to score. When one of them is “out” the third batter comes “in” to replace them, when one of that pair is out the fourth batter comes in, and so on. The amount by which the team score has increased while a particular pair is together is called the “stand”].

    What were the scores of all the batters, in their batting order?

    [teaser3182]

     
    • Jim Randell's avatar

      Jim Randell 5:14 pm on 15 September 2023 Permalink | Reply

      This Python program works through each partnership, considering stands of the specified ratios.

      It runs in 60ms. (Internal runtime is 1.5ms).

      Run: [ @replit ]

      from enigma import (irange, inf, div, map2str, printf)
      
      # total score
      T = 182
      
      # add deltas <ds> to keys <ks> of dict <d>
      def add(d, ks, ds):
        d = dict(d)
        for (k, i) in zip(ks, ds):
          d[k] += i
        return d
      
      # n = number of next bat
      # A = current lower numbered bat
      # B = current higher numbered bat
      # rs = remaining stand ratios
      # ss = current scores per bat
      # t = total runs scored
      def solve(n, A, B, rs, ss, t):
        # choose scores for this stand
        (a, b) = rs[0]
        # remaining ratios
        rs_ = rs[1:]
        if rs_:
          # minimum remaining total
          rt = sum(a + b for (a, b) in rs_)
          # consider possible multipliers for this stand
          for k in irange(1, inf):
            (rA, rB) = (a * k, b * k)
            t_ = t + rA + rB
            if t_ + rt > T: break
            ss_ = add(ss, [A, B], [rA, rB])
            # each batsman may be dismissed
            yield from solve(n + 1, A, n, rs_, ss_, t_)
            yield from solve(n + 1, B, n, rs_, ss_, t_)
        else:
          # can we achieve the total?
          k = div(T - t, a + b)
          if k is not None:
            yield add(ss, [A, B], [a * k, b * k])
      
      rs = [(7, 3), (10, 7), (1, 11), (11, 19)]  # stand ratios
      ss = dict((k, 0) for k in irange(1, 5))  # scores
      
      # find totals for each batsman
      for ss in solve(3, 1, 2, rs, ss, 0):
        # batsman 3 scored the most
        if max(ss.values()) != ss[3]: continue
        # output solution
        printf("{ss}", ss=map2str(ss, sep=" ", enc=""))
      

      Solution: The totals are: bat 1 = 21; bat 2 = 49; bat 3 = 52; bat 4 = 22; bat 5 = 38.

      The stands are:

      1: bat 1 = 21; bat 2 = 9; ratio = 7:3; bat 1 dismissed
      2: bat 2 = 40; bat 3 = 28; ratio = 10:7; bat 2 dismissed
      3: bat 3 = 2; bat 4 = 22; ratio = 1:11; bat 4 dismissed
      4: bat 3 = 22; bat 5 = 38; ratio = 11:19; total = 182 runs

      Like

      • Jim Randell's avatar

        Jim Randell 7:18 pm on 15 September 2023 Permalink | Reply

        Here’s an alternative (faster) version.

        We can generate possible batting pairings for each stand. And the denominators of the ratios are all different, so we can use the [[ express() ]] function to determine the multipliers for each stand.

        We then use the ratios and the multiplies to calculate the scores for each batsman.

        This Python program runs in 58ms, and has an internal runtime of 386µs.

        from enigma import (irange, subsets, express, map2str, printf)
        
        # generate possible pairings
        def _pairs(k, A, B, n, ds=[]):
          ds = ds + [(A, B)]
          # are we done?
          if k < 1:
            yield ds
          else:
            # one of A and B is dismissed
            yield from _pairs(k - 1, B, n, n + 1, ds)
            yield from _pairs(k - 1, A, n, n + 1, ds)
        
        pairs = list(_pairs(3, 1, 2, 3))
        
        # calculate scores with a sequence of multipliers and a sequence of pairs
        def scores(ks, ps):
          ss = dict((i, 0) for i in irange(1, 5))
          for (k, (a, b), (x, y)) in zip(ks, ps, [(7, 3), (10, 7), (1, 11), (11, 19)]):
            ss[a] += k * x
            ss[b] += k * y
          return ss
        
        # generate possible multipliers for each stand
        for (k1, k3, k2, k4) in express(182, [10, 12, 17, 30], min_q=1):
          for ps in pairs:
            ss = scores((k1, k2, k3, k4), ps)
            if ss[3] == max(ss.values()):
              printf("{ss}", ss=map2str(ss, sep=" ", enc=""))
        

        Like

    • Frits's avatar

      Frits 6:01 pm on 15 September 2023 Permalink | Reply

      from enigma import SubstitutedExpression
      
      # the alphametic puzzle
      p = SubstitutedExpression(
        [
          # 10 * W + 17 * X + 12 * Y + 30 * Z = total score 182
          "div(182 - (10 * W + 17 * X + 12 * Y), 30) == Z",
          
          # who whon the first session
          "F < 3",
          # who whon the third session
          "2 < T < 5",
          
          # third batter must have won in 2nd session
          
          # possible score for the first  batter 7 * W + (F == 1) * 10 * X
          # possible score for the second batter 3 * W + (F == 2) * 10 * X 
          # possible score for the third  batter 7 * X + Y + 11 * (T == 3) * Z
          # possible score for the fourth batter 11 * Y + (T == 4) * 11 * Z
          #          score for the fifth  batter 19 * Z
          
          # the third batter was the highest scorer
          "max(sc := [7 * W + (F == 1) * 10 * X, \
                      3 * W + (F == 2) * 10 * X , \
                      7 * X + Y + 11 * (T == 3) * Z, \
                      11 * Y + (T == 4) * 11 * Z, \
                      19 * Z]) == sc[2]", 
        ],
        answer="sc",
        distinct="",
        digits=range(1, 10),
        reorder=0,
        verbose=0,    # use 256 to see the generated code
      )
      
      # print answers
      for ans in p.answers():
        print(f"answer: {ans}")   
      

      Like

      • Frits's avatar

        Frits 6:17 pm on 15 September 2023 Permalink | Reply

        @Jim, Thank you for leaving the easy solution (SubstitutedExpression) for me.

        Like

      • Frits's avatar

        Frits 6:30 pm on 15 September 2023 Permalink | Reply

        Theoretically I should have used base=13 and digits=range(1, 13) to allow for high W and Y’s.

        Like

    • Frits's avatar

      Frits 11:49 am on 16 September 2023 Permalink | Reply

      A more general version without analysis.

      from enigma import SubstitutedExpression
      
      # ratio sums
      rs = [10, 17, 12, 30]
      multipliers = "WXYZ"
      
      # maxima per multiplier
      d = {multipliers[i]: (182 - sum(rs) + rs[i]) // rs[i] for i in range(4)}    
      mx = max(d.values())
      
      # invalid digit / symbol assignments
      d2i = {n: set(k for k, v in d.items() if n > v) for n in range(1, mx + 1)} 
      # F/S/T were not "out" in the 1st/2nd/3rd play
      for i, v in enumerate("FST"):
        for j in range(3 + i, mx + 1):
          d2i[j].add(v)
      
      # the alphametic puzzle, use multipliers W, X, Y and Z
      p = SubstitutedExpression(
        [ 
          # 10 * W + 17 * X + 12 * Y + 30 * Z = total score 182
          "div(182 - (17 * X + 12 * Y + 30 * Z), 10) = W",
          
          # S wasn't "out" in the second play
          "S in {F, 3}",
          # T wasn't "out" in the third play
          "T in {S, 4}",
          
          # score for the first  batter 7W + (F == 1).10X + (S == 1).Y + (T == 1).11Z
          # score for the second batter 3W + (F == 2).10X + (S == 2).Y + (T == 2).11Z
          # score for the third  batter                7X + (S == 3).Y + (T == 3).11Z
          # score for the fourth batter                            11Y + (T == 4).11Z
          # score for the fifth  batter                                           19Z
          
          # the third batter was the highest scorer
          "max(sc := [7 * W + (F == 1) * 10 * X + (S == 1) * Y + (T == 1) * 11 * Z, \
                      3 * W + (F == 2) * 10 * X + (S == 2) * Y + (T == 2) * 11 * Z, \
                                          7 * X + (S == 3) * Y + (T == 3) * 11 * Z, \
                                                        11 * Y + (T == 4) * 11 * Z, \
                                                                            19 * Z])\
               == sc[2]", 
        ],
        answer="sc",
        d2i=d2i,
        distinct="",
        base=mx + 1,
        digits=range(1, mx + 1),
        reorder=0,
        verbose=0,    # use 256 to see the generated code
      )
      
      # print answers
      for ans in p.answers():
        print(f"answer: {ans}")   
      

      Like

    • Jim Olson's avatar

      Jim Olson 3:46 am on 26 September 2023 Permalink | Reply

      What is the correct answer?

      Like

  • Unknown's avatar

    Jim Randell 8:35 am on 14 September 2023 Permalink | Reply
    Tags: by: J David Jones   

    Teaser 2008: Divide and add 

    From The Sunday Times, 11th March 2001 [link]

    In the following arithmetic the fractions have four digits in the numerator and denominator, and the digits have been replaced consistently by letters. with different letters used for different digits.

    ETON/NOTE + TANG/GNAT

    Each fraction is a whole number.

    What is the total?

    [teaser2008]

     
    • Jim Randell's avatar

      Jim Randell 8:36 am on 14 September 2023 Permalink | Reply

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

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

      Run: [ @replit ]

      #! python3 -m enigma -rr
      
      SubstitutedExpression
      
      "ETON % NOTE = 0"
      "TANG % GNAT = 0"
      
      --answer="(ETON // NOTE) + (TANG // GNAT)"
      

      Solution: The total is: 13.

      The expression is:

      9801/1089 + 8712/2178 = 9 + 4 = 13

      Like

  • Unknown's avatar

    Jim Randell 10:12 am on 12 September 2023 Permalink | Reply
    Tags:   

    Teaser 2651: Parsnip Farm 

    From The Sunday Times, 14th July 2013 [link] [link]

    On Parsnip Farm there was a triangular field with one of its boundaries running north to south. From that boundary’s southernmost point Farmer Giles built a fence in an easterly direction, thus partitioning the field into two smaller triangular fields, with the area of the northern field being forty per cent of the area of the southern field. Each side of each field was a whole number of furlongs in length, one of the sides of the southern field being twenty-five furlongs in length.

    What are the lengths of the other two sides of the southern field?

    [teaser2651]

     
    • Jim Randell's avatar

      Jim Randell 10:12 am on 12 September 2023 Permalink | Reply

      If the area of the original field is A, then it is split such that the northern field has an area N = (2/7)A and the southern field S = (5/7)A.

      The boundaries of N are all integers and so form a Pythagorean triple (x, y, z).

      And we can expand the northern field by a factor of f until its hypotenuse exactly covers the boundary of the original field, and we get this:

      The we can then write the area of the original field in two ways:

      A = (7/2)N = 7xy / 4
      A = fxy / 2

      f = 7/2

      And we can calculate the unknown sides of S:

      z′ = (f − 1)z = 5z/2
      y′ = hypot(7x/2, 5y/2) = hypot(7x, 5y) / 2

      This Python program runs in 58ms. (Internal runtime is 334µs).

      Run: [ @replit ]

      from enigma import (pythagorean_triples, div, ihypot, ordered, printf)
      
      for (a, b, z) in pythagorean_triples(100):
        z_ = div(5 * z, 2)
        if z_ is None: continue
        N = ordered(a, b, z)
        for (x, y) in [(a, b), (b, a)]:
          y_ = div(ihypot(7 * x, 5 * y), 2)
          if y_ is None: continue
          S = ordered(x, z_, y_)
          if 25 in S:
            # output solution
            printf("N = {N}; S = {S}")
      

      Solution: The other two sides of the southern field are 6 and 29 furlongs.

      N is a (6, 8, 10) triangle, (area = 24 square furlongs ≈ 0.97 sq km).

      S is a (6, 25, 29) triangle, (area = 60 square furlongs ≈ 2.43 sq km).

      So the original field was a (8, 29, 35) triangle, (area = 84 square furlongs ≈ 3.40 sq km).

      Like

    • Frits's avatar

      Frits 5:44 pm on 12 September 2023 Permalink | Reply

      Avoiding imports.

       
      is_square = lambda n: int(rt := n**.5) == rt
      
      # generate Pythagoren triples for a fixed hypothenuse
      def triples(h):
        sqs = {i * i for i in range(1, h)}
        return [(int(s1**.5), int(s2**.5)) for s1 in sqs 
                 if (s2 := h**2 - s1) >= s1 and s2 in sqs]
        
      side = 25
      
      # can x be 25?  
      # then f.x = 87.5, y' can never be a whole number  (f = 3.5)
      # if other side (2.5y) is k.0 or k.5, so x != 25
      
      # can y' be 25?
      for c, d in triples(side): 
         # are these lenghts multiples of 2.5 and 3.5?
        x, y = -1, -1
        if (c % 2.5 == 0 and d % 3.5 == 0):
          y, x = c // 2.5, d // 3.5    
        if ((c % 3.5 == 0 and d % 2.5 == 0)):
          x, y = c // 3.5, d // 2.5    
        if x == -1: continue
        
        # y' can be 25
        if is_square(z2 := x**2 + y**2):
          z = int(z2**.5)
          if z % 2 == 0:
            print(f"answer {int(x)} and {int(2.5 * z)} furlongs")
        
      # can z' be 25?
      if side % 5: exit(0)
      z = int(side * 2 / 5)
      
      ts = triples(z)
      # determine z'
      for x, y in ts + [x[::-1] for x in ts]:
        if is_square(y1 := 3.5**2 * x**2 + 2.5**2 * y**2):
          print(f"answer {int(x)} and {int(y1**.5)} furlongs")  
      

      Like

  • Unknown's avatar

    Jim Randell 8:05 am on 10 September 2023 Permalink | Reply
    Tags:   

    Brain-Teaser 928: Confused contracts 

    From The Sunday Times, 4th May 1980 [link]

    The results of the hands in a bridge tournament were written like this: “Joe Smith, two ♥”. Before I could calculate the scores, my dog tore up the results of the last four players. Fortunately the writing remained legible. By manoeuvring the fragments, and knowing there had been one contract in each suit, and one at each of the one, two, three and four levels, I was able to construct various feasible combinations.

    I first tried putting ♦ opposite Ted, Pete and Reg in turn. Ted could have ♦ only when Mr Green had the two contract; Pete only when ♠ were four; and Reg only when Mr Black had the one. Similarly, if Reg or Mr Black had ♣, then Mr Green had four; If Mr White had ♥ or ♣ then Mr Black had the other; if Reg had ♥ then Pete had ♦; if Mr Brown had ♥ then Mr Black had four; if Mr Black had ♥ then Mr Green had two; and if Mr Black didn’t have ♥ then ♠ were in less than four.

    Mr Black could have one only when Pete had three ♠; Mr Green could have two only when ♥ were four; Mr Black had four only when Reg had ♦; Mr Green had four only when ♦ were in three; and ♣ could be in three or four only when Reg had ♥.

    Finally I noted that Ted and Vic had the same coloured suits whenever I tried putting ♠ with the three, but different coloured suits if Mr White did not have ♥.

    Luckily, I then remembered that ♦ had actually been bid at the four level.

    What was the suit of the three contract, and what was the full name of the player who bid it?

    This puzzle is included in the book The Sunday Times Book of Brainteasers (1994). The puzzle text above is taken from the book.

    [teaser928]

     
    • Jim Randell's avatar

      Jim Randell 8:06 am on 10 September 2023 Permalink | Reply

      I know nothing of Bridge, so at first the puzzle text made no sense to me, but there is a handy hint in the 1974 book:

      Ignoring the Bridge jargon, you have to match each of the numbers 1 to 4 with one of the suits, a forename, and a surname.

      I used the [[ SubstitutedExpression ]] solver to allocate the values among the three groups, so all we need to do is translate the text into a collection of constraints which we can represent by Python expressions.

      I translated: “If A had X or Y, then B had the other” into: “(A = X) ⇒ (B = Y)” and “(A = Y) ⇒ (B = X)”.

      Note that we might expect to deduce “Reg != Black” from the statement “if Reg or Mr Black had …”, but if we try this then there are no solutions.

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

      Run: [ @replit ]

      #! python3 -m enigma -rr
      
      # allocate values 1-4 to the following:
      #
      #  suits    : C D S H [Clubs, Diamonds, Spades, Hearts]
      #  forenames: T R P V [Ted, Reg, Pete, Vic]
      #  surnames : B K G W [Brown, blacK, Green, White]
      
      SubstitutedExpression
      
      --digits="1-4"
      --distinct="CDSH,TRPV,BKGW"
      
      # specify the conditions
      "implies(T == D, G == 2)"
      "implies(P == D, S == 4)"
      "implies(R == D, K == 1)"
      "implies(R == C or K == C, G == 4)"
      "implies(W == H, K == C)" "implies(W == C, K == H)"
      "implies(R == H, P == D)"
      "implies(B == H, K == 4)"
      "implies(K == H, G == 2)"
      "implies(K != H, S != 4)"
      "implies(K == 1, P == 3 == S)"
      "implies(G == 2, H == 4)"
      "implies(K == 4, R == D)"
      "implies(G == 4, D == 3)"
      "implies(C == 3 or C == 4, R == H)"
      "implies(S == 3, {T, V} in [{C, S}, {D, H}])"
      "implies(W != H, {T, V} not in [{C, S}, {D, H}])"
      
      # diamonds was the 4th contract
      --assign="D,4"
      
      # mention all the variables
      "true(C, D, S, H, T, R, P, V, B, K, G, W)"
      
      --template="(C D S H) (T R P V) (B K G W)"
      --solution=""
      

      Solution: The 3 contract was in hearts. It was bid by Pete Green.

      The contracts are fully defined:

      1♣ = Ted Brown
      2♠ = Reg Black
      3♥ = Pete Green
      4♦ = Vic White

      And we see that Reg = Black.

      Like

    • Frits's avatar

      Frits 4:06 pm on 11 September 2023 Permalink | Reply

      More than 200 lines of code.

      from itertools import combinations 
      
      # allocate values 1-4 to the following:
      #
      #  suits    : C D S H [Clubs, Diamonds, Spades, Hearts]
      #  forenames: T R P V [Tom, Reg, Pete, Vic]
      #  surnames : B K G W [Brown, blacK, Green, White]
      
      # 0/1/2 for no/some/all details
      detail = 1
      
      rev = lambda x: "neq" if x == "eq" else "eq"
      
      # a specific print format
      p_frz = lambda x, y: f"{x:>3}-{''.join(sorted(y))}"
      
      # add implication if <x> then <y> 
      def implies(x, y):
        if "=" in x:
          op1 = "eq" if "==" in x else "neq"
          op2 = "eq" if "==" in y else "neq"
          # use frozenset to make it hashable
          var1, var2 = frozenset([x[0], x[-1]]), frozenset([y[0], y[-1]])
          imp[(op1, var1)] = imp.get((op1, var1), []) + [(op2, var2)]
          # if a implies b then not b implies not a
          imp[(rev(op2), var2)] = imp.get((rev(op2), var2), []) + [(rev(op1), var1)]
        else:
          if x in imp:
            if y not in imp[x]:
              # check if y results in a falsehood
              if y == (rev(x[0]), x[1]):
                print(f"ERROR {x}-{y} is false")
               
              if y[1] in fb[x[1]] and x[0] == y[0] == "eq":  
                if detail: 
                  print(f"{p_frz(x[0], x[1])} is false as it leads to "
                        f"eq-{''.join(y[1])} which is not allowed")
                add_truth("neq", x[1])
              imp[x] += [y]
          else:
             imp[x] = [y]
      
      # print implications
      def print_imp(d):
        print()  
        for (a, b), vs in sorted(d.items()):
          print(f"{p_frz(a, b)}  : ", end=' ')
          for (c, d) in vs:
            print(f"{p_frz(c, d)}", end=', ')
          print()
        print()  
            
      # add entries to truth list <t>
      def add_truth(c, s):
        s_ = frozenset(s)
        if (c, s_) in t: return
        l_ = list(s)
        if detail: print("add to t:", p_frz(c, s_))
        t.add((c, s_))
        if c != "eq": return
        
        # add forbidden entries
        for f in fb[s_]:
          if detail > 1: print("add inherited rules to t:", p_frz("neq", f))
          t.add(("neq", f)) 
      
        toadd = []
        # propagate 'eq-ab': if 'neq-ac' exists then also 'neq-bc' must be true
        for d, f in t:
          if d != "neq": continue
          for i, x in enumerate(l_):
            if x not in f: continue
            o, = f.difference([x])
            if o not in bd[l_[1 - i]]:
              toadd.append(frozenset([l_[1 - i], o]))
      
        for x in toadd:
          add_truth("neq", x)
                  
      imp, fb, bd = dict(), dict(), dict()
      
      # specify the conditions
      implies("T == D", "G == 2")
      implies("P == D", "S == 4")
      implies("R == D", "K == 1")
      implies("W == H", "K == C") 
      implies("W == C", "K == H")
      implies("R == H", "P == D")
      implies("B == H", "K == 4")
      implies("K == H", "G == 2")
      implies("K != H", "S != 4")
      implies("K == 1", "P == 3")
      implies("K == 1", "P == S")
      implies("K == 1", "S == 3")
      implies("G == 2", "H == 4")
      implies("K == 4", "R == D")
      implies("G == 4", "D == 3")
      
      #implies("R == C or K == C", "G == 4")
      implies("R == C", "G == 4")
      implies("K == C", "G == 4")
      #implies("C == 3 or C == 4", "R == H")
      implies("C == 3", "R == H")
      implies("C == 4", "R == H")
      
      #implies("S == 3", "{T, V} in [{C, S}, {D, H}]")
      #implies("W != H", "{T, V} not in [{C, S}, {D, H}]")
      implies("S == 3", "W == H")
      
      types = [x.split() for x in ["C D S H", "T P R V", "B K G W", "1 2 3 4"]]
      # buddies
      bd = {x: [y for y in types[i] if y != x] 
                for i, tp in enumerate(types) for x in tp}
      # forbidden values
      for a, b in combinations(bd.keys(), 2):
        if b in bd[a]: continue
        fb[frozenset([a, b])] = [frozenset([a, x]) for x in bd[b]] + \
                                [frozenset([b, x]) for x in bd[a]] 
      
      if detail > 1:
        print("forbidden\n---------")
        for k, vs in sorted(fb.items()):
          print(''.join(k), end="  :  ")
          for v in vs:
            print(''.join(v), end=", ")
          print()
        print()  
      
      t = set()
      # diamonds was the 4th contract
      add_truth('eq', frozenset(['D', '4']))
      
      loop, ln = 1, len(t)
      while True:
      
        if detail:
          print(f"\nloop {loop}\n------")
          if loop < 3: print_imp(imp)
      
        if detail > 1:
          print(f"\ntruths\n------")
          for x in sorted(t, key = lambda x: (x[0], sorted(x[1]) ) ):
            print(p_frz(x[0], ''.join(sorted(x[1]))))
        
        # expand implications by chaining
        for k, vs in imp.items():
          for v in vs:
            # check if v is allowed ...
            if (rev(v[0]), v[1]) in t:
              # ... if not disallow k
              add_truth(rev(k[0]), k[1])
            
            if v in imp:
              # add implications of v to k
              for i in imp[v]:
                implies(k, i)
      
        # check for 3 non-equalities in a group
        toadd = []
        for c, f in t:
          if c != "neq": continue
          lst = list(f)
          # for both elements within f
          for i in range(2):
            y = [("neq", frozenset([x, lst[1-i]])) in t for x in bd[lst[i]]]
            if sum(y) != 2: continue
            # we have 3 neq's so the remaining entry in group must be eq
            toadd.append(frozenset([lst[1-i], bd[lst[i]][y.index(0)]]))
        
        for x in toadd:
          add_truth("eq", x)
        
        # only if normal logic has been exhausted
        if len(t) == ln:
          lookup = lambda d, x: [f for c, f in d if c == "eq" and x in f and 
                                 len(f | set("1234")) == 5]
              
          # implies("S == 3", "{T, V} in [{C, S}, {D, H}]")
          # implies("W != H", "{T, V} not in [{C, S}, {D, H}]")
          s3 = ("eq", frozenset(["S", "3"])) in t
          ns3 = ("neq", frozenset(["S", "3"])) in t
          if not s3 and not ns3: break
          
          # D is 4 so try to find H
          tH = lookup(t, "H")      
          if not tH: break
      
          tT, tV = lookup(t, "T"), lookup(t, "V")    
          if not tV and not tT: break
      
          H, = tH[0].difference(["H"]) 
          DH = {'4', H}
          
          vr, ot = "V" if tV else "T", "T" if tV else "V"
         
          v, = (tV[0] if tV else tT[0]).difference([vr]) 
      
          n = DH.difference([v]).pop() if v in DH else (set("1234") - DH - {v}).pop()
          add_truth("neq" if ns3 else "eq", frozenset([ot, n]))
        
        r3 = [''.join(f.difference(["3"])) for c, f in t if c == "eq" and '3' in f]
        # is there enough data in row 3 for the answer?
        if len(r3) == 3: 
          print(f"\nanswer: {r3[0]}, {r3[1]} and {r3[2]}") 
          exit(0)
        
        ln = len(t)  
        loop += 1     
      

      Like

  • Unknown's avatar

    Jim Randell 4:51 pm on 8 September 2023 Permalink | Reply
    Tags:   

    Teaser 3181: “No slack, Alice!” says Grace 

    From The Sunday Times, 10th September 2023 [link] [link]

    Grace mimicked Mr Dodgson: “Take two different positive odd numbers with no shared prime factor. Multiply the larger by their sum, giving the perimeter of a distinct right-angled triangle with whole-number sides. Only such values and their multiples work”.

    Alice created a loop from part of a 1m thread. She was able to pull it tightly on a pinboard into a right-angled triangle with whole-number cm sides in two ways (with different-shaped triangles).

    Alice then pulled the same loop tight over the thin polar spike of the classroom globe, down two meridians and along the equator. Thinking “Logic’s dead!”, she saw 90° equatorial angles and a non-zero polar angle, which obviously didn’t add to 180°.

    Grace calculated the polar angle to the nearest degree. Curiously, transposing its two digits gave the globe’s whole-number centimetre radius.

    Find this radius.

    [teaser3181]

     
    • Jim Randell's avatar

      Jim Randell 5:09 pm on 8 September 2023 Permalink | Reply

      If the string has length p and angle (in radians) made by the loop at the pole is 𝛂 on a globe of radius r, then we have:

      p = r(𝛑 + 𝛂)

      This Python program finds perimeters (that are whole numbers of centimetres, less than 100), such that (at least) two dissimilar Pythagorean triangles can be constructed, and then looks for a corresponding radius for a globe that fits the remaining conditions.

      It runs in 58ms. (Internal runtime is 296µs).

      from math import (pi, degrees)
      from enigma import (pythagorean_triples, group, item, fdiv, irange, intr, nrev, printf)
      
      # generate possible pythagorean triangles, return (<perimeter>, <triangles>)
      def generate(M):
        for ss in pythagorean_triples(M // 2):
          p = sum(ss)
          if p < M:
            yield (p, ss)
      
      # group pythagorean triangles by their perimeter
      g = group(generate(100), by=item(0), f=item(1))
      
      # consider possible perimeters
      for (p, ts) in g.items():
        if len(ts) < 2: continue
        printf("[p={p} -> {ts}]")
      
        # consider possible globe radii
        for r in irange(10, 99):
          # calculate the polar angle (to the nearest degree)
          a = intr(degrees(fdiv(p, r) - pi))
          if a > 99: continue
          if a < 10: break
          if a == nrev(r):
            printf("-> r={r} a={a}")
      

      Solution: The globe has a radius of 19 cm.

      The loop used 90 cm of thread.

      Which allows (planar) right-angled triangles with sides of (15, 36, 39) cm and (9, 40, 41) cm to be formed.

      It can also be used on a 19cm radius globe to form a triangle on the globe with approx. 30.31 cm running along the equator and 29.85 cm running up meridians to the north pole, meeting at an angle of approx. 91.4°. So the three sides are each close to 30 cm, and the angles are all about 90°.

      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
Design a site like this with WordPress.com
Get started