圆形胶带令人兴奋吗?


32

Brainfuck衍生物

让我们定义一种类似于Brainfuck的简单编程语言。它有一个双向的单元格带,每个单元格容纳一位。所有位的起始位置均为0。磁带上的移动头起始位置为0。程序是一个在字符上的字符串<>01!,从左到右执行,具有以下语义:

  • < 将头部向左移动一步。
  • > 将头部向右移动一步。
  • 0 在当前单元格中放入0。
  • 1 在当前单元格中放入1。
  • ! 翻转当前单元格。

没有循环,因此n个字符的程序将在n个步骤之后终止。如果在执行结束时所有单元格都包含0,则程序很无聊,如果至少有1,则令人兴奋。请注意,未指定磁带的大小,因此,根据实现的不同,它可能是双向无限的或圆。

一个示例程序

考虑该程序1>>>!<<<<0>!>>>!。在无限磁带上,执行如下:

     v
00000000000000  Put 1
     v
00000100000000  Move by >>>
        v
00000100000000  Flip
        v
00000100100000  Move by <<<<
    v
00000100100000  Put 0
    v
00000100100000  Move by >
     v
00000100100000  Flip
     v
00000000100000  Move by >>>
        v
00000000100000  Flip
        v
00000000000000

最后,所有单元格均为0,因此该程序很无聊。现在,让我们在长度为4的圆形磁带上运行相同的程序。

v
0000  Put 1
v
1000  Move by >>>
   v
1000  Flip
   v
1001  Move by <<<< (wrapping around at the edge)
   v
1001  Put 0
   v
1000  Move by > (wrapping back)
v
1000  Flip
v
0000  Move by >>>
   v
0000  Flip
   v
0001

这次有一个值为1的单元格,因此程序令人兴奋!我们看到程序是无聊还是令人兴奋,取决于磁带的大小。

任务

您的输入是一个非空字符串<>01!,表示上述编程语言中的程序。字符数组也是可接受的输入格式。在无限磁带上运行时,该程序一定很无聊。您的输出将是程序令人兴奋的磁带长度列表。请注意,您只需要在比程序长度短的磁带上测试程序。

每种语言中字节数最少的解决方案是赢家。适用标准规则。

测试用例

> : []
110 : []
1>0<! : [1]
0>>1>0<<>! : [1]
1>>>!<<<<0>!>>>! : [2, 4]
!<!<><<0>!>!<><1!>>0 : [2]
>>!>><>001>0<1!<<!>< : [1, 2, 3]
1!><<!<<<!!100><>>>! : [1, 3]
!!1>!>11!1>>0<1!0<!<1><!0<!<0> : [3, 4]
<><<>>!<!!<<<!0!!!><<>0>>>>!>> : [1, 2, 4]
0>>><!<1><<<0>!>>!<<!!00>!<>!0 : [3]
0000!!!!><1<><>>0<1><<><<>>!<< : []
!>!>!>!>!>1>!>0<!<!<!<0<!<0<!<!<!<1>!>0<<! : [1, 2, 5, 7]
<!!>!!><<1<>>>!0>>>0!<!>1!<1!!><<>><0<<!>><<!<<!>< : [1, 2, 4, 5]
!>1<<11<1>!>!1!>>>0!!>!><!!00<><<<0<<>0<<!<<<>>!!> : [1, 2, 3, 5, 6]

1
我们可以选择任何不同且一致的字符代替<>01!吗?
Xcoder先生18年

1
指令数组是否可以接受?
Arnauld

@ Mr.Xcoder不,您应该使用这些确切的字符。
Zgarb

@Arnauld字符数组足够接近字符串,我会允许的。
Zgarb

Answers:


6

Haskell,119个字节

