Распределение частот смешанных кубиков

24

Продолжение этой проблемы

Учитывая набор смешанных кубиков, выведите распределение частоты броска всех их и суммируя бросанные числа на каждом кристалле.

Например, рассмотрим 1d12 + 1d8(бросание 1 12-сторонней матрицы и 1 8-сторонней матрицы). Максимальный и минимальный броски равны 20и 2, соответственно, аналогичны броскам 2d10(2 10-гранных кубиков). Тем не менее, 1d12 + 1d8приводит к более плоскому распределению, чем 2d10: [1, 2, 3, 4, 5, 6, 7, 8, 8, 8, 8, 8, 7, 6, 5, 4, 3, 2, 1]против [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1].

правила

  • Частоты должны быть перечислены в порядке возрастания суммы, которой соответствует частота.
  • Разметка частот соответствующими суммами разрешена, но не обязательна (поскольку суммы могут быть выведены из требуемого порядка).
  • Вам не нужно обрабатывать входные данные, если выходные данные превышают представимый диапазон целых чисел для вашего языка.
  • Ведущие или конечные нули не допускаются. На выходе должны появляться только положительные частоты.
  • Вы можете принимать входные данные в любом приемлемом формате (список костей ( [6, 8, 8]), список пар костей ( [[1, 6], [2, 8]]) и т. Д.).
  • Частоты должны быть нормализованы так, чтобы GCD частот был 1 (например, [1, 2, 3, 2, 1]вместо [2, 4, 6, 4, 2]).
  • У всех кубиков будет по крайней мере одно лицо (таков d1минимум).
  • Это , поэтому выигрывает самый короткий код (в байтах). Стандартные лазейки запрещены, как обычно.

Тестовые случаи

Эти тестовые примеры приведены как input: output, где входные данные представлены в виде списка пар, [a, b]представляющих a bкубики со стороны (так [3, 8]относится 3d8и [[1, 12], [1, 8]]относится 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
источник

Ответы:

7

Желе ,  14  7 байт

-3 байта благодаря г-ну Xcoder (использование неявного диапазона, чтобы избежать лидерства R; замена сокращения на двоичный декартовый продукт и выравнивание p/F€, с помощью декартового продукта, встроенного для этой цели Œp.)

ŒpS€ĠL€

Монадическая ссылка, принимающая список граней игральных костей и возвращающая нормализованное распределение возрастающих сумм.

Попробуйте онлайн!

Как?

Проходит список «размеров» игральных костей (неявно) превращает их в список лиц, затем получает декартово произведение этих списков (все возможные броски набора игральных костей), затем суммирует эти броски, получает группы равных индексы (по возрастанию значения) и принимает длину каждой группы.

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

Примечание: есть только один способ бросить минимум (бросая по одному на каждый кубик), и мы не учитываем дважды броски, поэтому нет необходимости выполнять нормализацию GCD.

Джонатан Аллан
источник
Спасибо, мне интересно, нужно ли нам когда-нибудь ÷g/$(разве всегда есть только один способ получить минимум или максимум?)
Джонатан Аллан
2
Мысль это альтернатива, ŒpS€µLƙ
достойная внимания
5

MATL , 8 байт

1i"@:gY+

Входные данные представляют собой массив (возможно, повторяющихся) размеров матрицы.

Попробуйте онлайн! Или проверьте все тестовые случаи .

объяснение

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)
Луис Мендо
источник
5

Шелуха , 7 байт

mLkΣΠmḣ

Вход представляет собой список игральных костей. Попробуйте онлайн!

объяснение

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
источник
4

Октава , 88 69 58 56 байт

Как упомянуто в ответе Хаскелла, здесь используется тот факт, что распределение, например, 3-сторонней и 5-сторонней кости является дискретной сверткой двух векторов [1,1,1]и [1,1,1,1,1]. Спасибо @LuisMendo за умную игру в гольф на 11 байт!

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

Попробуйте онлайн!

Это представление использует рекурсивный подход. Но если бы вы использовали цикл, он был бы немного длиннее:

function y=f(c);y=1;for k=cellfun(@(x)ones(1,x),c,'Un',0);y=conv(y,k{1});end
flawr
источник
4

Haskell , 80 78 64 байта

Это решение оказалось почти таким же, как у @ Sherlock9 в предыдущем испытании, возможно, с более естественным подходом. У @xnor есть еще более короткое решение для Haskell !

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

Объяснение:

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

Попробуйте онлайн!

Предыдущее решение:

