不是您的常规豆机


42

考虑类似的机制这个ASCII版本豆机plinko / 柏青哥游戏:

    O

    ^
   \ ^
  ^ ^ \
 \ ^ / ^
U U U U U
1 2 3 4 5

O是落下来球。

  • 当它达到时^,有50-50的机会会左右移动。
  • 当它/到达时,它总是向左走。
  • 当它达到时\,它总是正确的。

球最终落入U底部的编号槽之一。问题是,每个低谷结束的概率是多少?

对于这种特殊的情况下,该概率是0.00.18750.56250.125,和0.125,用于分别槽1至5。

这里的3个槽代替5.概率是另一个例子0.50.5以及0.0

  O

  /
 ^ ^
U U U
1 2 3

在这个挑战中,我们将把这个问题推广到一种以任何方式设置任意数量的层的机制。

挑战

编写一个程序或函数,该程序或函数采用该机制的金字塔结构的ASCII表示形式。(通过标准输入/命令行/功能参数输入。)

您可能会认为它带有适当形状的空间,例如

   ^
  \ ^
 ^ ^ \
\ ^ / ^

或者您可能会认为它根本没有空格,例如

^
\^
^^\
\^/^

(如果需要,您可以假定存在尾随换行符和/或尾随空格的某种一致模式。)

输入金字塔结构可以具有任意数量的级别(又称线),包括零。每一级具有一个以上^/\比上,并且有levels + 1在底部沟槽(其不是输入的一部分)。

您的程序/功能必须打印/返回球在每个槽中着陆的概率列表(按从最左边到最右边的顺序)。这些应该是浮点值,在打印时,它们至少应有3个小数位(不需要多余的零或小数点;1适用于1.000.5适用于0.500,等等)。如果编写了函数,则可以打印值或返回浮点数的列表/数组。

任何合理的打印列表格式都可以。例如0.5 0.5 0.0[0.5 0.5 0.0][0.5, 0.5, 0.0]{0.5, 0.5, 0.0},或0.5\n0.5\n0.0都将是好的。

例子

0级:(归结为一小部分U

输入:[no input/empty string given]
输出:1.0

1级:

输入:^
输出:0.5 0.5

输入:/
输出:1.0 0.0

输入:\
输出:0.0 1.0

2级:(上面的第二个示例)

输入:

 /
^ ^

输出: 0.5 0.5 0.0

3个级别:

输入:

  ^
 ^ ^
^ ^ ^

输出: 0.125 0.375 0.375 0.125

输入:

  \
 / \
/ / \

输出: 0.0 0.0 0.0 1.0

4级:(上面的第一个示例)

输入:

   ^
  \ ^
 ^ ^ \
\ ^ / ^

输出: 0.0 0.1875 0.5625 0.125 0.125

7级:

输入:

      ^
     / ^
    ^ ^ /
   / \ / \
  ^ ^ / ^ \
 ^ \ ^ \ / ^
\ ^ ^ ^ \ ^ /

输出: 0.0 0.09375 0.28125 0.4375 0.1875 0.0 0.0 0.0

计分

以字节为单位的最短答案将获胜。Tiebreaker是较早的帖子。


16
梅花更好的回答这个问题。
加尔文的爱好2015年

“尾随空间的某些一致模式”-我是否可以假设第N行上的尾随空间编码了球落在第N个铲斗中的概率?
Random832 2015年

4
@ Random832号(您真的认为那会飞吗?)
卡尔文的爱好

我将其发布为评论而不是答案是有原因的。我只是觉得有趣的是,这个难题对输入有多宽容-我所见过的大多数问题都更严格地规定了输入和/或输出的格式。
Random832

@ Random832:输入和输出非常明确。不需要在每个挑战中都解决标准漏洞(例如在输入中编码答案)。
Alex A.

Answers:


10

CJam,50 48 45 44 42 40字节

1]q{iD%"(+0 0+( (\Y/::+ (d2/_a+"S/=~+}/p

这期望输入没有空格并且尾随换行符。例如:

^
\^
^^\
\^/^

[0 0.1875 0.5625 0.125 0.125]

算法