t#'<'=last t:init t
(h:t)#c|c<'#'=1-h:t|c>'='=t++[h]|1<2=read[c]:t
f p=[n|n<-[1..length p],sum(foldl(#)(0<$[1..n])p)>0]

在线尝试!

函数#是单个命令的解释器cp通过将起始磁带插入fold来运行整个程序。对每个磁带执行,并保留单元总数至少为1的那些磁带。#pfp


n<-[1..length p] ... 0<$[1..n]似乎很长,必须有更短的方法。
nimi

我看不到更短的方法。我看到的问题是,您实际上需要n作为结果的值,因此,如果您构造0<$[1..n]了另一种方法(例如scanr(:)),则需要采用length它的。(我也尝试使用1(替换lengthsum)或Falseor用于测试)代替0,但它的出现时间并不短。)
ØrjanJohansen

@ØrjanJohansen:是的,我尝试n<-init$scanr(:)[]$0<$p ... n缩短2个字节,但是它返回起始磁带的列表,而不是其长度,例如[[0],[0,0,0]]。稍微弯曲一下规则,就可以将磁带看作一元数,所以也许还可以。
妮咪

init$可以通过放置[0]为初始列表来代替,但仍然不够简短。我认为一元语言仅适用于没有更自然的数字表示形式的语言
与Orjan约翰森

4

STAX56 54 43 38 35 字节CP437

è¥%►BΣ░ÜY⌂y(â&.═ªê►V½▲y▌)▀♫♂╣ª?√»!#

解压缩后为42个字节,

%fz(y{{|(}{|)}{B!s+}{0_]e&}4ls"><! "I@!F|a

在线运行和调试!

@recursive每个注释-2字节

说明

我将使用带有前缀i(即i%fz(y{{|(}{|)}{B!s+}{0_]e&}4ls"><! "I@!F|a)的版本进行说明,并说明为什么i可以将其删除

i               Suppress implicit eval
                    This prevents the test case "110" from being interpreted as a number
                    However, this can be removed because a program containing only numbers cannot be exciting and the output will be empty anyway.
                    This is based on the fact that the program is boring on non-circular tapes
 %f             Filter range [1..n] with the rest of this program
                    Where n is the length of the input
                    Implicit output the array after filtering, one element per line
   z(           Initialize the tape
     y{  F      Run the program
          |a    Any cell is non-zero

用于运行程序的代码:

{|(}                                 Block to rotate left by one element
    {|)}                             Block to rotate right by one element
        {B!s+}                       Block to perform logical not on the element at index 0
              {0_]e&}                Block to obtain current instruction,
                                         Convert it to a number
                                         And assign to element at index 0

                     4l              Pack the 4 blocks in an array
                       s"<>! "I      Find the index of current instruction in string, if not found, the index will be -1
                                         And when indexed with -1, it wraps around to the 4th element.

                               @!    And execute the corresponding block.

1
我添加了所有数字的测试用例以验证您的i支票。
Zgarb

0]*可以替换为z(。另外,如果你改变了字符串“<>!”,然后01将给指数-1,这样的方式阻止列表只需要4块,而不是5.这会工作,因为01处理程序是相同的反正。
递归

@recursive好点。




2

红色,243字节

func[p][repeat n length? p[b: copy[]insert/dup b 0 n i: 1
parse p[any["<"(i: i - 1 if i < 1[i: n])|">"(i: i + 1 if i > n[i: 1])|"0"(b/(i): 0)|"1"(b/(i): 1)|"!"(b/(i): either b/(i) = 0[1][0])|
skip]]s: 0 foreach c b[s: s + c]if s > 0[print n]]]

在线尝试!

漂亮的冗长而直接的实现。Red的1索引不允许我使用模块化算法循环遍历圆形磁带来减少字节数。

不打高尔夫球

f: func[p][ 
    repeat n length? p[
        b: [] 
        insert/dup b 0 n
        i: 1
        parse p[
            some [
                 "<" (i: i - 1 if i < 1[i: n])
               | ">" (i: i + 1 if i > n[i: 1])
               | "0" (b/(i): 0)
               | "1" (b/(i): 1)
               | "!" (b/(i): either b/(i) = 0 [1][0])
               | skip 
            ]
        ]
        s: 0
        foreach c b[s: s + c]
        if s > 0 [print n]
    ]
]


2

视网膜,121字节

.+
$.&*0¶$&
\G0
0$`¶
{ms`^.(?=.*¶¶(0|1))
$1
"¶¶!"&mT`d`10`^.
"¶¶>"&`(.)(.*)¶
$2$1¶
"¶¶<"&`(.*)(.)¶
$2$1¶
)`¶¶.
¶¶
G`1
%`.

在线尝试!说明:

.+
$.&*0¶$&
\G0
0$`¶

创建每个长度不超过输入程序长度的磁带阵列。

{

循环直到程序被使用。

ms`^.(?=.*¶¶(0|1))
$1

如果程序中的下一个字符为0或1,则将每行的第一个字符更改为该字符。

"¶¶!"&mT`d`10`^.

如果是a,!则切换每行的第一个字符。

"¶¶>"&`(.)(.*)¶
$2$1¶
"¶¶<"&`(.*)(.)¶
$2$1¶

如果它是><然后旋转线。(比移动头还容易。)

)`¶¶.
¶¶

删除指令并结束循环。

G`1

只保留令人兴奋的台词。

%`.

计算每行的长度。


2

的JavaScript(ES6),126个 118字节

@ user71546节省了3个字节

将输入作为1个字符的字符串数组。

f=(s,l=0,p=0,t=[])=>s[l++]?s.map(c=>1/c?t[p%l]=+c:c>'='?p++:c>';'?p+=l-1:t[p%l]^=1)&&+t.join``?[l,...f(s,l)]:f(s,l):[]

在线尝试!


更换t.some(x=>x)?+t.join``?代替检查数组为数字(0表示全零带),但3个字节以下。
Shieru Asakoto

2

APL(Dyalog Unicode)79 64 54字节(Adám的SBCS

⍸⊂{∨/⍎⍕(↓',',⍨5 3'0@11@1~@1 1⌽¯1⌽')['01!<'⍳⌽⍺]⍵}¨0=,\

在线尝试!

-15感谢Adám(忘记了monadic)。
-10感谢ngn


64
亚当

@Adám嗯,这似乎不是最佳选择(例如,您不需要)。我会研究它并进行更新。:)
暴民埃里克(Erik the Outgolfer)

但是,如果您删除,则需要一个;,不是吗?
亚当

@Adám ,你为什么呢?
暴民埃里克(Erik the Outgolfer)


1

MATL46 39字节

f"@:~G"@59>?@61-YS}@33=?t1)~}@U]1(]]a?@

