Частотний розподіл рулонів змішаної кістки


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]

Відповіді:


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]


4

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

Як було сказано у відповіді Хаскелла, для цього використовується той факт, що розподіл, наприклад, тристоронніх і 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

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 . Спостереження тут полягає в тому, що розподіл, наприклад, тристоронньої та 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

Спробуйте в Інтернеті!


4

Мова Вольфрама (Mathematica) , 26 байт

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

Спробуйте в Інтернеті!

Модифікація моєї відповіді на попередній виклик . Це просто генерує всі можливі результати, додає їх та сумарні результати.

Для розваги ми могли б написати це як Tally@*Total@*Thread@*Tuples@*Range, але це довше.

Мова Вольфрама (Mathematica) , 41 байт

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

Спробуйте в Інтернеті!

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


4

Математика, 44 байти

Виводить частоти, позначені відповідними сумами

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

Спробуйте в Інтернеті!

-5 байт від Мартіна Ендера

дякую Міші Лаврову за те, що він повідомив мені, що "мітка" є дійсною


3

Pyth , 12 байт

lM.gs.nk*FSM

Спробуйте тут!

Як?

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

          SM ~ Карта з включеним одинарним цілим діапазоном [1, N].
        * F ~ Скласти (зменшити на) декартовий продукт.
  .g ~ Згрупувати за результатом функції.
    sn ~ Сума списку при вирівнюванні.
lM ~ Довжина кожної групи.

3

Желе , 14 байт

R+Ѐ/FċЀSR$ḟ0

Спробуйте в Інтернеті!

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



2

05AB1E , 11 байт

€L.«âOO{γ€g

Спробуйте в Інтернеті!

Як це працює

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

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

Збережено 1 байт завдяки Emigna !


Ви можете зробити Oзамість цього€˜
Емінья

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 байт.


1

APL (Dyalog Classic) , 12 10 байт

-2 завдяки @ Adám

⊢∘≢⌸+/↑,⍳⎕

Спробуйте в Інтернеті!

вхід - це список N кубиків

⍳⍵ являє собою N-мірний масив вкладених векторів - усі можливі кидки вмираючих

+/↑, згладжує масиви і сумує кидки

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


1
-2: ⊢∘≢⌸+/↑,⍳⎕
Адама



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 , який імпортує необхідний для цього модуль.

Спробуйте в Інтернеті!


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.

Відформатовано та прокоментовано

Примітка: Це коментована версія мого початкового подання, яка використовувала скорочення (). Це на 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

0

Clojure, 96 байт

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

Перший вхід - це список кількості кісток, а другий - список кількості сторін на кожній кісті.


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

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]], але, на жаль, це набагато довше.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.