基本思想是继续解析每个字符(只有4个不同的字符),并对概率分布(最初是一个包含1个值1元素的数组)执行不同的操作。对于输入字符的每一行(从第一行的第一个字符开始),我们保持相同大小的概率数组。每个角色根据列表中的第一个概率进行操作,并将结果对推到列表的末尾。在每一行之后,我们对列表中的对进行汇总,以获取确切的项目数,作为下一行中的项目。

这是四个字符以及与每个字符相对应的必需操作:

  • ^:出现此字符时,将当前概率分为两部分。例如,如果我们在第一行上有此内容,则必须将转换[1][0.5 0.5]
  • /:出现此字符时,我们必须<current probability> 0在数组中代替当前概率。
  • \:出现此字符时,我们必须0 <current probability>在数组中代替当前概率。
  • \n:出现此字符时,我们会有一个新行。因此,我们将来自以上3个字符的所有对组合在一起,并将它们加起来以获得下一行中每个项目的概率。对于前。[0 0.5 0.25 0.25]转换为[0 0.75 0.25]。请注意,第一项和最后一项在其前后都有一个隐式对(值为0)。

现在我们只需要识别正确的角色并执行正确的操作即可。让我们在这里使用通常的数学来做到这一点。对于ASCII码^\/\n949247,和10。经过几次试验,我们得到了一个简单的方程式,将这些数字转换为0、1、2和3:

"^\/
":ied13f%ed4f%ed

给出:

Stack: [[94 92 47 10]]
Stack: [[3 1 8 10]]
Stack: [[3 1 0 2]]
3102

在长度为4的数组中,最后一个4f%将是隐式的。因此,我们只需%13对字符的ASCII码进行操作,然后从一系列操作中选择正确的操作即可。

代码说明

1]                                 e# Initial probability array with 1 probability
  q{                          }/   e# Read the whole input and iterate char by char
    iD%                            e# mod the ASCII code of the character with 13
"(+0 0+( (\Y/::+ (d2/_a+"S/        e# This is our actions array in order of [\ / \n ^]
                           =~      e# We pick the correct action and eval it
                             +     e# Evaling each action will leave one number out of the
                                   e# pairs out of the array. So we put it back in
                                p  e# Print the final probability array

在这里在线尝试


1
如何测试0行?
trichoplax

1
@trichoplax现在应该可以工作。
Optimizer

它现在可以使用空输入:)
trichoplax

15

红宝石140

->s{r=[1.0]
s.lines.map{|l|n=[i=0.0]*(r.size+1)
l.scan(/\S/).map{|e|a,b=e>?/?e>?]?[0.5]*2:[0,1]:[1,0]
z=r[i]
n[i]+=z*a
n[i+=1]+=z*b}
r=n}
r}

该函数将字符串(可以很好地格式化为金字塔)作为输入并返回浮点数数组。

在线测试:http//ideone.com/kmsZMe

非常简单的实现。这里是无高尔夫球的:

F = -> input {
  probabilities = [1.0]

  input.lines.each { |line|

    new_probabilities = [0.0] * (probabilities.size+1)
    elements = line.scan /\S/
    elements.map.with_index{|el, i|
      deltas = el > '/' ? (el > ']' ? [0.5,0.5] : [0,1]) : [1,0]

      d1, d2 = deltas

      new_probabilities[i] += probabilities[i] * d1
      new_probabilities[i + 1] += probabilities[i] * d2
    }
    probabilities = new_probabilities
  }
  return probabilities
}

13

Ruby 140158字节

有更好的红宝石版本,请不要继续对此表示赞同。这是给您的更多技巧。

具有一个参数的未命名函数。不得包含任何空格。可能包含也可能不包含结尾的换行符。

->s{Z=(s.split'
')<<[]
K=[]
F=->i,j,f{k=Z[i][j]
K[i]||=0
k==?^?2.times{|m|F[i+1,j+m,f/2]}:!k ?K[j]+=f :F[i+1,j+(k==?/?0:1),f]}
F[0,0,1.0]
K}

在必须处理时浪费9个字节0 levels(空字符串)。所有测试用例都能正常工作,请参见ideone此处


4
仅仅因为有一个“更好的” Ruby答案并不意味着您(或其他任何有关Ruby的答案)不值得投票。:)
Alex A.

我自己对此表示赞同,因为它包含一些不错的技巧。split例如,我喜欢您的多行。
克里斯蒂安·卢帕斯库

