Enigmatic Code

Programming Enigma Puzzles

Enigma 1331: Three into two

From New Scientist #2490, 12th March 2005

There are four football teams in our league, each playing each other once in a season. At the end of the season I worked out the league table (with teams in alphabetical order) and consistently replaced digits by letters in some of the entries to give the table below.

Enigma 1331

Unfortunately I was a bit confused and the points for Albion were based on two points for a win (and one for draw) whereas the others were based on the correct three points for a win.

Which team was top of the league and which was bottom? And which of those two teams (if either) won when they played each other?

[enigma1331]

Advertisements

One response to “Enigma 1331: Three into two

  1. Jim Randell 18 April 2014 at 8:19 am

    This Python program uses the Football() class from the enigma.py library. It runs in 196ms.

    from enigma import Football, irange, printf
    
    # 3 points for a win scoring
    football = Football(games='wdl', points={ 'w': 3, 'd': 1 })
    
    # single digits
    digits = set(irange(0, 9))
    
    # possible match outcomes for C
    for (AC, BC, CD) in football.games(repeat=3):
      # compute the table C
      C = football.table([AC, BC, CD], [1, 1, 0])
      # drawn, lost and points are all different
      (T, H, E) = (C.d, C.l, C.points)
      if len(set((T, H, E))) != 3: continue
    
      # possible remaining match outcomes for B
      for (AB, BD) in football.games(repeat=2):
        # compute the table for B
        B = football.table([AB, BC, BD], [1, 0, 0])
        # lost = T
        if B.l != T: continue
    
        # and the final match
        for AD in football.games():
          # compute the tables for A
          A = football.table([AB, AC, AD], [0, 0, 0])
          # lost is a new digit, and points - won = T
          J = A.l
          if J in (T, H, E) or A.points != T + A.w: continue
    
          # compute the table for D
          D = football.table([AD, BD, CD], [1, 1, 1])
          # points is a new digit
          W = D.points
          ds1 = digits.difference((T, H, E, J, W))
          if len(ds1) != 5: continue
    
          # consider possible scorelines for C
          for R in ds1:
            for (sAC, sBC, sCD) in football.scores([AC, BC, CD], [1, 1, 0], R, E):
    
              # consider possible scorelines for B
              ds2 = ds1.difference([R])
              for O in ds2:
                for (sAB, sBD) in football.scores([AB, BD], [1, 0, 0], W, O, [sBC], [0]):
    
                  # consider possible remaining scorelines for D
                  ds3 = ds2.difference([O])
                  for N in ds3:
                    for (sAD,) in football.scores([AD], [1], N, O, [sBD, sCD], [1, 1]):
    
                      # compute the goals for A to find the remaining digits
                      (U, S) = football.goals([sAB, sAC, sAD], [0, 0, 0])
                      if len(ds3.difference([N, U, S])) > 0: continue
    
                      # sort teams by points
                      pts = { 'A': A.points, 'B': B.points, 'C': C.points, 'D': D.points }
                      order = sorted(pts.keys(), key=lambda x: pts[x], reverse=True)
                      (top, bottom) = (order[0], order[-1])
                      # check for ties at the top and bottom
                      assert pts[order[1]] < pts[top]
                      assert pts[bottom] < pts[order[-2]]
    
                      # determine top vs. bottom match outcome
                      matches = { 'AB': AB, 'AC': AC, 'AD': AD, 'BC': BC, 'BD': BD, 'CD': CD }
                      match = ''.join(sorted((top, bottom)))
                      outcome = matches[match]
    
                      printf("AB={AB}:{sAB} AC={AC}:{sAC} AD={AD}:{sAD} BC={BC}:{sBC} BD={BD}:{sBD} CD={CD}:{sCD}")
                      printf("A={A}")
                      printf("B={B}")
                      printf("C={C}")
                      printf("D={D}")
                      printf("T={T} H={H} E={E} J={J} W={W} R={R} O={O} N={N} U={U} S={S}")
                      printf("top = {top} / bottom = {bottom} / {match[0]} vs. {match[1]} = {outcome}")
                      printf()
    

    Solution: City was top of the league. Albion was bottom of the league. City won the match between the two teams.

    There are six different sets of scores for the matches that all produce the same table. The outcomes of the matches (win, draw, lose) and the winning margin for each match are the same in each of the six cases, but the actual numbers of goals scored in each match differ.

    The outcomes are: AvB, B wins by 1 goal; AvC, C wins by 1 goal; AvD, draw; BvC draw; BvD, D wins by 3 goals; CvD, C wins by 1 goal.

    Albion does not win any matches, so the although the first line may have been produced assuming the “2 points for a win” rule the values in it are no different from those produced using the correct “3 points for a win” rule.

Leave a Comment

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: