# Turn Two Dice Into One

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.

• May we assume that the input is given such that die1 <= die2? (or the other way around) Dec 13, 2022 at 22:43
• Can we output a flat array? Dec 14, 2022 at 10:41
• 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]] Dec 14, 2022 at 12:52
• @Arnauld I think the function shouldn't expect any ordering of the values, no.
– rtrb
Dec 14, 2022 at 20:09
• @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
– rtrb
Dec 14, 2022 at 20:21

# 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!

# 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!

# 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!

# 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]


# 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!

# Charcoal, 27 bytes

ＮθＮηＮζ≔﹪×…⁰θηζεＩ⟦ε⊕﹪…⁰η⁻ζ⌈ε


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

ＮθＮηＮζ


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.

Ｉ⟦ε


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.

# 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


# Rust, 170159 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!

• -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() Dec 15, 2022 at 14:27

# 05AB1E, 13 bytes

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


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

Could alternatively be output as a pair of lists:

L*I%ZIα²Ls%>‚


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


# 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!

• Alternative
– l4m2
Dec 14, 2022 at 13:30

# 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]

• 27 bytes Dec 14, 2022 at 9:53
• @Shaggy Good find Dec 14, 2022 at 16:25

# 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

# 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))
}
}