12

Pyth,43 42 41字节

umsdc+0sm@c[ZJhkJZKcJ2K)2x"\/"ekC,GH2.z]1

这期望输入没有空格。在线尝试:Pyth编译器/执行器

Pyth,40个字节(可疑)

umsdc+0sm,K@[ZJhkcJ2)x"\/"ek-JKC,GH2.z]1

感谢@isaacg,节省了一个字节。请注意,在询问问题时,该版本实际上不适用于Pyth版本。编译器中有一个小错误。尽管此代码未使用Pyth的新功能(仅在Pyth文档中使用了很长时间并且应该可以使用的东西),但这可能不是有效的答案。自行决定。

在线尝试:Pyth编译器/执行器

说明:

umsdc+0sm,K@[ZJhkcJ2)x"\/"ek-JKC,GH2.z]1   
u                                   .z]1  reduce G, starting with G = [1], for H in all_input():
                               C,GH         zip(G,H)
        m                                   map each pair k to:
            [ZJhkcJ2)                         create a list [0, k[0], k[0]/2]
                     x"\/"ek                  index of k[1] in "\/" (-1 for "^")
          K@                                  take the correspondent element of the list and store in K
         ,                  -JK               create a pair (K, k[0]-K)                                                      
     +0s                                    sum and insert 0 at the begin
    c                              2        chop into pairs
 msd                                        sum up each pair
                                            G gets updated with this new list

例如,如果我当前具有输入概率G = [0.5, 0.5, 0.0]和该行H = "^/^",则会发生以下情况:

  • 压缩 ... [(0.5,"^"), (0.5,"/"), (0.0,"^")]
  • 创建输出概率... [[0.25,0.25], [0.5,0.0], [0.0, 0.0]]
  • 0+和... [0, 0.25, 0.25, 0.5, 0.0, 0.0, 0.0]
  • 剁... [0,0.25], [0.25,0.5], [0.0,0.0], [0.0]]
  • 总和... [0.25, 0.75, 0.0, 0.0]

3
我试图打高尔夫球,这导致我遇到了编译器中的错误。现在,我已经修复了错误,高尔夫工作了。高尔夫是用一个列表替换2值列表的列表,然后通过从中减去第一个值来生成另一个值hk,K@[ZJhkcJ2)x"\/"ek-JK
2015年

1
当您修正错误时,这并不算是该语言的较新版本,所以这确实是一条好线(因此对于修正前的问题仍然有效)
Optimizer

1
@Optimizer您的权利。在答案中添加了一些注释,以解释情况。
雅库布2015年

2
@Optimizer在这种情况下,似乎是一个很好的经验法则是它是真正的语言更新版本还是修复错误的语言实现的更新版本,使实现更符合规范。
Desty

@Desty这就是为什么我提到这条线的原因;)
Optimizer

8

C#,274个 247字节

没什么花哨的完整程序可以从STDIN中读取行(带或不带空格,它只是将其删除),并将空格分隔的结果打印到STDOUT。

using Q=System.Console;class P{static void Main(){decimal[]k={1},t;string L;for(int l=0,i;(L=Q.ReadLine())!=null;k=t)for(L=L.Replace(" ",""),t=new decimal[++l+1],i=0;i<l;)t[i]+=k[i]-(t[i+1]=(8-L[i]%8)/2*k[i++]/2);Q.WriteLine(string.Join(" ",k));}}

带有注释的整理代码:

using Q=System.Console;

class P
{
    // / 47
    // \ 92
    // ^ 94

    static void Main()
    {
        decimal[]k={1},t; // k is old array, t is new array

        string L; // L is the current line, R is the current result (1 if no rows)
        for(int l=0,i; // l is length of old array, i is index in old array
            (L=Q.ReadLine())!=null; // for each line of input
            k=t) // swap array over
            for(L=L.Replace(" ",""), // remove spaces
                t=new decimal[++l+1], // create a new array
                i=0;

                i<l;) // for each position

                t[i]+=k[i]-( // add to left position (for last time)
                        t[i+1]=(8-L[i]%8)/2*k[i++]/2 // assign right position (k is decimal)
                    );

        Q.WriteLine(string.Join(" ",k)); // print result
    }
}

