Enigmatic Code

Programming Enigma Puzzles

Enigma 339a: Christmas dice

From New Scientist #1487, 19th December 1985 [link]

During last Christmas’s intellectual activity — backgammon, ludo, and so on — Pam complained about the unfairness of using a pair of ordinary dice.

“With this pair,” she said, “you can only throw a total from 2 up to 12. But I should like to be able to throw any whole number from 2 up to much more than that. And with this pair I am much more likely to throw some totals that others — I get 7, for instance, six times as often as I get 12. What I want is a pair of dice which will throw every possible total with equal probability. And finally, there’s a 4 on each of these dice, and I object to square numbers. I don’t mind 1 — I don’t think of 1 as really square — but I don’t like 4 and I would equally object to 9 or 16 or 25 or 36.”

So, I have designed a special pair of dice for Pam’s Christmas present this year, which, I am glad to say, meets her wishes entirely. They are six-sided dice of the ordinary shape, with a positive whole number on each face, and they are equally likely to throw any total from 2 to 37 inclusive.

What are the numbers on the faces of each die, please?

There are now 950 Enigma puzzles available on the site.

[enigma339a] [enigma339]

Advertisements

2 responses to “Enigma 339a: Christmas dice

  1. Jim Randell 1 April 2016 at 7:58 am

    This Python 3 program runs in 46ms.

    from enigma import irange, diff, printf
    
    # generate dice (d1, d2)
    # n = how many numbers on each die
    # ds = (d1, d2) numbers on dice (so far)
    # ss = numbers that can be thrown (so far)
    # ns = numbers that remain to be thrown
    # invalid = numbers that can't appear on a die
    def dice(n, ds, ss, ns, invalid):
      (d1, d2) = ds
      # check ordering
      if len(d1) == len(d2) and d2 < d1: return
      # are we done?
      if not ns:
        yield ds
      else:
        # make the next number
        x = ns[0]
        for (d1, d2, r) in ((d1, d2, 1), (d2, d1, -1)):
          if len(d1) < n:
            # choose a number on the other die
            for n2 in d2:
              # so the number to add to the first die is ...
              n1 = x - n2
              # check it's valid
              if n1 in invalid: continue
              # and the numbers that makes with the second die are...
              s = list(n1 + y for y in d2)
              # check there are no duplicate values
              if ss.intersection(s): continue
              # and try to finish the problem...
              yield from dice(n, (d1 + [n1], d2)[::r], ss.union(s), diff(ns, s), invalid)
    
    squares = (4, 9, 16, 25, 36)
    
    for (d1, d2) in dice(6, ([1], [1]), set([2]), irange(3, 37), set(squares)):
      printf("{d1} x {d2}")
    

    Solution: One die has faces (1, 2, 7, 8, 13, 14) the other has faces (1, 3, 5, 19, 21, 23).

    There are also 6 other pairs of dice that can make all the numbers from 2 to 37, but that include non-unity square numbers on their faces:

    (1, 2, 3, 4, 5, 6) (1, 7, 13, 19, 25, 31)
    (1, 2, 3, 19, 20, 21) (1, 4, 7, 10, 13, 16)
    (1, 2, 3, 10, 11, 12) (1, 4, 7, 19, 22, 25)
    (1, 2, 3, 7, 8, 9) (1, 4, 13, 16, 25, 28)
    (1, 2, 13, 14, 25, 26) (1, 3, 5, 7, 9, 11)
    (1, 2, 5, 6, 9, 10) (1, 3, 13, 15, 25, 27)

    And if we allow 0, instead of just positive numbers we can get three further solutions that don’t use non-unity squares:

    (0, 1, 2, 6, 7, 8) (2, 5, 14, 17, 26, 29)
    (0, 1, 2, 18, 19, 20) (2, 5, 8, 11, 14, 17)
    (0, 2, 12, 14, 24, 26) (2, 3, 6, 7, 10, 11)

    and 11 further solutions that do use non-unity squares:

    (0, 1, 2, 3, 4, 5) (2, 8, 14, 20, 26, 32)
    (0, 1, 2, 9, 10, 11) (2, 5, 8, 20, 23, 26)
    (0, 1, 4, 5, 8, 9) (2, 4, 14, 16, 26, 28)
    (0, 1, 6, 7, 12, 13) (2, 4, 6, 20, 22, 24)
    (0, 1, 12, 13, 24, 25) (2, 4, 6, 8, 10, 12)
    (0, 2, 4, 6, 8, 10) (2, 3, 14, 15, 26, 27)
    (0, 2, 4, 18, 20, 22) (2, 3, 8, 9, 14, 15)
    (0, 3, 6, 9, 12, 15) (2, 3, 4, 20, 21, 22)
    (0, 3, 6, 18, 21, 24) (2, 3, 4, 11, 12, 13)
    (0, 3, 12, 15, 24, 27) (2, 3, 4, 8, 9, 10)
    (0, 6, 12, 18, 24, 30) (2, 3, 4, 5, 6, 7)

  2. Brian Gladman 1 April 2016 at 3:04 pm
    # dice 'd1' and 'd2', numbers yet to be made in 'not_made'
    def compose(d1, d2, not_made):
      # are there numbers still to be made? 
      if not_made:
        # the number needed on a die to make the lowest unmade value
        nbr = min(not_made) - 1
        # try adding this number to the first die 
        if len(d1) < 6:
          # compile the numbers it makes with those on the other die
          s = set(x + nbr for x in d2)
          # if all of these are needed, add it to the die and continue 
          if s <= not_made:
            yield from compose(d1 + [nbr], d2, not_made - s)
        # now try to add it to the second die 
        if len(d2) < 6:
          s = set(x + nbr for x in d1)
          if s <= not_made:
            yield from compose(d1, d2 + [nbr], not_made - s)
      elif d1 < d2:
        yield (d1, d2)
      
    # squares to exclude from the dice 
    sq = set(x * x for x in range(2, 7))
    
    for d1, d2 in compose([1], [1], set(range(3, 38))):
      if not sq.intersection(d1 + d2):
        print(d1, d2)
    

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: