运行Stackylogic


45

Stackylogic是一种基于逻辑的编程语言我提出了称取在0的和1为输入的,并输出一个单一的01在完成。

Stackylogic程序由只能包含三个字符的行组成,并且只能在01?其中一行<的末尾包含一个字符。行不能为空,并与该行<必须至少有一个01?之前。

这是一个示例程序(如我将解释的那样),计算两个位的NAND

1
?<
11
?
0

Stackylogic程序中的每一行都被视为一个堆栈,其底部在左侧,顶部在右侧。隐式地,在程序的第一行之前和最后一行之后有一个空堆栈(空行)。

<,我们称之为的光标,标记堆栈的运行Stackylogic程序时开始。Stackylogic程序的执行过程如下:

  1. 将顶部字符从光标当前指向的堆栈中弹出。

    • 如果该字符为?,则提示用户输入a 0或a,1并像该字符一样进行操作。
    • 如果字符是0,则将光标向上移动一个堆栈(到当前行上方的行)。
    • 如果字符是1,则将光标向下移动一个堆栈(到当前行下方的行)。
  2. 如果光标移动到的堆栈为空,则输出从堆栈弹出的最后一个值(始终为a 01),然后结束程序。

  3. 否则,如果光标移动到的堆栈不为空,请返回步骤1并重复该过程。

请注意,Stackylogic程序始终会结束,因为它们最终必须耗尽堆栈。

NAND范例

在NAND程序中,光标从以下位置开始?

1
?<
11
?
0

我们假设用户1一旦输入,便输入a ?,这意味着光标将向下移动,使程序如下所示:

1

11<
?
0

现在,平原1位于游标堆栈的顶部。它会适当弹出,然后光标再次移动:

1

1
?<
0

现在假设用户输入0?,这意味着将光标向上移动:

1

1<

0

同样,1游标堆栈上还有a ,因此游标弹出并向下移动:

1


<
0

最后,游标堆栈为空,因此弹出最后一个值1,输出,程序结束。

这是准确的NAND门,因为1 NAND 01。如果您愿意检查的话,这当然适用于其他三个两位输入。

或例子

此Stackylogic程序模拟“ 或”门:

?
?<

很容易看到,初始输入1会将光标推到最后一行下面的隐式空堆栈,从而结束程序并输出1刚刚输入的内容。

00另一方面,对于输入,游标将进入顶部的隐式空堆栈,从而结束程序并输出最后一个0要输入的内容。

挑战

编写一个将Stackylogic程序作为字符串接收并运行,打印或返回结果0或的程序或函数1

在时?,您可能会提示用户输入01或者从您也将其作为输入的预设字符串0s和中读取值1。(这可以是输入到程序/函数的另一个字符串,或者您可以仅假设程序字符串的第一行或最后一行是输入流)。

您可以假设程序和输入始终格式正确。您可以选择假设输入程序带有一个尾随换行符(尽管请记住,结尾始终总是有一个隐式的空堆栈)。

以字节为单位的最短代码获胜。

更多示例程序

ZERO
0<

ONE
1<

BUFFER
?<

NOT
1
?<
0

AND
?<
?

NAND
1
?<
11
?
0

OR
?
?<

NOR
1
?
00
?<
0

XOR(v1)
?
0
1?<
?
0

XOR(v2)
?
?<
11
?
0

XNOR(v1)
1
?
0?<
1
?

XNOR(v2)
1
?
00
?<
?

MEDIAN(v1)
1
???<
0

MEDIAN(v2)
?
1?<
??

感谢Martin提供的中位 课程


如果要添加3输入函数,这是实现中值的一种方法:?\1?<\??。另外,这是一个对称的5行实现:?\?0\?<\?1\?
Martin Ender

哦,我发现了一个更整洁的实现:1\???<\0
Martin Ender

2
@MartinEnder对3输入中值函数(相当于多数规则函数)的更整洁的实现很好地概括了。例如,7输入多数规则函数为111\???????<\000
格雷格·马丁

令Stackylogic程序$ P $的“ bizarro”为程序$ BP $,该程序是通过反转原始程序的行顺序并将所有1改为0,反之亦然而形成的(但不包括?s和<)。看来输入$ b_1,b_2,\ dots $的$ BP $输出是输入$!b_1,!b_2,\ dots $的$ P $输出的NOT。请注意,AND和OR的给定实现以这种方式与奇异相关,NAND和NOR以及XOR / XNOR的两个版本也是如此。有些程序是它们自己的bizarro(缓冲区,NOT,MEDIAN(v1))。
格雷格·马丁

1
@GregMartin是的。我相信技术术语是双重性
加尔文的业余爱好

Answers:


15

视网膜79 78 73 68 66 65 63 62 55 44字节

