Tagged: by: M R Carter Toggle Comment Threads | Keyboard Shortcuts

  • Unknown's avatar

    Jim Randell 10:18 am on 11 September 2024 Permalink | Reply
    Tags: by: M R Carter,   

    Brain-Teaser 734: Golden orchard 

    From The Sunday Times, 10th August 1975 [link]

    A farmer grows apples in an orchard divided into plots —three to the East and three to the West of a central path. The apples are of two types — for eating (Cox, Laxton, Pearmain) and for cider making (Tremlitt, Coppin, Kingston).

    Adjacent plots contain apples of different basic type. The apples are of six colours (red, green, russet, golden, orange, yellow) and of six tastes (sweet, sour, acid, tart, pleasant, bitter).

    They ripen at different times, either early or late in July, August and September. Those ripening in early or late September are in plots directly opposite. Those South of Pearmain do not ripen in August. Tart are directly West of the acid variety, which ripens in early August. Yellow apples and those maturing in late September are adjacent. Yellow and orange are of the same type. Orange are North of pleasant and also North of Pearmain. Kingstons are adjacent to golden. Green is South of bitter.

    Cox ripen in early July, and Laxtons ripen early in a different month. Tremlitts are red, and Kingstons mature after Coppins, which are not sour.

    If cider apples taste unpleasant, what are the characteristics of the apples in North East plot? (Name, colour, taste, ripens).

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

    I think the puzzle as published in The Sunday Times and in the book is open to interpretation, and my first attempt using a reasonable interpretation gave two solutions (neither of which are the published solution). After examining the given solution in the book I think the following wording is clearer:

    A farmer grows apples in an orchard divided into plots — three to the East and three to the West of a central track. Adjacent plots are separated by a shared fence. The apples are of two basic types — for eating (Cox, Laxton, Pearmain) and for cider making (Tremlitt, Coppin, Kingston).

    Neighbouring plots contain apples of different basic type. The apples are of six colours (red, green, russet, golden, orange, yellow) and of six tastes (sweet, sour, acid, tart, pleasant, bitter).

    They ripen at different times, either early or late in July, August and September. Those ripening in early or late September are in plots directly opposite each other. Those directly South of Pearmain do not ripen in August. Tart are directly West of the acid variety, which ripens in early August. Yellow apples and those maturing in late September are in adjacent plots. Yellow and orange are of the same basic type. Orange are directly North of Permain, which are pleasant. Kingstons and golden are in adjacent plots. Green is directly South of bitter.

    Cox ripen in early July, and Laxtons ripen early in a different month. Tremlitts are red, and Kingstons mature after Coppins, which are not sour.

    If cider apples are neither pleasant nor sweet, what are the characteristics of the apples in North-East plot?

    [teaser734]

     
    • Jim Randell's avatar

      Jim Randell 10:20 am on 11 September 2024 Permalink | Reply

      When I first tackled this puzzle (using the text from the 1981 book, and what I considered to be the most reasonable interpretation of the text), I found two solutions. And neither of them matched the published solution.

      According to the solution published in The Sunday Times [link] there were:

      A load of wrong answers (and some unacceptable multi-entries) in diffuse permutations brightly offset by an authentic minority including the winner …

      However, I think the wording of the puzzle is too vague to permit a single solution.

      Having looked at the answer in the book, I constructed the alternative wording, which I hope is clearer.


      Using the [[ SubstitutedExpression ]] solver from the enigma.py library, we can assign the characteristics to the plots.

      This run-file executes in 81ms. (Internal runtime of the generated code is 1.2ms).

      #! python3 -m enigma -rr
      
      SubstitutedExpression
      
      # plots are:
      #
      #   1 || 2
      #   --++--
      #   3 || 4
      #   --++--
      #   5 || 6
      #
      # we need to assign each of the six characteristics from each group
      # to a different plot number
      #
      # Eating: A = Cox; B = Laxton; C = Permain
      # Cider: D = Tremlitt; E = Coppin; F = Kingston
      #
      # Colour: G = red; H = green; I = russet; J = golden; K = orange; L = yellow
      #
      # Taste: M = sweet; N = sour; P = acid; Q = tart; R = pleasant; S = bitter
      #
      # Season: T = early Jul; U = late Jul; V = early Aug; W = late Aug; X = early Sep; Y = late Sep
      
      --base=7
      --digits="1-6"
      
      --distinct="ABCDEF,GHIJKL,MNPQRS,TUVWXY"
      
      # row adjacency (W, E)
      --code="row_adj = {(1, 2), (3, 4), (5, 6)}"
      
      # col adjacency (N, S)
      --code="col_adj = {(1, 3), (2, 4), (3, 5), (4, 6)}"
      
      # adjacent plots contain apples of different types
      "{A, B, C} in ({1, 4, 5}, {2, 3, 6})"
      
      # those ripening in early/late September (X, Y) are opposite
      "ordered(X, Y) in row_adj"
      
      # Southerly neighbour of Permain (C) do not ripen in Aug (V, W)
      "C not in {5, 6}"  # implies Permain (C) is not in southernmost row
      "(C, V) not in col_adj"
      "(C, W) not in col_adj"
      
      # tart (Q) are directly West of acid (P)
      "(Q, P) in row_adj"
      
      # acid (P) ripens in early Aug (V)
      "P = V"
      
      # yellow apples (L) and those maturing in late Sep (Y) are adjacent
      "ordered(L, Y) in col_adj"
      
      # yellow (L) and orange (K) are of the same type
      "len(intersect([{L, K}, {A, B, C}])) != 1"
      
      # orange (K) are Northerly neighbours of pleasant (R), and also Northerly neighbours of Permain (C)
      "(K, R) in col_adj"
      "(K, C) in col_adj"
      
      # Kingston (F) are adjacent to golden (J)
      "ordered(F, J) in col_adj"
      
      # green (H) is Southerly neighbour of bitter (S)
      "(S, H) in col_adj"
      
      # Cox (A) ripen in early Jul (T)
      "A = T"
      
      # Laxtons (B) ripen early in [not Jul] (V, X)
      "B in {V, X}"
      
      # Tremlitts (D) are red (G)
      "D = G"
      
      # Kingstons (F) mature after Coppins (E)
      "[T, U, V, W, X, Y].index(F) > [T, U, V, W, X, Y].index(E)"
      
      # Coppins (E) are not sour (N)
      "E != N"
      
      # cider apples do not taste pleasant (R) or sweet (M)
      "R not in {D, E, F}"
      "M not in {D, E, F}"
      
      # make sure all the variables are filled out
      "true(A, B, C, D, E, F, G, H, I, J, K, L, M, N, P, Q, R, S, T, U, V, W, X, Y)"
      
      --template="(A B C D E F) (G H I J K L) (M N P Q R S) (T U V W X Y)"
      --solution=""
      --denest=-1
      

      And the following Python program can be used to make the output more friendly:

      from enigma import (SubstitutedExpression, join, printf)
      
      p = SubstitutedExpression.from_file("teaser734b.run")
      
      # labels for the characteristics
      label = dict(
        # Type:
        A="Cox", B="Laxton", C="Permain", D="Tremlitt", E="Coppin", F="Kingston",
        # Colour:
        G="red", H="green", I="russet", J="golden", K="orange", L="yellow",
        # Taste:
        M="sweet", N="sour", P="acid", Q="tart", R="pleasant", S="bitter",
        # Season:
        T="early Jul", U="late Jul", V="early Aug", W="late Aug", X="early Sep", Y="late Sep",
      )
      
      # solve the puzzle
      for s in p.solve(verbose=0):
        # collect the characteristics for each plot
        d = dict((k, list()) for k in [1, 2, 3, 4, 5, 6])
        for k in sorted(s.keys()):
          d[s[k]].append(label.get(k))
        # output the solution
        for k in sorted(d.keys()):
          printf("{k} -> {v}", v=join(d[k], sep="; "))
        printf()
      

      Solution: The North-East plot contains Cox, russet in colour, sweet in taste, and ripens in early July.

      The full solution is:

      Like

  • Unknown's avatar

    Jim Randell 8:05 am on 10 September 2023 Permalink | Reply
    Tags: by: M R Carter   

    Brain-Teaser 928: Confused contracts 

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

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

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

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

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

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

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

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

    [teaser928]

     
    • Jim Randell's avatar

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

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

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

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

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

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

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

      Run: [ @replit ]

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

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

      The contracts are fully defined:

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

      And we see that Reg = Black.

      Like

    • Frits's avatar

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

      More than 200 lines of code.

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

      Like

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