Distribución de frecuencia de rollos de dados mixtos

24

Un seguimiento de este desafío.

Dado un conjunto de dados mixtos, genera la distribución de frecuencias de tirarlos todos y sumar los números tirados en cada dado.

Por ejemplo, considere 1d12 + 1d8(tirar 1 dado de 12 lados y 1 dado de 8 lados). Las tiradas máximas y mínimas son 20y 2, respectivamente, que es similar al lanzamiento 2d10(2 dados de 10 lados). Sin embargo, 1d12 + 1d8resulta en una distribución más plana que 2d10: [1, 2, 3, 4, 5, 6, 7, 8, 8, 8, 8, 8, 7, 6, 5, 4, 3, 2, 1]versus [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1].

Reglas

  • Las frecuencias deben enumerarse en orden creciente de la suma a la que corresponde la frecuencia.
  • Se permite etiquetar las frecuencias con las sumas correspondientes, pero no es obligatorio (ya que las sumas se pueden inferir del orden requerido).
  • No tiene que manejar entradas donde la salida excede el rango representable de enteros para su idioma.
  • Los ceros iniciales o finales no están permitidos. Solo deben aparecer frecuencias positivas en la salida.
  • Puede tomar la entrada en cualquier formato razonable (lista de dados ( [6, 8, 8]), lista de pares de dados ( [[1, 6], [2, 8]]), etc.).
  • Las frecuencias deben normalizarse para que el MCD de las frecuencias sea 1 (por ejemplo, en [1, 2, 3, 2, 1]lugar de [2, 4, 6, 4, 2]).
  • Todos los dados tendrán al menos una cara (por lo que a d1es el mínimo).
  • Este es el , por lo que gana el código más corto (en bytes). Las lagunas estándar están prohibidas, como de costumbre.

Casos de prueba

Estos casos de prueba se dan como input: output, donde la entrada se da como una lista de pares que [a, b]representan a bdados de lado (así se [3, 8]refiere 3d8y se [[1, 12], [1, 8]]refiere a 1d12 + 1d8).

[[2, 10]]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
[[1, 1], [1, 9]]: [1, 1, 1, 1, 1, 1, 1, 1, 1]
[[1, 12], [1, 8]]: [1, 2, 3, 4, 5, 6, 7, 8, 8, 8, 8, 8, 7, 6, 5, 4, 3, 2, 1]
[[2, 4], [3, 6]]: [1, 5, 15, 35, 68, 116, 177, 245, 311, 363, 392, 392, 363, 311, 245, 177, 116, 68, 35, 15, 5, 1]
[[1, 3], [2, 13]]: [1, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 37, 36, 33, 30, 27, 24, 21, 18, 15, 12, 9, 6, 3, 1]
[[1, 4], [2, 8], [2, 20]]: [1, 5, 15, 35, 69, 121, 195, 295, 423, 579, 761, 965, 1187, 1423, 1669, 1921, 2176, 2432, 2688, 2944, 3198, 3446, 3682, 3898, 4086, 4238, 4346, 4402, 4402, 4346, 4238, 4086, 3898, 3682, 3446, 3198, 2944, 2688, 2432, 2176, 1921, 1669, 1423, 1187, 965, 761, 579, 423, 295, 195, 121, 69, 35, 15, 5, 1]
[[1, 10], [1, 12], [1, 20], [1, 50]]: [1, 4, 10, 20, 35, 56, 84, 120, 165, 220, 285, 360, 444, 536, 635, 740, 850, 964, 1081, 1200, 1319, 1436, 1550, 1660, 1765, 1864, 1956, 2040, 2115, 2180, 2235, 2280, 2316, 2344, 2365, 2380, 2390, 2396, 2399, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2400, 2399, 2396, 2390, 2380, 2365, 2344, 2316, 2280, 2235, 2180, 2115, 2040, 1956, 1864, 1765, 1660, 1550, 1436, 1319, 1200, 1081, 964, 850, 740, 635, 536, 444, 360, 285, 220, 165, 120, 84, 56, 35, 20, 10, 4, 1]
Mego
fuente
Sandbox
Mego

Respuestas:

7

Jalea ,  14  7 bytes

-3 bytes gracias al Sr. Xcoder (uso de un rango implícito para evitar el liderazgo R; reemplazo de reducir por el producto cartesiano diádico y aplanar p/F€, con el producto cartesiano incorporado para ese mismo propósito Œp).

ŒpS€ĠL€

Un enlace monádico que toma una lista de caras de dados y devuelve la distribución normalizada de las sumas crecientes.

Pruébalo en línea!

¿Cómo?

