48
\$\begingroup\$

You may have seen something called a "perpetual dice calendar":
perpetual dice calendar

Two 6-sided dice can be rearranged and rotated. One die has the numbers 0, 1, 2, 3, 4, and 5. The second die has the numbers 0, 1, 2, 6, 7, and 8. With this, any day of the month—from 1 to 31—can be displayed on the front of the calendar. The 6 can be rotated to be used as a 9.

However, what if I wanted to display any number up to... 100? 365? 50287? How many 6-sided dice would I need then, and what numbers would be printed on their sides?

The challenge:

  • Given a whole number input X, output the fewest possible 6-sided dice that are required to display all integers from 1 up to and including X.
  • Each side of a die must contain exactly one integer, from 0 to 8 inclusive.
  • 6's may be used as 9's.
  • If not every side of every die needs to have a number on it, then those side(s) must have 0.
  • Each line of the output should represent a die, e.g.:
Input: 4
Output:
0 0 1 2 3 4

Input: 6
Output:
1 2 3 4 5 6

Input: 9
Output:
0 1 2 3 4 5
0 0 0 6 7 8

Input: 31
Output:
0 1 2 3 4 5
0 1 2 6 7 8

Input: 35
Output:
0 1 2 3 4 5
0 1 2 3 6 7
0 0 0 0 0 8
  • The output lines can be in any format, e.g.:
123456
1 2 3 4 5 6
1,2,3,4,5,6
[1, 2, 3, 4, 5, 6]
  • Assume that all the dice are used for every number, using leading 0's if necessary. For instance, if X is 35, then 2 would be displayed as 002, because 3 dice are necessary.
  • The outputted numbers do not need to be in any particular order.
  • There may be multiple solutions for X. You need only output one.
  • Standard golfing rules apply.
\$\endgroup\$
17
  • 18
    \$\begingroup\$ Welcome to CGCC, and nice first question! \$\endgroup\$
    – Ginger
    Apr 25 at 13:02
  • 2
    \$\begingroup\$ I only now notice the "Each line of the output should represent a die, with the numbers on the die delimited by spaces" rule. Is this mandatory, or can we also just output as a list of lists of digits for example? \$\endgroup\$ Apr 25 at 14:18
  • 2
    \$\begingroup\$ What is the expected output for 6? I assume it is one normal six-sided die (i.e. no zero is required)? Probably worth adding to the examples either way. \$\endgroup\$ Apr 25 at 18:37
  • 4
    \$\begingroup\$ @Neil You'll need three 0's, as every dice needs to be used (with leading zeroes). eg. 001, 002, 003 ... will require a 0 on all 3 dice. \$\endgroup\$ Apr 26 at 1:14
  • 1
    \$\begingroup\$ @Stef With just those two dice, you would not be able to form 05 or 04. \$\endgroup\$
    – swinn
    Apr 27 at 18:47

9 Answers 9

12
\$\begingroup\$

Jelly,  22  20 bytes

D€EƇZḢḟ9s<7+5Ɗo0x6¤Y

A full program that accepts a positive integer and prints a set of dice as lines each having six digits from \$[0,8]\$.

Try it online!

How?

For small inputs (\$\le 6\$) we should fill a single die with the numbers we need and then zeros.

For larger numbers, we:

  • need multiple dice since one dice only has six sides, and
  • only place up to five non-zero digits on the first dice (since we will need at least one leading zero to represent small numbers like \$7\$ or \$8\$)

When we reach a rep-digit that is not repeated nines (e.g. \$444\$) we need to ensure that enough of the dice have that digit (in this case three of them), and that any others contain a zero (since we will need them in front to represent the rep-digit).

Thus an optimal output for numbers greater than six is to set the first face of every die to \$0\$ and fill the remaining faces with the digits \$1\$ to \$8\$ in order as required by either the number itself (excluding \$9\$) or the digit of the rep-digit we have reached that we cannot yet make.

Thus for inputs greater than six we:

  • fill the first dice with \$[1,2,3,4,5,0]\$
  • fill the second dice with \$[6,7,a,b,c,0]\$ where \$a\$, \$b\$ and \$c\$ are \$0\$ until we encounter \$8\$ (a non-nines rep-digit), \$11\$ and \$22\$ whereupon they should be filled with \$8\$, \$1\$ and \$2\$ respectively.
  • at \$33\$ create a new dice \$[3,d,e,f,g,0]\$ where \$d\$, \$e\$, \$f\$, and \$g\$ are \$0\$ until we encounter \$44\$, \$55\$, \$66\$, and \$77\$ whereupon they should be filled with \$4\$, \$5\$, \$6\$, and \$7\$ respectively.
  • etc.
D€EƇZḢḟ9s<7+5Ɗo0x6¤Y - Main Link: positive integer, N
 €                   - for each i in [1,N]:
D                    -   decimal digits
   Ƈ                 - keep those for which:
  E                  -   all equal -> [[1],[2],...,[9],[1,1],[2,2],...,[9,9],...,[1,1,1],...]
    Z                - transpose
     Ḣ               - head -> [1,2,...,9,1,2,...,9,1,...]
      ḟ9             - filter out nines
             Ɗ       - last three links as a monad - f(N):
         <7          -   less than seven?
            5        -   five
           +         -   add -> 6 if N < 7 else 5
        s            - (filtered list of digits) split into chunks of length (that)
                          e.g.:  N=3 -> [[1,2,3]]
                                N=44 -> [[1,2,3,4,5],[6,7,8,1,2],[3,4]]
                  ¤  - nilad followed by link(s) as a nilad:
               0     -   zero
                 6   -   six
                x    -   repeat -> [0,0,0,0,0,0]
              o      - logical OR (vectorises)
                          e.g.:  N=3 -> [[1,2,3,0,0,0]]
                                N=44 -> [[1,2,3,4,5,0],[6,7,8,1,2,0],[3,4,0,0,0,0]]
                   Y - join with newline characters
\$\endgroup\$
5
  • 1
    \$\begingroup\$ Excellent explanation of the algorithm. \$\endgroup\$
    – swinn
    Apr 26 at 11:36
  • 1
    \$\begingroup\$ If we're being a stickler for the rules, I'd mention that the lists of dice numbers need to be on separate lines, one per die. \$\endgroup\$
    – swinn
    Apr 26 at 12:15
  • \$\begingroup\$ @SpyderScript Thanks, great question too! I've edited it from a function that yields the list of dice to a full program that prints lines. I'd suggest keeping I/O as flexible as possible in future questions (I'm so used to this that I ignored that and just read it as a set of examples / tests). \$\endgroup\$ Apr 26 at 20:08
  • \$\begingroup\$ Sorry for mistyping your name. (Normally I copy and paste it but because I was mentioning @AndrovT as well I didn't bother.) \$\endgroup\$
    – Neil
    Apr 30 at 7:33
  • \$\begingroup\$ Not a problem :) \$\endgroup\$ Apr 30 at 17:17
7
\$\begingroup\$

Vyxal, 29 17 bytes

~≈∩h9F5?6=+ẇṅ6∆Z⁋

Try it Online!

-12 bytes by taking some ideas from @Jonathan Allan's Jelly answer

I believe this is correct but I'm not completely sure.

~≈                # keep only those numbers where all digits are equal from the implicit range [1, input]
  ∩               # transpose
   h              # first element
    9F            # remove nines 
      5?6=+       # 6 if input is 6 otherwise 5
           ẇ      # split into chunks of that length
            ṅ     # join
             6∆Z  # pad with zeros to length 6
                ⁋ # join by newlines
\$\endgroup\$
4
  • \$\begingroup\$ I was thinking along the same lines and I think it almost works. I think it becomes suboptimal though. For example, I think we can do away with the last die outputted for \$666666\$ by, instead, replacing one of the zeros on a die that does not currently contain a \$6\$ with a \$6\$. EDIT: but I could still be wrong about this! \$\endgroup\$ Apr 25 at 19:30
  • \$\begingroup\$ Actually, I'm not so sure about that anymore since all lower six digit rep-digit numbers (\$111111\$, \$222222\$, \$333333\$, \$444444\$, \$555555\$) need all of the zeros to remain in place on the existing dice for \$666665\$ - starting to think this must be optimal :) \$\endgroup\$ Apr 25 at 19:40
  • \$\begingroup\$ @JonathanAllan In order to produce all nine (or any seven) numbers less than ten, there needs to be a 0 on every die. \$\endgroup\$
    – Nitrodon
    Apr 27 at 17:35
  • \$\begingroup\$ @Nitrodon yep, I realised that and used it in my explanation - once we get to seven we need a zero on the other dice, and thereafter we need at least one zero on all the dice so we can make all the rep-digits (including single digit ones). \$\endgroup\$ Apr 27 at 22:58
5
\$\begingroup\$

Python3, 475 bytes:

from itertools import*
R=range
N=lambda k:k+[6,9]*(6 in k or 9 in k)
P=permutations
def f(n):
 q=[({*R(1,n+1)},[[]]if n<7 else[[0]])]
 while q:
  a,b=q.pop()
  if not a:return[[0]*(6-len(i))+i for i in b]
  t=str(min(a))
  for i in P(b,min(len(b),len(t))):
   for j,k in zip_longest(t,i):
    j=int(j)
    if not k or j not in N(k):
     D=[*b,[0,j]]if len(b[-1])==6 else[*b[:-1],b[-1]+[j]];q+=[(a-{int(''.join(map(str,K)))for d in P(D,len(D))for K in product(*map(N,d))},D)]

Try it online!

\$\endgroup\$
3
  • \$\begingroup\$ shouldn't the first 2 test cases have a 1? \$\endgroup\$
    – c--
    Apr 26 at 13:27
  • \$\begingroup\$ @c-- Yes indeed, thank you for catching. Saved a few bytes in the process :) \$\endgroup\$
    – Ajax1234
    Apr 26 at 14:15
  • \$\begingroup\$ 455 bytes, t feels like (6in k or 9in k) can be golfed but I didn't see how, maybe something in the tips? \$\endgroup\$
    – c--
    Apr 27 at 17:22
5
\$\begingroup\$

Excel, 161 122 120 122 bytes

saved 39 bytes after looking at AndrovT's solution and fixing error for n=6

saved 2 more bytes after realizing the die for N=6 didn't need to have a 1

added 2 bytes because the previous statement was false

=LET(x,ROW(1:8),y,LEN(A1),z,A1=6,IFERROR(HSTACK(z*1,MOD(SEQUENCE(INT((y*8+MAX(x*(REPT(x,y)*1<=A1))-4-z)/5),5)+z-1,8)+1),))

The formula above determines how many faces are needed to cover all numbers less than or equal to N then generates dice from the list below so there at least that many faces.

0 1 2 3 4 5
0 6 7 8 1 2
0 3 4 5 6 7
0 8 1 2 3 4
0 5 6 7 8 1
0 2 3 4 5 6
0 7 8 1 2 3
0 4 5 6 7 8 

If N = 6 it uses 1 2 3 4 5 6.

Explanation:

=LET(x,ROW(1:8),           # x = array 1..8
y,LEN(A1),                 # y = number of digits in N 
z,A1=6,                    # z = (N=6)
IFERROR(~,)                # Pads errors with 0
HSTACK(z*1,~)                # Concatenates 0 to other 5 faces
MOD(SEQUENCE(~,5)+z-1,8)+1 # array of last 5 faces for each die
INT((~)/5)                 # number of dice needed
y*8+MAX(x*(~))-4-z         # 4 + number of faces needed to cover all numbers up to ~
REPT(x,y)*1<=A1            # calculates the largest number the same length as N with repeated digits
                           
\$\endgroup\$
2
  • 1
    \$\begingroup\$ "saved 2 more bytes after realizing the die for N=6 didn't need to have a 1" Then how does it make 1 for \$n=6\$?.. For \$n=6\$ the output needs to be a single die with 1,2,3,4,5,6, doesn't it? \$\endgroup\$ Apr 26 at 6:29
  • 3
    \$\begingroup\$ You're right. That's what I get for trying to think too late at night. \$\endgroup\$
    – Axuary
    Apr 26 at 14:47
5
\$\begingroup\$

JavaScript (ES8), 111 bytes

Algorithm shamelessly borrowed from @AndrovT's latest version, which itself uses ideas from @JonathanAllan.

Returns an array of digit strings.

n=>n-6?(g=n=>n?g(n-1)+(/^([1-8])\1*$/.test(n)?n%10:''):'')(n).match(/.{1,5}/g).map(s=>s.padEnd(6,0)):["123456"]

Try it online!

\$\endgroup\$
5
\$\begingroup\$

Charcoal, 29 bytes

E⪪⁻⭆ΦI…·¹N⁼⌊ι⌈ι⌊ι9⁺⁵⁼θ6⭆◨ι⁶Σλ

Try it online! Link is to verbose version of code. Explanation: Once I'd figured out what the problem actually was, this is an implementation of @Axuary's observation, although comparing the other answers I see I ended up with the same basic algorithm as @AndrovT and @JonathanAllan but only by coincidence.

      …·                        Inclusive range from
        ¹                       Literal integer `1` to
         N                      First input as a number
     I                          Vectorised cast to string
    Φ                           Filtered where
           ⌊ι                   Minimum digit
          ⁼                     Is equal to
             ⌈ι                 Maximum digit
   ⭆           ⌊ι               Extract one digit from each repdigit
  ⁻              9              Remove `9`s
 ⪪                              Split into groups of
                   ⁵            Literal integer `5`
                  ⁺             Plus
                     θ          First input
                    ⁼           Equals
                      6         Literal string `6`
E                              Map over groups
                        ◨ι⁶     Pad to 6 characters
                       ⭆   Σλ   Replace spaces with `0`s
                                Implicitly print

The above code is sublinear in X, so here's more efficient 35-byte version:

E⪪⁻⭆⁺÷×⁹⊕NXχLθ×⁹⊖Lθ﹪⊕ι⁹0⁺⁵⁼θ6⭆◨ι⁶Σλ

Try it online! Link is to verbose version of code. Explanation: Calculates the number of repdigits up to X as equal to the first digit of (X+1)*9 plus 9 times the length of X as a string plus a correction factor, then takes the sequence modulo 9 omitting the zeros and wraps into rows as above.

The problem would have been much more interesting if each number only needed to be formed from 1+floor(log10(X)) dice. In that case, my best patterns so far are as follows:

  • 6: 123456
  • 9: 123456, 78
  • 10: 012345, 0678
  • 21: 012345, 06781
  • 32: 123450, 678012
  • 54: 123456, 781234, 0
  • 65: 123456, 781234, 05
  • 76: 123456, 781234, 056
  • 87: 123456, 781234, 0567
  • 99: 123456, 781234, 05678
  • 221: 123456, 781234, 056781, 0
  • 332: 123456, 781234, 056781, 02
  • 443: 123456, 781234, 056781, 023
  • 554: 123456, 781234, 056781, 0234
  • 665: 123456, 781234, 056781, 02345
  • 776: 123456, 781234, 056781, 023456
  • 887: 123456, 781234, 056781, 023456, 7
  • 999: 123456, 781234, 056781, 023456, 78
  • 1110: 123456, 781234, 056781, 023456, 780
  • 2221: 123456, 781234, 056781, 023456, 7801
  • 3332: 123456, 781234, 056781, 023456, 78012
  • 4443: 123456, 781234, 056781, 023456, 780123

I believe that the dice will then continue cyclically though the digits after that point.

\$\endgroup\$
4
\$\begingroup\$

05AB1E, 44 (or 42†) bytes

[8Ý6ãNã.ΔULε§Xgj„9 60‡œεXsøε`å}P}à}P}D¸àd#}»

Extremely slow brute-force, so it'll time out for \$n\geq7\$ on TIO..
Not too happy with how long §Igj„9 60‡œεXsøε`å}P}à is. Will see if I can find something shorter (and hopefully faster) later on.