Это использует дискретную функцию свертки @AndersKaseorg . Наблюдение здесь состоит в том, что распределение, например, 3-сторонней и 5-сторонней кости является дискретной сверткой двух векторов [1,1,1]и [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

Попробуйте онлайн!

flawr
источник
4

Wolfram Language (Mathematica) , 26 байтов

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

Попробуйте онлайн!

Модификация моего ответа на предыдущий вызов . Это просто генерирует все возможные результаты, суммирует их и подсчитывает результаты.

Ради интереса мы могли бы написать это как Tally@*Total@*Thread@*Tuples@*Range, но это дольше.

Wolfram Language (Mathematica) , 41 байт

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

Попробуйте онлайн!

Это основанный на свертках подход (здесь мы берем свертки через произведение производящих функций - 1+x+x^2+...+x^(N-1)это производящая функция для броска dN - и затем берем список коэффициентов). Я включил это, потому что первое решение не практично для больших входов.

Миша лавров
источник
4

Mathematica, 44 байта

Вывод частот, помеченных соответствующими суммами

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

Попробуйте онлайн!

-5 байтов от Мартина Эндера

спасибо Мише Лаврову за то, что он дал мне знать, что «помечено» действительно

J42161217
источник
3

Pyth , 12 байт

lM.gs.nk*FSM

Попробуй это здесь!

Как?

lM.gs.nk * FSM ~ Полная программа.

          SM ~ Карта с включенным унарным целочисленным диапазоном [1, N].
        * F ~ Fold (уменьшить на) декартово произведение.
  .g ~ Группировать по функциям результат.
    sn ~ Сумма списка при сведении.
ММ ~ Длина каждой группы.
Мистер Xcoder
источник
3

Желе , 14 байт

R+Ѐ/FċЀSR$ḟ0

Попробуйте онлайн!

Ввод представляет собой список значений матрицы. Я мог сыграть в гольф, украдя ĠL€у другого ответа Желе, но затем я мог бы сыграть в гольф в первой половине и закончить тем же, так что я просто оставлю все как есть

dylnan
источник
2

05AB1E , 11 байт

€L.«âOO{γ€g

Попробуйте онлайн!

Как это работает

€ L. «ÂOO {γ € g - Полная программа.

€ L - для каждого N в списке получите [1 .. N].
  . «- Сложите двоичную функцию между каждым элементом в списке справа налево.
    â - И выберите декартово произведение в качестве этой функции.
     O - Свести каждого.
      О - Сумма каждого.
       {γ - Сортировка и группировка в серии равных соседних значений.
         € г - Получить длину каждого.

Сохранено 1 байт благодаря Emigna !

Мистер Xcoder
источник
Вы могли бы сделать Oвместо€˜
Emigna
2

R , 51 байт

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

Попробуйте онлайн!

Принимает список игральных костей и возвращает названный вектор частот; названия (значения сумм костей) печатаются над частотами.

R , 59 байт

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

Попробуйте онлайн!

ReduceПодход , а не итеративной выше.

R , 62 байта

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

Попробуйте онлайн!

Сверточный подход. Это даст несколько предупреждений, что он использует только первый элементD выражения для выражения, 1:Dно не влияет на вывод. Если бы нам не пришлось принимать всю Reчасть решения, это было бы 58 байтов.

Giuseppe
источник
1

APL (Дьялог Классик) , 12 10 байт

-2 благодаря @ Adám

⊢∘≢⌸+/↑,⍳⎕

Попробуйте онлайн!

вход представляет собой список из N кубиков

⍳⍵ является N-мерным массивом вложенных векторов - все возможные броски

+/↑, выравнивает массивы и суммирует броски

⊢∘≢⌸ подсчитывает, сколько каждой уникальной суммы, перечисленной в порядке их первого появления, что, к счастью, совпадает с их возрастающим порядком

СПП
источник
1
-2: ⊢∘≢⌸+/↑,⍳⎕
Адам
1

Рубин , 72 байта

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

Попробуйте онлайн!

Принимает список игральных костей в качестве входных данных. Без сомнения, это может быть в гольфе, но не так уж плохо.

Восстановить Монику Ямнотмайнард
источник
0

Чистый , 154 142 136 107 100 85 + 13 = 98 байт

Вход представляет собой список игральных костей.

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

Ответ в форме лямбды.

+13 байт изimport StdEnv , который импортирует модуль, необходимый для этой работы.

Попробуйте онлайн!

Οurous
источник
0

JavaScript (ES6), 83 байта

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

Принимает ввод каждого кубика как отдельный параметр.

Нил
источник
0

JavaScript (ES6), 76 74 байта

Принимает ввод в виде списка игральных костей.

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=[])

Контрольные примеры

Для обработки двух последних тестовых случаев потребуется включить TCO или увеличить предельный размер стека по умолчанию для механизма JS.

Отформатировано и прокомментировано

NB. Это закомментированная версия моего первоначального представления, в котором использовалась Redu (). Это на 2 байта длиннее, но легче для чтения.

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
источник
0

Clojure, 96 байт

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

Первый вход - это список количества кубиков, а второй - список количества сторон на каждом кубике.

NikoNyrh
источник
0

Perl 5 , 94 байта

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

Попробуйте онлайн!

Формат ввода представляет собой список игральных костей, разделенных символами новой строки. Таким образом, 1d10 + 2d8 будет вводить как:

10
8
8
Xcali
источник
0

SageMath, 46 байт

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

Попробуйте онлайн

Это адаптация моего решения к другому вызову . Он принимает любое количество кубиков в качестве параметров (например, f(4,4,6,6,6)для 2d4+3d6) и возвращает список.


Python 2 + NumPy , 62 байта

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

Попробуйте онлайн!

Как и раньше, я включил это решение в приведенное выше, поскольку они по сути эквивалентны. Обратите внимание, что эта функция возвращает массив NumPy, а не список Python, поэтому выходные данные выглядят немного иначе, если вы printэто сделаете .

numpy.ones(x)это «правильный» способ сделать массив для использования с NumPy, и, таким образом, его можно использовать вместо него [x*[1]], но, к сожалению, он намного длиннее.

Mego
источник