Enigmatic Code

Programming Enigma Puzzles

Enigma 1148: Four-way fairway tie

From New Scientist #2304, 18th August 2001 [link]

After they had each played four rounds in the golf tournament Bernhard, Colin, Darren and Ernie all ended up with the same total score even though the scores for the 16 individual rounds that they played were all different. Each player’s score for each round was in the 60s or 70s (that is to say between 60 and 79 inclusive). Bernhard’s score in each of his four rounds was a prime number, Colin’s score in each of his four rounds was a semi-prime (the product of two prime numbers), Darren’s and Ernie’s scores in each of their four rounds were numbers that are neither prime nor semi-prime. Darren’s best (lowest) round was better than Ernie’s best round, and Darren’s worst round was better than Ernie’s worst round.

List in ascending order Ernie’s scores for the four rounds.

[enigma1148]

Advertisements

3 responses to “Enigma 1148: Four-way fairway tie

  1. Jim Randell 26 September 2016 at 8:10 am

    This Python program runs in 38ms.

    from collections import defaultdict
    from itertools import combinations, product
    from enigma import irange, factor, printf
    
    # categorise the numbers from 60 to 79 into exactly one of:
    # primes, semiprimes, others
    (primes, semiprimes, others) = (set(), set(), set())
    for i in irange(60, 79):
      n = len(factor(i))
      if n == 1:
        primes.add(i)
      elif n == 2:
        semiprimes.add(i)
      else:
        others.add(i)
    
    # record sets of k numbers by their sum
    def scores(ns, k=4):
      r = defaultdict(set)
      for s in combinations(ns, k):
        r[sum(s)].add(tuple(sorted(s)))
      return r
    
    # B's scores are 4 primes
    Bs = scores(primes)
    
    # C's scores are 4 semi-primes
    Cs = scores(semiprimes)
    
    # D's and E's are 4 others
    DEs = scores(others)
    
    # consider possible common total scores
    for t in set(Bs.keys()).intersection(Cs.keys()).intersection(DEs.keys()):
    
      # there must be two candidates for DE
      for DE in combinations(DEs[t], 2):
        # D's lowest score is lower than E's lowest score
        (D, E) = sorted(DE)
        if not(D[0] < E[0]): continue
        # D's highest score is also lower than E's highest score
        if not(D[-1] < E[-1]): continue
        # D and E have no scores in common
        if set(D).intersection(E): continue
    
        # B and C also have the same total score
        for (B, C) in product(Bs[t], Cs[t]):
          printf("t={t}, B={B} C={C} D={D} E={E}")
    

    Solution: Ernie’s scores were: 64, 66, 70, 78.

    The full results (lowest score to highest score) are:

    Bernhard: 61, 67, 71, 79;
    Colin: 62, 65, 74, 77;
    Darren: 63, 68, 72, 75;
    Ernie: 64, 66, 70, 78.

    Each total score is 278.

    By the time we reach line 46 we already know the solution to the problem (E’s score), and that there are scores for B and C (which must all be distinct from the other scores by definition).

  2. geoffrounce 27 September 2016 at 8:52 am

    The narrow range of maximum scores (60 – 79) makes it fairly easy to itemise
    the numbers into primes, semi-primes and others, as follows:

    Primes = 61, 67, 71, 73 and 79

    Semi-Primes = 62 (2*31), 65 (5*13), 69 (3*23), 74 (2*37), and 77 (7*11)

    Remaining numbers = 60, 63, 64, 66, 68, 70, 72, 75, 76 and 78

    These sets of numbers are used in my programme

    I did not find a general semi-prime constraint in MiniZinc.

    Any ideas ?.

    % A Solution in MiniZinc
    include "globals.mzn";
    
    var 240..280: tot_score;
    
    % Arrays of 4 rounds of 4 players
    array[1..4] of var 60..79: B;   % Bernhard
    array[1..4] of var 60..79: C;   % Colin
    array[1..4] of var 60..79: D;   % Darren
    array[1..4] of var 60..79: E;   % Ernie
    
    % Scores for the 16 individual rounds that they played were all different
    constraint all_different ([ B[1], B[2], B[3], B[4],  C[1], C[2], C[3], C[4],
                                D[1], D[2], D[3], D[4],  E[1], E[2], E[3], E[4] ]) ;
    
    % Bernhard, Colin, Darren and Ernie all ended up with the same total score
    constraint tot_score == B[1] + B[2] + B[3] + B[4] /\ tot_score == C[1] + C[2] + C[3] + C[4] 
            /\ tot_score == D[1] + D[2] + D[3] + D[4] /\ tot_score == E[1] + E[2] + E[3] + E[4]; 
    
    % Bernhard’s score in each of his four rounds was a prime number (between 60 and 79)
    constraint forall (i in 1..4) (B[i] in {61, 67, 71, 73, 79});
    
    % Colin’s score in each of his four rounds was a semi-prime (between 60 and 79)
    constraint forall (i in 1..4) (C[i] in {62, 65, 69, 74, 77});
    
    % Darren’s and Ernie’s scores in each of their four rounds were numbers that 
    % are neither prime nor semi-prime (between 60 and 79)
    constraint forall (i in 1..4) (D[i] in {60, 63, 64, 66, 68, 70, 72, 75, 76, 78});
    
    constraint forall (i in 1..4) (E[i] in {60, 63, 64, 66, 68, 70, 72, 75, 76, 78});
    
    % Darren’s best (lowest) round was better than Ernie’s best round
    % and Darren’s worst(highest) round was better than Ernie’s worst round
    constraint increasing( [D[1], D[2], D[3], D[4]]) 
            /\ increasing( [E[1], E[2], E[3], E[4]]) 
            /\ D[1] < E[1] /\ D[4] < E[4];
    
    solve satisfy;
    
    output [ "B: " ++ show(sort( (B))) ++ "\n" ++ 
             "C: " ++ show(sort((C))) ++ "\n" ++
             "D: " ++ show( sort((D))) ++ "\n" ++
             "E: " ++ show(sort((E))) ++ "\n" ++
             "Total score = " ++ show(tot_score) ];
    
    % B: [61, 67, 71, 79]
    % C: [62, 65, 74, 77]
    % D: [63, 68, 72, 75]
    % E: [64, 66, 70, 78]  <<< the answer
    % Total score = 278
    % Finished in 89msec
    
  3. geoffrounce 27 September 2016 at 8:34 pm

    Brian Gladman has found a neat solution to the semi-prime constraint in MiniZinc, as shown in the sample test code below

    % semi primes test
    
    include "globals.mzn";
    
    int: max_val = 100;
    
    % the primes up to max_val
    set of int: primes = {2} union (2..max_val diff { i | i in 2..max_val, 
                                          j in 2..ceil(sqrt(i)) where i mod j = 0});  % ex Hakan
    % the semi-primes up to max_val
    set of int: semi_primes = {i * j | i in primes, j in primes where i * j <= max_val};
    
    solve satisfy;
    
    output[ "Semi Primes = "  ++ show(semi_primes) ];
    
    % Semi Primes = {4,6,9,10,14,15,21,22,25,26,33,34,35,38,39,46,49,51,55,57,58,62,65,69,
    % 74,77,82,85,86,87,91,93,94,95}
    

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: