22
\$\begingroup\$

A neat trick is if you ever need a nine-sided die, it is possible to make one using two six-sided dice using the numbers below. This is assuming you either have a way to rewrite the faces on the dice, or use some algorithm to map the numbers on a normal die onto these new numbers.

  0 0 3 3 6 6
  -----------
1|1 1 4 4 7 7 
1|1 1 4 4 7 7
2|2 2 5 5 8 8
2|2 2 5 5 8 8
3|3 3 6 6 9 9 
3|3 3 6 6 9 9

The challenge is:

  • You are given two fair dice, die1 with A faces and die2 with B faces, where A may not necessarily equal B. You need to write numbers on the faces of those dice to create a "target die" with N faces. The numbers of the faces of die1 and die2 will be such that, if rolled and their results summed, it would yield a fair target die. The new numbers written on the dice must greater than or equal to zero (that is, no negative numbers can be on the new dice).
  • Results should be a list (or whatever appropriate and reasonable format) of new faces for both die1 and die2. The numbers in those lists are not required to be in any sorted order.
  • Assume A, B, and N are all given as positive integers, and that N is a divisor of A*B.
  • The target die is a regular, fair die with numbers 1 to N on its faces.
  • If there are multiple solutions (such as when creating a one-sided die), you only need to return one solution from any of the possible solutions.

Examples

input:                     input:
die1 = 6                   die1 = 5
die2 = 6                   die2 = 12
target = 9                 target = 20

output:                    output:
[0,0,3,3,6,6]              [1,2,3,4,5]
[1,1,2,2,3,3]              [0,0,0,5,5,5,10,10,10,15,15,15]


input:                     input:
die1 = 6                   die1 = 12
die2 = 4                   die2 = 12
target = 8                 target = 18

output:                    output:
[0,0,0,4,4,4]              [1,1,2,2,3,3,4,4,5,5,6,6]
[1,2,3,4]                  [0,0,0,0,6,6,6,6,12,12,12,12]

Normal code golf rules apply. Shortest answer in bytes wins.

\$\endgroup\$
6
  • 2
    \$\begingroup\$ May we assume that the input is given such that die1 <= die2? (or the other way around) \$\endgroup\$
    – Arnauld
    Dec 13, 2022 at 22:43
  • 1
    \$\begingroup\$ Can we output a flat array? \$\endgroup\$
    – Shaggy
    Dec 14, 2022 at 10:41
  • \$\begingroup\$ Or if not a flat array, could we output the second die as an element within the first's array? e.g., [0,0,3,3,6,6,[1,1,2,2,3,3]] \$\endgroup\$
    – Shaggy
    Dec 14, 2022 at 12:52
  • \$\begingroup\$ @Arnauld I think the function shouldn't expect any ordering of the values, no. \$\endgroup\$
    – rtrb
    Dec 14, 2022 at 20:09
  • 2
    \$\begingroup\$ @Shaggy I don't think a flat array would be acceptable for this question. The second proposed method is probably fine. I think as long as you can hard-code the divisions it's fine. So a flat array wouldn't work because you need to know the number of faces on the dice, but with the second method die1=outp[0:-1]; die2=outp[-1] works \$\endgroup\$
    – rtrb
    Dec 14, 2022 at 20:21

13 Answers 13

9
\$\begingroup\$

Python NumPy, 67 bytes

lambda n,m,o:(x:=r_[:n]*m%o,r_[:m]%(o-max(x))+1)
from numpy import*

Attempt This Online!

Python, 77 bytes

lambda n,m,o,r=range:(x:=[a*m%o for a in r(n)],[b%(o-max(x))+1for b in r(m)])

Attempt This Online!

Just saw that output is not required to be sorted.

Python NumPy, 75 bytes

lambda n,m,o:(x:=sort(r_[:n]*m%o),r_[:m]*(o-x[-1])//m+1)
from numpy import*

Attempt This Online!

Python, 85 bytes

lambda n,m,o,r=range:(x:=sorted(a*m%o for a in r(n)),[b*(o-x[-1])//m+1for b in r(m)])

Attempt This Online!

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

JavaScript (ES6), 116 bytes

Expects (die1,die2)(target).

(a,b,d=b+1)=>g=c=>c%--d||a%d&&b%d?g(c):[a,b].map((n,j)=>[...Array(n)].map((_,i)=>~~(i*(j?d:c/d)/n+j)*(j||d),j^=a<b))

Try it online!

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

Python 3, 93 bytes

import math
def f(a,b,t):A=math.gcd(a,t);return[*range(1,A+1)]*(a//A),([*range(0,t,A)]*b)[:b]

Try it online!

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

Japt, 17 15 bytes

Output is [d1.1,...,d1.n,[d2.1,...,d2.n]]

Ç*V%WÃpVogVyW õ

Try it (footer splits & sorts output) or run all test cases

Ç*V%WÃpVogVyW õ     :Implicit input of integers U=a, V=b & W=n
Ç                   :Map the range [0,U)
 *V%W               :  Multiply by V and modulo by W
     Ã              :End map
      p             :Push
       Vo           :  Range [0,V)
         g          :  Index (0-based and modular) each into
          VyW       :    GCD of V & W
              õ     :    Range [1,VyW]
\$\endgroup\$
4
\$\begingroup\$

Go, 139 bytes

func f(a,b,t int)(l,r[]int){i,j,x,y:=0,0,b,t
for y!=0{g:=y;y,x=x%y,g}
for;i<a;i++{l=append(l,i*b%t)}
for;j<b;j++{r=append(r,j%x+1)}
return}

Attempt This Online!

Port of Shaggy's answer.

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

Charcoal, 27 bytes

NθNηNζ≔﹪×…⁰θηζεI⟦ε⊕﹪…⁰η⁻ζ⌈ε

Try it online! Link is to verbose version of code. Explanation: Port of @loopywalt's Python answer.

NθNηNζ

Input the dice.

≔﹪×…⁰θηζε

Multiply all of the digits on a regular first die by the size of the second die and reduce modulo the size of the third die.

I⟦ε

Output that as the first die, and as the second die output...

⊕﹪…⁰η⁻ζ⌈ε

... the digits on a regular second die modulo the minimum step in values on the output first die (calculated as the size of the third die minus the maximum value on the output first die, although the minimum nonzero value also works), plus one.

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

Nibbles, 12 bytes (24 nibbles)

`:;.*@,_%$@+~.,_%$`/|@$[

Same approach as Neil's answer (which apparently is a port of loopy walt's answer): upvote those!

Input is target, die1, die2.

`:;.*@,_%$@+~.,_%$`/|@$[
`:                          # output list of 2 lists:
  ;                         #   save list 1:
    *                       #     multiply 
     @                      #     sides of die1 by
      ,_                    #     each value of die2
   .                        #     and map over each of thes values
        %$                  #       modulo it by
          @                 #       sides of the target die   
                            #   now make list 2:
                    |@$     #     remove nonzero values from list 1
                  `/        #     and fold over this
                       [    #     getting the minimum;
             .,_            #     now map over values of die1
                %$          #       moduloing each by
                            #       minimum nonzero value of list 1
           +~               #     and add 1 to each

enter image description here

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

Rust, 170 159 151 bytes

  • -8 bytes thanks to corvus_192
|a,b,c|(1..a).filter(move|d|a%d+b%d+c%(a/d)<1).flat_map(|d|[(d,1),(a/d,d)]).zip([b,c]).map(move|((u,w),e)|(0..e).map(|v|v/(e/u)*w).collect()).collect()

Attempt This Online!

\$\endgroup\$
1
  • 1
    \$\begingroup\$ -5 bytes by flipping the zip: |a,b:u8,c|(1..a).filter(move|d|a%d+b%d+c%(a/d)<1).flat_map(|d|[(d,1),(a/d,d)]).zip([b,c]).map(move|((u,w),e)|(0..e).map(|v|v/(e/u)*w).collect()).collect() \$\endgroup\$
    – corvus_192
    Dec 15, 2022 at 14:27
3
\$\begingroup\$

05AB1E, 13 bytes

L*I%=αß²Ls%>?

Port of @loopyWalt's Python answer.

Three loose inputs in the order \$die1,die2,target\$, output printed as two separated lists.

Try it online or verify all test cases.

Could alternatively be output as a pair of lists:

L*I%ZIα²Ls%>‚

Try it online or verify all test cases.

Explanation:

L         # Push a list in the range [1, first (implicit) input die1]
 *        # Multiply each value by the second (implicit) input die2
  I%      # Modulo each by the third input target
    =     # Print it with trailing newline (without popping)
α         # Take the absolute difference between the third (implicit) input target and
          # each value in the list
 ß        # Pop and push the minimum
  ²L      # Push a list in the range [1, input die2]
    s     # Swap so the minimum absolute difference is at the top
     %    # Modulo each value in the list by this
      >   # Increase each by 1
       ?  # Pop and output it (without trailing newline) as well
\$\endgroup\$
3
\$\begingroup\$

JavaScript (Node.js), 81 bytes

(a,b,x)=>(g=i=>x%i|b%i?g(--i):[a,b].map(Z=n=>n--?[n*i%x+1||n%i,...Z(n)]:x=''))(b)

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ Alternative \$\endgroup\$
    – l4m2
    Dec 14, 2022 at 13:30
2
\$\begingroup\$

Japt, 27 bytes

k
[V=ogVk fU2 ×õ)WogU×o*VÌ]

Try it

Input as target die1 die2, Output as [[<die1 sides>],[<die2 sides>]], unsorted.

Explanation:

k              
k              # Get the prime factors of <target>
               # Store as U

[...]          # Return the enclosed statements as an array:

V=ogVk fU2 ×õ) 
    Vk         #  Prime factors of <die1>
       fU2     #  Remove and return from U numbers that are in both
           ×   #  Multiply them together
            õ  #  Get the range [1...N]
   g         ) #  Index into that range (wrapping):
  o            #   Numbers in [0...<die1>-1]
V=             #  Store as V and return it

WogU×o*VÌ      
   U           #  The remaining numbers in U
    ×          #  Multiplied together
     o         #  For X in the range [0...N-1]:
      *        #   Multiply X by
       VÌ      #   The last (highest) number in V
  g            #  Index into the result (wrapping):
Wo             #   Numbers in the range [0...<die2>-1]
\$\endgroup\$
2
  • 1
    \$\begingroup\$ 27 bytes \$\endgroup\$
    – Shaggy
    Dec 14, 2022 at 9:53
  • \$\begingroup\$ @Shaggy Good find \$\endgroup\$ Dec 14, 2022 at 16:25
2
\$\begingroup\$

C (gcc), 101 bytes

x;y;*p;f(a,b,n,r){p=r;for(x=n,y=a;r=y%=x;x=r)y=x;for(;a--;*p++=y--)y=y?:x;for(;b--;*p++=y-=x)y=y?:n;}

Try it online!

Edit #1: -1 byte thanks to ceilingcat

\$\endgroup\$
0
2
\$\begingroup\$

Scala, 177 172 bytes

saved bytes due to replacing List to Seq


Golfed version, try it online!

val f=(a:Int,b:Int,c:Int)=>(1 to a).filter(d=>a%d+b%d+c%(a/d)<1).flatMap(d=>Seq((d,1),(a/d,d))).zip(Seq(b,c)).map{case ((u,w),e)=>(0 until e).map(v=>v/(e/u)*w).toSeq}.toSeq

Ungolfed version

object Main {
  def main(args: Array[String]): Unit = {
    val f = (a: Int, b: Int, c: Int) =>
      (1 to a)
        .filter(d => a % d + b % d + c % (a / d) < 1)
        .flatMap(d => List((d, 1), (a / d, d)))
        .zip(List(b, c))
        .map { case ((u, w), e) => (0 until e).map(v => v / (e / u) * w).toList }
        .toList

    val d = f(4, 4, 4)
    println(f(9, 6, 6))
    println(f(9, 6, 3))
    println(f(18, 6, 6))
    println(f(18, 6, 3))
    println(f(20, 5, 12))
  }
}
\$\endgroup\$

Your Answer

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

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