混合骰子辊的频率分布


24

应对这一挑战的后续行动

给定一组混合的骰子,输出滚动所有骰子并汇总每个骰子上的掷骰数的频率分布。

例如,考虑1d12 + 1d8(滚动1个12面模具和1个8面模具)。最大和最小掷骰分别是202,类似于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]vs 更平坦[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])。
  • 所有骰子将至少具有一张脸(因此a 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]

Answers:


7

果冻 14  7 字节

感谢Xcoder先生 -3个字节(使用隐式范围来避免超前R;用二进角的笛卡尔乘积和flatten替换reduce,并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ƙ
Xcoder先生17年

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字节

正如Haskell答案中提到的那样,这利用了以下事实:例如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

4

Haskell80 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

在线尝试!


4

Wolfram语言(Mathematica),26个字节

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

在线尝试!

我对先前挑战答案的修改。这只会生成所有可能的结果,将它们加起来并计算结果。

为了好玩,我们可以将其编写为Tally@*Total@*Thread@*Tuples@*Range,但这会更长。

Wolfram语言(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

在线尝试!

Martin Ender的-5字节

感谢Misha Lavrov让我知道“标签”有效


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-总计。
       {γ-排序,并分组为相等相邻值的游程。
         €g-获取每个的长度。

感谢Emigna节省了1个字节!


您可以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个字节。


1

APL(Dyalog Classic)12 10字节

-2感谢@Adám

⊢∘≢⌸+/↑,⍳⎕

在线尝试!

输入是N个骰子的列表

⍳⍵ 是嵌套向量的N维数组-所有可能的掷骰

+/↑, 展平数组并求和

⊢∘≢⌸ 计算按首次出现的顺序列出的每个唯一总和的多少,幸运的是,它们与升序一致


1
-2: ⊢∘≢⌸+/↑,⍳⎕
ADAM



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]

答案是lambda形式。

+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引擎的默认堆栈大小限制。

格式化和评论

注意:这是我最初提交的评论版本,它使用了reduce()。它长了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]],但不幸的是,它要长得多。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.