Tagged: by: Dr V W Bryant Toggle Comment Threads | Keyboard Shortcuts

  • Unknown's avatar

    Jim Randell 9:17 am on 26 July 2022 Permalink | Reply
    Tags: by: Dr V W Bryant   

    Brain-Teaser 727: Right hand 

    From The Sunday Times, 22nd June 1975 [link]

    When South, who was bored with being dummy, had left the card room of the Logic Club for good, West extracted four kings, three queens and two jacks from the pack, showed them round, shuffled them, and dealt three cards to each of the three.

    “Forget the suits”, he said. “Let each of us look at his own three cards and see if he can make a sure statement about any kings, queens or jacks in the next man’s hand; we will use as evidence what we see in our own hands and what we hear each other say.

    They played with the full rigours of logic. West began by announcing that he could say nothing about North’s hand; North then said that he could say nothing about East’s hand; thereupon East said that he could deduce the value of one card — and one only — in West’s hand.

    What can you say about the cards that were dealt to East?

    This puzzle is included in the book The Sunday Times Book of Brain-Teasers: Book 2 (1981).

    [teaser727]

     
    • Jim Randell's avatar

      Jim Randell 9:18 am on 26 July 2022 Permalink | Reply

      There are 9 possible hands that could be dealt to W, and in each case W would be able to say something about the cards that are dealt to N:

      KKK → N holds at most 1K
      KKQ → N holds at most 2K, at most 2Q
      KKJ → N holds at most 2K, at most 1J
      KQQ → N holds at most 1Q
      KQJ → N holds at most 2Q, at most 1J
      KJJ → N holds no J
      QQQ → N holds at least 1K, no Q
      QQJ → N holds at least 1K, at most 1Q, at most 1J
      QJJ → N holds at least 1K, at most 2Q, no J

      So let’s use a tighter definition that each must declare if they know for certain cards that are held by the next player.

      This reduces the list to:

      QQQ → N holds at least 1K
      QQJ → N holds at least 1K
      QJJ → N holds at least 1K

      And this allows us to find an answer to the puzzle.

      This Python program runs in 58ms. (Internal runtime is 1.2ms).

      Run: [ @replit ]

      from collections import defaultdict
      from enigma import (multiset, join, printf)
      
      # format a hand
      fmt = lambda x: join(x).upper()
      
      # deal groups of <k> cards from <cards>
      def deal(cards, k, ss=[]):
        if not cards:
          yield ss
        else:
          # choose the first hand
          for hand in cards.subsets(size=3):
            yield from deal(cards.difference(hand), k, ss + [tuple(hand.sorted())])
      
      # initial cards
      cards = multiset(K=4, Q=3, j=2)
      values = sorted(cards.keys())
      
      # possible deals
      hands = list(deal(cards, 3))
      
      # look at W's hand, record the number of Ks, Qs, Js in N's
      w = defaultdict(lambda: defaultdict(set))
      for (W, N, E) in hands:
        for k in values:
          w[W][k].add(N.count(k))
      
      # W can't be sure of any cards held by N
      Ws = set(W for (W, d) in w.items() if all(0 in d[k] for k in values))
      printf("[W = {Ws}]", Ws=join(map(fmt, Ws), sep=", ", enc="{}"))
      
      # look at N's hand, record the number of Ks, Qs, Js in E's
      n = defaultdict(lambda: defaultdict(set))
      for (W, N, E) in hands:
        if W not in Ws: continue
        for k in values:
          n[N][k].add(E.count(k))
      
      # N can't be sure of any cards held by E
      Ns = set(N for (N, d) in n.items() if all(0 in d[k] for k in values))
      printf("[N = {Ns}]", Ns=join(map(fmt, Ws), sep=", ", enc="{}"))
      
      # look at E's hand, record the number of Ks, Qs, Js in W's
      e = defaultdict(lambda: defaultdict(set))
      for (W, N, E) in hands:
        if W not in Ws or N not in Ns: continue
        for k in values:
          e[E][k].add(W.count(k))
      
      # E can be sure of exactly 1 card held by W
      for (E, d) in e.items():
        if sorted(min(v) for v in d.values()) == [0, 0, 1]:
          printf("E = {E}", E=fmt(E))
      

      Solution: East held a King, a Queen, and a Jack.

      Like

      • John Crabtree's avatar

        John Crabtree 6:50 pm on 26 July 2022 Permalink | Reply

        In manually reaching the same solution, I concluded that West must hold at least one King, and that North must hold at least one King and one Queen. That gives three possible sets of hands.
        Do you agree? Thanks.

        Like

        • Jim Randell's avatar

          Jim Randell 8:20 am on 27 July 2022 Permalink | Reply

          @John: Yes, I found three possible sets of hands:

          W = KQJ; N = KKQ; E = KQJ
          W = KKJ; N = KQQ; E = KQJ
          W = KKQ; N = KQJ; E = KQJ

          Like

  • Unknown's avatar

    Jim Randell 10:32 am on 5 July 2022 Permalink | Reply
    Tags: by: Dr V W Bryant   

    Brain-Teaser 731: A little list 

    From The Sunday Times, 20th July 1975 [link]

    (1) In this list there is a true statement and a false statement whose numbers add up to give the number of a false statement.

    (2) Either statement 4 is false or there are three  consecutive true statements.

    (3) The number of the last false statement subtracted from the product of the numbers of the first and last true statements gives the number of a statement which is false.

    (4) The number of even-numbered true statements equals the number of false statements.

    (5) One of the first and last statements is true and the other is false.

    (6) When I first sent this problem to the editor, thanks to a typing error no sixth statement was included. However the answer to the following question was the same then as it is now:

    Which statements are false?

    This puzzle is included in the book The Sunday Times Book of Brain-Teasers: Book 2 (1981). The puzzle text above is taken from the book.

    [teaser724]

     
    • Jim Randell's avatar

      Jim Randell 10:33 am on 5 July 2022 Permalink | Reply

      This Python program runs in 62ms. (Internal runtime is 680µs).

      Run: [ @replit ]

      from enigma import (subsets, filter2, irange, first, product, tuples, icount, printf)
      
      # solve the puzzle with k (= 5 or 6) statements, considering only the first 5 statements
      def solve(k):
      
        # consider the puzzle with k statements
        for ss in subsets((True, False), size=k, select="M"):
          # check the first 5 statements
          (s1, s2, s3, s4, s5) = first(ss, 5)
          (ts, fs) = filter2((lambda n: ss[n - 1]), irange(1, k))
      
          # 1: "in this list there is a true statement and a false statement
          # whose numbers add up to give the number of a false statement"
          if not (s1 == any(x + y in fs for (x, y) in product(ts, fs))): continue
      
          # 2: "either statement 4 is false, or there are three consecutive
          # true statements"
          if not (s2 == ((s4 is False) != (any(all(xs) for xs in tuples(ss, 3))))): continue
      
          # 3: "the number of the last false statement subtracted from the
          # product of the numbers of the first and last true statements gives
          # the number of a statement which is false"
          if not (s3 == (ts and fs and ts[0] * ts[-1] - fs[-1] in fs)): continue
      
          # 4: "the number of even numbered true statements equals the number
          # of false statements"
          if not (s4 == (icount(n for n in ts if n % 2 == 0) == len(fs))): continue
      
          # 5: "one of the first and last statements is true and the other is false"
          if not (s5 == (s1 != ss[-1])): continue
      
          # return the numbers of the false statements
          yield fs
      
      # look for solutions for the first 5 statements of the 6 statement
      # version of the puzzle, grouped by the value of statement 6
      (fs6t, fs6f) = filter2((lambda fs: 6 not in fs), solve(6))
      
      # if statement 6 is false, we don't have to worry about the 5 statement version
      printf("false statements = {fs6f}")
      
      # if statement 6 is true, the solution(s) must be the same as the 5 statement version
      fs5 = list(solve(5))
      if fs5 == fs6t:
        printf("false statements = {fs6t}")
      

      Solution: Statements 3, 4, 6 are false.

      So statements 1, 2, 5 are true.

      1. (true) “in this list there is a true statement and a false statement whose numbers add up to give the number of a false statement”.
      There are two: 1 + 3 = 4, 2 + 4 = 6.

      2. (true) “either statement 4 is false, or there are three consecutive true statements”.
      4 is false; there are not three consecutive true statements.

      3. (false) “the number of the last false statement subtracted from the product of the numbers of the first and last true statements gives the number of a statement which is false”.
      1×5 − 6 = −1, is not the number of a statement.

      4. (false) “the number of even numbered true statements equals the number of false statements”.
      There is 1 even numbered true statement, and there are 3 false statements.

      5. (true) “one of the first and last statements is true and the other is false”.
      1 is true; 6 is false.

      6. (false) “When I first sent this problem to the editor, thanks to a typing error no sixth statement was included. However the answer to the following question was the same then as it is now: Which statements are false”.
      The first part could be false (there was no error). But if it was true there are no solutions given only the first 5 statements, so the answer to the puzzle could not be the same if the 6th statement was included.

      Like

  • Unknown's avatar

    Jim Randell 9:16 am on 7 October 2021 Permalink | Reply
    Tags: by: Dr V W Bryant   

    Brain-Teaser 851: Hay fever foiled 

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

    Our garden has paths as shown in the plan above. At each junction of paths there is a different variety of plant. The shortest walk (along the paths) from the Marigold to the Sneezewort passes only the Tickseed, and the shortest walk from the Nasturtium to the Quitch passes two plants, one of which is the Lobelia.

    My wife suffers from hay fever and so she never walks past the irritating Rosemary, Sneezewort or Tickseed. We are still able to walk together on the shortest route from the Polyanthus to the Nasturtium (past one other plant), but she has to walk over twice as far as in going from the Orpine to the Marigold.

    List the plants, in order, which my wife passes when taking her shortest route from the Nasturtium to the Marigold.

    This puzzle is included in the book The Sunday Times Book of Brain-Teasers: Book 1 (1980). The puzzle text above is taken from the book.

    [teaser851]

     
    • Jim Randell's avatar

      Jim Randell 9:17 am on 7 October 2021 Permalink | Reply

      This Python program runs in 144ms.

      Run: [ @replit ]

      from enigma import (empty, Accumulator, ordered, tuples, SubstitutedExpression, irange, translate, join, cached, printf)
      
      # adjacency matrix
      adj = [
        [1, 3, 4], # 0
        [0, 2, 5], # 1
        [1, 3, 6], # 2
        [0, 2, 7], # 3
        [0, 5, 7, 8], # 4
        [1, 4, 6, 8], # 5
        [2, 5, 7, 8], # 6
        [3, 4, 6, 8], # 7
        [4, 5, 6, 7], # 8
      ]
      
      # distances for each edge
      dist = {
        (0, 1): 314, (1, 2): 314, (2, 3): 314, (0, 3): 314, # = 100 pi
        (0, 4): 100, (1, 5): 100, (2, 6): 100, (3, 7): 100,
        (4, 5): 157, (5, 6): 157, (6, 7): 157, (4, 7): 157, # = 50 pi
        (4, 8): 100, (5, 8): 100, (6, 8): 100, (7, 8): 100,
      }
      
      # find paths from A to B, avoiding Xs
      def paths(A, B, Xs=empty, s=[]):
        if A == B:
          yield s
        else:
          # move forward from A
          for x in adj[A]:
            if x not in s and x not in Xs:
              yield from paths(x, B, Xs, s + [x])
      
      # find minimal distance paths
      @cached
      def min_path(A, B, Xs=empty):
        r = Accumulator(fn=min, collect=1)
        for s in paths(A, B, Xs, [A]):
          d = sum(dist[ordered(x, y)] for (x, y) in tuples(s, 2))
          r.accumulate_data(d, s)
        return r
      
      # is there a minimal path with n intermediates, that include incs?
      def check(A, B, Xs, n=None, incs=[]):
        incs = set(incs)
        r = min_path(A, B, frozenset(Xs))
        for p in r.data:
          if len(p) == n + 2 and incs.issubset(p): return True
        return False
      
      # check distance avoiding Xs is over twice as far
      def check2(A, B, Xs):
        r1 = min_path(A, B)
        r2 = min_path(A, B, frozenset(Xs))
        return (r2.value > 2 * r1.value)
      
      # make a solver
      p = SubstitutedExpression(
        [
          # M -> S passes only T
          "check(M, S, [], 1, [T])",
          # N -> Q passes L and 1 other
          "check(N, Q, [], 2, [L])",
          # P -> N passes 1 other plant
          "check(P, N, [R, S, T], 1)",
          # but she has to walk over twice as far going from O -> M
          "check2(O, M, [R, S, T])",
        ],
        digits=irange(0, 8),
        env=dict(check=check, check2=check2),
        verbose=0,
      )
      
      # run the solver
      for s in p.solve():
        # map positions to symbols
        m = dict((v, k) for (k, v) in s.items())
        # remove duplicate layouts
        if not (m[1] < m[3] and m[0] < min(m[1], m[2], m[3])): continue
      
        # output solution: (outer) (inner) (centre) -> wife's path from N to M
        printf("{m}", m=translate("({0} {1} {2} {3}) ({4} {5} {6} {7}) ({8})", (lambda x: m[int(x)])))
        r = min_path(s['N'], s['M'], frozenset([s['R'], s['S'], s['T']]))
        for p in r.data:
          printf("-> {p}", p=join((m[x] for x in p), sep=" "))
        printf()
      

      Solution: The plants passed are: Orpine, Polyanthus, Quitch.


      Here is a layout of the plants (reflections/rotations of this layout also work), with the wife’s best route from N to M indicated:

      Like

      • Frits's avatar

        Frits 11:39 am on 7 October 2021 Permalink | Reply

        @Jim, I would say there is no solution as normally “twice as far” would mean twice the distance, not at least twice the distance.

        Like

        • Jim Randell's avatar

          Jim Randell 11:50 am on 7 October 2021 Permalink | Reply

          @Frits: the puzzle text says “she has to walk over twice as far”, so the wife has to travel more than twice the distance of the shortest path.

          Like

  • Unknown's avatar

    Jim Randell 12:12 pm on 2 April 2020 Permalink | Reply
    Tags: by: Dr V W Bryant   

    Brain-Teaser 516: [Cabinet reshuffle] 

    From The Sunday Times, 2nd May 1971 [link]

    In Northminster the Premier is planning a reshuffle of five positions in his Cabinet. They are (in decreasing order of rank):

    Deputy Premier,
    Chancellor of the Purse-strings,
    Minister of Mails,
    Secretary of Science,
    Head Whip.

    At the moment these jobs are held (not respectively) by:

    Attler,
    Balfy,
    Chamberton,
    Disreel,
    Edane.

    Soon these five jobs are to be re-allocated among these five people and each person will get a different job from the one he holds at the moment.

    In the reshuffle the Premier is going to promote Chamberton to Minister of the Mails, or above. Edane is also to be promoted. Attler has made it clear that if he is going to be junior to Chamberton, then the only Deputy Premier he would work under would be Disreel.

    Balfy is going to be demoted, but one consolation is that after the reshuffle he will be senior to someone to whom at the moment he is junior. Finally, Disreel will become Deputy Premier only if Balfy becomes Minister of Mails.

    The Premier tries to avoid a party split by arranging his reshuffle to satisfy all the above demands. Also he arranges it with the least number of demotions possible in the circumstances.

    Who is the present Secretary of Science? And, who is to become Secretary of Science?

    This puzzle was originally published with no title.

    [teaser516]

     
    • Jim Randell's avatar

      Jim Randell 12:12 pm on 2 April 2020 Permalink | Reply

      In order to get a unique solution I had to add a couple of extra “implied” conditions (the kind that got me into trouble in Enigma 99).

      So: “… is going to promote Chamberton to Minister of the Mails, or above”, implies that C’s current position is below MoM.

      and: “Disreel will become Deputy Premier only if …”, implies that D is not currently Deputy Premier. (Also the fact that A would serve under D as Deputy Premier implies that D does not currently hold this position).

      and (maybe): “… Attler has made it clear that if he is going to be junior to Chamberton …”, implies that A is not currently junior to C (although this extra condition is not required to get a unique solution).

      With these conditions made explicit we find there is a single answer to the puzzle.

      This Python program runs in 86ms.

      Run: [ @repl.it ]

      from enigma import (defaultdict, irange, subsets, printf)
      
      # "p -> q" = "if p then q", "q if p", "p only if q"
      implies = lambda p, q: not(p) or q
      
      # record (by number of demotions) who occupies position 4
      r = defaultdict(set)
      
      # consider "before" positions
      for before in subsets(irange(1, 5), size=5, select="P"):
        (bA, bB, bC, bD, bE) = before
      
        # [implied] D is not currently 1
        if bD == 1: continue
      
        # [implied] A is not currently junior to C
        if (bC < bA): continue
      
        # [implied] C is currently below 3
        if not (bC > 3): continue
      
        # consider "after positions"
        for after in subsets(irange(1, 5), size=5, select="P"):
          (aA, aB, aC, aD, aE) = after
      
          # nobody keeps the same post
          if any(bX == aX for (bX, aX) in zip(before, after)): continue
      
          # if A is junior to C, then D must be 1
          if not implies(aA > aC, aD == 1): continue
      
          # D becomes 1 only if B becomes 3
          if not implies(aD == 1, aB == 3): continue
      
          # C is to be promoted to 3 or above
          if not (aC < 4 and aC < bC): continue
      
          # E is to be promoted
          if not (aE < bE): continue
      
          # B is to be demoted ...
          if not (aB > bB): continue
      
          # ... but will become senior to someone who was his junior
          if not any(aB < aX and bB > bX for (bX, aX) in zip(before, after)): continue
      
          # count the number of demotions
          d = sum(aX > bX for (bX, aX) in zip(before, after))
      
          printf("[d={d}, A: {bA}->{aA}; B: {bB}->{aB}; C: {bC}->{aC}; D: {bD}->{aD}; E: {bE}->{aE}]")
          b = dict(zip(before, "ABCDE"))
          a = dict(zip(after, "ABCDE"))
          r[d].add((b[4], a[4]))
      
      # look for the fewest number of demotions
      k = min(r.keys())
      for (b4, a4) in r[k]:
        printf("{k} demotions: SoS = {b4}->{a4}")
      

      Solution: Chamberton is the current Secretary of Science. Edane will be the new Secretary of Science.

      There is only one scenario that has only 2 demotions:

      A: demoted from Deputy Premier to Head Whip
      B: demoted from Chancellor to Minister of Mails
      C: promoted from Secretary of Science to Chancellor
      D: promoted from Minster of Mails to Deputy Premier
      E: promoted from Head Whip to Secretary of Science

      We are told B is to be demoted, and someone else who was above B must also be demoted under B, so we cannot do better than 2 demotions.

      There are 2 further scenarios that satisfy the conditions that have 3 demotions.

      Like

    • John Crabtree's avatar

      John Crabtree 10:06 pm on 3 April 2020 Permalink | Reply

      Let the five positions in order of rank be P1, P2, P3, P4 and P5.

      C and E will be promoted, D can be promoted, and B has somebody senior to him, and so A is currently in P1.
      B can be demoted to P3, and so is currently in P2.
      A will move to P4 or P5 (lower than B), and so will be junior to C (P3 or above), and so D moves to P1, and so B moves to P3, and so C moves to P2.
      To minimise the number of demotions A moves to P5, and E moves from P5 to P4.
      The current positions are not in order, and so currently C is in P4, and D is in P3.

      Chamberton is the current Secretary of Science.
      Edane will become the Secretary of Science.

      Like

  • Unknown's avatar

    Jim Randell 8:50 am on 12 November 2019 Permalink | Reply
    Tags: by: Dr V W Bryant   

    Brain-Teaser 509: [Truth and lies] 

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

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

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

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

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

    This puzzle was originally published with no title.

    [teaser509]

     
    • Jim Randell's avatar

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

      This Python program runs in 70ms.

      Run: [ @replit ]

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

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

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

      Beta is the middle, and always tells the truth.

      Gamma is the youngest, and always lies.

      Like

c
Compose new post
j
Next post/Next comment
k
Previous post/Previous comment
r
Reply
e
Edit
o
Show/Hide comments
t
Go to top
l
Go to login
h
Show/Hide help
shift + esc
Cancel
Design a site like this with WordPress.com
Get started