Try it online or verify some of the smaller test cases.

† With looser output-format of a list of lists of digits, the trailing can be removed for -2 bytes.

Explanation:

[               # Start an infinite loop:
 8Ý             #  Push a list in the range [0,8]
   6ã           #  Cartesian power of 6 to create all sextets using these digits
     Nã         #  Cartesian power with the 0-based loop-index
 .Δ             #  Find the first one that's truthy for,
                #  or -1 if none are truthy:
   U            #   Pop and store the current list in variable `X`
   Ý            #   Push a list in the range [0, (implicit) input-integer]
    ε           #   Map over each value:
      Xg        #    Push the length of list `X`
     §  j       #    Pad leading spaces to make the current integer that length
         „9 60‡ #    Transliterate 9s to 6s and spaces to 0s
     œ          #    Get all permutations of this integer
      ε         #    Map over each permutation:
       Xs       #     Push list of lists `X` and swap
         ø      #     Create pairs of the two lists
          ε     #     Map over each pair of [list,digit]
           `    #      Pop and push the list and digit separately to the stack
            å   #      Check if the digit is in the list
          }P    #     After the map: check whether it's truthy for all [list,digit]-pairs
      }à        #    After the map: check whether it's truthy for any permutation
    }P          #   After the map: check whether it's truthy for all values in the range
  }D            #  After the find_first: Duplicate the resulting -1 or list
    ¸           #  Wrap it into a list
     à          #  Pop and push the flattened maximum
      d         #  If this maximum is non-negative (thus not -1):
       #        #   Stop the infinite loop
}»              # After the infinite loop: join each inner list of the valid find_first
                # by spaces, and then all strings by newlines
                # (after which it is output implicitly as result)
\$\endgroup\$
4
\$\begingroup\$

Nibbles, 18 bytes (36 nibbles)

&"0"6`/ ?-$6 5 $ |+|.,$`$`@~$~<<$- 9

Same approach as Androv T's answer: upvote that one!

|+|.,$`$`@~$~<<$- 9 # part 1: get the nonzero digits needed:
   .                # map over
    ,               # range from 1..
     $              # input
        `@ $        #   convert to digits in base           
          ~         #   10
      `$            #   and remove duplicates
  |                 # now filter to keep only
            ~       # falsy elements when
             <<$    #   dropping the first element of each list
 +                  # flatten the list of (1-element) lists
|                   # and filter again to keep only
                    # elements that are truthy (positive) when
                - 9 #   subtracted from 9
&"0"6`/ ?-$6 5 $    # part 2: split them into dice:
     `/             # split into chunks of
        ?           #   if
         -$6        #     input minus 6 is truthy
             5      #   then 5
               $    #   else input
&                   # now justify each chunk
    6               # to a width of 6
 "0"                # using "0" as a filler

enter image description here


Frustratingly, if we were allowed to use 9s instead of 6s (rather than 6s instead of 9s), which would correspond to identical physical dice, we could have:

Nibbles, 16.5 bytes (33 nibbles; but not permitted output)

&"0";6`/ +`$- $@ $ +`%+|.,@`$`@~$~<<

enter image description here

\$\endgroup\$
3
\$\begingroup\$

Python 2, 120 bytes

n=input()
m=n>6
for v in zip(*[(i%10for i in range(n>1,n+1)+4*[0]if len(set(`i`))<2-i%10/9)]*(6-m)):print'0'*m+`v`[1::3]

A full program that accepts a positive integer from STDIN and prints the dice.

Try it online! Or see the test-suite.

This employs the same method I used in my Jelly answer.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.