Stackylogicを実行する


45

Stackylogicは、私がそのテイクアップ作られたロジックベースのプログラミング言語である0のと1、入力用のを単一出力0または1上に完了したことを。

Stackylogicプログラムは、3文字01?だけでなく<、1行の最後に1 文字だけを含むことができる行で構成されます。行は空ではないかもしれないとして行が<少なくとも一つ持っている必要があります01または?それ以前に。

これは(説明しますが)2ビットのNANDを計算するサンプルプログラムです。

1
?<
11
?
0

Stackylogicプログラムのすべての行はスタックと見なされ、下が左、上が右になります。暗黙的に、プログラムの最初の行の前と最後の行の後に空のスタック(空の行)があります。

<我々は呼んでよこれ、カーソルを Stackylogicプログラムが実行されたときに起動するマークスタック。Stackylogicプログラムの実行は次のように進行します。

  1. カーソルが現在指しているスタックから一番上の文字をポップします。

    • キャラクターがの場合、?ユーザーに0またはのプロンプトを表示し、それがキャラクターであるかのよう1に振る舞います。
    • 文字がの場合、0カーソルを1スタック上に(現在の行の上の行に)移動します。
    • 文字がの場合、1カーソルを1スタック下に(現在の行の下の行に)移動します。
  2. カーソルの移動先のスタックが空の場合、スタックからポップされた最後の値(常にa 0または1)を出力し、プログラムを終了します。

  3. それ以外の場合、カーソルの移動先のスタックが空でない場合は、手順1に戻ってプロセスを繰り返します。

Stackylogicプログラムは常にスタックを使い果たすため、常に終了することに注意してください。

NANDの例

NANDプログラムでは、カーソルは次の位置から始まります?

1
?<
11
?
0

私たちは、入力、ユーザーを仮定します1一度?カーソルがこのようなプログラムを見て作り、下に移動することを意味している、ポップされます。

1

11<
?
0

これ1で、カーソルスタックの最上部にプレーンが表示されます。適切にポップされ、カーソルが再び移動します。

1

1
?<
0

今、ユーザ入力仮定0のための?カーソルが上に移動することを意味し、:

1

1<

0

再び、a 1がカーソルスタック上にあるため、カーソルがポップして下に移動します。

1


<
0

最後に、カーソルスタックは空なので、最後にポップされた値が1出力され、プログラムが終了します。

であるため、これはNANDゲートに対して正確1 NAND 0です1。もちろん、これは他の3つの2ビット入力でも確認できます。

または例

このStackylogicプログラムはORゲートをシミュレートします

?
?<

の最初の入力により1、カーソルが最後の行の下にある暗黙の空のスタックにプッシュされ、プログラムが終了し、1入力されたばかりの出力が出力されることが簡単にわかります。

00一方、入力の場合、カーソルは最上部の暗黙的な空のスタックに移動し、プログラムを終了し、0入力する最後のスタックを出力します。

チャレンジ

Stackylogicプログラムを文字列として取り込んで実行するプログラムまたは関数を作成し、結果の0orを出力または返し1ます。

?の、あなたがのためにユーザーに促すことができる0か、1入力、またはのプリセット文字列から値を読み取る0さんと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?<
??

中央値の プログラムをありがとう。


3入力関数を追加する場合、中央値を実装する1つの方法を次に示します?\1?<\??。また、ここでは対称5行の実装です:?\?0\?<\?1\?
マーティン・エンダー

ああ、私はさらにきれいな実装を見つけました:1\???<\0
マーティンエンダー

2
@MartinEnderの3入力中央値関数(同様に、多数決関数)のきちんとした実装は、うまく一般化されます。たとえば、7入力多数決ルール関数は111\???????<\000です。
グレッグマーティン

Stackylogicプログラム$ P $の "bizarro"を、元のプログラムの行の順序を逆にし、すべての1を0に、またはその逆に変更することにより形成されるプログラム$ BP $とします(?sおよび<のみを残します)。入力$ b_1、b_2、\ dots $の$ BP $の出力は、入力$!b_1、!b_2、\ dots $の$ P $の出力ではないようです。ANDとORの特定の実装は、NANDとNOR、およびXOR / XNORの2つのバージョンと同様に、このように奇妙に関連していることに注意してください。一部のプログラムは独自の奇妙なものです(BUFFER、NOT、MEDIAN(v1))。
グレッグマーティン

1
@GregMartinうん。専門用語は二重性だと思います。
カルビンの趣味

回答:


15

網膜79 78 73 68 66 65 63 62 55 44バイト

バイトカウントはISO 8859-1エンコードを前提としています。

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

入力はSTDINを介して行われ、ソースコードから2つのラインフィードで区切られたユーザー入力であることが期待されます。