在线尝试!验证所有测试用例

怎么运行的

f             % Push indices of nonzero chars of (implicit) input string: gives
              % [1 2 ... n] where n is input length
"             % For each k in [1 2 ... n]. These are the possible tape lengths
  @:~         %   Push array of k zeros. This is the tape, in its initial state
  G           %   Push input string
  "           %   For each char in the input string
    @59>?     %     If code point of current char exceeds 59 (so it is '<' or '>')
      @61-    %       Push code point minus 61: gives -1 for '<', or 1 for '>'
      YS      %       Circularly shift the tape by that amount. Instead of moving
              %       the head, we shift the tape and keep the head at entry 1
    }         %     Else
      @33=?   %       If code point of current char is 33 (so it is '!')
        t1)   %         Duplicate the array representing the tape, and get its
              %         first entry
        ~     %         Logical negate
      }       %       Else
        @U    %         Push current char (it is '0' or '1') converted to number
      ]       %       End
      1(      %       Write (either 0, 1 or old value negated) at entry 1
    ]         %     End
  ]           %   End
  a?          %   If the tape contains at least a nonzero value
    @         %     Push tape length, k
              %   End (implicit)
              % End (implicit)
              % Display (implicit)

1

APL(Dyalog Unicode)192 78字节

⊂{t/⍵⊣⍵{t[m]←('01!'⍳⍵)⊃0 1,e,⍨~et[m←⍺|ii+←¯1 1 0⊃⍨'<>'⍳⍵]}¨⍺⊣i←⊃t←⍬⍳⍺}¨1+⍳∘≢