7

Python 3、113

P=[1]
for C in input().split():
 l,*Q=0,
 for p,c in zip(P,C):r=p*"\^/".find(c)/2;Q+=l+r,;l=p-r
 P=Q+[l]
print(P)

P响应每一行重复更新概率向量。Q每次创建一个新的概率向量。遍历新的插槽,并将桩钉向右r的贡献计算为,同时还将剩余的对即将到来的插槽的贡献计算为p-r

期望每行至少在一个空格结束,以避免出现行以反斜杠结尾的问题。


输入将有多行,所以我认为没有一个行input()可以处理。
randomra'5

输入的每一行都不需要尾随换行符。
Brian Minton

@randomra我是在Idle中编写的,在将多行输入添加到shell提示时效果很好。
xnor 2015年

6

Python 3,138个字节

def f(s):
 r=[1];p=t=0
 for e in s:
  if'!'<e:b=p==t*-~t/2;r+=[0]*b;t+=b;v=ord(e)%7+1;a=r[p]/2;r[-1]+=v//3*a;r+=v%3*a,;p+=1
 return r[~t:]

可与所有空格一起使用,因为它们都被(if'!'<e)过滤掉了。

方法:

  • 我们会不断增加列出r遇到任何障碍的可能性及其下方的隐性谷的清单。我们从清单开始[1]
  • 如果我们连续处于第一个障碍,则需要0在列表中添加一个额外的值以用于领先的槽。我们通过将其索引p与下一个三角数进行比较来确定它是否是第一个障碍t*-~t/2
  • 对于每个障碍,我们将其列表值部分添加到最后一个元素,部分添加到新的尾随元素。我们根据障碍物字符(^:0.5 0.5; /:1 0; \:0 1)划分列表值。我们使用以下方法:
    • v = ord(char) mod 7 + 1高产^:4 /:6 \:2
    • v div 3 / 2产生第一个分数(^:0.5 /:1 \:0
    • v mod 3 / 2产生第二个分数(^:0.5 /:0 \:1
  • 结果是t + 1最终列表的最后一个元素r

2个字节,感谢@ Sp3000的聊天建议。


4

Perl,78岁

#!perl -p0a
@r=($/=1);$^=.5;@r=map$r-$l+($l=$$_*($r=shift@r)),/./g,$r=$l=0for@F;$_="@r"

输入没有空格的输入。

试试


1

TI-BASIC,73 76

一次只输入一行,当单独输入一个空格时结束输入,因为在TI-BASIC中,字符串的换行和空字符串都不合法。

{1→X
Input Str1
While Str1≠"  //one space
.5seq(inString("^/",sub(Str1,I,1)),I,1,dim(Ans
augment(Ans∟X,{0})+augment({0},∟X-∟XAns→X
Input Str1
End
∟X

我确定我的大小正确(TI-BASIC已标记化,因此每个命令占用一个或两个字节-seq()占用一个字节,inString()占用两个字节,dim()占用一个字节,依此类推。手动计算尺寸。)

尽管反斜杠字符在字符串中有效,但是请注意,除非修改了计算器,否则无法从程序内部输入一个。


0

Javascript-117

尝试使用递归,但这太长了...

xnor提出建议,以求减法想法,从而减少了12个或更多字符。

w=s=>{a=[1];s.split('\n').map(m=>{for(b=[i=0];z=a[i],f=m[i];b[i++]+=z-b[i])b[i+1]=f>']'?z/2:f<':'?0:z;a=b})
return a}

取消高尔夫:

// s must not have spaces
w=s=>{
  // a is the current probability array
  a=[1];
  s.split('\n').map(
    // for each row of input...
    m=>{
      b=[0];  // b is the next row's probability array
      for(i=0; i<m.length;){
        z=a[i]; // z = probability
        f=m[i]; // f = letter
                                  // let's assume i == 0
        b[i+1] = (f>']') ? z/2 :  // if f == '^', b[1] = z/2
          (f<':' ? 0 :            // else if f == '/', b[1] = 0 
            z);                   // else b[1] = z
        b[i++]+=z-b[i];           // then add (z-b[1]) to b[0]
      }
      a=z-b    // increment current probability array
    }
  )
  return a;
}
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.