Enigmatic Code

Programming Enigma Puzzles

Tantalizer 430: Hop, skip and jump

From New Scientist #981, 1st January 1976 [link]

To shake down the plum pud, the five adults held three post-prandial athletic events. Each competitor scored the number of the place gained in each event, with the aim of totalling as few points as possible overall. Thus Uncle Arthur came second in the hop and scored 2 points for it. There were no ties in any event or in the overall totals and no one took the same place in two or more events.

Aunt Barbara, although bottom in one event, was top at skipping, Mother having been forced down to third place by a fit of hiccoughs. Father did better than Uncle Charlie at hopping. Uncle Arthur did not win the jumping. Mother did better at jumping than at hopping. Aunt Barbara was not second overall. The overall winner did not win the hopping.

As your post-prandial exercise, would you care to list the order in each event?

The puzzle can be solved as presented, but has two solutions. To arrive at the published single solution we seem to need an extra fact — “Uncle Arthur finished in third place overall”.

News

This puzzle completes the archive of Tantalizer puzzles from 1976. There is a full archive from this puzzle to the final Tantalizer puzzle in May 1977 (when the Puzzle series started).

[tantalizer430]

One response to “Tantalizer 430: Hop, skip and jump

  1. Jim Randell 1 May 2019 at 8:38 am

    The puzzle as published appears to admit two solutions, one of which is the published answer. To arrive at the single required solution we can add a condition to the puzzle text:

    [… Uncle Arthur did not win the jumping,] but finished in third place overall. […]

    This MiniZinc model includes this extra condition. It executes in 118ms.

    %#! minizinc -a --solver chuffed
    
    include "globals.mzn";
    
    % label the participants
    int: M = 1;
    int: F = 2;
    int: A = 3;
    int: B = 4;
    int: C = 5;
    set of int: Participant = 1..5;
    
    % label the events
    int: H = 1;
    int: S = 2;
    int: J = 3;
    set of int: Event = 1..3;
    
    % the scores: x[participant, event] = score
    array [Participant, Event] of var 1..5: x;
    
    % total points for particpant k
    function var int: total(var int: k) =
      sum (j in Event) (x[k, j]);
    
    % overall position for particpant k is n
    predicate overall(var int: k, var int: n) =
      sum (i in Participant where i != k) (total(i) < total(k)) = n - 1;
    
    % each event has 5 positions / scores
    constraint forall (j in Event) (all_different([x[i, j] | i in Participant]));
    
    % no-one got the same score for two events
    constraint forall (i in Participant) (all_different([x[i, j] | j in Event]));
    
    % the total scores are all different
    constraint all_different([total(i) | i in Participant]); 
    
    % A came second in the hop
    constraint x[A, H] = 2;
    
    % B was bottom in one event
    constraint exists (j in Event) (x[B, j] = 5);
    
    % B was top at skipping
    constraint x[B, S] = 1;
    
    % M was third at skipping
    constraint x[M, S] = 3;
    
    % F did better than C at hopping
    constraint x[F, H] < x[C, H];
    
    % A did not win the jumping
    constraint x[A, J] > 1;
    
    % M did better at jumping than at hopping
    constraint x[M, J] < x[M, H];
    
    % B was not second overall
    constraint not overall(B, 2);
    
    % the overall winner did not with the hopping
    constraint forall (i in Participant) (not(overall(i, 1) /\ x[i, H] = 1));
    
    % [additional] A was third overall
    constraint overall(A, 3);
    
    solve satisfy;
    

    And here is a Python program to format the output (using the minizinc.py wrapper):

    from minizinc import MiniZinc
    from enigma import irange, join, unpack, printf
    
    # the model
    p = MiniZinc("tantalizer430.mzn", use_shebang=1)
    
    # map labels to participants and events, positions
    P = [ '?', 'Mother', 'Father', 'Arthur', 'Barbara', 'Charlie' ]
    E = [ '?', 'Hop', 'Skip', 'Jump' ]
    K = [ '?', '1st', '2nd', '3rd', '4th', '5th' ]
    
    # solve the model
    for (x,) in p.solve(result="x"):
      # t[i] = total points for participant i
      # e[(j, k)] = participant at position k in event j
      e = dict()
      t = dict((i, 0) for i in irange(1, 5))
      # output the solution
      for (i, d) in x.items():
        for (j, k) in d.items():
          e[(j, k)] = i
          t[i] += k
      for j in irange(1, 3):
        ps = list((k, e[(j, k)]) for k in irange(1, 5))
        printf("{j}: {ps}", j=E[j], ps=join((f"{K[k]} = {P[i]}" for (k, i) in ps), sep="; "))
        ts = sorted(t.items(), key=unpack(lambda i, x: x))
      printf("Total: {ts}", ts=join((f"{K[k]} = {P[i]} ({x} pts)" for (k, (i, x)) in enumerate(ts, start=1)), sep="; "))
      printf()
    

    Solution: The positions and points were:

    Hop: 1st = Father; 2nd = Arthur; 3rd = Charlie; 4th = Barbara; 5th = Mother
    Skip: 1st = Barbara; 2nd = Charlie; 3rd = Mother; 4th = Arthur; 5th = Father
    Jump: 1st = Charlie; 2nd = Father; 3rd = Arthur; 4th = Mother; 5th = Barbara
    Overall: 1st = Charlie (6 pts); 2nd = Father (8 pts); 3rd = Arthur (9 pts); 4th = Barbara (10 pts); 5th = Mother (12 pts)


    The explanation given with the answer is:

    Of 45 points awarded no one scored less than 6 or more than 12. So possible scores were (6, 7, 9, 11, 12) or (6, 8, 9, 10, 12) or (7, 8, 9, 10, 11), all implying 9 for Arthur the overall 3rd. Barbara scored 8 or 10 and, as she was not second, 10. A and B scored a 4, as did whoever got 11 or 12. So the winner got 1+2+3, the loser 3+4+5 and the runner-up 1+2+5. Now prove that Mother was bottom overall and then fill in.

    Which makes use of the additional condition, not given in the original puzzle text, i.e. A finished in 3rd place overall.

    Without using this additional condition there is an additional solution of:

    Hop: 1st = Father; 2nd = Arthur; 3rd = Barbara; 4th = Charlie; 5th = Mother
    Skip: 1st = Barbara; 2nd = Charlie; 3rd = Mother; 4th = Father; 5th = Arthur
    Jump: 1st = Charlie; 2nd = Mother; 3rd = Father; 4th = Arthur; 5th = Barbara
    Overall: 1st = Charlie (7 pts); 2nd = Father (8 pts); 3rd = Barbara (9 pts); 4th = Mother (10 pts); 5th = Arthur (11 pts)

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 )

Google photo

You are commenting using your Google 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 )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: