Tagged: by: Bob Walker Toggle Comment Threads | Keyboard Shortcuts

  • Unknown's avatar

    Jim Randell 9:08 am on 28 November 2025 Permalink | Reply
    Tags: by: Bob Walker   

    Teaser 2474: [Flipping counters] 

    From The Sunday Times, 21st February 2010 [link]

    Imagine that you have 64 small round counters, black on one side and white on the other, and you have to place them all on the different squares of a chessboard, so that those on the black squares all finish white side up and those on the white squares finish black side up.

    Note that as each counter is placed on the chessboard, you must turn over any counters already on the two, three or four adjacent squares.

    In completing this task, how many times would you turn counters over?

    This puzzle was originally published with no title.

    [teaser2474]

     
    • Jim Randell's avatar

      Jim Randell 9:10 am on 28 November 2025 Permalink | Reply

      (See also: Enigma 1256, Enigma 1767, both also set by Bob Walker).

      For an N×M array, counters will be turned over N×(M − 1) + M×(N − 1) times. In this case N = M = 8.

      Solution: 112 counters are turned over.

      We can use the code from Enigma 1767 to generate a sequence of moves for an 8×8 grid:

      % python3 enigma1767b.py 8 8
      64: [63, 62, 61, 60, 59, 58, 57, 55, 54, 53, 52, 51, 50, 49, 48, 56, 47, 46, 45, 44, 43, 42, 41, 39, 38, 37, 36, 35, 34, 33, 32, 40, 31, 30, 29, 28, 27, 26, 25, 23, 22, 21, 20, 19, 18, 17, 16, 24, 8, 9, 10, 11, 12, 13, 14, 7, 15, 5, 6, 3, 4, 1, 2, 0]
      

      At the end of this procedure each counter is placed, and then turned over 0 or 2 times. So when we first place a counter we do so with the desired final face uppermost.

      Like

  • Unknown's avatar

    Jim Randell 6:45 am on 24 April 2025 Permalink | Reply
    Tags: by: Bob Walker   

    Teaser 2555: Today’s value 

    From The Sunday Times, 11th September 2011 [link] [link]

    These 10 children’s bricks are numbered from 1 to 10. Where a brick rests on two others its number is the difference of their two numbers. Given that U = 1 …

    What is the number DAY?

    [teaser2555]

     
    • Jim Randell's avatar

      Jim Randell 6:46 am on 24 April 2025 Permalink | Reply

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

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

      #! python3 -m enigma -rr
      
      SubstitutedExpression
      
      # numbers range from 1 to 10
      --base=11
      --digits="1-10"
      
      "abs(U - N) = S"
      "abs(D - A) = U"
      "abs(A - Y) = N"
      "abs(T - I) = D"
      "abs(I - M) = A"
      "abs(M - E) = Y"
      
      --assign="U,1"
      --answer="(D, A, Y)"
      
      --template=""
      

      Solution: DAY = 672.

      At least the digits have values: D = 6, A = 7, Y = 2.

      But since the digits go from 1 to 10, you could argue that the result is expressed in base 11, so:

      DAY = 672 [base 11] = 805 [base 10]

      Like

      • Ruud's avatar

        Ruud 6:14 am on 28 April 2025 Permalink | Reply

        Brute force one liner:

        import itertools
        
        print(
            *(
                f"{d}{a}{y}"
                for s, n, d, a, y, t, i, m, e in itertools.permutations(range(2, 11), 9)
                if s == abs(1 - n) and 1 == abs(d - a) and n == abs(a - y) and d == abs(t - i) and a == abs(i - m) and y == abs(m - e)
            )
        )
        

        Like

    • Frits's avatar

      Frits 10:51 am on 26 April 2025 Permalink | Reply

      #    S
      #   U N                            U = 1
      #  D A Y
      # T I M E
      
      sols = set()
      U, mx = 1, 10
      r0 = set(range(2, mx + 1)) # remaining digits to use
      
      for N in range(2, mx - 1):  # no using <mx - 1> and <mx> on this level
        S = N - U
        r1 = r0 - {N, S}
        if len(r1) != len(r0) - 2: continue
        for A in r1 - {mx}:       
          r2 = r1 - {A}
          for D in (A - U, A + U):
            if D not in r2 or D == mx: continue
            r3 = r2 - {D}
            for Y in (A - N, A + N):
              if Y not in r3 or Y == mx: continue
              r4 = r3 - {Y}
              if max(r4) - min(r4) < max(D, A, Y): continue
              for I in r4:
                for M in (I - A, I + A):
                  if M not in r4: continue
                  for T in (I - D, I + D):
                    if T not in r4: continue
                    for E in (M - Y, M + Y):
                      if {T, I, M, E} != r4: continue
                      sols.add(100 * D + 10 * A + Y)
      
      print("answer(s):", ' or '.join(str(s) for s in sols))
      

      Like

  • Unknown's avatar

    Jim Randell 9:49 am on 25 February 2025 Permalink | Reply
    Tags: by: Bob Walker   

    Teaser 2504: [Hidden crosses] 

    From The Sunday Times, 19th September 2010 [link] [link]

    Here are 18 black cards and there is a cross on the back of some of them.

    The clue in any gap indicates how many crosses there are on cards that are adjacent to that gap.

    How many black cards have a cross on them?

    This puzzle was originally published with no title.

    [teaser2504]

     
    • Jim Randell's avatar

      Jim Randell 9:50 am on 25 February 2025 Permalink | Reply

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

      It runs in 80ms. (And the internal runtime of the generated program is just 53µs).

      #! python3 -m enigma -rr
      
      SubstitutedExpression
      
      #  +---+---+---+---+---+---+
      #  | A |   | B |   | C |!=0|
      #  +---+---+---+---+---+---+
      #  | 1 | D | >2| E | <2| F |
      #  +---+---+---+---+---+---+
      #  | G |   | H |!=1| I |   |
      #  +---+---+---+---+---+---+
      #  |   | J |   | K | >1| L |
      #  +---+---+---+---+---+---+
      #  | M | >2| N |!=3| P |   |
      #  +---+---+---+---+---+---+
      #  |!=2| Q |   | R | =1| S |
      #  +---+---+---+---+---+---+
      
      --distinct=""
      --digits="0,1"
      
      # the clues
      "C + F != 0"
      "A + D + G = 1"
      "B + D + E + H > 2"
      "C + E + F + I < 2"
      "E + H + I + K != 1"
      "I + K + L + P > 1"
      "J + M + N + Q > 2"
      "K + N + P + R != 3"
      "M + Q != 2"
      "P + R + S = 1"
      
      --answer="sum([A, B, C, D, E, F, G, H, I, J, K, L, M, N, P, Q, R, S])"
      --template=""
      

      Solution: 10 of the black cards have a cross on them.

      There are 4 possible arrangements, that can be summarised as follows:

      8 of the crosses are marked X, and the remaining 2 crosses appear in squares marked a and b.

      Like

    • ruudvanderham's avatar

      ruudvanderham 12:26 pm on 1 March 2025 Permalink | Reply

      import itertools
      
      
      def s(*args):
          return sum(a[arg] for arg in args)
      
      
      for a in itertools.product((0, 1), repeat=18):
          if (
              s(2, 5) != 0
              and s(0, 3, 6) == 1
              and s(1, 3, 4, 7) > 2
              and s(2, 4, 5, 8) < 2
              and s(4, 7, 8, 10) != 1
              and s(8, 10, 11, 14) > 1
              and s(9, 12, 13, 15) > 2
              and s(10, 13, 14, 16) != 3
              and s(12, 15) != 2
              and s(14, 16, 17) == 1
          ):
              print(a, sum(a))
      

      Like

  • Unknown's avatar

    Jim Randell 11:10 am on 8 October 2024 Permalink | Reply
    Tags: by: Bob Walker   

    Teaser 2580: Hard times 

    From The Sunday Times, 4th March 2012 [link] [link]

    Penny found a multiplication table in the back of one of Joe’s old school books – the top corner of it is illustrated. She noticed that prime numbers only appeared twice in the body of the table, whereas 4 (for example) appeared 3 times and 12 appeared 6 times. Penny could not help wondering how many times large numbers appeared in a huge table.

    What is the smallest number that will appear 250 times?

    Note: In this puzzle we are looking for exact numbers of appearances (rather than minimum number of appearances).

    [teaser2580]

     
    • Jim Randell's avatar

      Jim Randell 11:11 am on 8 October 2024 Permalink | Reply

      See also: Teaser 11.

      Here is a straightforward, but slow solution. It runs in 7.6s (using PyPy):

      from enigma import (irange, inf, tau, arg, printf)
      
      N = arg(250, 0, int)
      
      for n in irange(1, inf):
        if tau(n) == N:
          printf("{N} divisors -> n = {n}")
          break
      

      Solution: The first number to appear exactly 250 times is: 5670000.

      5670000 = (2^4)(3^4)(5^4)(7)

      Although this is not the first number to appear at least 250 times. That is: 1081080, which appears 256 times.

      1081080 = (2^3)(3^3)(5)(7)(11)(13)


      However, with a bit more work we can come up with a much faster program:

      If n has divisors d1, …, dk then it will appear at the following positions in the table:

      d1 × d1
      d2 × d2

      dk × dk

      (where dj = n / dj).

      So n appears k times if it has k divisors.

      And if a number is expressed as a product of its prime factors:

      n = (p1^e1) × (p2^e2) × … × (pk^ek) = ∏(pj^ej)

      Then each prime pj can appear 0 to ej times, hence the number of different divisors is:

      tau(n) = (e1 + 1) × (e2 + 1) × … × (ek + 1) = ∏(ej + 1)

      We are looking for a number with exactly 250 divisors, so we can look at possible factorisations of 250.

      So, for example, if we factorise 250 as:

      250 = a × b × c

      Then any number of the form:

      p1^(a − 1) × p2^(b − 1) × p3^(c − 1)

      (for primes p1, p2, p3) will have exactly 250 divisors.

      So, by considering the possible factorisations of 250, and using the smallest primes, we can find the smallest candidate number for each factorisation, and then choose the smallest of the candidate numbers found. (Often, but not always, the smallest number is given by the prime factorisation of the original number).

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

      from enigma import (Accumulator, primes, trim, rev, multiply, arg, printf)
      
      # number of divisors to find
      N = arg(250, 0, int)
      
      # find factorisations of <n> using divisors <ds>
      def _factorisations(n, ds, i, ss=[]):
        # are we done?
        if n == 1:
          yield tuple(ss)
        else:
          # look for the next divisor
          while i >= 0:
            d = ds[i]
            if n >= d:
              (r, x) = divmod(n, d)
              if x == 0:
                yield from _factorisations(r, ds, i, [d] + ss)
            i -= 1
      
      # find factorisations of <n> (aka multiplicative partitions)
      def factorisations(n):
        # always return the trivial factorisation
        yield (n,)
        if n < 4: return
        # look for other factorisations using divisors (other than 1 and n)
        ds = trim(primes.divisors(n), head=1, tail=1)
        yield from _factorisations(n, ds, len(ds) - 1)
      
      # find smallest number with k divisors
      def solve(k):
        # consider factorisations of k
        r = Accumulator(fn=min)
        for ds in factorisations(k):
          # pair the largest powers with the smallest primes
          n = multiply(p**(x - 1) for (p, x) in zip(primes, rev(ds)))
          r.accumulate(n)
        return r.value
      
      n = solve(N)
      printf("{N} divisors -> n = {n}")
      assert primes.tau(n) == N
      

      The [[ factorisations() ]] function will appear in the next release of the enigma.py library.

      Like

  • Unknown's avatar

    Jim Randell 3:43 pm on 30 April 2023 Permalink | Reply
    Tags: by: Bob Walker   

    Teaser 2406: [Powers of three] 

    From The Sunday Times, 2nd November 2008 [link]

    For a school project, Penny was investigating the powers of 3. She wrote some down and explained to Joe that the first power was 3, the second power was 9, the third power was 27, and so on. Soon the numbers were in the millions and Joe asked how close to a whole number of millions one of the high powers could be.

    Simply by some clever logic and algebra Penny was soon able to answer the question. She also found the lowest power of 3 that actually came that close.

    Which power (e.g. 248th) was it?

    This puzzle was originally published with no title.

    [teaser2406]

     
    • Jim Randell's avatar

      Jim Randell 3:44 pm on 30 April 2023 Permalink | Reply

      For positive integers k we have 3^k is an odd number, so we are never going to land on an exact number of millions.

      But if we consider the sequence:

      a[k] = (3^k) mod 1000000

      Then it will form a repeating sequence of values, all less than a million. So we can calculate a[k] for increasing k, until we see a repeated value, and that will tell us where 3^k is closest to an exact million.

      This Python program runs in 96ms. (Internal runtime is 41ms).

      Run: [ @replit ]

      from enigma import (Accumulator, divr, number, arg, printf)
      
      M = number(arg("1_000_000", 0))  # M is the modulus
      n = arg(3, 1, int)  # n is the base
      
      # find the closest value (= smallest delta)
      r = Accumulator(fn=min, collect=1)
      
      # consider increasing powers of n mod M
      (p, k, a) = (1, 0, dict())
      while True:
        p *= n
        p %= M
        k += 1
        # have we already seen this residue?
        if p in a:
          # calculate the period
          printf("[period = {d}]", d=k - a[p])
          break
        # otherwise, record the value
        a[p] = k
        if r.count > 0 or divr(pow(n, k), M) > 0:
          r.accumulate_data(min(p, M - p), k)
      
      # output solution
      for k in r.data:
        printf("{n}^{k} mod {M} = {x} [delta = {r.value}]", x=pow(n, k, M))
      

      Solution: The lowest power of 3 that comes closest to an exact million is the 50,000th.

      We have:

      >>> pow(3, 50_000, 1_000_000)
      1
      

      In fact 3^50000 is a 23,857 digit number: 1155409630…2761000001.

      And we see that the sequence has a period of 50,000, so:

      >>> pow(3, 50_000 * 2, 1_000_000)
      1
      >>> pow(3, 50_000 * 3, 1_000_000)
      1
      >>> pow(3, 50_000 * 117, 1_000_000)
      1
      

      And of course, we have a[0] = 1.


      It is not possible for a power of 3 to be −1 (mod 10^6), which we can see by calculating values of 3^k mod 100. There are only 20 possible values, and 99 never occurs.

      But we can use Euler’s Theorem [@wikipedia] to determine that there is some value k such that:

      3^k (mod 10^6) = 1

      (as 10^6 and 3 are co-prime).

      And we can calculate one possible value of k using Euler’s totient function [@wikipedia] as φ(10^6).

      However this is not necessarily the smallest value of k (although Lagrange’s theorem [@wikipedia] tells that the smallest value of k must divide φ(10^6)).

      But we can calculate the required value with a relatively modest amount of calculation.

      If we consider the powers of 3^k mod 10^n, we find that when n = 1 we have:

      mod 10:
      3^1 = 3
      3^2 = 3×3 = 9
      3^3 = 9×3 = 7
      3^4 = 7×3 = 1

      So every a[4k] = 1 (mod 10).

      For n = 2 we can just look at 3^(4k) mod 100:

      mod 100:
      3^4 = 81
      3^8 = 81×81= 61
      3^12 = 61×81 = 41
      3^16 = 41×81 = 21
      3^20 = 21×81 = 1

      So every a[20k] = 1 (mod 100).

      For n = 3:

      mod 1000:
      3^20 = 401
      3^40 = 401×401 = 801
      3^60 = 801×401 = 201
      3^80 = 201×401 = 601
      3^100 = 601×401 = 1

      So every a[100k] = 1 (mod 1000).

      For n = 4:

      mod 10000:
      3^100 = 2001
      3^200 = 2001×2001 = 4001
      3^300 = 4001×2001 = 6001
      3^400 = 6001×2001 = 8001
      3^500 = 8001×2001 = 1

      So every a[500k] = 1 (mod 10000).

      For n = 5:

      mod 100000:
      3^500 = 10001
      3^1000 = 10001×10001 = 20001
      3^1500 = 20001×10001 = 30001
      3^2000 = 30001×10001 = 40001
      3^2500 = 40001×10001 = 50001
      3^3000 = 50001×10001 = 60001
      3^3500 = 60001×10001 = 70001
      3^4000 = 70001×10001 = 80001
      3^4500 = 80001×10001 = 90001
      3^5000 = 90001×10001 = 1

      So every a[5000k] = 1 (mod 100000).

      For n = 6:

      mod 1000000:
      3^5000 = 100001
      3^10000 = 100001×100001 = 200001
      3^15000 = 200001×100001 = 300001
      3^20000 = 300001×100001 = 400001
      3^25000 = 400001×100001 = 500001
      3^30000 = 500001×100001 = 600001
      3^35000 = 600001×100001 = 700001
      3^40000 = 700001×100001 = 800001
      3^45000 = 800001×100001 = 900001
      3^50000 = 900001×100001 = 1

      So every a[50000k] = 1 (mod 1000000).

      And this provides our answer.


      Or using Euler’s totient function (as mentioned above).

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

      Run: [ @replit ]

      from enigma import (prime_factor, divisors, number, arg, printf)
      
      # Euler's totient function
      def phi(n):
        t = n
        for (p, _) in prime_factor(n):
          t -= t // p
        return t
      
      M = number(arg("1_000_000", 0))  # M is the modulus
      n = arg(3, 1, int)  # n is the base
      
      # the order of the multiplicative group of integers modulo M is ...
      m = phi(M)
      printf("[phi({M}) = {m}]")
      
      # Lagrange's Theorem = "The smallest k such that a^k = 1 (mod M) divides m"
      # look for the smallest value ...
      for k in divisors(m):
        if pow(n, k, M) == 1:
          printf("{n}^{k} mod {M} = 1")
          break
      

      Like

      • Jim Randell's avatar

        Jim Randell 2:16 pm on 1 May 2023 Permalink | Reply

        In fact we can be a bit cleverer by solving the equivalent problem for the prime factors of the modulus, and then the required result is the lowest common multiple of these exponents.

        Run: [ @replit ]

        from enigma import (prime_factor, divisors, mlcm, gcd, number, arg, printf)
        
        # calculate the totient of p^k, for prime p
        phi_pk = lambda p, k: pow(p, k - 1) * (p - 1)
        
        def solve(n, M):
          assert gcd(n, M) == 1
          # collect exponents for prime factors of the modulus
          ks = list()
          for (p, e) in prime_factor(M):
            f = pow(p, e)
            for k in divisors(phi_pk(p, e)):
              if pow(n, k, f) == 1:
                ks.append(k)
                break
          return mlcm(*ks)
        
        M= number(arg("1_000_000", 0))  # M is the modulus
        n = arg(3, 1, int)  # n is the base
        
        k = solve(n, M)
        r = pow(n, k, M)
        printf("{n}^{k} mod {M} = {r}")
        assert r == 1
        

        Like

  • Unknown's avatar

    Jim Randell 9:22 am on 16 June 2022 Permalink | Reply
    Tags: by: Bob Walker   

    Teaser 2499: [Supermarket milk] 

    From The Sunday Times, 15th August 2010 [link] [link]

    Joe was talking to the supermarket manager about shelf stocking, and she mentioned a recent exercise with milk. Each morning, they added sufficient new stock to ensure there were 1,200 litres on the shelves. They found that 56% of the new stock was sold on the first day, half that amount the next day and half that new amount the day after. Any remaining stock was regarded as out of date and removed next morning before restocking. Hence, they calculated the number of litres to be added each morning.

    What is that number?

    This puzzle was originally published with no title.

    [teaser2499]

     
    • Jim Randell's avatar

      Jim Randell 9:23 am on 16 June 2022 Permalink | Reply

      I assumed that the numbers are fixed. So the same quantity of fresh milk is added each day, and the same quantities sold each day.

      If x litres of fresh milk are stocked at the beginning of the day (to bring the total stocks to 1200 litres).

      We can track what happens to this batch milk on the following days.

      At the start of the next day 0.56x has been sold, so there is only 0.44x of this batch of milk remaining (and a new batch of x litres of fresh milk are added).

      At the start of the next day an additional 0.28x has been sold, so there is only 0.16x of the original batch remaining (along with 0.44x litres of the previous days new batch, and x litres of fresh milk).

      At the start of the next day an additional 0.14x has been sold, so there is only 0.02x of the original batch remaining, but this is removed as it is too old.

      So the 1200 litres of milk on the shelves consists of:

      x litres of fresh milk
      0.44x litres of 1-day old milk
      0.16x litres of 2-day old milk

      Hence:

      x + 0.44x + 0.16x = 1200
      1.6x = 1200
      x = 750

      Solution: Each morning 750 litres of fresh milk are added to the shelves.

      So the milk available at the start of the day consists of:

      750 litres of fresh milk (420 litres are sold during the day, leaving …)
      330 litres of 1-day old milk (210 litres are sold during the day, leaving …)
      120 litres of 2-day old milk (105 litres are sold during the day, leaving 15 litres to dispose of)
      1200 litres in total (735 litres sold)

      Like

    • Hugh+Casement's avatar

      Hugh+Casement 8:55 am on 17 June 2022 Permalink | Reply

      That’s some supermarket! How ever many metres of shelf space do 1200 litres take up?
      I suggest that a more realistic puzzle would have all the numbers a fifteenth as much.

      Like

  • Unknown's avatar

    Jim Randell 9:02 am on 20 October 2020 Permalink | Reply
    Tags: by: Bob Walker   

    Teaser 1917: Trick shots 

    From The Sunday Times, 13th June 1999 [link]

    Joe’s billiard table is of high quality but slightly oversized. It is 14 ½ feet long by 7 feet wide, with the usual six pockets, one in each corner and one in the middle of each long side.

    Joe’s ego is also slightly oversized and he likes to show off with his trick shots. One of the most spectacular is to place a ball at a point equidistant from each of the longer sides and 19 inches from the end nearest to him. He then strikes the ball so that it bounces once off each of the four sides and into the middle pocket on his left.

    He has found that he has a choice of directions in which to hit the ball in order the achieve this effect.

    (a) How many different directions will work?
    (b) How far does the ball travel in each case?

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

    [teaser1917]

     
    • Jim Randell's avatar

      Jim Randell 9:03 am on 20 October 2020 Permalink | Reply

      As with beams of light, it is easier to mirror the table and allow the ball to travel in a straight line. (See: Enigma 1039, Enigma 1532, Teaser 2503).

      If we mirror the table along all four sides we get a grid-like pattern of tables and the path of the ball becomes a straight line between the source and the target pocket.

      The line must cross each colour side once. So vertically it must cross a green and a red (in some order) before ending up in the pocket. Which means only an upward line will do. Horizontally it must cross an orange and a blue line before hitting the pocket. The two possible paths are indicated in this diagram:

      We can then calculate the distances involved. In both cases the vertical distance is 2.5 widths = 210 inches.

      And the horizontal distances are: 2.5 lengths − 19 inches = 416 inches, and: 1.5 lengths + 19 inches = 280 inches.

      The required distances are then:

      >>> hypot(210, 416)
      466.0
      >>> hypot(210, 280)
      350.0
      

      Solution: (a) There are 2 directions which will work; (b) In once case the ball travels: 38 feet, 10 inches; in the other case: 29 feet, 2 inches.

      The paths of the ball on the table look like this:


      Like

  • Unknown's avatar

    Jim Randell 9:57 am on 18 October 2019 Permalink | Reply
    Tags: by: Bob Walker   

    Teaser 2821: Magic cards 

    From The Sunday Times, 16th October 2016 [link] [link]

     Joe placed nine cards on the table to form the magic square shown on the left below (where each row, column and diagonal has the same total). Then he turned over each card one at a time and the result is shown on the right below: it is not magic.

    Penny then rearranged the cards to form a magic square which, after each card was turned over, was also magic.

    What (in increasing order) were the four corner numbers in her magic square with the higher total?

    [teaser2821]

     
    • Jim Randell's avatar

      Jim Randell 9:58 am on 18 October 2019 Permalink | Reply

      A magic square can be characterised using three variables: x, y, z as the sums:

      
      a = x+y       | b = x+z+z | c = x+y+y+z
      --------------+-----------+------------
      d = x+y+y+z+z | e = x+y+z | f = x
      --------------+-----------+------------
      g = x+z       | h = x+y+y | i = x+y+z+z
      
      

      Each row, column, and diagonal combine to give 3(x+y+z) = the magic constant.

      Given values for a, e, f we can derive: x = f, y = a − f, z = e − a and generate the complete square.

      This Python program solves the puzzle in 87ms.

      Run: [ @replit ]

      from enigma import (unpack, div, subsets, cproduct, printf)
      
      # make an additive magic square (a b c d e f g h i) given (a e f)
      def magic(a, e, f):
        (x, y, z) = (f, a - f, e - a)
        return (
          x + y, x + z + z, x + y + y + z,
          x + y + y + z + z, x + y + z, x,
          x + z, x + y + y, x + y + z + z,
        )
      
      # is a magic square canonical? (a < c, g, i; b < d)
      is_canonical = unpack(lambda a, b, c, d, e, f, g, h, i: a < min(c, g, i) and b < d)
      
      # the cards are all different, so can stand for themselves
      # (here we list them in canonical sorted order)
      cards = [ (1, 12), (2, 7), (3, 9), (3, 13), (4, 7), (4, 11), (5, 14), (6, 8), (8, 9) ]
      
      # consider a card both ways up
      flips = unpack(lambda x, y: ((x, y), (y, x)))
      
      # we arrange the cards as:
      #
      #   a1 b1 c1    a2 b2 c2
      #   d1 e1 f1    d2 e2 f2
      #   g1 h1 i1    g2 h2 i2
      
      # the centre card must have a sum of s
      s = div(sum(x + y for (x, y) in cards), 9)
      assert s is not None
      
      # find a card with the right sum for the e's
      for (k, (e2, e1)) in enumerate(cards):
        if not (e1 + e2 == s): continue
      
        # choose cards for the a's and the f's
        for (a, f) in subsets(cards[:k] + cards[k + 1:], size=2, select="P"):
          for ((a1, a2), (f1, f2)) in cproduct([flips(a), flips(f)]):
            # and generate the squares
            s1 = magic(a1, e1, f1)
            if not is_canonical(s1): continue
            s2 = magic(a2, e2, f2)
            # check the corresponding cards
            cs = sorted(min(flips(c)) for c in zip(s1, s2))
            if cs != cards: continue
            # collect the corners (a, c, g, i)
            corners = sorted(s1[x] for x in (0, 2, 6, 8))
            printf("corners={corners} [s1={s1} s2={s2}]")
      

      Solution: The four corner squares are: 3, 7, 9, 13.

      The magic constant in the first square is 24, in the second square it is 18.

      Like

  • Unknown's avatar

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

    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 7:08 am on 21 March 2019 Permalink | Reply
    Tags: by: Bob Walker   

    Teaser 1986: Protracted calculation 

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

    In the circle illustrated the numbers represent the sizes of the sectors:

    By combining adjacent ones it is possible to find sectors in this circle of sizes 1, 2, 3, … all the way up to 13 (13 being the whole circle). For example:

    7 = 4 + 1 + 2.

    In a similar fashion, given a circle divided into five sectors in a particular way, it is possible to combine adjacent sectors to give sizes 1, 2, 3, … up to the biggest possible in the circumstances.

    What, in increasing order, are the sizes of the five sectors?

    The text of this puzzle is taken from the book Brainteasers (2002), the wording differs only slightly from the puzzle originally published in the newspaper.

    [teaser1986]

     
    • Jim Randell's avatar

      Jim Randell 7:09 am on 21 March 2019 Permalink | Reply

      If the circle is divided into k sectors, then for each starting sector (and there are k of them) we can make a contiguous region consisting of 1, 2, 3, …, (k − 1) sectors. We don’t make a region of k sectors because that is the whole circle, so we add that in separately giving a total number of arrangements of:

      n(k) = k(k − 1) + 1 = k² − k + 1

      To make the arrangements correspond to the numbers 1, 2, 3, … n(k), the whole circle needs to correspond to the value n(k), and there needs to be a single sector corresponding to the number 1. So we place the number 1 in the first sector, and then distribute the remaining (n(k) − 1) between the remaining (k − 1) sectors.

      This Python 3 program finds the solution in 83ms.

      Run: [ @replit ]

      from itertools import permutations
      from enigma import (irange, arg, printf)
      
      # generate (non-empty) tuples of adjacent sectors
      def sectors(k):
        # consider n consecutive sectors
        for n in irange(1, k - 1):
          # possible start sector
          for i in irange(0, k - 1):
            yield tuple((i + j) % k for j in irange(0, n - 1))
        # the whole circle
        yield tuple(irange(0, k - 1))
      
      # decompose <t> into <n> different numbers, min <m>
      def decompose(t, n, m, s=[]):
        if n == 1:
          if not (t < m):
            yield s + [t]
        else:
          for x in irange(m, t - n):
            yield from decompose(t - x, n - 1, x + 1, s + [x])
      
      # number of sectors to divide the circle into
      k = arg(5, 0, int, prompt="number of sectors")
      assert k > 1
      
      # make a list of adjacent sectors
      ss = list(sectors(k))
      t = len(ss)
      printf("[k={k}: {t} arrangements]")
      
      # put 1 at sector 0, and decompose the remainder
      for d in decompose(t - 1, k - 1, 2):
        for p in permutations(d):
          if p[0] > p[-1]: continue
          s = (1,) + p
          # calculate the values of adjacent sectors
          vs = set(sum(s[i] for i in x) for x in ss)
          if len(vs) == t:
            printf("{s}")
      

      Solution: The five sectors have values: 1, 2, 3, 5, 10 (in numerical order).

      They can be arranged like this:

      As well as the example given it is also possible to make a circle with 4 sectors using the values: 1, 3, 2, 7.

      The program is suitable for experimenting with small values of k. (One simple way to improve the program is to note that as well as a 1 sector, we will also need a 2 sector in the remaining decomposition).

      Here are the number of solutions for various values of k:

       k  n(k)  solutions
       1     1    1
       2     3    1
       3     7    1
       4    13    2
       5    21    1
       6    31    5
       7    43    0
       8    57    6
       9    73    4
      10    91    6
      11   111    0
      12   133   18
      13   157    0
      14   183   20
      ...

      (See: OEIS A058241 [ link ]).

      We’ve come across the following formula before:

      n(k) = k^2 − k + 1

      Specifically in the exploration of Teaser 2907, where it is the number of elements in a finite projective plane of order (k − 1).

      The fact that there is no solution for (k = 7, n = 43), (k = 11, n = 111) and (k = 13, n = 157) makes me wonder if there is a link with projective planes, as finite projective planes of order 6, 10, and 12 (probably) do not exist.


      For a more efficient way to generate “magic circles” see my comment on Enigma 985.

      Like

      • Frits's avatar

        Frits 11:47 am on 13 June 2022 Permalink | Reply

        @Jim,

        You might use (and in Enigma 985):

           
        for x in irange(m, t - n * (n - 1) // 2):
        

        in decompose() as we need different numbers. It doesn’t seem to make much of a difference in the performance.

        Like

        • Jim Randell's avatar

          Jim Randell 11:29 am on 14 June 2022 Permalink | Reply

          @Frits: If I were to re-write the code now I would probably just use [[ decompose() ]] from enigma.py (and [[ tuples() ]] to generate the adjacent sectors). [See: @replit]

          from enigma import (irange, tuples, decompose, arg, printf)
          
          # generate (non-empty) tuples of adjacent sectors
          def sectors(k):
            # the whole circle
            t = tuple(irange(k))
            # consider n consecutive sectors
            for n in irange(1, k - 1):
              yield from tuples(t, n, circular=1)
            # and the whole circle
            yield t
          
          # number of sectors to divide the circle into
          k = arg(5, 0, int)
          assert k > 1
          
          # make a list of adjacent sectors
          ss = list(sectors(k))
          t = len(ss)
          printf("[k={k}: {t} arrangements]")
          
          # put 1 at sector 0, and 2 somewhere, and decompose the remainder
          for d in decompose(t - 3, k - 2, increasing=0, sep=1, min_v=3, fn=list):
            # insert 2 somewhere
            for i in irange(0, (0 if k == 2 else k - 3)):
              s = list(d)
              s.insert(i, 2)
              if s[0] > s[-1]: continue
              # insert 1 at sector 0
              s.insert(0, 1)
              # calculate the value for adjacent sectors
              vs = set(sum(s[i] for i in x) for x in ss)
              if len(vs) == t:
                printf("{s}", s=tuple(s))
          

          But using magic_circles.py gives a much shorter and faster program:

          from enigma import (arg, printf)
          from magic_circles import magic_circle
          
          # number of sectors to divide the circle into
          k = arg(5, 0, int, prompt="number of sectors")
          assert k > 1
          
          # find magic k-circles
          for s in magic_circle(k):
            # output solution
            printf("{s}")
          

          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