在线尝试!(非拼合结果)

在线尝试!(展平)

在花了一些时间将我的头撞在墙上之后,我决定制作Tradfn而不是Dfn。这就是结果。比我聪明的人也许可以摆脱困境。

惊喜,惊喜,比我聪明的高尔夫球赫克出于此。谢谢Adám的114个字节。

他说:

请注意,这是您的确切程序,除了使用索引而不是内部的{If}和折叠的:For循环到{_}¨,同时给出一个左参数来替换全局变量。

该函数假定⎕IO←0


怎么样?

(此说明使用“ unolfed”版本以方便阅读)

⊂{                                   Enclose
      i←⊃t←⍬⍳⍺                       Assign a vector of 0s to t (the tape), then assign the first 0 to i.
      t/⍵⊣⍵{                         Use  as left argument for the nested function, then compress the result into t. If there is a 1 anywhere in t, the result will be a vector of the result. If not, the result is an empty vector.
          i+←¯1 1 0⊃⍨'<>'⍳⍵          Map the string '<>' to the argument (which is the BF program). That yields 0 for <, 1 for >, and 2 for anything else.
                                     The resulting vector will then be used as the argument for  to add -1 (index 0), 1 (index 1) or 0 (index 2) to the variable i.
          et[m←⍺|i]                 Assign i mod  (left arg) to m, and use it to index t. Then, assign the value to e.
          t[m]←('01!'⍳⍵)⊃0 1,e,⍨~e   Map the string '01!' to ⍵. As before, this yields 0 for 0, 1 for 1, 2 for ! and 3 for anything else.
                                     Then, concatenate (not e) with e, then concatenate that with the vector 0 1. This is used as argument to be picked from, and it is assigned to t[m].
      }¨⍺                            Do that for each argument
  1+⍳∘≢                            And do that for each possible tape length from 1 to the length of the input.

1
通过使t←l⍴0be t←l⍴i←0并删除其上方的行来节省一个字节。您也可以通过更改t[i|⍨≢t]←1-t[i|⍨≢t]为保存另一个t[i|⍨≢t]←~t[i|⍨≢t]
扎卡里

2
@Zacharý,然后进一步节省112字节。完全相同的代码,只是打了一点球。
亚当

是的,只是有点“刺耳”。您不需要s吗?
扎卡里

@Zacharý是什么?这是默认功能。
亚当

@Zacharý我会认为这很漂亮,不是吗?
J.Sallé18年


0

C(clang),171个字节

l,i;f(S){for(char*p,t[l=strlen(S)];l;memchr(t,1,l)&&printf("%d ",l),l--)for(memset(t,i=0,l),p=S;*p;p++)*p==60?i=i?i-1:l-1:*p==62?i=i^l-1?i+1:0:*p^33?t[i]=*p-48:(t[i]^=1);}

在线尝试!

必须使用clang,因为char*p,t[l=strlen(S)]出于某种原因将其用作初始化表达式使GCC认为我想声明strlen而不是调用它。

简单明了:在长度减小的圆形磁带上运行程序,输出任何导致磁带上某处为1的长度。

试图缩短三元运算符的缠结,但最终需要比健康括号更多的括号。


推荐i=0,bzero(t,l)替代memset(t,i=0,l)*p-62?t[i]=*p^33?*p-48:t[i]^1:(i=~i+l?i+1:0)取代*p==62?i=i^l-1?i+1:0:*p^33?t[i]=*p-48:(t[i]^=1)
ceilingcat
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.