量子醉汉步道


69

众所周知,一个人在酒精的影响下,在网格上的人有朝任何可用方向前进的机会均等。但是,这种常识性声明并不适用于非常小的酒鬼,他们的行为非常像他们一次采取所有可用路径,并且他们采取的可能路径可能会相互干扰。您的任务是在n步骤之后显示此类量子醉汉的可能位置。

规格

讨论中的酒鬼占据了一个正方形网格,可以被认为是使用冯·诺依曼(加号)邻域的三态细胞自动机,遵循以下简单规则:

  • EmptyAwake,如果它是毗邻只有一个Awake,否则进入Empty
  • AwakeSleeping
  • SleepingSleeping

电路板的初始状态是一个AwakeEmptys 的无限字段包围的单个状态。

挑战

给定一个非负整数n,请在n步骤之后创建酒鬼的ASCII表示形式。每个状态应由不同的字符表示,解决方案应说明哪个字符表示哪个状态。如果您将空格用于Empty,则无需在行尾添加一行空格。

这是,因此最短的答案会获胜。适用标准漏洞,允许使用前导和尾随空格,允许使用字符串数组/ 2d char数组输出,等等。

例子

这些示例使用for Empty@for Awake#for Sleeping

n=0
@

n = 1
 @
@#@
 @

n = 2
  @
  #
@###@
  #
  @

n = 3
   @
  @#@
 @ # @
@#####@
 @ # @
  @#@
   @

n=6

      @
      # 
    @###@
     @#@  
  @  ###  @
  #@# # #@#
@###########@
  #@# # #@#
  @  ###  @
     @#@
    @###@
      #
      @

n=10
          @
          #
        @###@
         @#@
         ###
        # # #
       #######
      #  ###  #
  @  ##  ###  ##  @
  #@# ### # ### #@#
@###################@
  #@# ### # ### #@#
  @  ##  ###  ##  @
      #  ###  #
       #######
        # # #
         ###
         @#@
        @###@
          #
          @

有趣的笔记

通过查找OEIS中占据的细胞数的序列,我发现量子醉汉与研究得更好的牙签序列同构。如果您可以将这些知识融入更好的高尔夫运动中,那么我将给您留下深刻的印象。


1
您可以检查以确保您的情况n=10正确吗?我尝试了几种方法,但都得到了相同(错误)的答案,所以我只想确定一下。看起来有点不对劲,但我不知道。
HyperNeutrino


1
是否可以使用一维char数组?
乔纳森·弗雷希

4
伟大的第一个挑战,顺便说一句!
路易斯·门多

1
@ PM2Ring有效。numpy数组与我的书中的本机python数组一样多
stellatedHexahedron

Answers:


34

Wolfram语言(Mathematica)92 91字节

