With one die of 6 sides we will have six different possible results:```  1, 2, 3, 4, 5, 6``` .

With 2 dice of six sides, we will have 36 different possible results:
``` 
(1,1),(1,2),(2,1),(1,3),(3,1),(1,4),(4,1),(1,5),
(5,1), (1,6),(6,1),(2,2),(2,3),(3,2),(2,4),(4,2),
(2,5),(5,2)(2,6),(6,2),(3,3),(3,4),(4,3),(3,5),(5,3),
(3,6),(6,3),(4,4),(4,5),(5,4),(4,6),(6,4),(5,5),
(5,6),(6,5),(6,6)
``` 
So, with 2 dice of 6 sides we get 36 different events.
``` 
([6,6] ---> 36)
``` 
But with 2 different dice we can get for this case, the same number of events.
One die of ```4 sides```  and another of ```9 sides```  will produce the exact amount of events.
``` 
([4,9] ---> 36)
``` 
We say that the dice set ```[4,9]``` is equivalent to ```[6,6]``` because both produce the same number of events.

Also we may have an amount of three dice producing the same amount of events. It will be for:
``` 
[4,3,3] ---> 36
``` 
(One die of 4 sides and two dice of 3 sides each)

Perhaps you may think that the following set is equivalent: ```[6,3,2]``` but unfortunately dice have a **minimum of three sides** (well, really a 
tetrahedron with one empty side)

The task for this kata is to get the amount of equivalent dice sets, having **2 dice at least**,for a given set.

For example, for the previous case: [6,6] we will have 3 equivalent sets that are: ``` [4, 3, 3], [12, 3], [9, 4]``` .

You may assume that dice are available from 3 and above for any value up to an icosahedral die (20 sides).
``` 
[5,6,4] ---> 5 (they are [10, 4, 3], [8, 5, 3], [20, 6], [15, 8], [12, 10])
``` 
For the cases we cannot get any equivalent set the result will be `0`.
For example for the set `[3,3]` we will not have equivalent dice.

Range of inputs for Random Tests:
``` 
3 <= sides <= 15
2 <= dices <= 7
``` 
See examples in the corresponding box.

Enjoy it!!

Difficulty: introductory

Starter code:

def eq_dice(set_):
	

Solutions:
import numpy as np

def products(n, min_divisor, max_divisor):      
    if n == 1:
        yield []
    for divisor in range(min_divisor, max_divisor+1):
        if n % divisor == 0:
            for product in products(n // divisor, divisor, max_divisor):
                yield product + [divisor] 

def eq_dice(set):
    product = np.prod(set)
    lista = list(products(product, 3, min(product-1, 20)))
    return len(lista) - 1 if len(set) > 1 else len(lista)

from functools import reduce

def getDivisors(n):
    lst, p = [], 2
    while n > 1:
        while not n%p:
            lst.append(p)
            n //= p
        p += 1 + (p!=2)
    return lst
    
    
def eq_dice(diceSet):
    events  = reduce(int.__mul__, diceSet)
    lstDivs = getDivisors(events)
    combos  = set(genCombDices(tuple(lstDivs), set()))
    return len(combos - {tuple(sorted(diceSet))})

            
def genCombDices(tup, seens):
    
    if tup[0] != 2: yield tup
    
    if len(tup) > 2:
        for i,a in enumerate(tup):
            for j,b in enumerate(tup[i+1:],i+1):
                m = a*b
                t = tuple(sorted(tup[:i] + tup[i+1:j] + tup[j+1:] + (m,)))
                if m > 20 or t in seens: continue
                seens.add(t)
                yield from genCombDices(t, seens)

from itertools import combinations_with_replacement
from pprint import pprint

def multiples(f):
    m = []
    for i in range(2,8):
        m.append(combinations_with_replacement(f,i))
    return m
    
def eq_dice(set_):
    mul = 1
    for e in set_:
        mul *= e
    facts = [x for x in range(3, 21) if not mul % x]
    count = 0
    for r in multiples(facts):
        for m in r:
            mu = 1
            for e in m:
                mu *= e
            if mu == mul and set(m) != set(set_):
                print(m)
                count += 1
    print(count)
    return count

from functools import reduce

def eq_dice(set_):
    n = reduce(int.__mul__, [s for s in set_ if s not in (11, 13)])
    stack = [[n, [s for s in set_ if s in (11, 13)]]]
    result = set()
    while stack:
        n, status = stack.pop()
        if (3 <= n <= 20) and (len(status) > 0):
            result.add(tuple(sorted(status + [n])))
        for i in range(3, min(20, int(n//3))+1):
            if (n % i == 0) and (n // i >= 3):
                stack.append([n//i, sorted(status + [i])])
    result.discard(tuple(sorted(set_)))
    return len(result)

from math import floor, sqrt
from numpy import prod

def f(n, l=3):
    if n < l:
        return
    for p in range(l, min(floor(sqrt(n)) + 1, 21)):
        if not n % p:
            for l in f(n // p, p):
                yield [p] + l
    if n <= 20:
        yield [n]

def eq_dice(l):
    return sum(1 for l in f(prod(l)) if len(l) > 1) - (len(l) > 1)

from functools import reduce
from math import floor, sqrt

def f(n, l=3):
    if n < l:
        return
    for p in range(l, min(floor(sqrt(n)) + 1, 21)):
        if not n % p:
            for l in f(n // p, p):
                yield [p] + l
    if n <= 20:
        yield [n]

def eq_dice(l):
    return sum(1 for l in f(reduce(lambda p, n: p * n, l, 1)) if len(l) > 1) - (len(l) > 1)

def product (dice):return dice[int()]*product(dice[1:]) if len(dice)>1 else dice[int()]
def eq_dice(dice):return len(recursive(product(dice),[],[]))-1 if len(dice)>1 else len(recursive(product(dice),[],[]))
def recursive(num,x,y,dice=3):
    if 3>num//3:return y
    while dice<=num//dice and dice<21:
        if num%dice==int():
            if sorted(x+[dice,num//dice]) not in y and num//dice<21:
                y.append(sorted(x+[dice,num//dice]))
            y=recursive(num//dice,x+[dice],y)
        dice+=1
    return y

from functools import reduce
def get_factors(m):
    li, j = [], 2
    while j * j <= m:
        if m % j:
            j += 1
            continue
        m //= j
        li.append(j)
    return li+([m] if m>1 else [])

def divide(arr, cache):
    store = []
    for i in range(len(arr)):
        for j in range(i + 1, len(arr)):
            m = arr[:i] + arr[i + 1:j] + [arr[i] * arr[j]] + arr[j + 1:]
            tp = tuple(sorted(m))
            if m != arr and len(m)>1 and tp not in cache:
                cache.add(tp)
                store.extend([tp] + divide(m,cache))
    return store

def eq_dice(arr):
    m, arr = reduce(lambda x, y: x * y, arr), tuple(sorted(arr))
    return sum(1 for i in set(divide(get_factors(m),set())) if i!=arr and all(2<k<21 for k in i))

from itertools import combinations_with_replacement
from numpy import prod

def eq_dice(set_):
    lst = sorted(set_)
    eq, dice, count = 0, [], prod(lst)
    
    for sides in range(3, 21):
        if count % sides == 0: dice.append(sides)
    
    for num_dice in range(2, 8): 
        for c in combinations_with_replacement(dice, num_dice):
            if prod(c) == count and sorted(c) != lst: eq += 1
            
    return eq