Tagged: by: John Feather Toggle Comment Threads | Keyboard Shortcuts

  • Unknown's avatar

    Jim Randell 11:43 am on 11 August 2020 Permalink | Reply
    Tags: by: John Feather   

    Brainteaser 1839: It’s a knockout 

    From The Sunday Times, 14th December 1997 [link]

    Sixteen teams, A-P, entered a knockout football competition. In none of the matches did any team score more than five goals, no two matches had the same score, and extra time ensured that there were no draws.

    The table shows the total goals, for and against, for each team:

    My own team, K, was knocked out by the team who were the eventual champions.

    Who played whom in the semi-finals, and what were the scores.

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

    [teaser1839]

     
    • Jim Randell's avatar

      Jim Randell 11:44 am on 11 August 2020 Permalink | Reply

      When we look at the table we can spot teams that might have been knocked out in the first round. The number of goals for and against must be different (no draws) and neither must be more than 5. We can then choose 8 such teams, and their values in the table give the scores in the matches. We then choose 8 of the remaining teams to be their opponents and see if we can construct a new table for the next round of the tournament (which will have half as many matches). And so on until we reach the last 2 teams.

      This Python 3 program runs in 1.2s.

      Run: [ @repl.it ]

      from enigma import subsets, diff, ordered, flatten, join, printf
      
      # the total goals scored/conceded
      gs0 = dict(
        A=(5, 6), B=(14, 0), C=(15, 8), D=(2, 4), E=(1, 3), F=(0, 5), G=(4, 6), H=(1, 4),
        I=(1, 2), J=(12, 12), K=(6, 5), L=(0, 1), M=(4, 5), N=(1, 5), O=(2, 3), P=(7, 6),
      )
      
      # do the list of <ls>, <ws> make a set of matches using goals scored/conceded in <gs>?
      # return list of (<winner> + <loser>, (<scored>, <conceded>))
      # and a new version of <gs> for the next round
      def matches(gs, ls, ws):
        ms = list()
        d = dict()
        for (w, l) in zip(ws, ls):
          ((fw, aw), (fl, al)) = (gs[w], gs[l])
          (f, a) = (fw - al, aw - fl)
          if f < 0 or a < 0: return (None, None)
          ms.append((w + l, (al, fl)))
          d[w] = (f, a)
        return (ms, d)
      
      # allowable score:
      # no side scores more than 5 goals, and no draws
      score = lambda x, y: not(x > 5 or y > 5 or x == y)
      
      # play out a tournament
      # k = number of matches in this round
      # gs = total number of goals scored in the remaining rounds
      # ms = match outcomes in each round
      # ss = scores used so far
      def tournament(k, gs, ms=list(), ss=set()):
        # how many matches?
        if k == 1:
          # there should be 2 teams
          (x, y) = gs.keys()
          ((fx, ax), (fy, ay)) = (gs[x], gs[y])
          if fx == ay and ax == fy and score(fx, ax):
            yield ms + [[(x + y, (fx, ax)) if fx > ax else (y + x, (fy, ay))]]
        else:
          # teams that can be knocked out in this round
          teams = list(k for (k, (f, a)) in gs.items() if score(f, a))
          # choose the losers
          for ls in subsets(teams, size=k):
            # choose the winners from the remaining teams
            for ws in subsets(diff(gs.keys(), ls), size=k, select="P"):
              (ms_, gs_) = matches(gs, ls, ws)
              if not gs_: continue
              ss_ = set(ordered(*xs) for (ts, xs) in ms_)
              if ss_.intersection(ss): continue
              yield from tournament(k // 2, gs_, ms + [ms_], ss.union(ss_))
              
      
      # there are 8 matches in the first round
      for ms in tournament(8, gs0):
        # check K is knocked out by the champions
        champ = ms[-1][0][0][0]
        if not(champ + 'K' in (ts for (ts, xs) in flatten(ms))): continue
        # output the tournament
        for (i, vs) in enumerate(ms, start=1):
          printf("Round {i}: {vs}", vs=join((f"{t[0]}v{t[1]} = {x}-{y}" for (t, (x, y)) in sorted(vs)), sep="; "))
        printf()
      

      Solution: The semi-finals were: B vs K = 3-0; C vs J = 5-3.

      So the final was: B vs C = 2-0, and B were the champions.

      The strategy given above finds two possible tournaments, but only in one of them is K knocked out by the eventual champions.

      Like

      • Frits's avatar

        Frits 8:13 pm on 18 August 2020 Permalink | Reply

        @Jim

        Did you also solve the puzzle manually?

        It is not so difficult to determine who is playing whom in the semi-finals.
        The scores are not easy to determine.

        Like

        • Jim Randell's avatar

          Jim Randell 12:00 pm on 19 August 2020 Permalink | Reply

          @Frits: I didn’t do a manual solution for this one. But I imagine the fact there are only 15 possible scores for the 15 games must make things a bit easier. (This is something I didn’t use in my program).

          Like

  • Unknown's avatar

    Jim Randell 9:55 am on 12 July 2020 Permalink | Reply
    Tags: by: John Feather   

    Brainteaser 1835: Dominic’s dominoes 

    From The Sunday Times, 16th November 1997 [link]

    Dominic thought up a variation of the domino jigsaw game. He laid out a standard set of dominoes and produced the pattern below by copying the numbers of spots in each place. He put a 0 for all the blanks except for the one blank which stuck out of a side of the rectangle:

    Find the positions of all the dominoes.

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

    [teaser1835]

     
    • Jim Randell's avatar

      Jim Randell 9:56 am on 12 July 2020 Permalink | Reply

      I used the [[ DominoGrid() ]] solver from the enigma.py library (see: Teaser 1590). We pair up one of the edge squares with a 0 to make a domino, then attempt to fit the rest into the remainder of the grid. The following program runs in 88ms.

      Run: [ @repl.it ]

      from enigma import DominoGrid, update, printf
      
      # the grid
      (X, Y, grid) = (5, 11, [
        6, 2, 6, 2, 0,
        6, 3, 1, 2, 0,
        3, 5, 1, 2, 0,
        3, 5, 3, 3, 1,
        6, 6, 5, 3, 0,
        4, 3, 0, 3, 2,
        2, 5, 4, 4, 4,
        4, 2, 4, 6, 6,
        5, 5, 4, 1, 1,
        2, 4, 1, 5, 0,
        1, 1, 0, 5, 6,
      ])
      
      # remove one of the border squares and solve for the rest
      for (i, b) in enumerate(grid):
        (y, x) = divmod(i, X)
        if x == 0 or x == X - 1 or y == 0 or y == Y - 1:
          # place the 0-b domino and solve for the remaining dominoes
          p = DominoGrid(X, Y, update(grid, [(i, None)]))
          for s in p.solve(used=[(0, b)]):
            printf("[0-{b} placed @ {x},{y}]\n")
            p.output_solution(s, prefix="  ")
      

      Solution: The layout of the dominoes is shown below:

      So the missing square is part of 0-2 domino.

      Like

  • Unknown's avatar

    Jim Randell 10:57 am on 2 June 2019 Permalink | Reply
    Tags: by: John Feather   

    Brainteaser 1590: Demonoes 

    From The Sunday Times, 28th February 1993 [link]

    Damien deleted a dot from one of the dominoes so that when I laid them out randomly to form a rectangle I ended up with the following arrangement:

    Fill in the outlines of the dominoes.

    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.

    [teaser1590]

     
    • Jim Randell's avatar

      Jim Randell 10:58 am on 2 June 2019 Permalink | Reply

      The puzzle uses a standard set of dominoes, so there should be 8 instances of each digit.

      In the supplied grid there 9 0’s and only 7 1’s, so one of the 0’s should be a 1.

      I adapted the code used in Enigma 179, Enigma 303 and Enigma 342 to give a generic solver for this type of problem, which also includes code to output solution grids.

      This Python code runs in 204ms.

      Run: [ @repl.it ]

      from enigma import update, printf
      from domino import DominoGrid
      
      grid = [
        6, 2, 4, 2, 4, 4, 5, 4,
        3, 0, 3, 5, 5, 3, 6, 6,
        4, 4, 3, 5, 5, 2, 2, 3,
        3, 6, 3, 0, 0, 1, 1, 6,
        1, 5, 6, 6, 0, 2, 1, 4,
        1, 4, 2, 5, 0, 2, 1, 3,
        1, 2, 0, 0, 0, 5, 0, 6,
      ]
      
      # look for 0's in the grid
      for (i, x) in enumerate(grid):
        if x != 0: continue
        # try to fit the dominoes with the 0 replaced by a 1
        p = DominoGrid(8, 7, update(grid, [(i, 1)]))
        for s in p.solve():
          printf("[@{i}: 0 -> 1]\n")
          p.output_solution(s)
      

      Solution: The dominoes are arranged thus:

      There are two 0-5 dominoes shown highlighted in yellow. One of them should be a 1-5 domino (although we don’t know which one).

      It is likely I will fold the [[ DominoGrid() ]] class into the enigma.py library in a future release.

      Like

      • John Crabtree's avatar

        John Crabtree 5:09 am on 13 August 2020 Permalink | Reply

        The 4-0 is unique, and then 3-0 is unique. With some perseverance, one gets to the grid shown by Jim.

        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