字节数假定为ISO 8859-1编码。

+`(.)([^_]*)\?<|(¶.*)0<|1<(¶.+)
$2$1$4<$3
1<

输入是通过STDIN进行的,并且应该是与源代码进行两次换行分隔的用户输入。

在线尝试!(前两行启用一个测试套件,其中每行是一个单独的测试用例,/而不是换行。)

我不完全确定这里发生了什么。这听起来像是一个笨拙的解决方案,这确实不是Retina 遇到的那种问题,但由于某种原因,它仍然胜过所有当前的答案。

说明

最终的版本实际上非常简单。

+`(.)([^_]*)\?<|(¶.*)0<|1<(¶.+)
$2$1$4<$3

第一阶段只是一个循环(由于该+选项),它会进行语言的实际解释。该阶段是单个正则表达式替换,但实际上,通过利用在替换过程中从未使用的分支中捕获组被简单认为是空的事实,实际上是将三个不同的替换压缩到一个阶段。

  1. 加工方式?

    (.)([^_]*)\?<
    $2$1<
    

    这只是获取输入的第一个字符,然后匹配任意字符,直到找到为止?<,然后将第一个字符放在的前面<(删除?)。

  2. 加工方式0

    (¶.*)0<
    <$1
    

    此匹配之前的行0<之后,并把它<,移除0。(有效地,这只是删除0并将上<一行向上移动。)

  3. 加工方式1

    1<(¶.+)
    $1<
    

    除了<删除时我们向下移动一行外,几乎是一样的事情1。需要注意的一个重要细节是+代替的使用*,也就是说,我们要求下一行不要为空。

有趣的部分是弄清楚为什么它起作用以及为什么我们不需要跟踪为确定最终输出而弹出的最后一个值。为此,我们需要考虑上述循环如何终止。由于每个可能的匹配项都会更改字符串(因为从字符串中删除了至少一个字符),因此我们只需要考虑匹配项完全失败的情况。

如果前面的字符<?匹配失败的唯一方法,那就是前面没有任何非换行符,但这不会发生,因为我们保证总是有足够的输入。

如果前面的字符<0,则正则表达式将始终匹配,因为当前行上方总是有另一行(可能是将输入与源代码分隔开的空行)。

如果前面的字符<1,则如果我们在最后一行(因为将不匹配)或下一行为空(因为.+将不匹配),则正则表达式将失败。请注意,这两种情况都对应于在弹出a之后终止程序1

最后,还有<任何一种都没有的可能性?01。事实证明,我们只能通过弹出a 0并上移至空行来达到这种情况,因此,<现在必须在其前面加上换行符。

因此,当程序在处终止时1<仍将在之后1。但是,如果程序在处终止0,它将移至空行。我们可以通过简单的匹配阶段轻松地将此信息转换为所需的输出:

1<

这只是计算1<字符串中的匹配项。由于上述原因,这将是1程序是否在上终止1,以及程序是否在上0终止0


3
先生,您是向导。
GamrCorps '16

这样的Regex Mch Wow
Rohan Jhunjhunwala

12

102 95字节

嗯,用基于堆栈的语言编码的基于堆栈的语言非常困难。写下我的话:我将获得100个字节或更少的字节数!编辑:成功!

N/S\+{s)_'<={R:M;}{R):R;+}?}%'<-M){(æ=)s_:Q;"?10 ""l+ M):M; M(:M; W:M;A~p"S/Ë~~_!S*+tM)Q:A;}h;;

在线尝试!

程序输入是通过命令行参数。通常输入0s和1s(在TIO上,这意味着在“输入”框中用换行符分隔)。


说明:

所有代码都可以分为三部分:

N/S\+

该位仅使用输入程序并将其转换为行数组,并将" "行添加到数组的开头。由于Convex的数组会自动换行,因此在开始时只需要一个空栈即可。

{s)_'<={R:M;}{R):R;+}?}%'<-

这部分确定开始执行的行(或堆栈)。它搜索每一行,并将正确的堆栈号放入M变量中。

M){(æ=)s_:Q;"?10 ""l+ M):M; M(:M; W:M;A~p"S/Ë~~_!S*+tM)Q:A;}h;;

这很有趣!它不断循环直到到达一行上只有空格(" ")的行(表示一个空堆栈)。如果该行不为空,则执行以下操作:

  1. 从堆栈中弹出最后一个字符。
  2. 切换语句:
    1. 如果字符是?,请输入并将该字符附加到行中。
    2. 如果字符是a 0,则将行指针向上移动一个。
    3. 如果字符是a 1,则将行指针向下移动一个。
    4. 如果字符是(空格),则打印最近弹出的项目并结束程序。

6

32位x86机器代码,70字节

十六进制:

FC89E1565F31D28A07A8DF740B3C3C7511428D5C24FCEB0A5729142484C07405B20147EBE2578B3B8A17F6C2DF7414FF0B923C3F7501AC3C30750383C30883EB04EBE389CCC3

输入是通过ESI传递的以NULL终止的多行字符串(以换行分隔)。假定用户输入为第一行。在AL中返回“ 0” /“ 1”。

拆卸:

fc           cld
89 e1        mov    ecx,esp
56           push   esi
5f           pop    edi                  ;EDI=ESI
31 d2        xor    edx,edx              ;EDX=0
_loop0:
8a 07        mov    al,BYTE PTR [edi]    ;AL=*EDI
a8 df        test   al,0xf5              ;AL&~0x0a==0 => separator ('\n' or '\0')
74 0b        je     _stck
3c 3c        cmp    al,'<'
75 11        jne    _loop0end
42           inc    edx                  ;For "cursor" symbol adjust stack pointer offset
8d 5c 24 fc  lea    ebx,[esp-0x4]        ;and load EBX with the address where this pointer
eb 0a        jmp    _loop0end            ;is going to be stored in the next iteration
_stck:
57           push   edi                  ;Pointer to the separator
29 14 24     sub    DWORD PTR [esp],edx  ;adjusted to point to the top of the stack
84 c0        test   al,al                ;AL==0?
74 05        je     _loop0break          ;break
b2 01        mov    dl,0x1               ;EDX can be [0..2], resets to 1
_loop0end:
47           inc    edi                  ;++EDI
eb e2        jmp    _loop0
_loop0break:
57           push   edi                  ;*EDI==0, add lower implicit empty stack
_loop1:                                  ;The actual state machine code
8b 3b        mov    edi,DWORD PTR [ebx]  ;EDI=*EBX
8a 17        mov    dl,BYTE PTR [edi]    ;DL=*EDI
f6 c2 df     test   dl,0xf5              ;DL&~0x0a
74 14        je     _loop1break          ;ZF==1 => current stack is empty
ff 0b        dec    DWORD PTR [ebx]      ;--(*EBX): pop the stack
92           xchg   edx,eax              ;AL=DL
3c 3f        cmp    al,'?'
75 01        jne    _skplods             ;AL=='?' => substitute char from the input string
ac           lodsb
_skplods:
3c 30        cmp    al,'0'
75 03        jne    _0x31                ;EBX+=AL==0?4:-4
83 c3 08     add    ebx,0x8              ;But to avoid wasting 2 bytes for the jump after the 'add'
_0x31:                                   ;add 8 and fall through to subtract 4 back
83 eb 04     sub    ebx,0x4
eb e3        jmp    _loop1
_loop1break:
89 cc        mov    esp,ecx              ;Clear the stack
c3           ret                         ;Returns '0'/'1' in AL

5

的JavaScript(ES6),136 138

假设程序中有换行符

(p,i,j=0)=>eval("for(p=`\n${p}`.split`\n`.map((x,i)=>((c=(x=[...x]).pop())=='<'?k=i:x.push(c),x));a=p[k].pop();k-=1-c-c)c=1/a?a:i[j++]")

少打高尔夫球

(p, i, j=0)=>{
  p=`\n${p}`
     .split`\n`
     .map(
       (x,i)=>
       (
         x = [...x],
         c = x.pop(),
         c == '<' ? k=i : x.push(c),
         x
       )
     )
  for(; a = p[k].pop(); k -= 1-c-c)
    c = 1/a ? a : i[j++];
  return c;
}

测试

F=(p,i,j=0)=>eval("for(p=`\n${p}`.split`\n`.map((x,i)=>((c=(x=[...x]).pop())=='<'?k=i:x.push(c),x));a=p[k].pop();k-=1-c-c)c=1/a?a:i[j++]")

function run() {
  var pgm=P.value+'\n'
  var i=I.value
  O.textContent = F(pgm,i)
}

run()
#P { width:60%; height: 6em }
#I { width:50%;  }
Program<br>
<textarea id=P>1
?&lt;
11
?
0</textarea><br>
Input<br>
<input id=I value=01>
<button onclick='run()'>Run</button>
<br>Output
<pre id=O></pre>


5

05AB1E58 56 55 53 51 50 46字节

感谢Emigna节省了2个字节!码:

õ|`õ)[¤'<å#À]`¨[¬V¨Y'?QiI«ëYi1U)À`ëY_i0U)Á`ëXq

使用CP-1252编码。在线尝试!


2

Python 3中,147个 146 145 144字节

1个字节感谢@Lynn。

def f(p):
 i=p[:p.find("<")].count("\n");p=p.split()
 try:
  while 1:*p[i],c=p[i];c=c>"<"and input()or c;i+=c<"<"and int(c)*2-1
 except:return c

1

Python 3、318

def s(f,z):
 p=b="";g=0;a=[];n=a.append;n(p)
 for i in f:
  if i=="\n":n(p);p=''
  else:p+=i
 n(p);p=b;n(p)
 while g<len(a):
  if'<'in a[g]:q=g;a[q]=a[q][:-1]
  g+=1
 while 1:
  v=a[q]
  if v=='':print(b);break
  if v[-1]=='1':a[q]=v[:-1];q+=1;b=1
  elif v[-1]=="0":a[q]=v[:-1];q-=1;b=0
  else:a[q]=v[:-1]+z[0];z=z[1:]

F是程序,z是输入。是的,我的变量名很疯狂。


1

ES6,190字节

f=(p,i)=>{
n=p.split`<`[0].split`\n`.length-1
p=p.split`\n`.map(o=>o.split``)
i=i.split``
p[n].pop()
while(p[n]&&p[n].length){
c=p[n].pop()
v=c=='?'?i.shift():Number(c)
n+=v*2-1
}
return v
}

使用方式 f(program, input)


2
几个通用的打高尔夫球技巧(在某处列出了这些技巧):使用[...o]代替o.split``,和使用for代替while,因为这样您可以将两个表达式移到for节省两个字节的位置。一些特定的技巧:我认为您的Number演员是不必要的,因为*2遗嘱对您来说是正确的,我会阅读i使用j=0i[j++]而且我认为它可以节省11个字节。
尼尔

1
您不需要f=,允许使用匿名函数。
gcampbell '16

0

Java,256 255 231 219 215 213字节

int f(char[][]p,char[]I){int l=p.length,d=0,j=-1,c=0,k=0,i[]=new int[l];while(++j<l)if(p[j][i[j]=p[j].length-1]==60)i[k=j]--;try{for(;;k+=c>48?1:-1)c=(c=p[k][i[k]--])>49?I[d++]:c;}catch(Throwable t){}return c-48;}

关于Ideone的演示。

将程序和输入作为参数,并将结果作为整数返回。


@LeakyNun更改为for循环,但是您的第一个评论是什么意思?
PurkkaKoodari '16

@ Pietu1998 LeakyNun表示可以int f(String[]I)...,您可以避免String[]p=I.split("\n");
cat

这意味着您可以将函数声明为int f(String[]P)
Leaky Nun 16'7

1
@cat ninja's by 7 seconds:/
Leaky Nun

另外,如果你满足于Java的8,你可以有一个像拉姆达(我认为)->(String[]I){...

0

PHP(<7.0),195192字节

将程序作为第一个参数,并将每个值作为附加参数。
请注意,我使用split(“”,..)asn空格(而不是换行符)对它进行了测试,但是仍然可以正常工作。
如果在php> 5.3中运行,则不推荐使用。
如果您退出程序顶部,还会发出警告。但是它仍然可以正常工作并正确输出,所以很好。

<?php foreach(split("\n",$argv[++$t])as$l)$p[]=str_split($l);for($i=-1;end($p[++$i])!='<';);array_pop($p[$i]);for(;($v=array_pop($p[$i]))!==null;$i+=$n?:-1)($n=$v)=='?'&&$n=$argv[++$t];echo$n;

0

电话:264 249 244 242

C在处理字符串方面做得不好,但这很短。

它的工作方式是扫描光标的字符串(<),后退1位,读取命令,将其替换为tab字符,然后向前或向后移动一行。输入采用C char数组的形式,例如char array[]="1\n?<\n11\n?\n0";result = f(array);,尽管也允许回车。

尽管输入字符串已修改,但长度未更改。

t;f(char*n){char*p=strchr(n,60);for(*p--=9;;){if(*p==63)scanf("%d",&t),*p=t+48;if(*p^49){for(*p--=9;p>n&&*p^10;--p);for(--p;p>n&&*p==9;--p);if(p<n||*p==10)return 0;}else{for(*p++=9;*p&&*p^10;++p);for(p+=!!*p;*p>10;++p);if(*--p<11)return 1;}}}

测试程序

使用单个反斜杠代替换行符,将每个测试用例作为一个单独的参数运行该程序。测试用例将由空白行分隔。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(int argc, const char **argv)
{
    while (*++argv)
    {
        char *input=malloc(strlen(*argv)+1),*p;
        strcpy(input,*argv);
        printf("testing %s\n",input);
        for (p=input;*p;++p)
            if (*p=='\\')
                *p=10;
        printf("result: %d\n\n",f(input));
        free(input);
    }
    return 0;
}
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.