Revisa la lista de "tamaños" de dados (implícitamente) los convierte en su lista de caras, luego obtiene el producto cartesiano de esas listas (todas las tiradas posibles del conjunto de dados), luego resume esas tiradas, obtiene los grupos iguales índices (por valor ascendente) y toma la longitud de cada grupo.

ŒpS€ĠL€ - Link: list of numbers, dice  e.g. [2,5,1,2]
Œp      - Cartisian product (implicit range-ification -> [[1,2],[1,2,3,4,5],[1],[1,2]])
        -                   -> [[1,1,1,1],[1,1,1,2],[1,2,1,1],[1,2,1,2],[1,3,1,1],[1,3,1,2],[1,4,1,1],[1,4,1,2],[1,5,1,1],[1,5,1,2],[2,1,1,1],[2,1,1,2],[2,2,1,1],[2,2,1,2],[2,3,1,1],[2,3,1,2],[2,4,1,1],[2,4,1,2],[2,5,1,1],[2,5,1,2]]
  S€    - sum €ach          -> [4,5,5,6,6,7,7,8,8,9,5,6,6,7,7,8,8,9,9,10]
    Ġ   - group indices     -> [[1],[2,3,11],[4,5,12,13],[6,7,14,15],[8,9,16,17],[10,18,19],[20]]
     L€ - length of €ach    -> [1,3,4,4,4,3,1]

Nota: solo hay una forma de tirar el mínimo (tirando uno en cada dado) y no contamos dos veces, por lo que no es necesario realizar una normalización GCD.

Jonathan Allan
fuente
Gracias, me pregunto si alguna vez necesitamos algo así ÷g/$(¿no hay siempre una sola forma de obtener el mínimo o el máximo?)
Jonathan Allan
2
Pensé que esta era una alternativa que valía la pena compartir:ŒpS€µLƙ
Sr. Xcoder
5

MATL , 8 bytes

1i"@:gY+

La entrada es una matriz de tamaños de troqueles (posiblemente repetidos).

Pruébalo en línea! O verificar todos los casos de prueba .

Explicación

1      % Push 1
i      % Input: numeric array
"      % For each k in that array
  @    %   Push k
  :    %   Range: gives [1 2 ... k]
  g    %   Convert to logical: gives [1 1 ... 1]
  Y+   %   Convolution, with full size
       % End (implicit). Display (implicit)
Luis Mendo
fuente
5

Casco , 7 bytes

mLkΣΠmḣ

La entrada es una lista de dados. Pruébalo en línea!

Explicación

mLkΣΠmḣ  Implicit input, say x=[3,3,6].
     mḣ  Map range: [[1,2,3],[1,2,3],[1,2,3,4,5,6]]
    Π    Cartesian product: [[1,1,1],[1,1,2],..,[3,3,6]]
  kΣ     Classify by sum: [[[1,1,1]],[[1,1,2],[1,2,1],[2,1,1]],..,[[3,3,6]]]
mL       Map length: [1,3,6,8,9,9,8,6,3,1]
Zgarb
fuente
4

Octava , 88 69 58 56 bytes

Como se menciona en la respuesta de Haskell, esto utiliza el hecho de que la distribución de, por ejemplo, un dado de 3 lados y uno de 5 lados es la convolución discreta de los dos vectores [1,1,1]y [1,1,1,1,1]. ¡Gracias @LuisMendo por -11 bytes de golf inteligente!

function y=f(c);y=1:c;if d=c(2:end);y=conv(~~y,f(d));end

Pruébalo en línea!

Esta presentación está utilizando un enfoque recursivo. Pero si usaras un bucle, sería un poco más largo:

function y=f(c);y=1;for k=cellfun(@(x)ones(1,x),c,'Un',0);y=conv(y,k{1});end
falla
fuente
4

Haskell , 80 78 64 bytes

Esta solución terminó siendo casi la misma que la de @ Sherlock9 en el desafío anterior con el enfoque quizás más natural. ¡@xnor tiene una solución Haskell aún más corta !

import Data.List
g x=[1..x]
map length.group.sort.map sum.mapM g

Explicación:

                              mapM g -- all possible outcomes
                      map sum        -- the sums of all possible outcomes
map length.group.sort                -- count the frequency of each sum

Pruébalo en línea!

Solución previa:

Esto está utilizando la función de convolución discreta @AndersKaseorg . La observación aquí es que la distribución de, por ejemplo, un dado de 3 lados y un dado de 5 lados es la convolución discreta de los dos vectores [1,1,1]y [1,1,1,1,1].

foldl1(#).map(`take`l)
(a:b)#c=zipWith(+)(0:b#c)$map(a*)c++[]#b
_#c=0<$c
l=1:l

Pruébalo en línea!

falla
fuente
4

Wolfram Language (Mathematica) , 26 bytes

Tally[Tr/@Tuples@Range@#]&

Pruébalo en línea!

Una modificación de mi respuesta al desafío anterior . Esto solo genera todos los resultados posibles, los suma y cuenta los resultados.

Por diversión, podríamos escribirlo como Tally@*Total@*Thread@*Tuples@*Range, pero eso es más largo.

Wolfram Language (Mathematica) , 41 bytes

CoefficientList[1##&@@((x^#-1)/(x-1)),x]&

Pruébalo en línea!

Este es el enfoque basado en convolución (aquí, tomamos convoluciones a través del producto de funciones generadoras - 1+x+x^2+...+x^(N-1)es la función generadora para lanzar un dN - y luego tomamos la lista de coeficientes). Lo incluyo porque la primera solución no es práctica para entradas grandes.

Misha Lavrov
fuente
4

Mathematica, 44 bytes

Emite las frecuencias etiquetadas con las sumas correspondientes.

Tally@*Fold[Join@@Table[#+i,{i,#2}]&]@*Range

Pruébalo en línea!

-5 bytes de Martin Ender

gracias a Misha Lavrov por informarme que "etiquetado" es válido

J42161217
fuente
3

Pyth , 12 bytes

lM.gs.nk*FSM

Pruébalo aquí!

¿Cómo?

lM.gs.nk * FSM ~ Programa completo.

          SM ~ Mapa con rango entero unario inclusivo [1, N].
        * F ~ Doblar (reducir por) producto cartesiano.
  .g ~ Agrupar por resultado de función.
    sn ~ La suma de la lista cuando se aplana.
lM ~ Longitud de cada grupo.
Sr. Xcoder
fuente
3

Jalea , 14 bytes

R+Ѐ/FċЀSR$ḟ0

Pruébalo en línea!

La entrada es una lista de valores de troquel. Podría jugar golf al robar ĠL€de la otra respuesta de Jelly, pero también podría jugar golf la primera mitad y terminar con lo mismo, así que lo dejaré como está.

dylnan
fuente
2

Python 2 , 120 119 bytes

lambda v:[reduce(lambda a,c:sum([[b+y for b in a]for y in range(c)],[]),v,[0]).count(d)for d in range(sum(v)-len(v)+1)]

Pruébalo en línea!

Gracias por Mego / Jonathon Allan por 1 byte.

Chas Brown
fuente
... es decir, guardar un byte .
Jonathan Allan
2

05AB1E , 11 bytes

€L.«âOO{γ€g

Pruébalo en línea!

Cómo funciona

€ L. «ÂOO {γ € g - Programa completo.

€ L - Por cada N en la lista, obtenga [1 .. N].
  . «- Dobla una función diádica entre cada elemento en una lista de derecha a izquierda.
    â - Y elige el producto cartesiano como esa función.
     O - Aplane cada uno.
      O - Suma cada uno.
       {γ - Ordenar y agrupar en series de valores adyacentes iguales.
         € g - Obtenga las longitudes de cada uno.

¡Guardado 1 byte gracias a Emigna !

Sr. Xcoder
fuente
Podrías hacerlo en Olugar de€˜
Emigna
2

R , 51 bytes

function(D){for(x in D)F=outer(F,1:x,"+")
table(F)}

Pruébalo en línea!

Toma una lista de dados y devuelve un vector de frecuencias con nombre; Los nombres (valores de las sumas de los dados) están impresos sobre las frecuencias.

R , 59 bytes

function(D)table(Reduce(function(x,y)outer(x,1:y,"+"),D,0))

Pruébalo en línea!

Un Reduceenfoque en lugar del iterativo anterior.

R , 62 bytes

function(D)Re(convolve(!!1:D,"if"(sum(x<-D[-1]),f(x),1),,"o"))

Pruébalo en línea!

Un enfoque de convolución. Le dará algunas advertencias de que solo está usando el primer elemento de Dpara la expresión, 1:Dpero no afecta la salida. Si no tuviéramos que tomar la Reparte completa de la solución, serían 58 bytes.

Giuseppe
fuente
1

APL (Dyalog Classic) , 12 10 bytes

-2 gracias a @ Adám

⊢∘≢⌸+/↑,⍳⎕

Pruébalo en línea!

la entrada es una lista de N dados

⍳⍵ es una matriz N-dimensional de vectores anidados: todos los posibles lanzamientos de dados

+/↑, aplana las matrices y suma los lanzamientos

⊢∘≢⌸ cuenta cuántos de cada suma única, enumerados en orden de su primera aparición, que afortunadamente coincide con su orden creciente

ngn
fuente
1
-2: ⊢∘≢⌸+/↑,⍳⎕
Adám
1

Ruby , 72 bytes

->d{r=[0]*d.sum
[0].product(*d.map{|e|[*1..e]}){|e|r[e.sum-1]+=1}
r-[0]}

Pruébalo en línea!

Toma una lista de dados como entrada. Sin duda se puede jugar golf, pero no está mal.

Restablecer a Monica iamnotmaynard
fuente
0

Limpio , 154 142 136 107 100 85 + 13 = 98 bytes

La entrada es una lista de dados.

\l#t=foldr(\a-> \b=[x+y\\x<-[1..a],y<-b])[0]l
=[length[v\\v<-t|u==v]\\u<-removeDup t]

La respuesta es en forma de lambda.

+13 bytes de import StdEnv, que importa el módulo necesario para que esto funcione.

Pruébalo en línea!

Οurous
fuente
0

JavaScript (ES6), 83 bytes

f=(n,...a)=>n?f(...a).map((e,i)=>[...Array(n)].map(_=>r[i]=~~r[i++]+e),r=[])&&r:[1]
g=s=>o.textContent=f(...(s.match(/\d+/g)||[]).map(n=>+n)).join`, `
<input oninput=g(this.value)><p id=o>1

Toma la entrada de cada dado como un parámetro separado.

Neil
fuente
0

JavaScript (ES6), 76 74 bytes

Toma entrada como una lista de dados.

a=>(g=k=>a.map(d=>(s+=n%d|0,n/=d),s=0,n=k)|n?x:g(k+1,x[s]=-~x[s]))(0,x=[])

Casos de prueba

El procesamiento de los dos últimos casos de prueba requeriría habilitar TCO o aumentar el límite de tamaño de pila predeterminado del motor JS.

Formateado y comentado

NB: Esta es una versión comentada de mi envío inicial que usaba reduce (). Es 2 bytes más largo pero más fácil de leer.

a =>                    // given the list of dice a
  (g = k =>             // g = recursive function taking k = counter
    a.reduce((k, d) =>  //   for each die d in a:
      (                 //     k % d represents the current face of d
        s += k % d,     //     we add it to the total s
        k / d | 0       //     and we update k to pick the face of the next die
      ),                //     initialization:
      k,                //     start with the current value of k
      s = 0             //     total = 0
    ) ?                 //   reduce() returns 1 as soon as k = product of all dice
      x                 //     in which case we're done: stop recursion and return x
    :                   //   else:
      g(                //     do a recursive call to g() with:
        k + 1,          //       k incremented
        x[s] = -~x[s]   //       x[s] incremented
      )                 //     end of recursive call
  )(0, x = [])          // initial call to g() with k = 0 and x = empty array
Arnauld
fuente
0

Clojure, 96 bytes

#(sort-by key(frequencies(reduce(fn[R D](for[d(range D)r R](+ r d 1)))[0](mapcat repeat % %2))))

La primera entrada es una lista de la cantidad de dados, y la segunda entrada es una lista de la cantidad de lados en cada dado.

NikoNyrh
fuente
0

Perl 5 , 94 bytes

map$k{$_}++,map eval,glob join'+',map'{'.(join',',1..$_).'}',<>;say$k{$_}for sort{$a-$b}keys%k

Pruébalo en línea!

El formato de entrada es una lista de dados separados por nuevas líneas. Por lo tanto, 1d10 + 2d8 ingresaría como:

10
8
8
Xcali
fuente
0

SageMath, 46 bytes

lambda*a:reduce(convolution,[x*[1]for x in a])

Pruébalo en línea

Esta es una adaptación de mi solución al otro desafío . Toma cualquier número de dados como parámetros (por ejemplo, f(4,4,6,6,6)para 2d4+3d6) y devuelve una lista.


Python 2 + NumPy , 62 bytes

lambda*a:reduce(numpy.convolve,[x*[1]for x in a])
import numpy

Pruébalo en línea!

Como antes, he incluido esta solución con la anterior, ya que son esencialmente equivalentes. Tenga en cuenta que esta función devuelve una matriz NumPy y no una lista de Python, por lo que la salida se ve un poco diferente si lo printhace.

numpy.ones(x)es la forma "correcta" de hacer una matriz para usar con NumPy y, por lo tanto, podría usarse en lugar de [x*[1]], pero desafortunadamente es mucho más larga.

Mego
fuente