Recent Updates Page 61 Toggle Comment Threads | Keyboard Shortcuts

  • Unknown's avatar

    Jim Randell 9:42 am on 15 July 2019 Permalink | Reply
    Tags:   

    Teaser 2796: George and the Dragon 

    From The Sunday Times, 24th April 2016 [link] [link]

    Yesterday was St George’s day and to celebrate George getting even with the dragon I wrote down an addition sum. Then I replaced digits consistently by letters, using different letters for different digits, to give:

    SAINT + GEORGE = DRAGON

    Given that GEORGE is even, what number is DRAGON?

    [teaser2796]

     
    • Jim Randell's avatar

      Jim Randell 9:43 am on 15 July 2019 Permalink | Reply

      This puzzle can be solved using the [[ SubstitutedSum() ]] solver from the enigma.py library.

      The following run file executes in 153ms.

      Run: [ @replit ]

      #! python -m enigma -rr
      
      SubstitutedSum
      
      # GEORGE is even, so E cannot be an odd digit
      --invalid="1|3|5|7|9,E"
      
      # the alphametic sum
      "SAINT + GEORGE = DRAGON"
      

      Solution: DRAGON = 932801.

      The full sum is: 72415 + 860386 = 932801. In this sum E = 6.

      There are two further solutions to the alphametic sum where E is odd:

      64123 + 790579 = 854702 → E = 9
      92138 + 650465 = 742603 → E = 5

      Like

    • GeoffR's avatar

      GeoffR 1:02 pm on 15 July 2019 Permalink | Reply

      % A Solution in MiniZinc
      include "globals.mzn";
      
      var 0..9:S; var 0..9:A; var 0..9:I; var 0..9:N; var 0..9:T;
      var 0..9:G; var 0..9:E; var 0..9:O; var 0..9:R; var 0..9:D;
      
      constraint all_different ([S, A, I, N, T, G, E, O, R, D]);
      constraint S > 0 /\ G > 0 /\ D > 0;
      
      var 10000..99999: SAINT = 10000*S + 1000*A + 100*I + 10*N + T;
      var 100000..999999: GEORGE = 100010*G + 10001*E + 1000*O + 100*R;
      var 100000..999999: DRAGON = 100000*D + 10000*R + 1000*A 
      + 100*G + 10*O + N;
      
      constraint GEORGE mod 2 == 0;
      constraint SAINT + GEORGE == DRAGON;
      
      solve satisfy;
      
      output ["Equation is " ++ show(SAINT) ++ " + " ++ show(GEORGE)
      ++ " = " ++ show(DRAGON) ];
      
      % Equation is 72415 + 860386 = 932801
      % ----------
      % ==========
      

      Like

  • Unknown's avatar

    Jim Randell 9:00 am on 14 July 2019 Permalink | Reply
    Tags:   

    Brain-Teaser 486: [Counting cards] 

    From The Sunday Times, 20th September 1970 [link]

    So as to encourage my four children to practise their arithmetic I have invented a game played with a standard pack of playing-cards. For scoring purposes an Ace counts as 1; Jack, Queen and King as 11, 12 and 13 respectively; and each other card by its numerical value.

    To make matters a little complicated, I decided that Hearts should count at face value, Clubs at double value, Diamonds at triple value, and Spades at quadruple value. Before each deal, one card is extract from the pack, and a Joker, valued at 50 points, is substituted.

    The cards are then dealt in the normal manner, and each child then counts up the points value of his or her hand. There is a small reward for the child who most rapidly correctly counts up his points, but the winner is the child with the highest total.

    At the conclusion of one such game, each of the totals was an exact multiple of 7, and the winner, Bert, had scored 42 more than Amy, who had beaten Don by 35. Poor Clara came last with 14 points fewer than Don.

    Which card had been replaced by the Joker?

    This puzzle was originally published with no title.

    [teaser486]

     
    • Jim Randell's avatar

      Jim Randell 9:01 am on 14 July 2019 Permalink | Reply

      The scores in order from lowest to highest are:

      C
      D = C + 14
      A = C + 49
      B = C + 91

      So the total number of points is:

      A + B + C + D = 4C + 154

      and C must be divisible by 7.

      This program creates a set of cards, and then looks at replacing one of the cards with a Joker (value 50), to find possible values for C (and hence A, B, D).

      It runs in 79ms.

      Run: [ @repl.it ]

      from enigma import irange, update, div, printf
      
      # multipliers
      mul = dict(H=1, C=2, D=3, S=4)
      
      # map each card to the corresponding score
      score = dict()
      for v in irange(1, 13):
        score.update(((v, k), m * v) for (k, m) in mul.items())
      
      # one card is replaced with a 50
      for k in score.keys():
        s = update(score, [(k, 50)])
        # total number of points
        t = sum(s.values())
      
        # score for C (= 7x)
        x = div(t - 154, 28)
        if x is None: continue
      
        # calculate the scores
        C = 7 * x
        (B, A, D) = (C + 91, C + 49, C + 14)
        printf("k={k} t={t}, A={A} B={B} C={C} D={D}")
      

      Solution: The card replaced by the Joker is the Jack of Clubs.

      This is the only card which gives a viable value for C.

      The scores are: B = 287; A = 245; D = 210; C = 196 (being 41×; 35×; 30×; 28× 7).

      We can get the program to additionally look for a way of dealing the cards that achieves the required scores. Fortunately there are many ways of dealing the cards. Here is one of them:

      A = 5♠ + 6♥ + 6♣ + 6♦ + 7♥ + 7♣ + 7♦ + 7♠ + 8♥ + 8♣ + 8♠ + X♦ + J♦
        = 20 +  6 + 12 + 18 +  7 + 14 + 21 + 28 +  8 + 16 + 32 + 30 + 33 = 245
      
      B = 8♦ + 9♥ + 9♣ + X♥ + X♣ + X♠ + J♥ + J♠ + Q♥ + Q♣ + Q♦ + K♥ + K♣
        = 24 +  9 + 18 + 10 + 20 + 40 + 11 + 44 + 12 + 24 + 36 + 13 + 26 = 287
      
      C = A♥ + A♣ + A♦ + A♠ + 2♥ + 2♣ + 2♦ + 2♠ + 3♥ + 6♠ + Q♠ + K♦ + K♠
        =  1 +  2 +  3 +  4 +  2 +  4 +  6 +  8 +  3 + 24 + 48 + 39 + 52 = 196
      
      D = 3♣ + 3♦ + 3♠ + 4♥ + 4♣ + 4♦ + 4♠ + 5♥ + 5♣ + 5♦ + 9♦ + 9♠ + JK
           6 +  9 + 12 +  4 +  8 + 12 + 16 +  5 + 10 + 15 + 27 + 36 + 50 = 210

      Like

  • Unknown's avatar

    Jim Randell 6:18 pm on 12 July 2019 Permalink | Reply
    Tags:   

    Teaser 2964: “Bingo a go-go” lingo a no-go 

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

    My rest home’s Bingo set uses numbers 1 to 99. To win, nine numbers on your game card must be called. Our caller, not knowing “bingo-lingo”, says “Number 1, total factors 1”, “Number 11, total factors 2” and “Number 30, total factors 8”, etc.

    Yesterday, in one game, my hearing aid howled whenever a call started. I missed each number, but heard each “total factors” value. Fortunately, after just nine calls I shouted “HOUSE!” certain that I’d won.

    I told my daughter how many different “factor” values I’d heard, but didn’t say what any of the values were. Knowing that I had won after nine calls, she could then be sure about some (fewer than nine) of my winning numbers.

    Find, in ascending order, the numbers that she could be sure about.

    [teaser2964]

     
    • Jim Randell's avatar

      Jim Randell 6:43 pm on 12 July 2019 Permalink | Reply

      (See also: Enigma 1004 for another puzzle that involves counting divisors).

      This Python program groups the numbers from 1 to 99 into collections that have the same number of divisors, and then looks for groups of those collections that give a set of exactly 9 numbers, and these groups are recorded by the size of the group.

      We can then find groups of the same size that have a non-empty set of fewer than 9 numbers in common, and this gives our solution.

      It runs in 78ms.

      Run: [ @repl.it ]

      from enigma import (defaultdict, irange, tau, subsets, flatten, intersect, printf)
      
      # consider the numbers, and group them by number of divisors
      g = defaultdict(list)
      for n in irange(1, 99):
        t = tau(n)
        g[t].append(n)
      
      # [optional] we can discard groups with > 9 elements
      g = dict((k, v) for (k, v) in g.items() if not (len(v) > 9))
      
      # collect possible keys that give a set of 9 numbers
      # grouped by the total number of keys
      rs = defaultdict(list)
      for ks in subsets(g.keys()):
        ns = flatten(g[k] for k in ks)
        if not (len(ns) == 9): continue
        
        n = len(ks)
        printf("[{n}: {ks} -> {ns}]")
        rs[n].append(ns)
      
      # find groups with more than 0, but less than 9 elements in common
      for (n, ns) in rs.items():
        s = intersect(ns)
        if not (0 < len(s) < 9): continue
      
        # output solution
        printf("{s} [n={n}]", s=sorted(s))
      

      Solution: The 7 numbers she could be sure about are: 1, 4, 9, 25, 36, 49, 64.

      The daughter was told that 5 different “factor” values were heard, so she knows the divisors are either:

      (1, 3, 5, 7, 9), which identify the numbers (1, 4, 9, 16, 25, 36, 49, 64, 81); or:
      (1, 3, 7, 9, 10), which identify the numbers (1, 4, 9, 25, 36, 48, 49, 64, 80)

      So the solution is given by the subset of the numbers that have 1, 3, 7, or 9 divisors.

      1 is the only number with 1 divisor.
      4, 9, 25, 49 (the squares of primes) have 3 divisors.
      64 (a prime to the power of 6) has 7 divisors
      36 (the square of the product of two different primes) has 9 divisors.

      Like

  • Unknown's avatar

    Jim Randell 9:33 am on 12 July 2019 Permalink | Reply
    Tags:   

    Teaser 2803: Easy as ABC 

    From The Sunday Times, 12th June 2016 [link] [link]

    George and Martha have replaced the digits 0 to 9 by the letters A to J in some order. George then noted a neat product, namely:

    AB × CDE = FGHIJ

    Then Martha noted a neat sum, namely:

    AB + CD + EF + GH + IJ = CCC

    What, in order, are the values of the letters A to J?

    [teaser2803]

     
    • Jim Randell's avatar

      Jim Randell 9:34 am on 12 July 2019 Permalink | Reply

      When this puzzle was published (June 2016) I wrote a couple of programs to solve it using the [[ SubstitutedSum() ]] solver from the enigma.py (which itself was originally written to solve Enigma 63 and similar puzzles).

      However, shortly afterwards I started work on a solver for general alphametic expressions in Python, and this puzzle was one of the examples I used to test it. I wrote up my thoughts as Solving Alphametics with Python and Solving Alphametics with Python, Part 2. And although there have been many incremental improvements to the code over the last 3 years, the ideas from Part 2 still form the basis of the [[ SubstitutedExpression() ]] solver in the enigma.py library, which I have used it to solve a wide variety of alphametic puzzles in that time.

      For this puzzle we can use the following command line (which executes in 88ms):

      Run: [ @replit ]

      % python3 -m enigma SubstitutedExpression --answer="ABCDEFGHIJ" "AB * CDE = FGHIJ" "AB + CD + EF + GH + IJ = CCC"
      (AB * CDE = FGHIJ) (AB + CD + EF + GH + IJ = CCC) (ABCDEFGHIJ)
      (52 * 367 = 19084) (52 + 36 + 71 + 90 + 84 = 333) (5236719084) / A=5 B=2 C=3 D=6 E=7 F=1 G=9 H=0 I=8 J=4
      ABCDEFGHIJ = 5236719084 [1 solution]
      

      Solution: The values of the letters are: A=5, B=2, C=3, D=6, E=7, F=1, G=9, H=0, I=8, J=4.

      Like

    • GeoffR's avatar

      GeoffR 11:18 am on 12 July 2019 Permalink | Reply

      % A Solution in MiniZinc
      include "globals.mzn";
      
      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;
      
      constraint A > 0 /\ C > 0 /\ E > 0 /\ F > 0
      /\ G > 0 /\ I > 0;
      
      constraint all_different ([A, B, C, D, E, F, G, H, I]);
      
      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 100..999: CCC = 111*C;
      var 100..999: CDE = 100*C + 10*D + E;
      var 10000..99999: FGHIJ = 10000* F + 1000*G + 100*H + 10*I + J;
      
      % two alphametic equations to solve
      constraint AB * CDE == FGHIJ;
      constraint AB + CD + EF + GH + IJ == CCC;
      
      solve satisfy;
      
      output ["A,B,C,D,E,F,G,H,I,J = " ++ show([A,B,C,D,E,F,G,H,I,J])]
      ++ ["\n" ++ show(AB) ++ " * " ++ show(CDE) ++ " = " ++ show(FGHIJ)]
      ++ ["\n" ++ show (AB) ++ " + " ++  show(CD) ++ " + " ++ show(EF) ++ " + "
      ++ show(GH) ++ "  + " ++ show(IJ) ++ " = "  ++ show(CCC) ] ;
      
      % A,B,C,D,E,F,G,H,I,J = [5, 2, 3, 6, 7, 1, 9, 0, 8, 4]
      % 52 * 367 = 19084
      % 52 + 36 + 71 + 90  + 84 = 333
      % ----------
      % ==========
      
      
      

      Like

  • Unknown's avatar

    Jim Randell 9:53 am on 11 July 2019 Permalink | Reply
    Tags:   

    Brainteaser 1625: Jolly sticks 

    From The Sunday Times, 31st October 1993 [link]

    In a qualifying round of the European Ladies Hockey Cup held recently, each of the four participating countries played each of the others once. There were no draws. The final results looked like this:

    If I gave you the score of the Holland vs. France game you could deduce the scores of all the other games. But if instead I gave you the score of any one of the other games you would not be able to do so.

    This puzzle is included in the book Brainteasers (2002), where it appears under the title “Qualifier“. The wording above is mostly taken from original puzzle, but I have slightly changed it using the book for clarity.

    [teaser1625]

     
    • Jim Randell's avatar

      Jim Randell 9:55 am on 11 July 2019 Permalink | Reply

      The following program uses the [[ Football() ]] helper class from the enigma.py library. It runs in 80ms.

      Run: [ @repl.it ]

      from enigma import (Football, filter_unique, printf)
      
      # scoring system (all games played)
      football = Football(games='wdl')
      
      # match outcomes are determined by the table
      HS = HF = HW = SF = SW = FW = 'w'
      
      # record possible scores
      ss = list()
      
      # find scores in F's matches
      for (sHF, sSF, sFW) in football.scores([HF, SF, FW], [1, 1, 0], 2, 4):
      
        # find scores in S's remaining matches
        for (sHS, sSW) in football.scores([HS, SW], [1, 0], 8, 3, [sSF], [0]):
      
          # and the remaining match (using H's goals)
          for (sHW,) in football.scores([HW], [0], 12, 1, [sHS, sHF], [0, 0]):
      
            # check W's goals
            if not (football.goals([sHW, sSW, sFW], [1, 1, 1]) == (1, 15)): continue
      
            printf("[HS={HS}:{sHS} HF={HF}:{sHF} HW={HW}:{sHW} SF={SF}:{sSF} SW={SW}:{sSW} FW={FW}:{sFW}]")
            ss.append((sHS, sHF, sHW, sSF, sSW, sFW))
      
      # determine unique results by each individual match
      vs = [None] * 6
      for (i, _) in enumerate(vs):
        (vs[i], _) = filter_unique(ss, (lambda r: r[i]))
      
      # solution is unique by HF (i=1) but not by any of the others
      rs = set(vs[1]).difference(*(vs[:1] + vs[2:]))
      
      # output solutions
      for (sHS, sHF, sHW, sSF, sSW, sFW) in rs:
        printf("HS={HS}:{sHS} HF={HF}:{sHF} HW={HW}:{sHW} SF={SF}:{sSF} SW={SW}:{sSW} FW={FW}:{sFW}")
      

      Solution: The scores were as follows:

      Holland vs Spain = 2-0
      Holland vs France = 2-1
      Holland vs Wales = 8-0
      Spain vs France = 2-0
      Spain vs Wales = 6-1
      France vs Wales = 1-0

      Like

  • Unknown's avatar

    Jim Randell 10:22 am on 10 July 2019 Permalink | Reply
    Tags:   

    Teaser 2900: An ancestral equation 

    From The Sunday Times, 22nd April 2018 [link] [link]

    I recently discovered a 16th-century ancestor called David, which happens to be my maiden name. (I never really liked Bricket, even when pronounced in the French way). I have always been partial to word arithmetic (or cryptarithms) and the other day I found a solution to this one:

    MY × NAME = DAVID

    When eight distinct digits are substituted for the eight letters and no number starts with zero, the equation holds. Amazingly the solution gave me more information about my ancestor. MY turned out to be his age when he died and NAME was the year he was born.

    What was that year?

    [teaser2900]

     
    • Jim Randell's avatar

      Jim Randell 10:24 am on 10 July 2019 Permalink | Reply

      This is a simple alphametic puzzle that can be solved using the [[ SubstitutedExpression() ]] solver from the enigma.py library.

      The multiplication expression is enough to find a unique solution, but we can also check that the date is in the required range.

      This run file executes in 166ms.

      Run: [ @replit ]

      #! python -m enigma -rr
      
      SubstitutedExpression
      
      # this is enough to solve the puzzle
      "MY * NAME = DAVID"
      
      # [optional] check they were alive in the 16th century (1501 - 1600)
      "1500 - MY < NAME < 1601"
      

      Solution: He was born in 1543.

      And died aged 49 around 1592.

      Like

    • GeoffR's avatar

      GeoffR 12:13 pm on 11 July 2019 Permalink | Reply

      % A Solution in MiniZinc
      include "globals.mzn";
      
      var 0..9:M; var 0..9:Y; var 0..9:N; var 0..9:A; 
      var 0..9:E; var 0..9:D; var 0..9:V; var 0..9:I; 
      
      % 16th-century means N = 1 and A = 5, as year born = NAME
      constraint M > 0 /\ D > 0 /\ N == 1 /\ A == 5;
      constraint all_different([M, Y, N, A, E, D, V, I]);
      
      var 10..99: MY = 10*M + Y;
      var 1000..9999: NAME = 1000*N + 100*A + 10*M + E;
      var 10000..99999: DAVID = 10001*D + 1000*A + 100*V + 10*I;
      
      constraint MY * NAME == DAVID;
      
      solve satisfy;
      output[ "Equation: "  ++ show(MY) ++ " * " ++ show(NAME) ++ " = " ++ show(DAVID)]
      ++ [ "\nYear born = " ++ show(NAME) ];
      
      % Equation: 49 * 1543 = 75607
      % Year born = 1543
      % ----------
      % ==========
      
      

      Like

  • Unknown's avatar

    Jim Randell 8:26 am on 9 July 2019 Permalink | Reply
    Tags:   

    Brain-Teaser 485: Delphic oracle 

    From The Sunday Times, 13th September 1970 [link]

    Delphi has three computers, in order to confuse the faithful. The 1969 one always gives a true answer; the 1960 one always gives an untrue answer; the 1965 is quite unpredictable.

    Professor Binary, who is visiting the shrine, fed to each computer in turn the question: “What is the date of the largest computer?”

    The first computer replied “1969”; the second replied “Not 1960”; and Binary, who could see the size, though not the date, of the computers as they replied, had no need to study the third computer’s reply, since he now knew the answer to his question.

    What is the date of the largest computer?

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

    [teaser485]

     
    • Jim Randell's avatar

      Jim Randell 8:28 am on 9 July 2019 Permalink | Reply

      This Python program runs in 81ms.

      Run: [ @replit ]

      from enigma import (subsets, printf)
      
      # the behaviours of the computers
      def F(s): return (not s)
      def U(s): return True
      def T(s): return bool(s)
      
      # the professor asks two of the computers (identified by size)
      for (a, b) in subsets((0, 1, 2), size=2):
      
        # record largest computers in scenarios that work
        rs = set()
      
        # consider all possible size orders (L, M, S)
        for size in subsets((F, U, T), size=3, select='P'):
          (L, A, B) = (size[0], size[a], size[b])
      
          # first computer states "1969 (T) is largest"
          if not A(L == T): continue
      
          # second computer states "1960 (F) is not largest"
          if not B(L != F): continue
      
          rs.add(L)
      
        # look for unique solutions
        if len(rs) == 1:
          L = rs.pop()
          printf("L={L.__name__} [a={a} b={b}]")
      

      Solution: The largest computer is from 1965.

      So the largest computer, from 1965, is unreliable.

      The medium sized computer is from 1960, and always makes false statements.

      The smallest computer is from 1969, and always makes true statements.

      The Professor asks his first question to the medium sized computer, and his second question to the smallest computer.


      We can verify manually that this does indeed give a solution.

      First we refer to the computers by their behaviour, instead of their year. So:

      1960, always makes false statements = F
      1965, makes unreliable statements = U
      1969, always makes true statements = T

      The Professor asks the firsts question (“which computer is largest”) to M (the medium sized computer), and gets an answer of “T”, and he then asks the same question to S (the smallest computer), and gets an answer of “not F”.

      There are six possible orders of computer (Largest, Medium, Smallest):

      L=F, M=U, S=T: S would not say “not F” (as S=T and L=F). Impossible.
      L=F, M=T, S=U: M would not say “T” (as M=T and L=F). Impossible.
      L=U, M=F, S=T: M would say “T” (as M=F and L=U), and S would say “not F” (as S=T and L=U). Possible.
      L=U, M=T, S=F: M would not say “T” (as M=T and L=U). Impossible.
      L=T, M=F, S=U: M would not say “T” (as M=F and L=T). Impossible.
      L=T, M=U, S=F: S would not say “not F” (as S=F and L=T). Impossible.

      So there is only one possible situation, and so the Professor can determine that: L=U=1965 (and also: M=F=1960, S=T=1969).

      Asking the question to M and S is the only situation where a single largest computer is identified, so this is the only solution.

      Like

  • Unknown's avatar

    Jim Randell 8:15 am on 8 July 2019 Permalink | Reply
    Tags:   

    Teaser 2812: Sum card trick 

    From The Sunday Times, 14th August 2016 [link] [link]

    Joe has nine cards, white on one side and grey on the other, with a single digit written on each side of each card. He gave them to Penny to arrange white-side-up to form three 3-figure numbers with the sum of the first two equalling the third. This was her attempt:

    (2 1 9) (6 5 4) (8 7 3)

    Then Joe turned the cards over one at a time to reveal

    (9 8 7) (1 4 2) (3 6 5)

    where the total of the first two did not equal the third. So he challenged Penny to arrange the cards so that both white-side-up and grey-side-up the third number was the sum of the first two, which she did.

    What was her third grey number?

    [teaser2812]

     
    • Jim Randell's avatar

      Jim Randell 8:17 am on 8 July 2019 Permalink | Reply

      The following run file uses the [[ --code ]] parameter of the [[ SubstitutedExpression() ]] solver (from the enigma.py library) to provide a function that translates from white numbers to grey numbers. This can then be used in the alphametic expressions.

      The run file executes in 236ms.

      Run: [ @replit ]

      #! python -m enigma -rr
      
      SubstitutedExpression
      
      # map from white to corresponding grey digit
      --code="w2g = dict(zip(nsplit(219654873), nsplit(987142365)))"
      
      # return the grey number for a corresponding white number <n>
      --code="grey = lambda n: nconcat(w2g[x] for x in nsplit(n))"
      
      # solve the sum so the white side and the grey side are both valid
      --digits="1-9"
      --answer="grey(GHI)"
      
      "ABC + DEF = GHI"
      "grey(ABC) + grey(DEF) == grey(GHI)"
      

      Solution: The third grey number is 738.

      Like

    • GeoffR's avatar

      GeoffR 8:41 am on 16 July 2019 Permalink | Reply

      # Equations are ABC + DEF = GHI for white cards
      # and abc + def1 = ghi for grey cards
      
      from itertools import permutations
      
      # dictionary for white to grey card values
      wtg = {2:9, 1:8, 9:7, 6:1, 5:4, 4:2, 8:3, 7:6, 3:5}
      
      # permute white card digits
      for p in permutations( (2, 1, 9, 6, 5, 4, 8, 7, 3) ): 
          A, B, C, D, E, F, G, H, I = p
          ABC = 100*A + 10*B + C
          DEF = 100*D +10*E + F
          GHI = 100*G + 10*H + I
          if ABC + DEF != GHI: continue
          if ABC < DEF: continue
      
          # Look up grey card values from white cards
          a, b, c = wtg[A], wtg[B], wtg[C]
          abc = 100*a + 10*b + c
          
          d, e, f1 = wtg[D], wtg[E], wtg[F]
          def1 = 100*d + 10*e + f1
      
          g, h, i = wtg[G], wtg[H], wtg[I]
          ghi = 100*g + 10*h + i
          if abc + def1 == ghi:
              print(f"White cards are ({ABC}), ({DEF}), ({GHI})" )
              print(f"Grey Cards are  ({abc}), ({def1}), ({ghi})")
              print()
      
      # White cards are (624), (357), (981)
      # Grey Cards are  (192), (546), (738)
      
      # White cards are (627), (354), (981)
      # Grey Cards are  (196), (542), (738)
      
      # White cards are (654), (327), (981)
      # Grey Cards are  (142), (596), (738)
      
      # White cards are (657), (324), (981)
      # Grey Cards are  (146), (592), (738)
      
      # Third grey number was 738
      
      
      

      Like

  • Unknown's avatar

    Jim Randell 5:26 pm on 5 July 2019 Permalink | Reply
    Tags:   

    Teaser 2963: A result 

    From The Sunday Times, 7th July 2019 [link] [link]

    For any number, I square the digits and then add the resulting numbers. If necessary, I keep repeating the process until I end up with a single digit, called the result. For example: 142 gives 1 + 16 + 4 = 21 which then gives 4 + 1 = 5, the result.

    I have written down a two-digit number. If I tell you one of the digits [the key digit], you should be able to work out the result.

    I then use a 3rd digit to get a three-digit number. The result of that number happens to be the key digit.

    In increasing order, what are the three digits?

    [teaser2963]

     
    • Jim Randell's avatar

      Jim Randell 5:59 pm on 5 July 2019 Permalink | Reply

      The following Python program runs in 90ms.

      Run: [ @repl.it ]

      from enigma import (nsplit, subsets, irange, unpack, filter_unique, printf)
      
      # process a sequence of digits
      def process(ds):
        while True:
          n = sum(d * d for d in ds)
          if n < 10: return n
          ds = nsplit(n)
      
      # collect the results for 2 digit numbers
      ss = list((ds, process(ds)) for ds in subsets(irange(0, 9), size=2, select='R') if ds != (0, 0))
      
      # if I tell you "one of the digits is <k>" you should be able to work out the result
      for k in irange(0, 9):
        (rs, _) = filter_unique(ss, unpack(lambda ds, r: k in ds), unpack(lambda ds, r: r))
      
        # consider possible 2-digit sequences
        for (ds, _) in rs:
          # and add an extra digit
          for x in irange(0, 9):
            # the result should be the digit <k>
            if process(ds + (x,)) == k:
              printf("k={k}: {ds} + {x}")
      

      Solution: The three digits are: 5, 6, 9.

      The order of the digits in a number does not matter. 24 will have the same result as 42 (both are 2² + 4² = 20 → 2² + 0² = 4).

      The key digit is 5. Any 2-digit sequence that contains a 5 has a result of 4.

      The initial number is one of: 56, 59, 65, 95. An extra digit is added so the three digit sequence consists of the digits 5, 6, 9 (in some order). And this sequence has a result of 5.


      Most of the 2-digit numbers give a result of 4, and if the process is allowed to continue summing the squares of the digits we see the following cycle emerge:

      4 → 16 → 37 → 58 → 89 → 145 → 42 → 20 → 4

      Numbers that eventually result in this cycle are known as “unhappy numbers” (see [ link ]).

      The other 2-digit numbers give results of 1, 2, 5, 8, 9, we can also continue the process with these values:

      1 → 1
      2 → 4
      5 → 25 → 29 → 85 → 89 → … → 4
      8 → 64 → 52 → 29 → … → 4
      9 → 81 → 65 → 61 → 37 → … → 4

      We see that any numbers with a result of 2, 5, 8, 9 are also “unhappy”, and only those numbers that have a result of 1 are “happy”. (See OEIS A124095 [ link ]).

      Like

      • Jim Randell's avatar

        Jim Randell 3:54 pm on 7 July 2019 Permalink | Reply

        Here’s a simpler program to solve the puzzle.

        Run: [ @repl.it ]

        from enigma import (nsplit, seq_all_same, irange, subsets, printf)
        
        # process a sequence of digits
        def process(*ds):
          while True:
            n = sum(d * d for d in ds)
            if n < 10: return n
            ds = nsplit(n)
        
        # look for possible key digits
        for k in irange(0, 9):
          # must give the same result when combined with all other digits
          if seq_all_same(process(k, d) for d in irange(0, 9) if k + d > 0):
        
            # look for two additional digits to give a result of k
            for (a, b) in subsets(irange(0, 9), size=2, select='R'):
              if process(k, a, b) == k and k + a + b > 0:
                printf("k={k}: {s}", s=sorted([k, a, b]))
        

        Like

  • Unknown's avatar

    Jim Randell 8:26 am on 5 July 2019 Permalink | Reply
    Tags:   

    Teaser 2901: Square deal 

    From The Sunday Times, 29th April 2018 [link] [link]

    George and Martha have five daughters who have periodically appeared in my teasers over the years. They are all working for the same company and have perfect-square four-digit telephone extensions, in all five cases. The letters ABCDEFGHIJ stand for the digits 0-9 but in no particular order. The extensions are as follows:

    Andrea = IBHC
    Bertha = DJJC
    Caroline = BAFH
    Dorothy = GFID
    Elizabeth = GAEE

    What are the five extensions?

    [teaser2901]

     
    • Jim Randell's avatar

      Jim Randell 8:27 am on 5 July 2019 Permalink | Reply

      This is a straightforward alphametic problem which can be handled directly by the [[ SubstitutedExpression() ]] solver in the enigma.py library.

      The following run file executes in 127ms.

      Run: [ @repl.it ]

      #! python -m enigma -rr
      
      SubstitutedExpression
      
      --answer="(IBHC, DJJC, BAFH, GFID, GAEE)"
      
      "is_square(IBHC)"
      "is_square(DJJC)"
      "is_square(BAFH)"
      "is_square(GFID)"
      "is_square(GAEE)"
      

      Solution: The five extension numbers are: 2916, 5776, 9801, 3025, 3844.

      Like

    • GeoffR's avatar

      GeoffR 12:13 pm on 5 July 2019 Permalink | Reply

      % A Solution in MiniZinc
      include "globals.mzn";
       
      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;
      
      constraint all_different ([A,B,C,D,E,F,G,H,I,J]);
      constraint I > 0 /\ D > 0 /\ B > 0 /\ G > 0;
      
      set of int: sq4 = {n*n | n in 32..99};
      
      % The five extensions
      var 1000..9999: IBHC = 1000*I + 100*B + 10*H + C;
      var 1000..9999: DJJC = 1000*D + 100*J + 10*J + C;
      var 1000..9999: BAFH = 1000*B + 100*A + 10*F + H;
      var 1000..9999: GFID = 1000*G + 100*F + 10*I + D;
      var 1000..9999: GAEE = 1000*G + 100*A + 10*E + E;
      
      constraint IBHC in sq4 /\ DJJC in sq4 /\ BAFH in sq4
      /\ GFID in sq4 /\ GAEE in sq4;
      
      solve satisfy;
      
      output [ "The five extensions are " ++ show(IBHC) ++ "," ++ show(DJJC) 
      ++ "," ++ show(BAFH) ++ "," ++ show(GFID) ++ " and " ++ show(GAEE) ];
      
      % The five extensions are 2916,5776,9801,3025 and 3844
      % % time elapsed: 0.02 s
      % ----------
      % ==========
      % Finished in 437msec
      

      Like

  • Unknown's avatar

    Jim Randell 9:52 am on 4 July 2019 Permalink | Reply
    Tags: ,   

    Brain-Teaser 484: [Family ages] 

    From The Sunday Times, 6th September 1970 [link]

    The total ages of my children, all of single birth, exactly equal my own age. On the same day next year they will exactly equal my husbands age.

    At present my husband’s age is divisible by the age of only one child, but in one year’s time it will be divisible by the separate ages of three children and also by the number of children in the family, while my own age will be divisible by the age of one child only.

    During the year ahead, on just one day in May, my husband’s age will be divisible by that of my eldest child.

    What are the children’s ages?

    Note: This puzzle is flawed, as there is not a single solution. A note was published with Brain-Teaser 485 saying that as there are three solutions no prize can be awarded.

    This puzzle was originally published with no title.

    [teaser484]

     
    • Jim Randell's avatar

      Jim Randell 9:54 am on 4 July 2019 Permalink | Reply

      I found many solutions to this puzzle, not just the 3 mentioned when Brain-Teaser 485 was published.

      The simplest solution was with 4 children with ages: 1, 2, 11, 18. This gives:

      The wife’s age is 32, the husband’s age is 35.

      Only 1 divides into 35, but next year (when the children are 2, 3, 12, 19 and the husband is 36) three of the children ages (2, 3, 12) will divide in 36.

      And the wife will be 33, and 3 divides into this.

      During May the eldest child’s age (18) does not divide into the husband’s age (35), until the husband’s birthday, when he is 36. The next day is the eldest child’s birthday, who become 19, which not divide the husband’s age.

      The problem with this solution is that at the time of birth of the eldest child the wife would be 14 and the husband 17. While not impossible, it’s probably not what the setter had in mind, so we’ll stick with more conventional scenarios.

      To make a version of the puzzle with a single solution I added a couple of extra conditions.

      Firstly I strengthened the “all of single birth” condition to the children all having different ages (in years), and restricted the current ages of the children to be between 2 and 16.

      This gets me down to 5 solutions (one with 5 children, and four with 7 children). Adding a further reasonable conditions such as “the husband and wife are both aged less than 50” or “the wife was in her twenties at the time of the birth of the eldest child” can be used to narrow the possibilities down to a single solution.

      So I settled on the following additional conditions to give a single solution:

      • The children are aged between 2 and 16, and their ages (expressed in years) are all different.
      • The husband and wife are currently aged less than 50.

      This Python program solves the revised puzzle. It runs in 159ms.

      Run: [ @repl.it ]

      from enigma import (subsets, irange, div, printf)
      
      # x is divisible by y
      divides = lambda x, y: div(x, y) is not None
      
      # consider sets of at least 3 children ([extra] with no repeated ages)
      for ages in subsets(irange(2, 16), min_size=3, select='C'):
        k = len(ages)
      
        # wife's current age is the sum
        w = sum(ages)
        # husbands age + 1 is w + k
        h = w + k - 1
      
        # [extra] husband and wife are less than 40
        if not (h < 50): continue
      
        # husbands current age is divisible by the age of only one child
        if not (sum(divides(h, x) for x in ages) == 1): continue
      
        # in 1 years time it is divisible by the ages of three children...
        if not (sum(divides(h + 1, x + 1) for x in ages) == 3): continue
        # ... and also the number of children ...
        if not divides(h + 1, k): continue
      
        # ... while the wifes age is divisible by only one child
        if not (sum(divides(w + 1, x + 1) for x in ages) == 1): continue
      
        # on one day the husbands age will divide the age of the eldest child
        # so their birthdays must be on consecutive days
        a = ages[-1]
        # so they don't divide in general either now or both incremented
        if divides(h, a) or divides(h + 1, a + 1): continue
        # but they do divide when one of them is incremented
        if not (divides(h + 1, a) or (divides(h, a + 1))): continue
      
        # output solution (w0 and h0 are ages at the birth of the first child)
        printf("k={k}, ages={ages}, w={w}, h={h} [{w0}, {h0}]", w0=w - a, h0=h - a)
      

      Solution: The children are aged: 3, 6, 7, 9, 10.

      The wife’s current age is 35 (the sum of the children’s ages). The husband’s current age is 39. (So they would be 25 and 29 at the birth of eldest child).

      Of the children’s current ages, only 3 divides into 39. But when the ages are all increased by one to 4, 7, 8, 10, 11 then 4, 8 and 10 divide into 40. And the wife will be 36, which is divisible by 4.

      During May the eldest child’s age (10) does not divide into the husband’s age (39), until the husband’s birthday, when he is 40. The next day is the eldest child’s birthday (11) and non-divisibility is resumed.

      The intended solution was apparently 1, 6, 7, 9, 12.

      Like

  • Unknown's avatar

    Jim Randell 12:43 pm on 1 July 2019 Permalink | Reply
    Tags:   

    Teaser 2902: Birthdays 2018 

    From The Sunday Times, 6th May 2018 [link] [link]

    Several friends have birthdays on different days in 2018.

    Replacing A by 1, B by 2, C by 3 … and Z by 26, each month and day can be replaced by a sequence of numbers. Every birthday is given numerically by day, date and month, as described above. For each friend, there is just one number common to each of their 3 sets of numbers. The number of friends is the largest possible.

    How many friends are there and what is the largest number of clear days between consecutive birthdays?

    [teaser2902]

     
    • Jim Randell's avatar

      Jim Randell 12:45 pm on 1 July 2019 Permalink | Reply

      The puzzle text is not completely clear, and allows several interpretations.

      I interpreted it as follows:

      A date, such as Friday 25th May 2018, is translated into a sequence of numbers as follows:

      Friday = (6, 18, 9, 4, 1, 25)
      25 = (25)
      May = (13, 1, 25)

      The “day of month” always provides a sequence with a single number in it, and this number must also appear in the “day name” sequence and the “month name” sequence (which are created by translating the letters to numbers). Furthermore it must be the only number that is shared between the translated sequences.

      In the example 25=Y occurs in FRIDAY and also in MAY, but it is not the only letter in common A=1 also occurs.

      Using this interpretation we find there are only four dates that meet the requirements. And we then look for the longest gap between consecutive dates in this set.

      This Python program runs in 83ms.

      Run: [ @repl.it ]

      import datetime
      from enigma import (tuples, printf)
      
      # days (0-indexed)
      days = ( 'MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY', 'SUNDAY' )
      
      # months (1-indexed)
      months = ( None,
        'JANUARY', 'FEBRUARY', 'MARCH', 'APRIL', 'MAY', 'JUNE', 'JULY',
        'AUGUST', 'SEPTEMBER', 'OCTOBER', 'NOVEMBER', 'DECEMBER'
      )
      
      # turn letters into numbers
      letters = "?ABCDEFGHIJKLMNOPQRSTUVWXYZ"
      l2n = lambda s: tuple(letters.index(x) for x in s)
      
      year = 2018 # year
      inc = datetime.timedelta(1) # 1 day increment
      
      # consider days in the required year
      d = datetime.date(year, 1, 1)
      n = 0
      bd = list()
      while d.year == year:
        (day, date, month) = (l2n(days[d.weekday()]), d.day, l2n(months[d.month]))
        # find letters in both day and month
        s = set(day).intersection(month)
        if len(s) == 1 and date in s: # maybe just [[ date in s ]]
          n += 1
          printf("n={n}: {d} -> {wday} {date} {wmonth} -> {day} ({date}={wdate}) {month}", wday=days[d.weekday()], wdate=letters[date], wmonth=months[d.month])
          bd.append(d)
        d += inc
      
      # number of birthdays
      n = len(bd)
      
      # find the maximum delta
      deltas = list((b - a).days - 1 for (a, b) in tuples(bd, 2))
      printf("{n} values, max delta = {m} days (deltas={deltas})", m=max(deltas))
      

      Solution: There are 4 friends. The longest gap between consecutive dates is 81 days.

      The 4 dates are:

      [1] SUNDAY 1 APRIL
      [2] THURSDAY 21 JUNE (gap = 80 days)
      [3] WEDNESDAY 25 JULY (gap = 33 days)
      [4] MONDAY 15 OCTOBER (gap = 81 days)

      The longest gap between these dates is 81 non-birthday days between [3] and [4].

      However, if we’re looking at “the maximum number of consecutive non-birthday days in 2018” there is a longer run from 1st January to 31st March, which is 90 days. (The run from 16th October to 31st December is 77 days).

      And the puzzle just asks for the longest gap between birthdays, and once we have fixed the dates we can see that the gap between birthday [4] and the next occurrence of birthday [1] (in 2019) is 167 days, and this gap would be 1 day longer if a leap year is involved. So the longest possible gap between birthdays is 168 days.

      Like

  • Unknown's avatar

    Jim Randell 9:07 am on 30 June 2019 Permalink | Reply
    Tags:   

    Brainteaser 1611: Scrambled egg 

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

    When HUMPTY fell he broke into six pieces, each comprising one letter from his name, and they landed in a row to read as a rubbish six-letter word with none of the six piece in the correct position.

    The King’s horses tried to put HUMPTY together again by arranging the pieces in the reverse order, which meant that more than one piece was in the right place.

    The King’s men then split that arrangement into two threes and placed the last three pieces before the first. This gave a higher number of letters in the correct place.

    What was the arrangement of letters just after HUMPTY fell?

    This puzzle is included in the book Brainteasers (2002). The wording above is taken from the book. It is slightly changed from the original puzzle.

    [teaser1611]

     
    • Jim Randell's avatar

      Jim Randell 9:07 am on 30 June 2019 Permalink | Reply

      This Python program tries all possible derangements of the letters, and checks to see if the conditions are satisfied. It runs in 85ms.

      Run: [ @repl.it ]

      from enigma import (subsets, join, printf)
      
      # word with letters in their correct positions
      word = "HUMPTY"
      
      # count the number of correct letters
      def correct(w):
        return sum(a == b for (a, b) in zip(w, word))
      
      # find derangements of the word
      for w in subsets(word, size=len(word), select='P'):
        if correct(w) > 0: continue
      
        # reversing gives more than 1 piece in the correct position
        w1 = w[::-1]
        k1 = correct(w1)
        if not (k1 > 1): continue
      
        # putting the last 3 before the first 3 gives even more in the correct position
        w2 = w1[3:] + w1[:3]
        k2 = correct(w2)
        if not (k2 > k1): continue
      
        # output solution
        printf("{w} [{w1} -> {k1}, {w2} -> {k2}]", w=join(w), w1=join(w1), w2=join(w2))
      

      Solution: The arrangement after HUMPTY fell was MTHYUP.

      Like

  • Unknown's avatar

    Jim Randell 5:48 pm on 28 June 2019 Permalink | Reply
    Tags:   

    Teaser 2962: Book receipts 

    From The Sunday Times, 30th June 2019 [link] [link]

    My wife recently purchased two books from her local bookshop. She showed me the receipt, which showed the cost of each book and the three-figure total cost. I noticed that all of the digits from 1 to 9 had been printed. Coincidentally, exactly the same happened to me when buying two different books, but my more expensive book cost more than hers. In fact, it would not have been possible for that book to have cost more.

    How much did I pay for the more expensive book?

    [teaser2962]

     
    • Jim Randell's avatar

      Jim Randell 5:57 pm on 28 June 2019 Permalink | Reply

      Assuming each digit from 1 to 9 is used exactly once, we can consider the following alphametic sum:

      ABC + DEF = GHI

      Which gives the prices of the books, and the total in whatever currency units we are using.

      This Python program uses a couple of useful routines from the enigma.py library to solve the puzzle.

      It runs in 163ms.

      Run: [ @replit ]

      from enigma import (SubstitutedExpression, Accumulator, irange, printf)
      
      # the alphametic sum
      p = SubstitutedExpression(
        [ "ABC + DEF = GHI", "A > D" ],  # "ABC > DEF"
        digits=irange(1, 9),
        answer="ABC",
        verbose=0
      )
      
      # find the maximum answer
      r = Accumulator(fn=max, collect=1)
      r.accumulate_data_from(p.solve(), value=1, data=0)
      
      # output the solution
      for s in r.data:
        t = p.substitute(s, "ABC + DEF = GHI")
        printf("max summand = {r.value} [{t}] [{n} sums]", n=r.count)
      

      Solution: The more expensive book cost 784 currency units.

      There are 168 possible sums, and the largest possible summand is 784, making the sum:

      784 + 152 = 936

      If the digit 0 is allowed (but we are still looking for 9 different digits) then there are 544 possible sums, and the largest possible summand is 847, in the sum:

      847 + 106 = 953

      Like

    • GeoffR's avatar

      GeoffR 12:11 pm on 3 March 2020 Permalink | Reply

      from itertools import permutations
      
      from collections import defaultdict
      DI = defaultdict(list) 
      
      for p in permutations('123456789'):
          A, B, C, D, E, F, G, H, I = p
          ABC = int(A + B + C)
          DEF =int(D + E + F)
          GHI = int(G + H + I)
          # ABC is most expensive book below
          if ABC > DEF and ABC + DEF == GHI:
              DI[ABC] += [(ABC, DEF, GHI)]
              
      L = []  # List of most expensive books in equation
      
      for K in DI.keys():
          L.append(K)
      
      print(f"Most expensive book costs {max(L)} currency units")
      # Most expensive book costs 784 currency units
      
      
      

      I also found that the summands 546 and 654 both had six solutions to the alphametic equation.

      Like

  • Unknown's avatar

    Jim Randell 11:54 am on 21 June 2019 Permalink | Reply
    Tags:   

    Teaser 2961: Alan and Cat 

    From The Sunday Times, 23rd June 2019 [link] [link]

    Alan and Cat live in a city which has a regular square grid of narrow roads. Avenues run west/east, with 1st Avenue being the furthest south, while Streets run south/north with 1st Street being the furthest west.

    Cat lives at the intersection of 1st Street and 1st Avenue, while Alan lives at an intersection due northeast from Cat. On 1 January 2018, Cat walked to Alan’s house using one of the shortest possible routes (returning home the same way), and has done the same every day since. At first, she walked a different route every day and deliberately never reached an intersection where the Street number is less then the Avenue number. However, one day earlier this year she found that she could not do the same, and repeated a route.

    What was the date then?

    [teaser2961]

     
    • Jim Randell's avatar

      Jim Randell 12:20 pm on 21 June 2019 Permalink | Reply

      We have encountered problems similar to this before, see: Enigma 1108.

      The puzzle can be solved using Catalan’s Triangle [ link ], hence the names Cat and Alan.

      This Python program counts the paths constructively. It runs in 95ms.

      import datetime
      from enigma import (irange, inf, cached, printf)
      
      # count paths from (0, 0) to (x, y) where x =< y
      @cached
      def paths(x, y):
        if x == 0: return 1
        n = paths(x - 1, y)
        if x < y: n += paths(x, y - 1)
        return n
      
      for n in irange(1, inf):
        p = paths(n, n)
        printf("[{n} -> {p} paths]")
        if p < 365: continue
        if p > 538: break
        d = datetime.date(2018, 1, 1) + datetime.timedelta(p)
        printf("first repeat on date = {d}")
      

      Solution: The date of the first repeat was 6th March 2019.


      Instead of counting the paths we can use the formula for Catalan numbers:

      import datetime
      from enigma import (C, irange, inf, printf)
      
      # generalised Catalan numbers
      def catalan(n, k, m=1):
        if k > n + m - 1:
          return 0
        elif 0 <= k < m:
          return C(n + k, n)
        else:
          return C(n + k, k) - C(n + k, k - m)
      
      for n in irange(1, inf):
        p = catalan(n, n)
        printf("[{n} -> {p} paths]")
        if p < 365: continue
        if p > 538: break
        d = datetime.date(2018, 1, 1) + datetime.timedelta(p)
        printf("first repeat on date = {d}")
      

      Like

  • Unknown's avatar

    Jim Randell 12:37 pm on 17 June 2019 Permalink | Reply
    Tags:   

    Teaser 2903: What’s my card? 

    From The Sunday Times, 13th May 2018 [link] [link]

    Four expert logicians play a game with a pack of six cards, numbered from 1 to 6. The cards are shuffled and each draws a card, holding it in front of him so that he cannot see his own number but can see the numbers held by the others. The winner is the player who can first deduce what number he is holding.

    Each player in turn is asked to announce the sum of two numbers that he can see on the other cards. One game started with Alf announcing 6. After a long pause, no-one claimed victory, so Bert then announced 5. There was a significant pause, but before Charlie spoke, someone claimed victory.

    Which cards did Alf and Bert hold, and which cards remained on the table?

    [teaser2903]

     
    • Jim Randell's avatar

      Jim Randell 12:38 pm on 17 June 2019 Permalink | Reply

      I took the “long pause” to mean that no-one can immediately declare victory, and each player can take the fact that no-one can immediately declare victory into account. And even with this additional information no-one can declare victory, and this too can be taken into account, and so on until the process provides no further information to any of the players.

      I took the “significant pause” to mean that no-one can immediately declare victory, and each player can take this fact into account.

      This Python program starts by consider all possible P(6, 4) = 360 ways the cards can be dealt, and then reduces the possibilities as each piece of new information is taken into account.

      It runs in 84ms.

      from enigma import (unpack, subsets, filter_unique, intersect, irange, printf)
      
      # cards for A, B, C, D
      cA = unpack(lambda A, B, C, D: A)
      cB = unpack(lambda A, B, C, D: B)
      cC = unpack(lambda A, B, C, D: C)
      cD = unpack(lambda A, B, C, D: D)
      
      # what A, B, C, D can see
      sA = unpack(lambda A, B, C, D: (B, C, D))
      sB = unpack(lambda A, B, C, D: (A, C, D))
      sC = unpack(lambda A, B, C, D: (A, B, D))
      sD = unpack(lambda A, B, C, D: (A, B, C))
      
      # cards
      cards = set(irange(1, 6))
      
      # start with all possible arrangements of cards for (A, B, C, D)
      r = set(subsets(cards, size=4, select="P"))
      printf("[{n} possibilities]", n=len(r))
      
      # A declares 6, which the value of B+C, B+D or C+D
      r = set((A, B, C, D) for (A, B, C, D) in r if 6 in (B + C, B + D, C + D))
      printf("[{n} possibilities]", n=len(r))
      
      # no-one claims immediate victory
      def unclaimed(r):
        rA = filter_unique(r, sA, cA).non_unique
        rB = filter_unique(r, sB, cB).non_unique
        rC = filter_unique(r, sC, cC).non_unique
        rD = filter_unique(r, sD, cD).non_unique
        return intersect([rA, rB, rC, rD])
      
      # apply filter until the results remain unchanged (according to ==)
      def repeat(fn, x):
        while True:
          x0 = x
          x = fn(x0)
          if x == x0: return x0
      
      # there is a long pause
      # so repeat unclaimed() until there is nothing further eliminated
      r = repeat(unclaimed, r)
      printf("[{n} possibilities]", n=len(r))
      
      # B declares 5, which is the value of A+C, A+D, C+D
      r = set((A, B, C, D) for (A, B, C, D) in r if 5 in (A + C, A + D, C + D))
      printf("[{n} possibilities]", n=len(r))
      
      # at this point no-one claims immediate victory
      r = unclaimed(r)
      printf("[{n} possibilities]", n=len(r))
      
      # so what possibilities are left?
      printf("remaining = {r}")
      
      
      # output possible declarations
      dA = filter_unique(r, sA, cA).unique
      dB = filter_unique(r, sB, cB).unique
      dC = filter_unique(r, sC, cC).unique
      dD = filter_unique(r, sD, cD).unique
      
      for s in r:
        (A, B, C, D) = s
        printf("\nA={A} B={B} C={C} D={D}, table={t}:", t=cards.difference(s))
        if s in dA: printf("  A declares {A}")
        if s in dB: printf("  B declares {B}")
        if s in dC: printf("  C declares {C}")
        if s in dD: printf("  D declares {D}")
      

      Solution: Alf has 3. Bert has 5. The cards remaining on the table are 2 and 6.

      Starting from 360 possibilities the possible hands are reduced as follows:

      Initially, 360 possibilities.
      “A declares 6”, 144 possibilities.
      “there is a long pause”, 48 possibilities.
      “B declares 5”, 20 possibilities.
      “no-one claims immediate victory”, 2 possibilities.

      The two remaining possibilities are (A=3, B=5, C=1, D=4) and (A=3, B=5, C=4, D=1). We don’t know from the information given which order C and D are holding 1 and 4, but each player can see at least one of the cards, so they would know the exact hand dealt, and presumably all four of them would declare victory simultaneously.


      Here is my manual solution:

      A says “6”, so can see 1+5 or 2+4 (3 and 6 cannot participate in any pair that sum to 6)

      If A is holding one of these cards (1, 2, 4, 5) they must be seeing the sum that doesn’t involve their own card. B, C, D can see which card A is holding, so would know which of the sums A is seeing, and so the people who can only see one half of that sum would immediately be able to declare their number (as the other half of that sum). This doesn’t happen.

      Hence A must be holding 3 or 6. And the other card (6 or 3) must still be on the table, as if one of B, C, D were holding it the other two could deduce their cards immediately.

      So B, C, D are holding three cards from 1, 2, 4, 5.

      B says “5”, so can see 1+4 or 2+3.

      If A is holding 6, then 3 is still on the table, so B can see 1+4 from C and D. C and/or D can immediately declare their cards as soon as B says “5”. This doesn’t happen.

      So A can deduce he is holding 3 (and can declare victory, after the pause where neither C nor D declare victory).

      B must be able to see 1+4 (from C and D) or 2+3 (from A’s 3 and one of C and D holds the 2).

      If B is holding 1 or 4, then he must be able to see 2+3, so whichever of C and D cannot see the 2 must be holding it and can declare immediately. This doesn’t happen.

      Similarly if B is holding 2, then he must be able to see 1+4 from C and D, so C and D can declare their cards immediately. This doesn’t happen.

      So B can deduce he is holding 5 (and can declare, after the pause where neither C nor D declare victory).

      This leaves C and D holding two cards from 1, 2, 4, and the other is still on the table (along with 6).

      If C and D are holding 1 and 2, then when B says “5” A would immediately know his card was 3 (which goes with the 2 to make 5). This doesn’t happen.

      If C and D are holding 2 and 4, then when B says “5” A would immediately know his card was 3 (which goes with the 2 to make 5). This doesn’t happen.

      So C and D are holding 1 and 4, and can declare (after the pause where A does not declare victory). 2 and 6 remain on the table.

      Like

    • John Crabtree's avatar

      John Crabtree 3:00 pm on 21 June 2019 Permalink | Reply

      Let a declared value be D.
      If the non-declarers have cards >= D or = D/2, two players can immediately determine their cards.
      If two pairs of cards add to D, two players can immediately determine their cards.

      After A’s call, only A can have and as 1 + 5 = 2 + 4 = 6 must have, 3 or 6
      After B’s call, A must have 3 and, as 1 + 4 = 2 + 3 = 5, B must have 5.
      After B’s call, A knows immediately that he has 3 unless he can see C + D = 5 = 1 + 4.
      The cards on the table are 2 and 6.

      Like

  • Unknown's avatar

    Jim Randell 11:16 pm on 14 June 2019 Permalink | Reply
    Tags:   

    Teaser 2960: Bags of sweets! 

    From The Sunday Times, 16th June 2019 [link] [link]

    I recently bought a number of equally priced bags of sweets for a bargain price, spending more than 50p in total. If they had been priced at 9p less per bag, I could have had 2 bags more for the same sum of money. In addition, if each had cost 12p less than I paid, then I could also have had an exact number of bags for the same sum of money.

    How much did I spend in total on the sweets?

    [teaser2960]

     
    • Jim Randell's avatar

      Jim Randell 11:47 pm on 14 June 2019 Permalink | Reply

      If we buy n bags of sweets at x pence per bag, then the total outlay n.x can be expressed as:

      n.x = (n + 2)(x − 9)
      n.x = k(x − 12)
      n.x > 50

      (for some whole number k, where n > 1).

      From which we see:

      x = (18 + 9n) / 2

      This Python program finds the first value of n that satisfies the conditions and gives an integer value for k.

      Run: [ @repl.it ]

      from enigma import (Rational, irange, inf, div, printf)
      
      Q = Rational()
      
      # consider n the number of bags of sweets bought
      for n in irange(1, inf):
        x = Q(18 + 9 * n, 2)
        t = n * x
        if not (t > 50): continue
      
        # find the number of bags if the prices were 12p less
        k = div(t, x - 12)
        if k is None: continue
      
        printf("{t}p = {n} bags @ {x}p [= {n2} bags @ {x9}p = {k} bags @ {x12}p]", n2=n+2, x9=x-9, x12=x-12)
        break
      

      Solution: The total spend was 216p.


      With a bit more analysis we can show this is the only solution.

      We can write an expression for k as:

      k = 9n(n + 2) / (9n − 6) = n + 8/3 + 16 / (9n − 6)

      And this only gives a whole number when 16 / (9n − 6) has a fractional part of 1/3.

      This is only possible for n = 1, 2, 6.

      n = 1 gives x = 13.5p, n.x = 13.5p, which is not more than 50p (and we want n > 1 anyway).

      n = 2 gives x = 18p, n.x = 36p, which is not more than 50p.

      n = 6 gives x = 36p, n.x = 216p, so this is the solution.

      Here is a program that uses this analysis to consider all possible solutions, by looking at the divisors of 48:

      from enigma import (Rational, divisors, div, printf)
      
      Q = Rational()
      
      # consider divisors of 48
      for d in divisors(48):
        # we only want divisors of the form (3z + 1)
        if not (d % 3 == 1): continue
        # compute n
        n = div(48 // d + 6, 9)
        if n is None: continue
        # compute x and t
        x = Q(18 + 9 * n, 2)
        t = n * x
        if not (t > 50): continue
        # compute k
        k = div(9 * n * (n + 2), 9 * n - 6)
        # output solution
        printf("[d={d}] n={n} x={x} t={t} k={k}")
      

      Removing the check at line 15 will give all three solutions for the equations.

      Like

    • GeoffR's avatar

      GeoffR 6:49 pm on 16 June 2019 Permalink | Reply

      We can put Jim’s initial three equations into a MinZinc constraint for an easy solution

      % A Solution in MiniZinc
      include "globals.mzn";
       
      var 1..50: n;   % no of bags bought originally
      var 1..50: k;   % no bags bought at 12p less
      var 1..100: x;  % original cost per bag (pence)
      
      constraint n * x > 50 /\ n * x == (n + 2) * (x - 9) 
      /\ n * x = k * (x - 12);
      
      solve satisfy;
      output ["Total spent on sweets = " ++ show(n * x) ++ " pence" ];
      

      Like

      • Jim Randell's avatar

        Jim Randell 8:46 am on 17 June 2019 Permalink | Reply

        @GeoffR: This approach works OK for cases where the price per bag is a whole number (which is the case in the actual solution).

        I didn’t assume that and found there were 3 candidate solutions that satisfied the 2 equations, one of which has the bags priced with a fractional amount. Two of the candidates are eliminated by the inequality (including the one where the bags are priced a fractional amount), leaving a single solution.

        Like

    • GeoffR's avatar

      GeoffR 3:12 pm on 17 June 2019 Permalink | Reply

      @Jim: I can see you are making a mathematical point about prices for fractional amounts, but is this applicable for this teaser ?

      We don’t have fractional pennies these days in our monetary system, so maybe we should assume that prices per bag are in whole numbers of pennies ?

      Like

      • Jim Randell's avatar

        Jim Randell 4:56 pm on 18 June 2019 Permalink | Reply

        @GeoffR: It was just a comment to try and extract a bit more interest from a relatively straightforward puzzle.

        I try not to make additional assumptions about the puzzle if I can help it. From the formula for x we see that the price per pack is a whole number of half-pennies, so it seemed reasonable to allow this. And we do get an extra potential solution if we do. Although this solution is then removed by the “more than 50p” requirement, so it doesn’t really matter if we consider it or not.

        Like

  • Unknown's avatar

    Jim Randell 12:41 pm on 13 June 2019 Permalink | Reply
    Tags: by: Simon Porter   

    Brainteaser 1610: Word game 

    From The Sunday Times, 18th July 1993 [link]

    An unusual card game consisted of 12 cards each with a different well-known word of four letters on it. No letter appeared on more than three cards and no two cards had more than one letter in common. The winner was the first person to collect among his or her cards a set of three cards with the same letter on each.

    In one game against George I started and after two goes I had chosen:

    ZEST
    CHEW

    while George had picked up:

    DAWN
    RILE

    (the second to stop me getting a set of three with a common “E“).

    For my third I chose:

    QUAY

    and after George had selected his third card he told me that whatever card I now chose he would certainly win on this next turn.

    I picked up:

    SHIN

    for my fourth card and, as predicted, George chose:

    FLOW

    giving him a winning set.

    The unused cards were:

    CURT
    JUGS
    MOTH
    PARK

    what was George’s third card?

    This puzzle is included in the book Brainteasers (2002). The wording above is taken from the book. It is slightly changed from the original puzzle.

    [teaser1610]

     
    • Jim Randell's avatar

      Jim Randell 12:42 pm on 13 June 2019 Permalink | Reply

      This Python program extracts candidate 4-letters words from the supplied word list, selects those that are permissible according to the given rules, and then looks at each one as a possible third card for George.

      It runs in 391ms, although the run time will depend on the word list used. I used the [[ sowpods.txt ]] word list from Enigma 1195 and Enigma 288a.

      from enigma import (union, printf)
      
      # the known cards
      player1 = [ 'ZEST', 'CHEW', 'QUAY' ]
      player2 = [ 'DAWN', 'RILE' ] # and a mystery card
      remaining = [ 'SHIN', 'FLOW', 'CURT', 'JUGS', 'MOTH', 'PARK' ]
      cards = player1 + player2 + remaining
      
      # "no letter appears on more than three cards"
      # so any letter that appears on three of the known cards cannot appear
      # on the missing card
      inv = set(x for x in union(cards) if sum(x in c for c in cards) > 2)
      
      # look for 4 letter words in the word list
      path = "sowpods.txt"
      words = list()
      for w in open(path).readlines():
        w = w.strip().upper()
        if len(w) == 4:
          # discard words containing letters already on 3 cards
          if inv.intersection(w): continue
          # discard words with more than one letter in common with a known card
          s = set(w)
          if any(len(s.intersection(c)) > 1 for c in cards): continue
          words.append(w)
      printf("[{n} candidate words found]", n=len(words))
      
      # find winning cards from rs for hand hs
      def win(hs, rs):
        # pick up a card
        for w in rs:
          # have we won?
          # i.e. are there two cards in the hand containing a letter on the card?
          for x in set(w):
            if sum(x in h for h in hs) > 1:
              yield w
      
      # consider each candidate word as a possible mystery card
      for w in words:
        # George must be able to win in (at least) 2 ways, one of them using FLOW
        ss = list(win(player2 + [w], remaining))
        if len(ss) > 1 and 'FLOW' in ss:
          printf("{w} -> {ss}", ss=sorted(ss))
      

      Solution: George’s third card was LYNX.

      George is holding:

      DAWN
      RILE
      LYNX

      There are two cards with L and two cards with N.

      Picking FLOW will give a set of 3 cards with L, and picking SHIN will give a set of 3 cards with N.

      Like

  • Unknown's avatar

    Jim Randell 2:15 pm on 12 June 2019 Permalink | Reply
    Tags:   

    Teaser 2904: Catching another bus 

    From The Sunday Times, 20th May 2018 [link] [link]

    I want to catch a bus into town, and I arrive at the bus stop at a random time.

    The number 12 bus runs every 12 minutes, the number 15 bus runs every 15 minutes and the number 20 bus runs every 20 minutes.

    All the buses leave the bus stop at an exact number of minutes past the hour and no two buses leave at the same time. Interestingly, given the above information, the probability that I catch a number 12 bus is as small as it possibly could be.

    What is the probability that I catch a number 12 bus?

    [teaser2904]

     
    • Jim Randell's avatar

      Jim Randell 2:16 pm on 12 June 2019 Permalink | Reply

      The period between each type of bus exactly divides 60, so in any hour period the pattern of buses is the same as the previous hour.

      So if we make a timetable of the buses, as no buses arrive at the same time, the periods in between buses arriving is spent waiting for the next bus, so by examining the gaps between buses we can determine the proportions of the hour spent waiting for each type of bus.

      This Python program runs in 76ms.

      Run: [ @repl.it ]

      from enigma import (irange, update, tuples, Accumulator, unpack, fraction, printf)
      
      # period we are interested in (60 minutes)
      T = 60
      
      # generate timetables for a bus leaving at intervals of <t>
      # that doesn't coincide with the times in <d>
      # yield: (<t0>, <d1>), where:
      # t0 = earliest time for the bus
      # d1 = updated cumulative timetable
      def generate(t, d):
        for t0 in irange(0, t - 1):
          ks = list(irange(t0, T - 1, step=t))
          if any(k in d for k in ks): continue
          yield (t0, update(d, ((k, t) for k in ks)))
      
      # find minimum wait for #12 bus
      r = Accumulator(fn=min)
      
      # suppose the #20 bus leaves at t=0
      t20 = 0
      ts1 = dict((t, 20) for t in irange(t20, T - 1, step=20))
      
      # consider the time the first #15 bus leaves
      for (t15, ts2) in generate(15, ts1):
      
        # consider the time the first #12 bus leaves
        for (t12, ts3) in generate(12, ts2):
      
          # make the timeline
          ts = sorted(ts3.items(), key=unpack(lambda t, n: t))
          (t, n) = ts[0]
          ts.append((t + T, n))
      
          # count the total waits for each type of bus
          w = { 12: 0, 15: 0, 20: 0 }
          for ((t1, _), (t2, n)) in tuples(ts, 2):
            w[n] += t2 - t1
          r.accumulate_data(w[12], (t12, t15, t20))
      
      # output minimal solution
      (a, b) = fraction(r.value, T)
      printf("min P(12) = {a}/{b} [{r.data}]")
      

      Solution: The probability of catching a number 12 bus is 7/20.

      If we start the hour when a #20 bus is at the stop, then the #20 buses arrive at: +0, +20, +40, +60.

      The first #12 bus arrives at +5 minutes, so has a timetable of: +5, +17, +29, +41, +53.

      The first #15 bus arrives at +13 minutes, so has a timetable of: +13, +28, +43, +58.

      So the timetable looks like this:

      +00: #20 bus
      (5 minute wait for #12 bus)
      +05: #12 bus
      (8 minute wait for #15 bus)
      +13: #15 bus
      (4 minute wait for #12 bus)
      +17: #12 bus
      (3 minute wait for #20 bus)
      +20: #20 bus
      (8 minute wait for #15 bus)
      +28: #15 bus
      (1 minute wait for #12 bus)
      +29: #12 bus
      (11 minute wait for #20 bus)
      +40: #20 bus
      (1 minute wait for #12 bus)
      +41: #12 bus
      (2 minute wait for #15 bus)
      +43: #15 bus
      (10 minute wait for #12 bus)
      +53: #12 bus
      (5 minute wait for #15 bus)
      +58: #15 bus
      (2 minute wait for #20 bus)
      +60: #20 bus

      Adding the waiting times for each type of bus we get:

      21 minutes for #12 bus
      23 minutes for #15 bus
      16 minutes for #20 bus

      So if we arrive at a random time during the hour the probability the next bus is #12 is 21/60 = 7/20.

      Like

  • Unknown's avatar

    Jim Randell 9:15 am on 11 June 2019 Permalink | Reply
    Tags:   

    Brain-Teaser 483: Absentees 

    From The Sunday Times, 30th August 1970 [link]

    Only seven men still had ammunition. Aden had 1 round, Bill 2 rounds, Cuff 3, Dudd 4, Edge 5, Ford 6 and Good 7. The commander ordered there should always be five of the seven men on duty and that the duty roster should be so arranged that those on duty never had fewer than 17 rounds of ammunition.

    Next day he was told that only four men were on duty. It appeared that three of the five who should have been present were sick and that the four doing duty included two who should have been off. It so happened that the four had between them the same number of rounds as the five would have had.

    The commander had no copy of the duty roster, but he knew how many rounds each of the seven men had.

    He asked how many rounds the four men doing duty had between them. When given the figure the commander said, after some thought, that he could say with certainty who the three absentees were.

    Can you name them?

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

    [teaser483]

     
    • Jim Randell's avatar

      Jim Randell 9:16 am on 11 June 2019 Permalink | Reply

      We can identify the men by the number of rounds each man has.

      Three men are sick, and two provide cover. The remaining two were scheduled to be on duty and actually were on duty.

      This Python program runs in 81ms.

      Run: [ @repl.it ]

      from enigma import (irange, subsets, diff, filter_unique, unpack, printf)
      
      # the numbers of rounds available
      rounds = list(irange(1, 7))
      
      # generate possible (<number of rounds>, <sick>, <cover>)
      def generate():
        T = sum(rounds)
      
        # consider the 3 sick men
        for sick in subsets(rounds, size=3):
          # the number of rounds amongst the sick men is...
          n = sum(sick)
          # and so the total number of rounds on duty is...
          t = T - n
          if (t < 17): continue
          # find 2 men to cover with the same number of rounds
          for cover in subsets(diff(rounds, sick), size=2):
            if not (sum(cover) == n): continue
            yield (t, sick, cover)
      
      # find solutions where...
      (ss, _) = filter_unique(
        generate(),
        # ... if I knew the total number of rounds ...
        unpack(lambda t, s, c: t),
        # ... I could deduce who was sick
        unpack(lambda t, s, c: s),
      )
      
      # output solutions
      for (t, s, c) in ss:
        printf("{t} rounds -> sick = {s}, cover = {c}")
      

      Solution: The three absentees are Aden, Cuff and Dudd.

      A, C, D have 1+3+4 = 8 rounds between them, and are covered by B and F, who also have 2+6 = 8 rounds between them.

      The remaining 2 men, E and G, with 5 + 7 = 12 rounds between them were scheduled to be on duty and were not sick.

      So altogether there were 8 + 12 = 20 rounds on duty.

      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