Print@@@CellularAutomaton[{7049487784884,{3,{a={0,3,0},3-2a/3,a}},{1,1}},{j={{1}},0},{j#}]&

使用Mathematica的内置功能是一个完美的挑战CellularAutomaton

在线尝试!

空= 0,清醒= 1,睡眠= 2

前256次迭代的动画(白色=空,灰色=唤醒,黑色=睡眠):

在此处输入图片说明

说明

CellularAutomaton[ ... ]

运行CellularAutomaton规范...

{7049487784884,{3,{a={0,3,0},3-2a/3,a}},{1,1}}

应用三色总计规则7049487784884,并在冯·诺依曼(Von Neumann)附近...

{j={{1}},0}

在中间为1且背景为0的板上...

{j#}

重复<input>次数({j#}计算为{{{#}}})。如果边框外的单元格与背景不同,数组将自动展开

7049487784884

此规则来自基-3-号码220221220221220221220221220,这意味着“所有改变122,并改变01当且仅当有奇数个的1S周围它”。

Print@@@

打印数组。

“'odd 1s' ”的半证明等同于“正好一个1'”:

考虑此5x5像素网格。白色是一个0或一个2单元(非清醒像素),灰色是一个1单元。

在此处输入图片说明

如果1围绕三个0像元生成一个像元,则网格必须看起来像这样:它1以U形(或旋转形式)排列三个s,如下所示:

在此处输入图片说明

由于此细胞自动机的自相似性,因此细胞自动机中出现的任何模式都必须出现在对角线上(通过感应)。但是,此模式不是对角线对称的。即它不能出现在对角线上,也不能出现在细胞自动机的任何地方。

唤醒/睡眠等效

请注意,一个0单元格不能被一个或三个2单元格和其余0单元格完全包围,因为这意味着在某些步骤之前,该单元格具有一个或三个1单元格的邻居-并且必须已经变成一个1(矛盾的)。因此,可以忽略和之间的区别12并且将状态“全部更改11,将a 0更改为1if且仅当其具有奇数个非零邻居”时可以。

最终的细胞自动机确实与原始自动机相同,唯一的区别是“清醒的”和“睡着的”醉汉之间没有区别。OEIS A169707中描述了此模式。

Print@@@CellularAutomaton[{750,{2,{a={0,2,0},2-a/2,a}},{1,1}},{j={{1}},0},{j#}]&

在线尝试!

前16个迭代的并排比较:

在此处输入图片说明

添加两个连续的迭代,其结果将遵循挑战规范(94个字节):

Print@@@Plus@@CellularAutomaton[{750,{2,{a={0,2,0},2-a/2,a}},{1,1}},{{{1}},0},{Ramp@{#-1,#}}]&

在线尝试!


11

Python 2,192字节

x=input()
o=c={x+x*1j}
R=range(x-~x)
exec"n=[C+k for k in-1j,1j,-1,1for C in c];n={k for k in n if(k in o)<2-n.count(k)};o|=c;c=n;"*x
print[[`(X+Y*1jin c)+(X+Y*1jin o|c)`for Y in R]for X in R]

在线尝试!

Xcoder先生-17个
字节,使用了Jonathan的输出格式-9个
字节,Lynn了-11个
字节,ovs了-3个字节


切换到可以使用的完整程序,它exec节省了9个字节,并…for k in 0,1,2,3for…节省了一个字节:链接
Lynn

1
实际上,再n=[C+k for k in-1j,1j,-1,1for C in c]节省一个字节!
林恩

1
...好吧,我不得不承认这X+Y*1jin是我认为不可能的事情:P
ETHproductions'Nov

1
@ETHproductions我也没想到它也能工作,但是我就像“嘿,您可以在标识符/关键字之前的数字后删除空格,因此,如果它贪婪地匹配,那么它将适用于复数吗?:D Python很棒:P
HyperNeutrino

10

C,360 354 343 319

#define A(i,b,e)for(int i=b;i<e;++i)
#define B(b,e)A(r,b,e){A(c,b,e)
#define W(n)(n<0?-(n):n)
#define C(r,c)b[W(r)*s+W(c)]
#define D C(r,c)

q(n){char N,s=n+2,(*b)[2]=calloc(s,2*s);C(0,0)
[1]=1;A(g,0,n+1){B(0,s)*D=D[1];}B(0,g+2){N=(*C
(r-1,c)+*C(r+1,c)+*C(r,c-1)+*C(r,c+1))&1;D[1]=
*D?2:N;}}}B(2-s,s-1)putchar(*D+32);puts("");}}

换行符之后的#define换行符仅在此处显示,因此不包括在内。我包含了一个包装函数,因此如果不计算该函数,并且假设n来自其他位置,则它为-6(313)。q(10)输出:

          !          
          "          
        !"""!        
         !"!         
         """         
        " " "        
       """""""       
      "  """  "      
  !  ""  """  ""  !  
  "!" """ " """ "!"  
!"""""""""""""""""""!
  "!" """ " """ "!"  
  !  ""  """  ""  !  
      "  """  "      
       """""""       
        " " "        
         """         
         !"!         
        !"""!        
          "          
          !          

使用空,"睡觉,和!对清醒。

这是这样的:

  • A(i,b,e)是“∀i∈[b,e)”,B(b,e)是“∀r∈[b,e).∀c∈[b,e)”。

  • 观察n代后,电路板为2 n +1平方。

  • 由于板的对称性,这仅需模拟右下象限,因此我们为n + 1矩阵分配了1行和一列填充,供以后的邻居查找(so n + 2)使用。

  • 通过分配,calloc我们可以同时将宽度乘以高度,并将板子清除为0(空)。

  • 通过其坐标(CD)查找单元格时,它使用行和列的绝对值(W)自动镜像坐标。

  • 电路板以代表当前和上一代产品的整数对数组的形式存储。有问题的整数是char这样的,我们可以避免sizeof

  • (通过邻居测试)查找最多的一代是上一代,因此将其放置在该对中的索引0处,以便可以使用对其进行访问*

  • 在每个世代(g),使用B循环将当前世代复制到上一代,然后从旧世代生成新世代。

  • 每个单元格都0用于表示空,1唤醒和2睡眠。邻居计数最初是对将4个邻居作为标志(N)进行移位和或运算以16用于休眠时在单元的低4位中设置的位数的计算。但是观察到邻居的奇数等于1个邻居,我们只需使用带有1的掩码即可保存几个字符。

  • 最后,使用相同的绝对值坐标技巧(减去填充)在右下象限上进行迭代,以完全印刷电路板,因此我们不会在电路板上打印外部填充。这也是B循环包含一个花括号的原因,因为我们在外部循环中有多余的换行符。

  • ASCII代码方便地将0 + 32(空)映射到一个空间,将2 + 32(睡眠)映射到一个空间,将"1 + 32(唤醒)映射到!

总的来说,由于问题的结构很好,我认为这是令人惊讶的可读性。


哇。小东西,但我认为你可以用乘法和更换班次节省几个字节putchar(10)puts("")
undercat

1
@undercat:谢谢!添加到答案。有时候,我专注于减少某些事情,以至于我错过了别人指出的其他显而易见的胜利。
乔恩·普迪


@JonathanFrech:谢谢,补充。我忘记了邻居计数可以使用NAND。
乔恩·普迪

@JonathanFrech:对不起,我想还不清楚。&~是不是NAND,我的意思,我有时想的!(a &~ b)来讲a NAND (NOT b),虽然在这种情况下,逻辑!是不一样的逐位~,因为我们依靠01结果!
乔恩·普迪

6

MATL,39字节

QtE:=&*G:"tt0=w1Y6Z+Xj1=*w|gJ*+]Q|U31+c

显示

  • Empty作为(空间)
  • Awake#
  • Sleeping作为!

在线尝试!您还可以观看模式以ASCII艺术或图形(修改的代码)的形式增长

说明

该代码使用复数01j代表三种状态:空,之后,分别睡觉。

Q         % Implicitly input n. Add 1
tE        % Duplicate and multiply by 2
:         % Range [1 2 ... 2*n]
=         % Test for equalty. Gives [0 ... 0 1 0... 0], with 1 at position n
&*        % Matrix of all pairwise products. Gives square matrix of size 2*n
          % filled with 0, except a 1 at position (n,n). This is the grid
          % where the walk will take place, initiallized with an awake cell
          % (value 1). The grid is 1 column and row too large (which saves a
          % byte)
G:"       % Do n times
  tt      %   Duplicate current grid state twice
  0=      %   Compare each entry with 0. Gives true for empty cells, false
          %   for the rest
  w       %   Swap: moves copy of current grid state to top
  1Y6     %   Push 3×3 matrix with Von Neumann's neighbourhood
  Z+      %   2D convolution, maintaining size
  Xj      %   Real part
  1=      %   Compare each entry with 1. This gives true for cells that
          %   have exactly 1 awake neighbour
  *       %   Multiply, element-wise. This corresponds to logical "and": 
          %   cells that are currently empty and have exactly one awake
          %   neighbour. These become 1, that is, awake
  w       %   Swap: moves copy of current grid state to top
  |g      %   Absolute value, convert to logical: gives true for awake or
          %   sleeping cells, false for empty cells
  J*+     %   Mulltiply by j and add, element-wise. This sets awake and 
          %   sleeping cells to sleeping. The grid is now in its new state
]         % End
Q         % Add 1, element-wise. Transforms empty, awake, sleeping 
          % respectively from 0, 1, j into 1, 2, 1+j
|U        % Abolute value and square, element-wose. Empty, awake, sleeping 
          % respectively give 1, 4, 2
31+c      % Add 31 element-wise and convert to char. Empty, awake, sleeping 
          % respectively give characters ' ' (codepoint 32), '#' (codepoint 
          % 35) and '!' (codepoint 33). Implicitly display

5

Befunge,384304字节

&:00p->55+,000g->>00g30p:40p\:50p\5>>40g!50g!*vv0g05g04p03-<
@,+55_^#`g00:+1$_^>p:4+4g5%2-50g+5#^0#+p#1<v03_>30g:!#v_:1>^
#v_>$99g,1+:00g`^ ^04+g04-2%5g4:\g05\g04\p<>g!45*9+*3+v>p:5-
 >\50p\40p\30p:#v_>>0\99g48*`!>v >30g:1-30^>>**\!>#v_>v^9 9<
$0\\\\0$        >\99g88*-!+\:4->#^_\>1-!48>^       >$3>48*+^

在线尝试!

尝试在Befunge中实现此类操作的问题是有限的内存大小(数据和代码均为2000字节)。因此,我不得不使用一种算法,该算法可以为任何给定坐标计算正确的字符,而无需参考先前的计算。它通过在酒鬼可能遵循的所有可能路径上递归地回顾时间来实现这一点。

不幸的是,这不是一个特别有效的解决方案。它可以工作,但是它的速度非常慢,并且n的值越大,它就会成指数地变慢。因此,尽管它可能对任何工作ñ高达约127(Befunge的7位存储单元的限制),在实践中你将不可避免地失去兴趣等待结果。在TIO上,它将超过60秒(最好)达到60秒超时。编译器的性能会好很多,但是即使那样,您可能也不想超过10。

不过,我认为值得提交,因为它实际上很好地证明了Befunge中的递归“函数”。


4

Python 2,214字节

def f(n):k=n-~n;N=k*k;A=[0]*N;A[N/2]=2;exec"A=[[2*([j%k>0and A[j-1],j%k<k-1and A[j+1],j/k>0and A[j-k],j/k<k-1and A[j+k]].count(2)==1),1,1][v]for j,v in enumerate(A)];"*n;print[map(str,A)[k*x:][:k]for x in range(k)]

在线尝试!

说明

用途0empty1sleeping2awake。打印出二维字符(一长串)列表。
定义一个接受非负整数的函数n。连续推进细胞自动机,直到达到所需状态。最后,在内部整数值和实际字符之间进行转换。


4

的Lua251 242 239 238个字节

通过简化数组初始化程序来减少-8个字节,但要付出一些额外的前导空白的代价。变成
-1个字节。 -3字节,首先构建完整的字符串,最后打印一次。 -1字节感谢乔纳森·弗雷奇Jonathan Frech)改写为。c=i==2+...and print(s)c=i~=2+...or print(s)

or(g(...)==1 andor(1==g(...)and

function g(x,y)return(a[x]or{})[y]or 0 end a={{1}}for i=2,2+...do n={}s=""for x=-i,i do n[x]=n[x]or{}q=a[x]or{}for y=-i,i do n[x][y]=q[y]and 0or(1==g(x+1,y)+g(x,y+1)+g(x-1,y)+g(x,y-1)and 1)s=s..(q[y]or" ")end s=s.."\n"end a=n end print(s)

在线尝试!

空=
觉醒= 1
睡眠=0

从命令行获取输入并打印到stdout。

通过将状态表示为false/ nil1并且在0内部,检测“空”不需要任何代码,而“正好醒着”的检查只需添加一个即可。


我认为or(g(...)==1 and可以or(1==g(...)and
乔纳森·弗雷希


4

果冻39 29字节

-,1ṙ@€Sµ+Z
‘ṬŒḄ×þ`µÇ׬Ḃ+Ḃ+µ³¡

在线尝试!

用途01以及2空清醒和睡眠。在链接页脚转换这@#

  • -1字节,用ṬŒḄ代替ḤḶ=¹
  • 通过使用-2个字节-代替1N。也使¤不必要。
  • -1字节,用S代替+/
  • 使用Ḃ+Ḃ+代替-6个字节%3=1+=1Ḥ$+。现在2用于代替3

说明即将到来...


4

APL(Dyalog Classic),38字节

((2∘∧⌈2|⍉∘g∘⍉+g3+/0,,∘0)(⌽0,⍉)⍣4)⍣⎕⍪1

在线尝试!

基于Outgolfer的解决方案Erik

⍪1 是包含1的1x1矩阵

评估输入

( )⍣⎕ 申请多次

  • (⌽0,⍉)⍣4用0环绕,即做4倍:转置(),在左侧(0,)加0 ,水平反转(

  • g←3+/0,,∘0 将水平三元组相加的函数,称为 g

  • ⍉∘g∘⍉一个将垂直三元加起来的函数- g正在换位

  • 2 | ⍉∘g∘⍉ + g←3+/0,,∘0 两个和的和取模2

  • 和...之间的最大值

  • 2∘∧ 2的LCM和原始矩阵-将1s变成2s,同时保留0s和2s


3

Perl 5,192 + 1(-n)= 193字节

for$i(1..2*$_+1){push@a,[()x$_]}$a[$_][$_]=1;map{@b=();for$i(0..$#a){map$b[$i][$_]=$a[$i][$_]?2:$a[$i-1][$_]+($_&&$a[$i][$_-1])+$a[$i+1][$_]+$a[$i][$_+1]==1?1:0,0..$#a}@a=@b}1..$_;say@$_ for@a

在线尝试!

使用0表示空,使用1表示清醒,使用2表示睡眠。


3

红宝石164153字节

->n{(r=([e=' ']*(l=2*n+1)<<"
")*l)[n+n*l+=1]=a=?@
n.times{r=r.map.with_index{|c,i|c==a ??#:c==e ?r.values_at(i-1,i+1,i-l,i+l).one?{|v|v==a}?a:e:c}}
r*""}

在线尝试!

使用“”表示为空,“ @”表示“唤醒”,使用“#”表示“睡眠”(如示例中所示)。我想我可以通过使用数字来节省6个字节,但是看起来更好。


2

69 61字节

60个字节的代码,-l标志+1 。

YZG2*a+1y@a@a:1LaY{y@a@b?2oN(y@(a+_)@(b+B)MP[0o0v0])=1}MC#yy

注意到n作为命令行参数。用途0为空,1对于清醒,2睡觉。(为了获得更好的ASCII艺术作为挑战的例子,替换最终y" @#"@y。)

在线尝试!

说明

设定:

YZG2*a+1y@a@a:1

                 Implicit: a is 1st cmdline arg; o is 1; v is -1
 ZG2*a+1         Square grid (i.e. nested list) of 0's, with side length 2*a+1
Y                Yank into y variable
        y@a@a:1  Set the element at coordinates (a,a) to 1

主循环:

LaY{...}MC#y

La            Loop (a) times:
          #y  Len(y) (i.e. 2*a+1)
   {   }MC    Map this function to the coordinate pairs in a 2*a+1 by 2*a+1 grid
  Y           and yank the resulting nested list back into y

函数体在哪里:

y@a@b?2oN(y@(a+_)@(b+B)MP[0o0v0])=1

                                     The function args, representing the coords of the
                                     current cell, are a and b
y@a@b?                               Is the cell at these coords 0 or nonzero?
      2                              If nonzero (1 or 2), make it 2
                                     Else, if zero, we need to check the neighbors
                         [0o0v0]     List of [0; 1; 0; -1; 0]
                       MP            Map this function to each adjacent pair of values--
                                     i.e. call it four times with args (0; 1), (1; 0),
                                     (0; -1), and (-1; 0)
          y                           Index into the grid using
           @(a+_)                     a + the 1st item in the pair as the row and
                 @(b+B)               b + the 2nd item in the pair as the column
                                     The result of MP is a list of the values of the cells
                                     in the Von Neumann neighborhood
       oN(                      )    Get the number of 1's in that list
                                 =1  and test if it equals 1
                                     If so, the new value of this cell is 1; if not, it's 0

循环后,我们只需自动打印y。该-l标志表示通过将每行的内容连接起来并用换行符分隔行来打印嵌套列表。


2

Java(OpenJDK 8),220字节

n->{int s=n*2+3,i=0,x,y;char[][]a=new char[s][s],b;for(a[s/2][s--/2]=61;i++<n;a=b)for(b=new char[s+1][s+1],x=0;++x<s;)for(y=0;++y<s;)b[x][y]=a[x][y]>32?'0':(a[x][y-1]+a[x][y+1]+a[x-1][y]+a[x+1][y])%8==5?61:' ';return a;}

在线尝试!

注意:返回的数组包含边框或'\0'字符。由于假定平面是无限的,因此仅使用非边界。

字符映射:

  • 空:(空格)
  • 苏醒: =
  • 睡眠: 0

节省

  • 感谢Jonathan S,节省了29个字节。
  • 多亏了乔纳森·S(Jonathan S.),他通过与其他人交换字符并“用素数和模块化算术进行魔术”而又获得了9个字节


谢谢@JonathanS。我一直在努力改善自己的@-check,然后您找到了关键!真好 这次char演出是我的全部疏忽。
奥利维尔·格雷戈尔(OlivierGrégoire),

1
通过使用素数和模块化算术执行魔术来获得220个字节
Jonathan S.

那是个很好的想法!
OlivierGrégoire17年

1
谢谢!我刚刚找到了一个更漂亮的版本,它也是220字节,不同的模数。
Jonathan S.

2

Python,199192字节

该代码可在Python 2和Python 3上运行,但是它使用流行的第三方Numpy库进行数组处理。

from numpy import*
def f(n):
 m=2*n+1;g=zeros((m+2,)*2,'i');g[n+1,n+1]=1
 while n:a=g[1:-1,1:-1];a[:]=(a<1)*(sum(g[r:r+m,c:c+m]&1for r,c in((0,1),(1,0),(1,2),(2,1)))==1)+(a>0)*2;n-=1
 return g

空= 0
清醒= 1
睡眠= 2

print(f(6)) 输出

[[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 1 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 2 0 0 0 0 0 0 0]
 [0 0 0 0 0 1 2 2 2 1 0 0 0 0 0]
 [0 0 0 0 0 0 1 2 1 0 0 0 0 0 0]
 [0 0 0 1 0 0 2 2 2 0 0 1 0 0 0]
 [0 0 0 2 1 2 0 2 0 2 1 2 0 0 0]
 [0 1 2 2 2 2 2 2 2 2 2 2 2 1 0]
 [0 0 0 2 1 2 0 2 0 2 1 2 0 0 0]
 [0 0 0 1 0 0 2 2 2 0 0 1 0 0 0]
 [0 0 0 0 0 0 1 2 1 0 0 0 0 0 0]
 [0 0 0 0 0 1 2 2 2 1 0 0 0 0 0]
 [0 0 0 0 0 0 0 2 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 1 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]]

如果要进行漂亮的打印,可以这样称呼:

n=6;print('\n'.join(''.join(' @#'[v]for v in u)for u in f(n)))

使用与问题中给出的相同字符打印。


我不知道是否允许输入整数矩阵,因为[e]ach state should be represented by a different character(我解释character为实际的ASCII字符,而不是整数)。
乔纳森·弗雷希

@JonathanFrech公平电话。我问问OP。
下午17年
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.