オンラインでお試しください!(最初の2行はテストスイートを有効にします。各行は、/改行ではなく個別のテストケースです。)

ここで何が起こったのか完全にはわかりません。これは本当に不格好な解決策のように感じられ、これは実際にRetinaが作成した種類の問題ではありませんが、それでも何らかの理由で現在のすべての答えを打ち負かしています。

説明

この最終バージョンは、実際にはかなり単純なものになりました。

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

最初の段階は+、言語の実際の解釈を行う単純なループ(オプションによる)です。ステージは単一の正規表現の置換ですが、実際には、置換中に未使用のブランチからグループをキャプチャすることは単純に空と見なされるという事実を利用して、実際には1つのステージに絞り込まれた3つの異なる置換です。

  1. 処理中?

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

    これは単に入力の最初の文字を取得し?<、が見つかるまで任意の文字に一致し、その最初の文字を<(の削除?)の前に置きます。

  2. 処理中0

    (¶.*)0<
    <$1
    

    これはaの前の行に一致し、の0<<に削除し0ます。(事実上、これは単に削除し0<1行上に移動します。)

  3. 処理中1

    1<(¶.+)
    $1<
    

    ほぼ同じことですが、を<削除しながら1行下に移動し1ます。注目すべき重要な詳細の1つは、の+代わりにを使用する*ことです。つまり、次の行が空でないことを要求します。

興味深いのは、これがなぜ機能するのか、そして最終出力を決定するためにポップした最後の値を追跡する必要がない理由を理解することです。そのためには、上記のループがどのように終了するかを考慮する必要があります。(少なくとも1文字が削除されるため)一致する可能性があるすべての文字列が変更されるため、一致が完全に失敗する場合のみを考慮する必要があります。

前の文字がマッチに失敗する唯一の方法である場合、その前に<?非改行文字はありませんが、常に十分な入力があることが保証されているため、それは起こりえません。

前に文字場合<ISは0常に(ソースコードからの入力を分離する空行であってもよい)現在の上記別のラインがありますので、正規表現は常に一致します。

目の前の文字が場合<1どちらか我々は最後の行(以降にしている場合、正規表現は失敗します一致に失敗します)、または次の行が(以降空の場合.+と一致するように失敗します)。これらのケースは両方とも、をポップした後にプログラムを終了することに対応することに注意してください1

最後に、の<いずれも先行しない可能性もあり?01ます。をポップ0して空の行に移動することによってのみこの状況に到達できるため、行の<先頭に改行が追加されます。

そのため、プログラムがa 1で終了するとき、それ<はまだです1。ただし、プログラムがで終了する場合は0、空の行に移動します。単純な一致ステージを使用して、この情報を簡単に目的の出力に変換できます。

1<

これは、単に1<文字列内の一致をカウントします。上記の推論により、これは1プログラムがで終了した1場合と0、それがで終了した場合0です。


3
あなたは、ウィザードです。
GamrCorps

そのような正規表現Mchワウ
ローハンジュンジュンワラ

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では、これは「入力」ボックスで改行で区切られていることを意味します)。


説明:

すべてのコードは3つの部分に分割できます。

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. Switchステートメント:
    1. 文字がの場合、?入力を取得し、その文字を行に追加します。
    2. 文字がの場合、0ラインポインターを1つ上に移動します。
    3. 文字がの場合、1ラインポインターを1つ下に移動します。
    4. 文字が(スペース)の場合、最後にポップされた項目を印刷してプログラムを終了します。

6

32ビットx86マシンコード、70バイト

16進数で:

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>



2

Pythonの3、147の 146 145 144バイト

@Lynnのおかげで1バイト。

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して、2つの式をfor2バイトの保存に移動できるようにします。いくつかの具体的なヒント:あなたのNumberキャストは不要だと思います、あなたのため*2にキャストするので、私はちょうどi使用j=0i[j++]て読んで、11バイトを節約すると思います。
ニール

1
を使用する必要はありませんf=。匿名関数が許可されています。
-gcampbell

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

@ Pietu1998 LeakyNunはそれができることint f(String[]I)...を意味し、避けることができますString[]p=I.split("\n");

関数を次のように宣言できることを意味しますint f(String[]P)
Leaky Nun

1
/:7秒でninja'd @cat
漏れ修道女

あなたは、Java 8のために解決した場合も、あなたは(私が思う)のようなラムダ持つことができます->(String[]I){...

0

PHP(<7.0)、195 192バイト

プログラムを最初の引数として受け取り、各値を追加の引数として受け取ります。
これは改行ではなく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

C、264 249 244 242

Cは文字列の操作ではうまくいきませんが、これはかなり短いです。

カーソル(<)の文字列をスキャンし、1箇所後ろに移動し、コマンドを読み取り、tab文字で置き換え、1行前後に移動します。入力はのような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;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.