Updates from Jim Randell Toggle Comment Threads | Keyboard Shortcuts

  • Unknown's avatar

    Jim Randell 5:21 pm on 20 December 2019 Permalink | Reply
    Tags:   

    Teaser 2987: Table mats 

    From The Sunday Times, 22nd December 2019 [link] [link]

    Beth and Sam were using computers to design two table mats shaped as regular polygons.

    The interior angles of Beth’s polygon were measured in degrees; Sam’s were measured in grads. [A complete turn is equivalent to 360 degrees or 400 grads.]

    On completion they discovered that all of the interior angles in the 2 polygons had the same numerical whole number value.

    If I told you the last digit of that number, you should be able to work out the number of edges in (a) Beth’s table mat and (b) Sam’s table mat.

    What were those numbers?

    [teaser2987]

     
    • Jim Randell's avatar

      Jim Randell 8:53 pm on 20 December 2019 Permalink | Reply

      This Python program determines the regular polygons with integer internal angles for 360 divisions (degrees) and 400 divisions (grads). It then finds the common values, and which of those are unique mod 10. It runs in 77ms.

      Run: [ @repl.it ]

      from enigma import (divisors_pairs, intersect, filter_unique, printf)
      
      # record n-gons by internal angles
      # t is the number of subdivisions in a circle
      # return map of: <internal angle> -> <number of sides>
      def ngons(t):
        r = dict()
        for (d, n) in divisors_pairs(t, every=1):
          if n > 2:
            r[t // 2 - d] = n
        return r
      
      # find n-gons for 360 subdivisions and 400 subdivisions
      A = ngons(360)
      B = ngons(400)
      
      # find interior angles that match
      ss = intersect([A.keys(), B.keys()])
      
      # filter them by the units digit
      ss = filter_unique(ss, (lambda x: x % 10))
      
      # output solution
      for i in ss.unique:
        printf("angle = {i} -> (a) {a}-gon, (b) {b}-gon", a=A[i], b=B[i])
      

      Solution: (a) Beth’s polygon has 72 sides; (b) Sam’s polygon has 16 sides.

      A 72-gon has internal angles measuring 175°. A 16-gon has internal angles measuring 157.5° = 175 grads.

      There are 4 numbers which will give regular n-gons for angles expressed in degrees and grads. These are:

      120: degrees → 6-gon (hexagon); grads → 5-gon (pentagon)
      150: degrees → 12-gon (dodecagon); grads → 8-gon (octagon)
      160: degrees → 18-gon (octadecagon); grads → 10-gon (decagon)
      175: degrees → 72-gon (heptacontakaidigon?); grads → 16-gon (hexadecagon)

      Obviously only the last of these is uniquely identified by the final (units) digit.

      Like

    • GeoffR's avatar

      GeoffR 8:53 am on 24 December 2019 Permalink | Reply

      This programme gives four answers to the constraints in the puzzle.
      The first three answers have a common units digit of zero, and the fourth answer has a unique digit of five, which provides the answer to the puzzle. Merry Xmas!

      % A Solution in MiniZinc
      include "globals.mzn";
      
      var 1..400: S;  % Sam's angle (grads)
      var 1..360: B;  % Beth's angle (degrees)
      
      var 1..150: n1; % edges to Sam's table mat
      var 1..120: n2; % edges to Beth's table mat
      constraint n1 != n2;
      
      % Internal angles equal gives 180 - 360/n1 = 200 - 400/n2 
      constraint B == 180 - 360 div n1 /\ 360 mod n1 == 0;
      constraint S == 200 - 400 div n2 /\ 400 mod n2 == 0;
      constraint 180 * n1 * n2 - 360 * n2 == 200 * n1 * n2 - 400 * n1;
       
      solve satisfy;
      
      output [" Edges for Sam's table mat = " ++ show(n1) ++ 
      ", Edges for Beth's table mat = " ++ show(n2)
      ++ "\n Sam's angle = " ++ show(S) ++ ", Beth's angle = " ++ show(B)];
      
      %  Edges for Sam's table mat = 6, Edges for Beth's table mat = 5
      %  Sam's angle = 120, Beth's angle = 120
      % ----------
      %  Edges for Sam's table mat = 12, Edges for Beth's table mat = 8
      %  Sam's angle = 150, Beth's angle = 150
      % ----------
      %  Edges for Sam's table mat = 18, Edges for Beth's table mat = 10
      %  Sam's angle = 160, Beth's angle = 160
      % ----------
      %  Edges for Sam's table mat = 72, Edges for Beth's table mat = 16
      %  Sam's angle = 175, Beth's angle = 175  << unique last digit
      % ----------
      % ==========
      
      
      

      Like

  • Unknown's avatar

    Jim Randell 9:19 am on 19 December 2019 Permalink | Reply
    Tags:   

    Teaser 2883: Happy Xmas 

    From The Sunday Times, 24th December 2017 [link] [link]

    I wrote down three perfect squares. In each square precisely three of its digits were even, the rest being odd. Then I consistently replaced digits by letters, with different letters for different digits. In this way the the three squares became appropriately:

    HAPPY
    XMAS
    TIMES

    What number does TIMES represent?

    [teaser2883]

     
    • Jim Randell's avatar

      Jim Randell 9:19 am on 19 December 2019 Permalink | Reply

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

      The following run file executes in 129ms.

      Run: [ @repl.it ]

      #! python -m enigma -rr
      
      SubstitutedExpression
      
      --answer="(HAPPY, XMAS, TIMES)"
      
      "is_square(HAPPY)"
      "is_square(XMAS)"
      "is_square(TIMES)"
      
      # the above is enough to solve the puzzle, but there are additional constraints:
      
      # count the number of digits with residue r mod m
      --code="count = lambda n, m=2, r=0: sum(x % m == r for x in nsplit(n))"
      
      "count(HAPPY) = 3"
      "count(XMAS) = 3"
      "count(TIMES) = 3"
      

      Solution: TIMES = 31684.

      And: HAPPY = 70225; XMAS = 9604.

      In fact, there is only one way to make HAPPY, XMAS and TIMES squares, without any additional restrictions of the squares.

      Like

    • GeoffR's avatar

      GeoffR 6:53 pm on 19 December 2019 Permalink | Reply

      % A Solution in MiniZinc
      include "globals.mzn";
      
      predicate is_sq(var int: y) =
        let {
           var 1..ceil(sqrt(int2float(ub(y)))): z
        } in z*z = y;
      
      var 1..9:H; var 0..9:A; var 0..9:P; var 0..9:Y;
      var 1..9:X; var 0..9:M; var 0..9:S; 
      var 1..9:T; var 0..9:I; var 0..9:E;
      
      constraint all_different ([H,A,P,Y,X,M,S,T,I,E]);
      
      var 10000..99999: HAPPY = 10000*H + 1000*A + 110*P + Y;
      var 1000..9999: XMAS = 1000*X + 100*M + 10*A + S;
      var 10000..99999: TIMES = 10000*T + 1000*I + 100*M + 10*E + S;
      
      constraint is_sq(HAPPY) /\ is_sq(XMAS) /\ is_sq(TIMES);
      
      % Three even digits in each of numbers HAPPY, XMAS and TIMES
      constraint sum ([H mod 2 == 0, A mod 2 == 0, P mod 2 == 0,
      P mod 2 == 0, Y mod 2 == 0]) == 3; 
      
      constraint sum ([X mod 2 == 0, M mod 2 == 0, 
      A mod 2 == 0, S mod 2 = 0]) == 3;
      
      constraint sum([T mod 2 == 0, I mod 2 == 0,
      M mod 2 == 0, E mod 2 == 0, S mod 2 == 0]) ==  3;
      
      solve satisfy;
      
      output ["TIMES = " ++ show(TIMES) ++ ", HAPPY = " ++ show(HAPPY)
      ++ ", XMAS = " ++ show(XMAS) ]; 
      
      % TIMES = 31684, HAPPY = 70225, XMAS = 9604
      % % time elapsed: 0.03 s
      % ----------
      % ==========
      
      
      

      Like

  • Unknown's avatar

    Jim Randell 9:55 am on 17 December 2019 Permalink | Reply
    Tags:   

    Teaser 2887: A convivial dinner party 

    From The Sunday Times, 21st January 2018 [link] [link]

    Three married couples, the Blacks, the Grays and the Pinks, are having dinner together seated around a circular table. The three men had provided one course each towards the dinner. Each lady was sitting between two men, neither being her husband. The first names are Henry, Robin, Tom, Jenny, Monica and Naomi. Robin and Mr Pink go to the same gym as the wife of the provider of the starter and Mrs Gray. The main course provider, an only child, has Monica on his right. The starter provider doesn’t have a sister. The dessert came from someone sitting closer to Naomi than he is to Mrs Black. Henry is brother in law to the starter provider and his only sister is on his left. Tom’s wife made the coffee, while the other two ladies washed up.

    What were the full names of all the ladies?

    [teaser2887]

     
    • Jim Randell's avatar

      Jim Randell 9:56 am on 17 December 2019 Permalink | Reply

      In this Python program I use a circular list, so I don’t have to worry about going off the end of the list when indexing. It examines the possibilities in 77ms.

      Run: [ @replit ]

      from itertools import (permutations, product)
      from enigma import (join, printf)
      
      # implement a circular list
      class CircularList(list):
        def __getitem__(self, i):
          return list.__getitem__(self, i % len(self))
      
      # distance between positions <a> and <b>
      _distance = CircularList([0, 1, 2, 3, 2, 1])
      
      def distance(a, b): return _distance[abs(a - b)]
      
      # left of position i is i + 1, right of position i is i - 1
      
      # seat Mr B at position 0 (and Mrs B at position 3)
      
      # choose surnames for positions 2, 4
      for (s2, s4) in permutations('GP'):
        # the full list of surnames (each pair sit opposite each other)
        surnames = CircularList([ 'B', s4, s2 ] * 2)
      
        # assign forenames (unlike surnames these are unique)
        for ((f0, f2, f4), (f1, f3, f5)) in product(permutations('HRT'), permutations('JMN')):
          # the full list of forenames
          forenames = CircularList([ f0, f1, f2, f3, f4, f5 ])
      
          # assign the positions of the providers of the starter, main, dessert
          for (S, M, D) in permutations((0, 2, 4)):
      
            # 1. "R and Mr P go to the same gym as the wife of the provider of the starter and Mrs G"
            # we assume the people mentioned separately are different,
            # so: R is not Mr P
            if not (surnames[forenames.index('R')] != 'P'): continue
            # and: Mr G did not provide the starter
            if not (surnames[S] != 'G'): continue
      
            # 2. "The main course provider ... has M on his right"
            # so: whoever is left of M provided the main course
            if not (distance(forenames.index('M') + 1, M) == 0): continue
      
            # 4. "The dessert came from someone sitting closer to N than he is to Mrs B"
            if not (distance(D, forenames.index('N')) < distance(D, 3)): continue
      
            # 2. "The main course provider... is an only child"
            # 3. "The starter provider doesn't have a sister"
            # 5. "H is brother in law to the starter provider and his only sister is on his left."
            # so, H is not the starter provider
            if not (forenames[S] != 'H'): continue
            # also H cannot be the main course provider (as H has a
            # sister, and the main course provider is an only child), so it
            # follows that H must provide the dessert
            if not (forenames[M] != 'H'): continue
            # either: H's wife is the sister of the starter provider (contradicted by statement 3)
            # or: H's sister is married to the starter provider (which must be the case)
            # and this sister is sitting on his left
            if not (surnames[forenames.index('H') + 1] == surnames[S]): continue
      
            # output solution
            printf("({names}) S={S} M={M} D={D}", names=join((a + b for (a, b) in zip(forenames, surnames)), sep=" "))
      

      Solution: The ladies names are Monica Pink, Jenny Black, Naomi Grey.

      The seating plan is:

      Henry Black; Monica Pink; Robin Grey;
      Jenny Black; Tom Pink; Naomi Grey

      The starter was provided by Tom Pink.

      The main course was provided by Robin Grey.

      The dessert was provided by Henry Black.

      Like

  • Unknown's avatar

    Jim Randell 1:57 pm on 15 December 2019 Permalink | Reply
    Tags:   

    Brainteaser 1771: Lottery logic 

    From The Sunday Times, 25th August 1996 [link]

    For his weekly flutter on the National Lottery my friend has to select six of the numbers between 1 and 49 inclusive. Last week he wrote his numbers in numerical order and noticed something which he thought would interest me.

    The first three numbers written in succession, with no gaps, formed a perfect square. The remaining three, similarly combined, formed another square. He suggested I try to deduce his six numbers.

    Fortunately I knew his largest number was even and that he always chose one single-digit number.

    Which numbers had he selected?

    This puzzle is included in the book Brainteasers (2002). The puzzle text above is taken from the book.

    [teaser1771]

     
    • Jim Randell's avatar

      Jim Randell 1:58 pm on 15 December 2019 Permalink | Reply

      This Python program runs in 74ms.

      Run: [ @replit ]

      from itertools import product
      from enigma import (irange, nsplit, printf)
      
      # consider 5- and 6- digit squares
      (n5s, n6s) = (list(), list())
      for i in irange(102, 689):
        n = i * i
        # split the square into 3 2-digit numbers
        (a, b, c) = nsplit(n, 3, 100)
        # the numbers must be increasing, less than 50
        if not (a < b < c < 50): continue
        if a < 10:
          # the first set has exactly one 1-digit number
          if not (b < 10): n5s.append((a, b, c))
        else:
          # the second set ends with an even number
          if c % 2 == 0: n6s.append((a, b, c))
      
      # choose two groups of three
      for (n5, n6) in product(n5s, n6s):
        # are the groups in order?
        if not (n5[-1] < n6[0]): continue
        # output the numbers
        printf("{s}", s=n5 + n6)
      

      Solution: The numbers chosen are: 2, 13, 16, 21, 34, 44.

      We have: 21316 = 146², 213444 = 462².

      Like

    • GeoffR's avatar

      GeoffR 10:21 am on 16 December 2019 Permalink | Reply

      
      % A Solution in MiniZinc
      include "globals.mzn";
      
      var 1..9:A; var 1..9:B; var 1..9:C; var 1..9:D; var 1..9:E;
      var 1..9:F; var 1..9:G; var 1..9:H; var 1..9:I; var 1..9:J;
      var 1..9:K;
      
      var 10..49:BC = 10*B + C; 
      var 10..49:DE = 10*D + E;
      var 10..49:FG = 10*F + G;
      var 10..49:HI = 10*H + I;
      var 10..49:JK = 10*J + K;
      
      % Lottery numbers are A, BC, DE, FG, HI, and JK
      constraint all_different ([BC, DE, FG, HI, JK]);
      
      % He wrote his numbers in numerical order
      constraint increasing([BC, DE, FG, HI, JK]);
      
      % Largest lottery number was even
      constraint JK mod 2 == 0;
      
      % Two perfect squares are ABCDE and FGHIJK
      var 10000..99999: ABCDE = 10000*A + 1000*B + 100*C + 10*D + E;
      
      var 100000..999999: FGHIJK = 100000*F + 10000*G
      + 1000*H + 100*I + 10*J + K;
      
      predicate is_sq(var int: y) =
        let {
           var 1..ceil(sqrt(int2float(ub(y)))): z
        } in z*z = y;
         
      % Split the six lottery numbers into two perfect squares
      constraint is_sq(ABCDE) /\ is_sq(FGHIJK);
      
      solve satisfy;
      
      output [ "Six Lottery numbers were " ++ show(A) ++ 
      ", " ++ show(BC) ++ ", " ++ show(DE)
      ++ ", " ++ show(FG) ++ ", " ++ show(HI) ++ 
      " and " ++ show(JK) ];
      
      % Six Lottery numbers were 2, 13, 16, 21, 34 and 44
      % % time elapsed: 0.03 s
      % ----------
      % ==========
      
      
      

      Like

      • John Crabtree's avatar

        John Crabtree 4:39 pm on 18 December 2019 Permalink | Reply

        The second square must end in 44 (sq. root = 362 + 50x or 338 + 50x), 36 (sq. root = 344 + 50x or 356 + 50x), or 24 (sq. root = 332 + 50x or 318 + 50x). By use of a calculator, the second square = 213444
        Then the first square must end in 16 (sq. root = 104 + 50x or 146 + 50x). Again by use of a calculator, the first square = 21316.
        And so the six numbers are 2, 13, 16, 21, 34 and 44.

        Like

  • Unknown's avatar

    Jim Randell 5:35 pm on 13 December 2019 Permalink | Reply
    Tags:   

    Teaser 2986: The Prhymes’ Numbers 

    From The Sunday Times, 15th December 2019 [link] [link]

    The Prhymes’ triple live album “Deified” has hidden numerical “tricks” in the cover notes. Track 1, with the shortest duration, is a one-and-a-half minute introduction of the band, shown as “1. Zak, Bob, Kaz 1:30” in the cover notes. The other nineteen tracks each have different durations under ten minutes and are listed similarly with durations in “m:ss” format.

    For each of tracks 2 to 20, thinking of its “m:ss” duration as a three-figure whole number (ignoring the colon), the track number and duration value each have the same number of factors. Curiously, the most possible are palindromic; and the most possible are even.

    What is the total album duration (given as m:ss)?

    [teaser2986]

     
    • Jim Randell's avatar

      Jim Randell 9:37 pm on 13 December 2019 Permalink | Reply

      This Python program collect possible numbers corresponding to track times by the number of divisors, and then the required track numbers, also by the number of divisors. It then correlates the lists, maximising the number of palindromes and even numbers. It runs in 78ms.

      Run: [ @repl.it ]

      from itertools import product
      from collections import defaultdict
      from enigma import irange, nconcat, tau, nsplit, printf
      
      # check a sequence is a palidrome
      def is_palindrome(s):
        return len(s) < 2 or (s[0] == s[-1] and is_palindrome(s[1:-1]))
      
      # collect possible track lengths as 3-digit numbers
      # recorded by the number of divisors
      d = defaultdict(list)
      for s in product(irange(1, 9), irange(0, 59)):
        n = nconcat(s, base=100)
        if n < 131: continue # shortest track is 1:30
        d[tau(n)].append(n)
      
      # collect the number of divisors for tracks from 2 to 20
      t = defaultdict(list)
      for n in irange(2, 20):
        t[tau(n)].append(n)
      
      # accumulate the total album duration (in seconds)
      total = 90
      
      # find track lengths for the categories of tracks
      for (k, ts) in t.items():
        # find the palindromes and evens
        (ps, es) = (set(), set())
        for n in d[k]:
          if is_palindrome(nsplit(n)): ps.add(n)
          if n % 2 == 0: es.add(n)
        # try and use even palindromes
        ss = ps.intersection(es)
        # otherwise, use the evens _and_ the palindromes
        if not ss: ss = ps.union(es)
        # otherwise use all available numbers
        if not ss: ss = d[k]
        ss = sorted(ss)
        printf("{k} divisors = {n} tracks {ts} -> {ss}", n=len(ts))
        # check there are no other choices
        assert len(ss) == len(ts)
      
        # add them to the total time
        total += sum(nconcat(nsplit(n, base=100), base=60) for n in ss)
      
      # output duration in minutes, seconds
      (m, s) = divmod(total, 60)
      printf("album duration = {m:d}m{s:02d}s")
      

      Solution: The total album duration is 106:01 (i.e. 1 hour, 46 minutes, 1 second).

      Like

  • Unknown's avatar

    Jim Randell 9:50 am on 12 December 2019 Permalink | Reply
    Tags:   

    Teaser 2889: Catching the bus 

    From The Sunday Times, 4th February 2018 [link] [link]

    I can travel to town by either the number 12 bus or the number 15 bus. The number 12 bus leaves every 12 minutes and the number 15 bus leaves every 15 minutes. The first number 15 bus leaves soon after the first number 12 bus. I arrive at the bus stop at random and catch the first bus to arrive.

    If the probability of me catching the number 15 bus is 2/5 how soon does the first number 15 bus leave after the first number 12 bus?

    [teaser2889]

     
    • Jim Randell's avatar

      Jim Randell 9:51 am on 12 December 2019 Permalink | Reply

      (See also: Teaser 2904).

      If we assume the #12 leaves at t=0, 12, 24, 36, 48, 60 minutes, and the first #15 bus leaves at x minutes after the first #12 bus, then if x < 3 we have the following schedule:

      +00: #12 bus
      [x minute wait for #15 bus]
      +x: #15 bus
      [(12 − x) minute wait for #12 bus]
      +12: #12 bus
      [(3 + x) minute wait for #15 bus]
      +(x + 15): #15 bus
      [(9 − x) minute wait for #12 bus]
      +24: #12 bus
      [(6 + x) minute wait for #15 bus]
      +(x + 30): #15 bus
      [(6 − x) minute wait for #12 bus]
      +36: #12 bus
      [(9 + x) minute wait for #15 bus]
      +(x + 45): #15 bus
      [(3 − x) minute wait for #12 bus]
      +48: #12 bus
      [12 minute wait for #12 bus]
      +60: #12 bus

      And the pattern repeats in subsequent hours.

      If we arrive at a random time during the hour the probability of catching a #15 bus is:

      (x + (x + 3) + (x + 6) + (x + 9)) / 60 = 2/5
      (4x + 18) / 60 = 2/5
      2x = 3
      x = 3/2

      Which means the first #15 bus leaves 1m30s after the first #12 bus.

      However, if 3 < x < 6, then the #15 bus that leaves at (x + 45), departs after the #12 bus that departs at 45 minutes past the hour.

      We get:

      (x + (x + 3) + (x + 6) + (x − 3)) / 60 = 2/5
      (4x + 6) / 60 = 2/5
      4x = 18
      x = 9/2

      Which means the first #15 bus leaves 4m30s after the first #12 bus.

      And we also get workable values at 7m30s and 10m30s.

      As found by this program which considers possible values (in seconds) for the times of the first #15 bus between the first and second #12 buses.

      Run: [ @repl.it ]

      from enigma import (irange, printf)
      
      # time (in seconds) the #12 bus leaves
      times12 = list((x, 12) for x in irange(0, 3600, step=12 * 60))
      
      # consider times that the first #15 bus leaves
      # (or 60 * 60 - 1 for further solutions)
      for t in irange(1, 12 * 60 - 1): 
        times15 = list((x, 15) for x in irange(t, 3600, step=15 * 60))
        times = times12 + times15
        times.sort()
      
        # sum the wait times for each type of bus
        w = { 12: 0, 15: 0 }
        x0 = 0
        for (x, n) in times:
          w[n] += x - x0
          x0 = x
      
        if 3 * w[15] == 2 * w[12]:
          (m, s) = divmod(t, 60)
          printf("t={t} (+{m}m{s}s) [{times}]")
      

      We are told that “the first #15 bus leaves soon after the first #12 bus”, so we can suppose we want the earliest possible value of 1m30s (although 4m30s would also seems to be “soon after” the first #12 bus).

      Solution: The first number 15 bus leaves 1m30s after the first number 12 bus.


      If the first #15 bus does not have to leave before the second #12 bus then we can get solutions where the #15 buses can run on a timetable of integer minutes, and still satisfy the probability constraint given in the hour from the first #12 bus.

      For instance if the first #15 bus leaves at 17m (so the timetable is: 17m, 32m, 47m, and then: 1h2m, 1h17m, 1h32m, 1h47m, …) then the probability of catching a #15 bus in the first hour is 0.4, similarly if the first #15 leaves at 29m.

      Here is a graph of “the probability of catching a #15 bus in the first hour” (y-axis) against “time of departure of the first #15 bus” (x-axis).

      We see that the probability is 0.4 for times of: 1m30s, 4m30s, 7m30s, 10m30s, 13m30s, 17m, 29m.

      Like

  • Unknown's avatar

    Jim Randell 11:47 am on 10 December 2019 Permalink | Reply
    Tags: by: G M L Tuchmann   

    Brain-Teaser 512: [Five nieces] 

    From The Sunday Times, 4th April 1971 [link]

    When I first met the Problem Setter, and let on that I was interested in his line of entertainment, he immediately told me that he had five nieces all going to the same primary school where each girl was entered on her fourth birthday and on each subsequent birthday morning was moved up into the next form.

    Forms I-III were the Infants section to which they all still belonged. Tomorrow (Tuesday) one of the five would have a birthday, on Wednesday another. Which?

    To get me going, he gave me their names in order of seniority and told me which niece would be in which form on Wednesday.

    I said all I could usefully deduce from this was that Alice wasn’t one of the celebrants; I couldn’t be at all sure of any of the other four; I was aware, needless to say, that Alice, though younger than Emily, was older than Isabel, and that Olive was older than Ursula, but would I be right in guessing that Wednesday’s celebrant was older than Tuesday’s? (This necessitating that Ursula and Olive were currently in the same form).

    When he said yes, I knew the answer, so …

    Whose birthday [was on] on Tuesday, and whose [was] on Wednesday?

    This puzzle was originally published with no title.

    [teaser512]

     
    • Jim Randell's avatar

      Jim Randell 11:47 am on 10 December 2019 Permalink | Reply

      I did this one manually before I wrote a program.

      This Python program looks at the girls in ascending age order, and the possible assignment of forms, such that the setter would be unable to deduce any celebrants, and only deduce one non-celebrant. From the information given we can then assign to the girls and verify the remaining conditions. It runs in 80ms.

      Run: [ @repl.it ]

      from collections import defaultdict
      from itertools import product
      from enigma import subsets, irange, tuples, intersect, diff, join, printf
      
      # update a sequence with (<index>, <delta>) pairs
      def update(s, *ps):
        s = list(s)
        for (i, v) in ps:
          s[i] += v
        return tuple(s)
      
      # is a sequence ordered?
      def is_ordered(s):
        return not any(x > y for (x, y) in tuples(s, 2))
      
      # indices for the girls
      girls = list(irange(0, 4))
      
      # record the celebrants by their forms (on Wednesday)
      r = defaultdict(list)
      
      # choose the forms that the girls are in on Wednesday
      for fs in subsets([1, 2, 3, 4], size=5, select="R"):
        # at most 2 girls can be promoted to form 4
        if fs.count(4) > 2: continue
      
        # choose the girls with birthdays on Tuesday and Wednesday
        for (Tu, We) in subsets(girls, size=2, select="P"):
          # the situation on Tuesday
          fsT = update(fs, (We, -1))
          if 0 in fsT or not is_ordered(fsT): continue
          # the situation on Monday
          fsM = update(fsT, (Tu, -1))
          if 0 in fsM or 4 in fsM or not is_ordered(fsM): continue
          r[fs].append((Tu, We))
      
      # for each key determine girls that definately are or aren't celebrants
      for (fs, vs) in r.items():
        # we can't positively identify any celebrant
        pos = intersect(vs)
        if pos: continue
        # we can only negatively identify one non-celebrant
        neg = set(girls).difference(*vs)
        if len(neg) != 1: continue
        # that non-celebrant is A
        A = neg.pop()
        # I and E are either side of A
        for (I, E) in product(girls[:A], girls[A + 1:]):
          # and U and O are the other two (in that order)
          (U, O) = diff(girls, (A, E, I))
      
          # we are then told Wednesday's celebrant is older than Tuesday's
          for (Tu, We) in vs:
            if not(We > Tu): continue
            # and U and O are in the same form on Monday
            fsM = update(fs, (We, -1), (Tu, -1))
            if not(fsM[U] == fsM[O]): continue
            # output solution
            d = dict(zip((A, E, I, O, U), "AEIOU"))
            s = join((join((d[i], '=', x)) for (i, x) in enumerate(fsM)), sep=", ")
            printf("Tu={Tu} We={We}; Mon=[{s}]", Tu=d[Tu], We=d[We])
      

      Solution: Isabel’s birthday is on Tuesday. Olive’s birthday is on Wednesday.

      The order of the girls (youngest to oldest) is: I, U, A, O, E.

      Mon: I=1, U=2, A=2, O=2, E=3
      Tue: I=2, U=2, A=2, O=2, E=3 [I moves up to Form 2]
      Wed: I=2, U=2, A=2, O=3, E=3 [O moves up to Form 3]

      Like

  • Unknown's avatar

    Jim Randell 10:27 am on 8 December 2019 Permalink | Reply
    Tags:   

    Brainteaser 1770: Magic spell 

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

    Marvo uses a prearranged pack of cards to perform the following trick. Holding the pack face downwards, one by one he would take a card from the top and place it on the bottom, calling out a letter each time so as to spell:

    A, C, E, [the next card is an ace, which is placed on the table]
    T, W, O, [next card is a 2]
    T, H, R, E, E, [next card is a 3]

    J, A, C, K, [next card is a Jack]
    Q, U, E, E, N, [next card is a Queen]
    K, I, N, G, [next card is a King]
    A, C, E, [next card is an ace]
    T, W, O, [next card is a 2]

    Once he had spelt out the name of the card he would remove the next card from the pack, turn it over and place it face up on the table. Of course it was always the card which he had just spelt out.

    In this way he worked through the clubs, then the hearts, then the diamonds and finally the spades, finishing with just the King of spades in his hand.

    One day his disgruntled assistant sabotaged his act by secretly cutting the pack. However the first card which Marvo turned over was still an ace, and the the second card was still a two.

    What was the next card Marvo turned over?

    This puzzle is included in the book Brainteasers (2002). The puzzle text above is taken from the book.

    [teaser1770]

     
    • Jim Randell's avatar

      Jim Randell 10:28 am on 8 December 2019 Permalink | Reply

      We can construct the initial configuration of the pack by starting with a pack of blank cards numbered in order from 1 to 52, and then performing the trick, but when we turn over one of the blank cards we write the appropriate value and suit on the card and continue until the end of the trick. We can then use the numbers to put the pack back into the desired order.

      We can then look through the pack for an ace followed 4 cards later by a two, and then we are interested what card occurs 6 cards after that.

      This Python program runs in 70ms.

      Run: [ @repl.it ]

      from enigma import irange, printf
      
      # words for each value
      word = {
        'A': 'ACE', '2': 'TWO', '3': 'THREE', '4': 'FOUR', '5': 'FIVE',
        '6': 'SIX', '7': 'SEVEN', '8': 'EIGHT', '9': 'NINE', 'X': 'TEN',
        'J': 'JACK', 'Q': 'QUEEN', 'K': 'KING',
      }
      
      # the positions in the pack
      pack = list(irange(0, 51))
      
      # map position -> value + suit
      m = dict()
      
      # go through the suits
      for s in "CHDS":
        # and then the values in each suit
        for v in "A23456789XJQK":
          # apply the operation the appropriate number of times
          for x in word[v]:
            pack.append(pack.pop(0))
          # reveal and discard the top card
          n = pack.pop(0)
          assert n not in m
          # record that card at this position
          m[n] = v + s
      
      # advance by counting value v
      advance = lambda k, v: (k + len(word[v]) + 1) % 52
      
      # look for an ace...
      for (k1, v1) in m.items():
        if v1[0] != 'A': continue
        # but not not the ace we are expecting
        if v1 == 'AC': continue
        # ... followed by a 2 ...
        k2 = advance(k1, '2')
        v2 = m[k2]
        if v2[0] != '2': continue
        # ... and what is the next card?
        k3 = advance(k2, '3')
        v3 = m[k3]
        printf("@{k1}: {v1} -> @{k2}: {v2} -> @{k3}: {v3}")
      

      Solution: The third card turned over is the three of diamonds.

      After that the trick would go awry. The next card turned over is not a 4, it is 8♦.

      The original layout of the pack is:

      After the pack is cut 4♣ is at the top (as highlighted in the diagram), after counting out A, C, E we get A♠, and then T, W, O gets 2♥, and then T, H, R, E, E gets 3♦.

      Like

  • Unknown's avatar

    Jim Randell 9:04 pm on 6 December 2019 Permalink | Reply
    Tags:   

    Teaser 2985: What’s my (land) line? 

    From The Sunday Times, 8th December 2019 [link] [link]

    My telephone has the usual keypad:

    My [11-digit] telephone number starts with 01 and ends in 0. All digits from 2 to 9 are used exactly once in between, and each pair of adjacent digits in the phone number appear in a different row and column of the keypad array.

    The 4th and 5th digits are consecutive as are the 9th and 10th and the 8th digit is higher than the 9th.

    What is my number?

    [teaser2985]

     
    • Jim Randell's avatar

      Jim Randell 9:25 pm on 6 December 2019 Permalink | Reply

      Suppose the phone number is: 01-ABCDEFGH-0.

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

      The following run file executes in 146ms.

      Run: [ @repl.it ]

      #! python -m enigma -rr
      
      SubstitutedExpression
      
      --digits="2-9"
      
      # 4th and 5th digits are consecutive numbers
      "abs(B - C) = 1"
      
      # as are 9th and 10th digits
      "abs(G - H) = 1"
      
      # 8th digit is greater than the 9th
      "F > G"
      
      # assign row/col values to the individual digits
      --code="row = [ 4, 1, 1, 1, 2, 2, 2, 3, 3, 3 ]"
      --code="col = [ 2, 1, 2, 3, 1, 2, 3, 1, 2, 3 ]"
      --code="check = lambda s: all(row[x] != row[y] and col[x] != col[y] for (x, y) in tuples(s, 2))"
      # adjacent digits appear in different rows/columns
      "check([1, A, B, C, D, E, F, G, H, 0])"
      
      # solution
      --code="number = lambda x: sprintf('01{x:08d}0')"
      --answer="number(ABCDEFGH)"
      

      Solution: The phone number is 01867295340.

      Like

    • Frits's avatar

      Frits 12:46 pm on 24 September 2020 Permalink | Reply

       
      # make sure loop variable value is not equal to previous ones
      def domain(v):
        # find already used loop values  ...
        vals = set()
        # ... by accessing previously set loop variable names
        for s in lvd[v]:
          vals.add(globals()[s])
        
        return [x for x in range(2,10) if x not in vals]
        
      def check(s):
        # row coord: (1 + (i - 1) // 3)
        # col coord: (1 + (i - 1) % 3)
        
        # Check adjacent fields
        for (x, y) in list(zip(s, s[1:])):
          # check if on same row 
          if (x - 1) // 3 == (y - 1) // 3:
            return False
          # check if on same col 
          if (x - y) % 3 == 0:
            return False  
        return True      
      
      # set up dictionary of for-loop variables
      lv = ['A', 'B', 'C', 'G', 'H', 'F', 'D', 'E']
      lvd = {v: lv[:i] for i, v in enumerate(lv)}
      
      sol = set()
      
      # Solve puzzle by testing all posssible values
      for A in {5, 6, 8, 9}:
        for B in domain('B'):
          if not check([A, B]): continue
          for C in domain('C'):
            if abs(B - C) != 1: continue
            if not check([B, C]): continue
            for G in domain('G'):
              for H in domain('H'):
                if abs(G - H) != 1: continue
                if not check([G, H]): continue
                for F in domain('F'):
                  if F < G: continue
                  if not check([F, G]): continue
                  for D in domain('D'):
                    for E in domain('E'):
                      if not check([C, D, E, F]): continue
                      sol.add((A, B, C, D, E, F, G, H))
      
      print("  ABCDEFGH ")             
      for s in sol:
        print(f"01{''.join(str(x) for x in s)}0")  
      
      # Output:
      #
      #   ABCDEFGH
      # 01867295340
      

      Like

  • Unknown's avatar

    Jim Randell 4:48 pm on 29 November 2019 Permalink | Reply
    Tags:   

    Teaser 2984: Shuffle the cards 

    From The Sunday Times, 1st December 2019 [link] [link]

    In the classroom I have a box containing ten cards each with a different digit on it. I asked a child to choose three cards and to pin them up to make a multiplication sum of a one-figure number times a two-figure number. Then I asked the class to do the calculation.

    During the exercise the cards fell on the floor and a child pinned them up again, but in a different order. Luckily the new multiplication sum gave the same answer as the first and I was able to display the answer using three of the remaining cards from my box.

    What was the displayed answer?

    [teaser2984]

     
    • Jim Randell's avatar

      Jim Randell 5:05 pm on 29 November 2019 Permalink | Reply

      If the original sum is A × BC, then none of the digits in the second sum can be in their original positions, so the second sum is one of: B × CA or C × AB.

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

      Run: [ @repl.it ]

      #! python -m enigma -rr
      
      SubstitutedExpression
      
      # initial sum
      "A * BC = DEF"
      
      # but it also works in a different order
      "DEF in (B * CA, C * AB)"
      
      # required answer
      --answer="DEF"
      

      Solution: The result of the two multiplications is 130.

      The two sums are: 2×65 and 5×26, but we don’t know which was the original one.

      Like

      • Jim Randell's avatar

        Jim Randell 9:42 pm on 2 December 2019 Permalink | Reply

        If we consider the two possible pairs of sums:

        A × BC = DEF ∧ B × CA = DEF
        A × BC = DEF ∧ C × AB = DEF

        Rewriting the first with A = X, B = Y, C = Z and the second with A = Y, B = Z, C = X, we get:

        X × YZ = DEF ∧ Y × ZX = DEF
        Y × ZX = DEF ∧ X × YZ = DEF

        Which are the same, so we can solve the puzzle with an even simpler one liner:

        % python -m enigma SubstitutedExpression "X * YZ = DEF" "Y * ZX = DEF" --answer="DEF"
        (X * YZ = DEF) (Y * ZX = DEF) (DEF)
        (5 * 26 = 130) (2 * 65 = 130) (130) / D=1 E=3 F=0 X=5 Y=2 Z=6
        DEF = 130 [1 solution]
        

        Like

    • GeoffR's avatar

      GeoffR 7:41 pm on 4 December 2019 Permalink | Reply

      
      from time import perf_counter_ns
      start = perf_counter_ns()
      
      from itertools import permutations
      
      for p in permutations((1,2,3,4,5,6,7,8,9),3):
          a, b, c = p    # choose 3 positive digits
      
          # Original displayed answer
          s = a * (10 * b + c)
          
          # 1st alternative position for digits to give same product
          if s == b * (10 * c + a):
              if len (set((a, b, c, s//100, s//10%10, s%10))) == 6:
                print(f"1.Original displayed answer = {s} ({a}*{10*b+c})")
                print(f"2nd displayed answer = {s} ({b}*{10*c+a})")
                print(f"1st digit={a}, 2nd digit={b}, 3rd digit={c}")
                print(f"{(perf_counter_ns() - start) / 1e6:.3f} milliseconds")
      
          # 2nd alternative positions for digits to give same product
          if s == c * (10 * a + b):
              if len (set((a, b, c, s//100, s//10%10, s%10))) == 6:
                print(f"2.Original displayed answer = {s} ({a}*{10*b+c})")
                print(f"2nd displayed answer = {s} ({c}*{10*a+b})")
                print(f"1st digit={a}, 2nd digit={b}, 3rd digit={c}")
                print(f"{(perf_counter_ns() - start) / 1e6:.3f} milliseconds")
      
      # 2.Original displayed answer = 130 (2*65)
      # 2nd displayed answer = 130 (5*26)
      # 1st digit=2, 2nd digit=6, 3rd digit=5
      # 49.703 milliseconds
      #
      # 1.Original displayed answer = 130 (5*26)
      # 2nd displayed answer = 130 (2*65)
      # 1st digit=5, 2nd digit=2, 3rd digit=6
      # 88.180 milliseconds
      
      
      

      Like

    • GeoffR's avatar

      GeoffR 4:54 pm on 5 December 2019 Permalink | Reply

      % A Solution in MiniZinc
      include "globals.mzn";
      
      var 1..9: A; var 1..9: B; var 1..9: C; var 1..9: D;
      var 0..9: E; var 0..9: F;
      
      constraint all_different([A, B, C, D, E, F]);
      
      var 10..99: BC = 10*B + C;
      var 10..99: CA = 10*C + A;
      var 10..99: AB = 10*A + B;
      var 100..999: DEF = 100*D + 10*E + F;
      
      % Original sum
      constraint A * BC == DEF;
      
      % Sums with digits in a different order
      constraint B * CA == DEF \/ C * AB == DEF;
      
      solve satisfy;
      
      output ["Displayed Sum is " ++ show(A) ++ " X " ++ show(BC)
      ++ " = " ++ show(DEF) ];
      
      % Displayed Sum is 2 X 65 = 130
      % Displayed Sum is 5 X 26 = 130
      % ==========
      
      
      
      

      Like

  • Unknown's avatar

    Jim Randell 2:50 pm on 28 November 2019 Permalink | Reply
    Tags:   

    Teaser 2890: Squares on cubes 

    From The Sunday Times, 11th February 2018 [link] [link]

    Liam has a set of ten wooden cubes; each has a different number (from 1 to 10) painted on one face (the other five faces are blank). He has arranged them in a rectangular block with all numbers upright and facing outwards. Each vertical side of the block shows some numbers which can be read as a number that is a perfect square. No two square numbers have the same number of digits.

    Which square number must be present?

    [teaser2890]

     
    • Jim Randell's avatar

      Jim Randell 2:51 pm on 28 November 2019 Permalink | Reply

      The cubes are placed on the table, so that the numbers are showing on vertical faces. They are then slid around on the table to arrange them into a contiguous rectangular block with all the numbers showing on the outside vertical edges of the block.

      The cubes must be arranged into a 2×5 block (a 1×10 block is not possible), and each of the 4 vertical sides of the block reads as a square number. And each of the 4 square numbers has a different number of digits.

      The sides composed of 2 blocks cannot involve 10 (as none of 10, 10_, _10 are square numbers), so they must display square numbers made of 1 number (1 digit) and 2
      numbers (2 digits) and the 5 block sides must show squares made of 3 numbers (3 digits) and 4 numbers (5 digits, including 10).

      This Python program runs in 103ms.

      Run: [ @repl.it ]

      from enigma import (irange, subsets, concat, is_square, Accumulator, diff, join, printf)
      
      # single digits (10 must appear in the 4-number square)
      digits = irange(1, 9)
      
      # make squares from k numbers
      def squares(numbers, k):
        for ns in subsets(numbers, size=k, select="P"):
          s = int(concat(ns))
          if is_square(s):
            yield ns
      
      # find values common to all solutions
      r = Accumulator(fn=set.intersection)
      
      # choose a 1 number square [1, 4, 9]
      for s1 in squares(digits, 1):
      
        # choose a 2 number square [not 10]
        for s2 in squares(diff(digits, s1), 2):
      
          # choose a 3 number square [not 10]
          for s3 in squares(diff(digits, s1 + s2), 3):
      
            # choose a 4 number square [must have 10]
            for s4 in squares(diff(digits, s1 + s2 + s3) + (10,), 4):
      
              # turn the squares into strings
              ss = tuple(map(concat, (s1, s2, s3, s4)))
      
              printf("{s1} {s2} {s3} {s4}")
              r.accumulate(set(ss))
      
      printf("common squares = {r}", r=join(sorted(r.value), sep=", "))
      

      Solution: The square number 9 must be present.

      The three possible arrangements for the square numbers are:

      (9, 36, 784, 11025)
      (9, 81, 324, 51076)
      (9, 81, 576, 23104)

      Here is a diagram of the first arrangement.

      Imagine the cubes are laid out like a 2×5 block of chocolate viewed from above. The numbers are etched on the the sides of the cubes. But the block has started to melt and so the bottom of it has splayed out, allowing us to see all four of the square numbers when viewed from directly above:

      Like

    • GeoffR's avatar

      GeoffR 8:23 am on 30 November 2019 Permalink | Reply

      
      % A Solution in MiniZinc
      include "globals.mzn";
      
      % Looking for 1-digit, 2-digit, 3-digit and 5-digit squares
      % on cubes to use up all 10 numbers (1-10) in a 5 by 2 block
      % of cubes in same arrangement as Jim
      
      var 0..9: A; var 0..9: B; var 0..9: C; var 0..9: D;
      var 0..9: E; var 0..9: F; var 0..9: G; var 0..9: H; 
      var 0..9: I; var 0..9: J; var 0..9: K;
      
      % 2,3 and 5 digit squares
      var 10..99: BC = 10*B + C;
      var 100..999: DEF = 100*D + 10*E + F;
      var 10000..99999: GHIJK; 
      
      set of int: sq2 = {n*n | n in 4..9 };
      set of int: sq3 = {n*n | n in 10..31};  
      set of int: sq5 = {n*n | n in 100..316};
      
      % Four squares
      constraint A == 4 \/ A == 9;
      constraint BC in sq2;
      constraint DEF in sq3;
      constraint GHIJK in sq5;
      
      constraint G == GHIJK div 10000 
      /\ H == GHIJK div 1000 mod 10
      /\ I = GHIJK div 100 mod 10 
      /\ J == GHIJK div 10 mod 10
      /\ K = GHIJK mod 10;
      
      % Number 10 must be in the five digit square GHIJK
      constraint (G == 1 /\ H = 0) \/  (H == 1 /\ I = 0)
      \/ (I == 1 /\ J = 0) \/ (J == 1 /\ K = 0);
      
      % check digit '1' occurs twice only i.e as 1 and 10
      constraint count_eq([A, BC div 10, BC mod 10,
      DEF div 100, DEF div 10 mod 10, DEF mod 10,
      G, H, I, J, K ], 1, 2);
      
      % the set of digits used
      var set of int: my_set  = {A, BC div 10, BC mod 10,
      DEF div 100, DEF div 10 mod 10, DEF mod 10,
      G, H, I, J, K };
      
      % maximum set of digits used
      set of int: all_dig == {1,2,3,4,5,6,7,8,9,0};
      
      constraint my_set == all_dig;
      
      solve satisfy;
      
      % Four squares
      output [ "Squares: 1-digit = " ++ show(A)
      ++ ", 2-digit = " ++ show(BC)
      ++ ", 3-digit = " ++ show(DEF)
      ++ ", 5-digit = " ++ show(GHIJK)];
      
      % Squares: 1-digit = 9, 2-digit = 36, 3-digit = 784, 5-digit = 11025
      % ----------
      % Squares: 1-digit = 9, 2-digit = 81, 3-digit = 576, 5-digit = 23104
      % ----------
      % Squares: 1-digit = 9, 2-digit = 81, 3-digit = 324, 5-digit = 51076
      % ----------
      % ==========
      % Finished in 684msec
      
      

      Without the constraint that the digit one is the duplicated digit, I found three more possible sets of squares:

      (4,36,289, 51076)
      (9,36,784,21025)
      (9,25,784, 36100)

      @Jim: Please confirm your run-time for this code.Thanks,

      Like

      • Jim Randell's avatar

        Jim Randell 8:43 am on 1 December 2019 Permalink | Reply

        @Geoff: On my machine I get a comparative runtime of 377ms for the code you posted (using the gecode solver – the chuffed solver fails on this model).

        Like

  • Unknown's avatar

    Jim Randell 2:31 pm on 26 November 2019 Permalink | Reply
    Tags:   

    Brain-Teaser 511: What’s my age? 

    From The Sunday Times, 28th March 1971 [link]

    I recently had an odd letter from a puzzle addict, who wrote:

    “I know that you are between 25 and 80, and I’ve made a bet (at fair odds) that I can deduce your age from your Yes/No answers to the following questions:

    1. Are you under 55?
    2. Is your age a prime number?
    3. If the digits of your age are reversed, is the result prime?
    4. Is the digital root of your age even?

    Please reply on enclosed stamped postcard.”

    I did so, and had a reply a few days later:

    “Many thanks. As soon as I read your first three answers I knew that the fourth answer must lead me to your age. You are …” (and he gave a figure wrong by well over 20 years).

    Puzzled, I rechecked my four answers and found to my horror that I had carelessly transposed two of them and so had misled him.

    How old am I?

    This puzzle is included in the book Sunday Times Brain Teasers (1974).

    [teaser511]

     
    • Jim Randell's avatar

      Jim Randell 2:32 pm on 26 November 2019 Permalink | Reply

      This Python program runs in 73ms.

      from enigma import (defaultdict, irange, is_prime, nreverse, digrt, subsets, update, printf)
      
      # collect <answers> -> <ages>
      d = defaultdict(list)
      
      # consider possible ages
      for n in irange(25, 80):
        # the statements
        ss = (
          # 1. "Age is under 55?"
          (n < 55),
          # 2. "Age is prime?"
          is_prime(n),
          # 3. "Reverse of age is prime?"
          is_prime(nreverse(n)),
          # 4. "Digital root of age is even?"
          (digrt(n) % 2 == 0),
        )
        d[ss].append(n)
      
      # generate sequences with two (different) values swapped
      def swap(s):
        s = list(s)
        # swap two of the values
        for ((i, x), (j, y)) in subsets(enumerate(s), size=2):
          if x != y: yield tuple(update(s, [(i, y), (j, x)]))
      
      # find values for the first three questions where the final question gives a definite answer
      Bool = (True, False)
      for k in subsets(Bool, size=3, select="M"):
        # possible mistaken keys
        ks = list(k + (x,) for x in Bool)
        # each must lead to a single answer
        if not all(len(d[k]) == 1 for k in ks): continue
        # consider possible mistaken keys
        for k in ks:
          m = d[k][0] # mistaken age
          # look for possible real keys
          for r in swap(k):
            # possible real age
            for n in d[r]:
              # must be more than 20 years difference
              if abs(n - m) > 20:
                printf("age = {n}, real = {r}; swap = {k}, age = {m}")
      

      Solution: The setter’s age is 71.


      There is only one set of values for the answers to the first three questions that lead to two ages that can be differentiated by the answer to the fourth question.

      If all the first three questions are answered “Yes”, then:

      If the answer to the fourth question is “Yes”, the age is 31.
      If the answer to the fourth question is “No”, the age is 37.

      The setter then discovers that he has exchanged the places of two of the answers.

      So the answer sent cannot be: (“Yes”, “Yes”, “Yes”, “Yes”), as swapping any two of them would make no difference.

      So the sent answers must have been: (“Yes”, “Yes”, “Yes”, “No”). Leading the puzzler to believe that the setters age was 37.

      But this is incorrect “by well over 20 years”, so the setter must be much less than 17 (not possible) or much more than 57.

      If we move the “No” into different positions we get:

      (“No”, “Yes”, “Yes”, “Yes”) → 71
      (“Yes”, “No”, “Yes”, “Yes”) → 35, 38
      (“Yes”, “Yes”, “No”, “Yes”) → 29, 47, 53

      Only the first of these gives an age much more than 57, so the answers for the first and fourth question were accidentally swapped.

      Like

  • Unknown's avatar

    Jim Randell 1:15 pm on 25 November 2019 Permalink | Reply
    Tags:   

    Teaser 2886: Metal arithmetic 

    From The Sunday Times, 14th January 2018 [link] [link]

    The area of one face of a hot, steel cuboid block was a single-figure whole number of square feet; and it was within one per cent of this after cooling and contraction. When cool, it was cut, parallel to this face, into blocks of the same width and height, but unequal length. For the first cut block, its width, height and length, in inches, were different two-figure whole numbers with only four factors (including 1 and the number), and they had only the factor 1 in common. The same applied to the other cut blocks. Curiously, the six digits of the width, height and length of the first cut block were also all different.

    In ascending order, what were the dimensions, in inches, of the shortest block?

    [teaser2886]

     
    • Jim Randell's avatar

      Jim Randell 1:16 pm on 25 November 2019 Permalink | Reply

      This Python program runs in 81ms.

      Run: [ @replit ]

      from enigma import (irange, divisors, subsets, divc, is_duplicate, printf)
      
      # find 2-digit numbers with exactly 4 divisors
      ns = dict()
      for n in irange(10, 99):
        fs = divisors(n)
        if len(fs) == 4:
          ns[n] = set(fs)
      
      # check x and y share exactly k divisors
      def check(x, y, k=1):
        return len(ns[x].intersection(ns[y])) == k
      
      # find x, y dimensions
      for (x, y) in subsets(ns.keys(), size=2):
      
        # cross section is within 1% of a single digit number of square feet
        A = x * y
        k = divc(A, 144)
        if k > 9: continue
        if not (100 * A > 99 * 144 * k): continue
      
        # x and y share only one divisor
        if not check(x, y): continue
      
        # find possible values for z dimension
        zs = list(z for z in ns.keys() if z != x and z != y and check(x, z) and check(y, z))
        # it is implied there are at least 3 blocks
        if not (len(zs) > 2): continue
      
        # and there must be a z such that x, y, z consist of 6 different digits
        if all(is_duplicate(x, y, z) for z in zs): continue
      
        # output dimensions of the smallest block
        printf("x={x} y={y} z={z} [A={A} k={k} zs={zs}]", z=min(zs))
      

      Solution: The shortest block measured 21 × 34 × 55 inches.

      The 21 in. × 34 in. face has an area of 714 sq. in., when heated up the face expands to exactly 5 square feet = 720 sq. in.

      The area of the face when cold is 99.17% of this area.

      The 4 divisors of 21 are: 1, 3, 7, 21.

      The 4 divisors of 34 are: 1, 2, 17, 34.

      The cold block was cut into lengths of 55 in., 65 in., 95 in. (it is implied the block was cut into at least 3 pieces).

      The 4 divisors of 55 are: 1, 5, 11, 55.

      The 4 divisors of 65 are: 1, 5, 13, 65.

      The 4 divisors of 95 are: 1, 5, 19, 95.

      So the first block cut could be: 21 × 34 × 65, using the digits: 1, 2, 3, 4, 5, 6, or: 21 × 34 × 95, using the digits: 1, 2, 3, 4, 5, 9.

      And the shortest block is 21 × 34 × 55, which repeats the digit 5.

      Like

  • Unknown's avatar

    Jim Randell 8:11 am on 24 November 2019 Permalink | Reply
    Tags:   

    Brainteaser 1766: House squares 

    From The Sunday Times, 21st July 1996 [link]

    There is an even number of houses in my road, numbered consecutively from 1 upwards, with the odd numbers on one side and the even numbers on the other.

    My neighbour’s son was practising with his new calculator. He found the sum of the squares of all the house numbers on one side of the road and subtracted it from the sum of the squares of all the house numbers on the other side of the road. The digits in his answer were all the same.

    Noticing that two of the houses displayed “For Sale” signs he decided to carry out a second calculation omitting those two houses. This gave an answer 50% higher than the first.

    Which two houses are for sale?

    This puzzle is included in the book Brainteasers (2002). The puzzle text above is taken from the book.

    [teaser1766]

     
    • Jim Randell's avatar

      Jim Randell 8:12 am on 24 November 2019 Permalink | Reply

      This Python program runs in 70ms.

      Run: [ @repl.it ]

      from enigma import seq_all_same, nsplit, irange, div, subsets, printf
      
      # generate the difference between the sum of the even and odd squares up to n
      def generate():
        # sums of squares
        n = d = 0
        while True:
          n += 1
          d -= n * n
          n += 1
          d += n * n
          yield (n, d)
      
      # find solutions to the puzzle
      def solve():
        # look at differences for increasing even n
        for (n, d) in generate():
          # the difference should be a repdigit
          if not seq_all_same(nsplit(d)): continue
          # the second answer is 50% higher
          diff = div(d, 2)
          if diff is None: continue
      
          # look for the house numbers for sale p, q
          for (p, q) in subsets(irange(1, n), size=2):
            delta = sum([-1, 1][x % 2] * x * x for x in (p, q))
            if abs(delta) == diff:
              yield (p, q, n, d, d + diff)
      
      # we only need the first solution
      for (p, q, n, d, d2) in solve():
        printf("for sale = {s} [{n} houses; difference = {d} -> {d2}]", s=(p, q))
        break
      

      Solution: The two houses for sale are 14 and 23.

      There are 36 houses in the street.

      The result of the first calculation is 666.

      The result of the second calculation is 999.

      The difference between the sums of the squares of the first n even numbers and the first n odd numbers can be expressed:

      D(n) = n (2n + 1)

      Which allows a slightly shorter program than generating the differences constructively.

      Like

  • Unknown's avatar

    Jim Randell 5:08 pm on 22 November 2019 Permalink | Reply
    Tags:   

    Teaser 2983: Maths for dessert 

    From The Sunday Times, 24th November 2019 [link] [link]

    George and Martha have their five daughters round the dinner table. After the meal, they had ten cards numbered 0 to 9 inclusive and randomly handed two to each daughter. Each was invited to form a two-digit number. The daughter drawing 0 obviously had no choice and had to announce a multiple of ten.

    However, the others each had the choice of two options. For example if 3 and 7 were present, either 37 or 73 would be permissible. George added up the five two-digit numbers (exactly one being divisible by 9) and Martha noticed that three of the individual numbers divided exactly into that total.

    What was the total of the remaining two numbers?

    [teaser2983]

     
    • Jim Randell's avatar

      Jim Randell 5:16 pm on 22 November 2019 Permalink | Reply

      This Python program runs in 76ms.

      Run: [ @repl.it ]

      from enigma import (partitions, irange, cproduct, filter2, ordered, printf)
      
      # form numbers from digits a and b
      def numbers(a, b):
        if a > 0: yield 10 * a + b
        if b > 0: yield 10 * b + a
      
      # deal out the 10 cards in pairs
      for ps in partitions(irange(0, 9), 2):
        # exactly one of the numbers is divisible by 9
        if sum((a + b) % 9 == 0 for (a, b) in ps) != 1: continue
        # form the numbers from the pairs
        for ns in cproduct(numbers(*p) for p in ps):
          # exactly three of the numbers divide into the total
          t = sum(ns)
          (ds, rs) = filter2((lambda n: t % n == 0), ns)
          if len(ds) != 3: continue
          # output solution
          printf("sum{rs} = {s} [numbers = {ns}, total = {t}]", rs=ordered(*rs), s=sum(rs), ns=ordered(*ns))
      

      Solution: The sum of the numbers that do not divide into the total is 147.

      The numbers are: 14, 28, 50, 63, 97.

      Of these only 63 is divisible by 9.

      The sum of the numbers is 252, which is divisible by 14, 28, and 63.

      And the remaining numbers (50 and 97) sum to 147.

      Like

    • GeoffR's avatar

      GeoffR 9:47 am on 25 November 2019 Permalink | Reply

      
      % A Solution in MiniZinc
      include "globals.mzn";
      
      var 1..9:A; var 1..9:B; var 1..9:C;
      var 1..9:D; var 1..9:E; var 1..9:F;
      var 1..9:G; var 1..9:H; var 1..9:I;
      
      % Make J the zero digit
      int: J == 0;
      
      constraint all_different ([A,B,C,D,E,F,G,H,I,J]);
        
      % Five 2-digit numbers 
      var 10..99: AB = 10*A + B;
      var 10..99: CD = 10*C + D;
      var 10..99: EF = 10*E + F;
      var 10..99: GH = 10*G + H;
      var 10..99: IJ = 10*I + J;
      
      var 10..400: all_dig; 
      var 10..200: dig2;   % sum of the remaining two numbers
      
      constraint all_dig = AB + CD + EF + GH + IJ;
      
      % One of the five 2-digit numbers is divisible by 9
      constraint sum ( [ AB mod 9 == 0, CD mod 9 == 0, 
      EF mod 9 == 0, GH mod 9 == 0, IJ mod 9 == 0 ] ) = 1;
      
      % Three of the 2-digit numbers divide the five digit total
      constraint all_dig mod AB == 0 /\ all_dig mod CD == 0 
      /\ all_dig mod EF == 0 /\ all_dig mod GH != 0 /\ all_dig mod IJ != 0;
      
      % Sum of two digits which do not divide the five digit total
      constraint  dig2 == GH + IJ ;
      
      solve satisfy;
      
      output [ "Total of the remaining two numbers = " ++ show(dig2)
      ++ "\nTotal of five 2-digit numbers = " ++ show(all_dig)++ "\n"
      ++"The five numbers are " ++ show(AB) ++ ", " ++ show(CD) ++ ", " 
      ++ show(EF) ++ ", " ++ show(GH) ++ " and " ++ show(IJ) ];
      
      % Total of the remaining two numbers = 147
      % Total of five 2-digit numbers = 252
      % The five numbers are 28, 14, 63, 97 and 50
      
      
      
      

      Like

    • GeoffR's avatar

      GeoffR 7:56 am on 28 November 2019 Permalink | Reply

      
      from itertools import permutations
      
      for p in permutations('1234567890'):
        a, b, c, d, e, f, g, h, i, j = p
        
        ab, cd, ef = int(a + b), int(c + d), int(e + f)
        gh, ij = int(g + h), int(i + j)
      
        # check all five numbers are 2-digit numbers
        n5 = (ab, cd, ef, gh, ij)
        if all( x < 100 and x >= 10 for x in n5):
          tot = ab + cd + ef + gh + ij
      
          # two conditions to check
          if (sum(1 for y in n5 if y % 9 == 0) == 1 
            and sum(1 for z in n5 if tot % z == 0) == 3) :
               
            if (tot % ab == 0 and tot % cd == 0 and tot % ef == 0
              and tot % gh != 0 and tot % ij != 0) :
              print(f"Three factors are {ab}, {cd} and {ef}" )
              print(f"Two remaining numbers are {gh} and {ij} (total {gh+ij})")
              break    # to stop repeated answers
      
      # Three factors are 14, 28 and 63
      # Two remaining numbers are 50 and 97 (total 147)
      
      

      Like

  • Unknown's avatar

    Jim Randell 9:48 pm on 18 November 2019 Permalink | Reply
    Tags:   

    Brain-Teaser 510: [Angling competition] 

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

    Announcing that the Baron’s team had won the angling competition, the Mayor told those assembled that the winning catch weighed 19st 1lb 7oz and consisted of plaice, halibut and turbot. He also disclosed the remarkable fact that each fish of the same kind had been precisely the same weight — each plaice 2lb 8oz, each halibut 4lb 1oz and each turbot 6lb 6oz.

    Although His Worship mentioned that half the total number of fish in the winning catch were of one and the same kind and that there were three times as many of one kind as of one other kind, he lamentably failed to give the further details so many were waiting to hear.

    One enthusiast, for example, wished to know the total weight of all the plaice landed by the Baron’s team.

    Can you say what it was? (Answers in lbs).

    This puzzle was originally published with no title.

    [teaser510]

     
    • Jim Randell's avatar

      Jim Randell 9:40 am on 21 November 2019 Permalink | Reply

      Using oz for for measuring weight, we have:

      1 lb = 16 oz
      1 st = 14 lb = 224 oz

      So the total weight of fish is:

      total = 19 st, 1 lb, 7 oz = 4279 oz

      And the individual types of fish weigh:

      plaice = 2 lb, 8 oz = 40 oz
      halibut = 4 lb, 1 oz = 65 oz
      turbot = 6 lb, 6 oz = 102 oz

      This Python program uses the [[ express() ]] function from the enigma.py library. It runs in 110ms.

      from enigma import (express, div, printf)
      
      # find numbers of plaice, halibut, turbot
      for s in express(4279, (40, 65, 102), min_q=1):
        t = sum(s)
        # half the total was of one kind
        h = div(t, 2)
        if h is None or h not in s: continue
        # and there were 3 times as many of one kind than of an other
        if not any(3 * x in s for x in s): continue
        # output solution
        (p, h, t) = s
        printf("plaice = {p}, halibut = {h}, turbot = {t}")
      

      Solution: The total weight of plaice was 82 lb, 8 oz (= 82.5 lb).

      There were 33 plaice (= 1320 oz = 82 lb, 8 oz = 5 st, 12 lb, 8 oz).

      There were 11 halibut (= 715 oz = 44 lb, 11 oz = 3 st, 2 lb, 11 oz).

      There were 22 turbot (= 2244 oz = 140 lb, 4 oz = 10 st, 4 oz).

      Like

  • Unknown's avatar

    Jim Randell 9:57 am on 17 November 2019 Permalink | Reply
    Tags: by: Conor Henderson   

    Brainteaser 1757: Enigma variations 

    From The Sunday Times, 19th May 1996 [link]

    I recently joined Enigma, the international club for puzzle-solvers. When I received my membership card I noticed that my membership number was a six-figure number and that its digits could be rearranged to make three consecutive two-figure numbers.

    I also noticed that its six digits could be rearranged to form two consecutive three-figure numbers.

    Furthermore, no one with a lower six-figure membership number could make the same claims.

    What is my membership number?

    This puzzle is included in the book Brainteasers (2002). The puzzle text above is taken from the book.

    [teaser1757]

     
    • Jim Randell's avatar

      Jim Randell 8:51 am on 19 November 2019 Permalink | Reply

      We can examine sequences of 3 consecutive 2-digit numbers (there are only 88 of them), and look for ones whose digits can be rearranged to form 2 consecutive 3-digit numbers. Each of these produces a collection of 6-digit membership numbers, and we can choose the smallest of these.

      This Python program runs in 135ms.

      Run: [ @repl.it ]

      from enigma import irange, tuples, multiset, nsplit, subsets, nconcat, Accumulator, printf
      
      # collect the digits from a sequence of numbers
      digits = lambda ns: multiset.from_seq(*(nsplit(n) for n in ns))
      
      # turn digits ds into n consecutive k-digit numbers
      def consecutive(ds, n, k):
        # extract the first k-digit number
        for s in subsets(ds, size=k, select="mP"):
          if s[0] == 0: continue
          # make the sequence of consecutive numbers
          s = nconcat(s)
          ss = tuple(irange(s, s + n - 1))
          # does it use the same digits?
          if digits(ss) == ds:
            yield ss
      
      # find the smallest number
      r = Accumulator(fn=min)
      
      # consider 3 consecutive 2-digit numbers
      for n2s in tuples(irange(10, 99), 3):
        ds = digits(n2s)
      
        # can the digits be rearranged to form 2 consecutive 3-digit numbers?
        n3s = list(consecutive(ds, 2, 3))
        if not n3s: continue
      
        # construct the smallest possible 6 digit number from the digits
        n = sorted(ds)
        # but leading zeros aren't allowed
        if n[0] == 0:
          # bring the first non-zero digit forward
          n.insert(0, n.pop(next(i for (i, x) in enumerate(n) if x > 0)))
        n = nconcat(n)
      
        printf("[{n:06d} -> {n2s} -> {n3s}]")
        r.accumulate(n)
      
      # output solution
      printf("membership number = {r.value:06d}")
      

      Solution: Your membership number is: 102222.

      The six digits of 102222 can be rearranged as (20, 21, 22) and also (220, 221).

      The largest such number is 999987:

      999987 → (97, 98, 99), (997, 998)

      There are 19 viable sequences of 3 consecutive 2-digit numbers, which give a total of 1195 candidate membership numbers.

      If leading zeros were allowed (which would not be uncommon for membership numbers) the lowest viable membership number would be 012222 (and there would be 1350 candidate numbers).

      Like

  • Unknown's avatar

    Jim Randell 9:06 am on 17 November 2019 Permalink | Reply
    Tags:   

    Brainteaser 1747: Lottery charges 

    From The Sunday Times, 10th March 1996 [link]

    Chargealot are having a new set of lottery balls made. They are going to be painted with numbers from 1 (not 01) to 49. The painter decides that this is one chance to make a fortune from the lottery and so he charges accordingly. He divides the digits into two types and charges a certain whole number of pounds for painting each digit of one type (each time it occurs) and a different whole number of pounds for all the other digits (each time they occur). Both charges are more than £50 but less than £100.

    To make the cost sound reasonable, instead of quoting a price for the whole set he quoted the average price per ball. Of course some balls cost less than average, and some balls cost more, but just one ball’s price was equal to the average.

    What were his two charges per digit?

    This puzzle is included in the book Brainteasers (2002). The puzzle text above is taken from the book.

    [teaser1747]

     
    • Jim Randell's avatar

      Jim Randell 9:07 am on 17 November 2019 Permalink | Reply

      We can divide the digits from 0-9 into two sets, “type A” and “type B” with associated costs a and b.

      There are 9 single digit numbers and 40 2-digit numbers, so the 49 numbers use 89 digits in total.

      If, in total, there are nA type A digits and nB type B digits then we have:

      nA + nB = 89
      T = a × nA + b × nB = 49 × m

      where T is the total cost and m is the average cost per ball, and only one of the balls can cost the average amount.

      This Python program runs in 158ms.

      Run: [ @repl.it ]

      from collections import defaultdict
      from enigma import subsets, diff, irange, nsplit, div, printf
      
      # place 0 in set A and choose some other digits to go in set B
      for B in subsets(irange(1, 9), min_size=1):
        A = diff(irange(0, 9), B)
      
        # group the numbers by (A, B) usage
        d = defaultdict(list)
        nA = 0
        for n in irange(1, 49):
          # count the A and B digits
          k = [0, 0]
          for x in nsplit(n):
            k[x in B] += 1
          d[tuple(k)].append(n)
          nA += k[0]
        nB = 89 - nA
      
        # find a number in a class by itself
        for ((i, j), vs) in d.items():
          if len(vs) != 1: continue
      
          # find costs for the digits in A and B
          for a in irange(51, 99):
            b = div(a * (49 * i - nA), nB - 49 * j)
            if b is None or b < 51 or b > 99: continue
      
            # check none of the other groups cost the same as the mean
            m = a * i + b * j
            if any(a * x + b * y == m for (x, y) in d.keys() if not(x == i and y == j)): continue
      
            # output solution
            printf("cost = ({a}, {b}), digits = ({A}, {B}); mean = {m}, number = {vs[0]}")
      

      Solution: Each digit costs £ 74 or £ 83.

      The ball that costs the mean amount is one of the repeated digit balls, i.e. 11, 22, 33, 44. It costs £ 148 (i.e. 2× £ 74).

      The digit used twice on the mean ball is the only digit that costs £ 74, all the other digits cost £ 83.

      The total cost for all the balls is therefore £ 7252.

      Like

  • Unknown's avatar

    Jim Randell 5:15 pm on 15 November 2019 Permalink | Reply
    Tags:   

    Teaser 2982: Antique tea pot 

    From The Sunday Times, 17th November 2019 [link] [link]

    My local antiques dealer marks each item with a coded price tag in which different digits represent different letters. This enables him to tell the whole number of pounds he paid for the item. I bought a tea pot from him tagged MOE.

    Inside the tea pot was a scrap of paper which I used to work out his code. The letters AMOUNT I SPENT had been rearranged to make the multiplication sum above.

    How much did he pay for the tea pot?

    [teaser2982]

     
    • Jim Randell's avatar

      Jim Randell 5:18 pm on 15 November 2019 Permalink | Reply

      The multiplication is straightforward to solve manually.

      Programatically, we can solve this puzzle using the [[ SubstitutedExpression() ]] solver from the enigma.py library.

      The following run file executes in 145ms.

      Run: [ @repl.it ]

      #! python -m enigma -rr
      
      SubstitutedExpression
      
      "MAN * PIN = TOOTIN"
      
      "MAN * N = TUON"
      "MAN * I = AASA"
      "MAN * P = TMEP"
      
      --answer="MOE"
      

      Solution: MOE = 350, so the teapot cost £ 350.

      The corresponding digits for AMOUNT I SPENT are 235961 7 84061.

      Like

    • GeoffR's avatar

      GeoffR 3:03 pm on 16 November 2019 Permalink | Reply

      % A Solution in MiniZinc
      include "globals.mzn";    
      
      %       M A N
      %    X  P I N 
      %    ---------
      %     T U O N
      %   A A S A
      % T M E P
      %------------
      % T O O T I N
      %-------------
      
      var 0..9: A; var 0..9: M; var 0..9: O; var 0..9: U;
      var 0..9: N; var 0..9: T; var 0..9: I;
      var 0..9: S; var 0..9: P; var 0..9: E;
      
      constraint M > 0 /\ P > 0 /\ T > 0 /\ A > 0;
      
      var 100..999: MAN = 100*M + 10*A + N;
      var 100..999: PIN = 100*P + 10*I + N;
      var 100..999: MOE = 100*M + 10*O + E;
      
      var 1000..9999: TUON = 1000*T + 100*U + 10*O + N;
      
      var 10000..99999: AASA = 11010*A + 100*S;
      
      var 100000..999999: TMEP = 100000*T + 10000*M
      + 1000*E + 100*P;
      
      var 100000..999999: TOOTIN = 100100*T + 11000*O
      + 10*I + N;
      
      constraint MAN * PIN == TOOTIN;
      constraint N * MAN == TUON;
      constraint I * MAN * 10 == AASA;
      constraint P * MAN * 100 == TMEP;
      
      solve satisfy;
      
      output [ "MOE = £" ++ show(MOE) ++ "\n" ++
      "Main sum is " ++ show(MAN) ++ " X " ++
      show(PIN) ++ " = " ++ show(TOOTIN) ];
      
      
      

      Like

  • Unknown's avatar

    Jim Randell 8:50 am on 12 November 2019 Permalink | Reply
    Tags:   

    Brain-Teaser 509: [Truth and lies] 

    From The Sunday Times, 14th March 1971 [link]

    Alpha, Beta, and Gamma are brothers. One of them always tells the truth, one always lies, and the other sometimes tells the truth and sometimes lies.

    I asked Gamma who was the elder of Alpha and Beta. Gamma (who was a little shy) whispered the answer to Alpha who the told me that Gamma had said that Alpha was older than Beta. Beta agreed that he was younger than Alpha, but he warned me that Alpha did not always tell the truth.

    The eldest of the three said that Gamma was more honest than Beta, and the youngest agreed with him. Furthermore, the younger of Beta and Gamma said that Alpha always told the truth.

    Who is the eldest? And who is the most honest?

    This puzzle was originally published with no title.

    [teaser509]

     
    • Jim Randell's avatar

      Jim Randell 8:51 am on 12 November 2019 Permalink | Reply

      This Python program runs in 70ms.

      Run: [ @replit ]

      from enigma import (subsets, printf)
      
      # the possible behaviours:
      
      # T tells the truth
      def T(s):
        return bool(s)
      
      # F lies
      def F(s):
        return not s
      
      # U is unreliable
      def U(s):
        return True
      
      # honesty ratings
      honest = { F: 0, U: 1, T: 2 }
      
      # assign behaviours to A, B, G
      for (fA, fB, fG) in subsets((T, F, U), size=3, select="P"):
      
        # "B said A does not always tell the truth"
        if not fB(fA != T): continue
      
        # choose an age ordering for A, B, G
        for (aA, aB, aG) in subsets((0, 1, 2), size=3, select="P"):
      
          # "B said B was younger than A"
          if not fB(aB < aA): continue
      
          # "the younger of B and G said that A always told the truth"
          if not (fB if aB < aG else fG)(fA == T): continue
      
          # "A said that G said that A was older than B"
          if not fA(fG(aA > aB)): continue
      
          # map ages to behaviours
          m = dict(zip((aA, aB, aG), (fA, fB, fG)))
      
          # "the eldest said G was more honest than B"
          # "the youngest agreed G was more honest than B"
          s = (honest[fG] > honest[fB])
          if not (m[2](s) and m[0](s)): continue
      
          # output solution
          (A, B, G) = (x.__name__ for x in (fA, fB, fG))
          (a, b, g) = (["youngest", "middle", "eldest"][x] for x in (aA, aB, aG))
          printf("A={A}, {a}; B={B}, {b}; G={G}, {g}")
      

      Solution: Alpha is the eldest. Beta is the most honest.

      Alpha is the eldest, and sometimes tells the truth and sometimes lies.

      Beta is the middle, and always tells the truth.

      Gamma is the youngest, and always lies.

      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