Jalankan Stackylogic


45

Stackylogic adalah bahasa pemrograman berbasis logika yang saya buat yang menerima 0dan 1memasukkan untuk input dan output tunggal 0atau 1setelah selesai.

Program Stackylogic terdiri dari garis-garis yang hanya dapat berisi tiga karakter 01?serta tepat satu <di akhir salah satu baris. Garis tidak boleh kosong dan garis dengan <harus memiliki minimal satu 0, 1atau ?sebelum.

Berikut adalah contoh program yang (seperti akan saya jelaskan) menghitung NAND dari dua bit:

1
?<
11
?
0

Setiap baris dalam program Stackylogic dianggap tumpukan , dengan bagian bawah di sebelah kiri dan bagian atas di sebelah kanan. Secara implisit, ada tumpukan kosong (baris kosong) sebelum baris pertama dalam suatu program dan setelah baris terakhir.

The <, yang akan kita panggil kursor , menandai tumpukan untuk memulai ketika program Stackylogic dijalankan. Eksekusi program Stackylogic berlangsung sebagai berikut:

  1. Lepaskan karakter teratas dari tumpukan yang saat ini ditunjuk kursor.

    • Jika karakternya adalah ?, minta pengguna untuk 0atau a 1dan bertindak seolah-olah itu adalah karakter.
    • Jika karakternya adalah 0, pindahkan kursor satu tumpukan ke atas (ke garis di atas garis saat ini).
    • Jika karakternya adalah 1, pindahkan kursor satu tumpukan ke bawah (ke garis di bawah garis saat ini).
  2. Jika tumpukan kursor bergerak kosong, output nilai terakhir yang muncul dari tumpukan (selalu a 0atau 1), dan akhiri program.

  3. Lain, jika tumpukan kursor bergerak ke tidak kosong, kembali ke langkah 1 dan ulangi prosesnya.

Perhatikan bahwa program Stackylogic selalu berakhir karena mereka akhirnya harus menguras tumpukan mereka.

Contoh NAND

Dalam program NAND kursor dimulai pada ?:

1
?<
11
?
0

Kami akan menganggap input pengguna 1setelah ?muncul, yang berarti kursor akan turun, membuat program terlihat seperti ini:

1

11<
?
0

Sekarang sebuah dataran 1berada di bagian atas tumpukan kursor. Ini muncul dan kursor bergerak lagi:

1

1
?<
0

Sekarang anggap input pengguna 0untuk ?, yang berarti kursor akan naik:

1

1<

0

Sekali lagi, a 1ada di tumpukan kursor sehingga kursor muncul dan bergerak ke bawah:

1


<
0

Akhirnya tumpukan kursor kosong, sehingga nilai terakhir muncul 1,, adalah output dan program berakhir.

Ini akurat untuk gerbang NAND karena 1 NAND 0ini 1. Ini tentu saja berfungsi untuk tiga input dua bit lainnya jika Anda ingin memeriksanya.

ATAU Contoh

Program Stackylogic ini mensimulasikan gerbang OR :

?
?<

Sangat mudah untuk melihat bahwa input awal 1akan mendorong kursor ke tumpukan kosong implisit di bawah baris terakhir, mengakhiri program dan mengeluarkan 1yang baru saja input.

Untuk input 00di sisi lain, kursor akan membuat jalan ke tumpukan kosong implisit di atas, mengakhiri program dan mengeluarkan yang terakhir 0menjadi input.

Tantangan

Tulis program atau fungsi yang menggunakan program Stackylogic sebagai string dan menjalankannya, mencetak atau mengembalikan hasilnya 0atau 1.

Setelah ?itu, Anda dapat meminta pengguna untuk input 0atau 1, atau membaca nilai dari string preset 0's dan 1yang juga Anda ambil sebagai input. (Ini bisa menjadi input string lain untuk program / fungsi Anda atau Anda bisa saja menganggap baris pertama atau terakhir dari string program akan menjadi aliran input).

Anda dapat mengasumsikan program dan input selalu terbentuk dengan baik. Anda dapat mengasumsikan program input datang dengan satu baris baru (meskipun ingat selalu ada tumpukan kosong implisit di akhir).

Kode terpendek dalam byte menang.

Lebih Banyak Contoh Program

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?<
??

Terima kasih Martin untuk program median .


Jika Anda ingin menambahkan fungsi 3-masukan, inilah salah satu cara untuk menerapkan median: ?\1?<\??. Atau, inilah implementasi 5-line simetris:?\?0\?<\?1\?
Martin Ender

Oh, saya menemukan sebuah implementasi lebih rapi bahkan: 1\???<\0.
Martin Ender

2
@ Implementasi MartinEnder yang lebih rapi dari fungsi median 3-input (ekuivalen, fungsi aturan mayoritas) digeneralisasikan dengan baik. Misalnya, fungsi aturan-mayoritas 7-input adalah 111\???????<\000.
Greg Martin

Biarkan "bizarro" dari program Stackylogic $ P $ menjadi program $ BP $ yang dibentuk dengan membalik urutan garis-garis dari program asli, dan mengubah semua 1s menjadi 0s dan sebaliknya (tetapi meninggalkan? S dan <sendiri). Tampaknya output $ BP $ pada input $ b_1, b_2, \ dots $ adalah BUKAN dari output $ P $ pada input $! B_1,! B_2, \ dots $. Perhatikan bahwa implementasi AND dan OR yang diberikan terkait dengan bizarro dengan cara ini, seperti halnya NAND dan NOR, dan dua versi XOR / XNOR. Beberapa program adalah bizarro mereka sendiri (BUFFER, NOT, MEDIAN (v1)).
Greg Martin

1
@GregMartin Yap. Saya percaya istilah teknis adalah dualitas .
Calvin Hobbies

Jawaban:


15

Retina , 79 78 73 68 66 65 63 62 55 44 byte

Hitungan byte mengasumsikan penyandian ISO 8859-1.

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

Input melalui STDIN dan diharapkan menjadi input pengguna yang dipisahkan oleh dua linefeeds dari kode sumber.

Cobalah online! (Dua baris pertama memungkinkan suite uji, di mana setiap baris adalah test case terpisah dengan /bukannya linefeeds.)

Saya tidak sepenuhnya yakin apa yang terjadi di sini. Ini terasa seperti solusi yang benar-benar kikuk dan ini sebenarnya bukan jenis masalah yang dibuat oleh Retina tetapi masih mengalahkan semua jawaban saat ini untuk beberapa alasan.

Penjelasan

Versi terakhir ini sebenarnya cukup sederhana.

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

Tahap pertama hanyalah sebuah loop (karena +opsi) yang melakukan penafsiran bahasa yang sebenarnya. Panggung adalah substitusi regex tunggal, tetapi sebenarnya itu adalah tiga substitusi berbeda yang diperas dalam satu tahap, dengan memanfaatkan fakta bahwa menangkap grup dari cabang yang tidak digunakan hanya dianggap kosong selama substitusi.

  1. Pengolahan ?:

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

    Ini hanya mengambil karakter pertama dari input, kemudian mencocokkan karakter arbitrer sampai ditemukan ?<, dan menempatkan karakter pertama di depan <(menghapus ?).

  2. Pengolahan 0:

    (¶.*)0<
    <$1
    

    Ini cocok dengan baris sebelum a 0<dan meletakkannya setelah <penghapusan 0. (Secara efektif, ini hanya menghapus 0dan memindahkan <satu baris ke atas.)

  3. Pengolahan 1:

    1<(¶.+)
    $1<
    

    Hampir sama, kecuali bahwa kita memindahkan <satu baris ke bawah sambil menghapus a 1. Satu detail penting yang perlu diperhatikan adalah penggunaan +alih-alih *, yaitu, kami meminta baris berikutnya tidak kosong.

Bagian yang menarik adalah mencari tahu mengapa ini bekerja dan mengapa kita tidak perlu melacak nilai terakhir yang kita muncul untuk menentukan hasil akhir. Untuk melakukan itu, kita perlu mempertimbangkan bagaimana loop di atas dapat berakhir. Karena setiap kecocokan yang mungkin mengubah string (karena setidaknya satu karakter dikeluarkan darinya), kita hanya perlu mempertimbangkan kasus-kasus di mana kecocokan itu gagal sama sekali.

Jika karakter di depan <adalah ?satu-satunya cara agar pertandingan gagal adalah bahwa tidak ada karakter non-linefeed di depannya, tetapi itu tidak dapat terjadi karena kami dijamin selalu ada input yang cukup.

Jika karakter di depan <adalah 0, regex akan selalu cocok, karena selalu ada baris lain di atas yang sekarang (yang mungkin merupakan baris kosong yang memisahkan input dari kode sumber).

Jika karakter di depan <adalah 1, regex akan gagal jika salah kita berada di baris terakhir (sejak akan gagal untuk mencocokkan) atau jika baris berikutnya kosong (karena .+akan gagal untuk mencocokkan). Perhatikan bahwa kedua kasus tersebut terkait dengan penghentian program setelah muncul 1.

Akhirnya, ada juga kemungkinan yang <tidak didahului oleh apapun ?01. Ternyata kita hanya dapat mencapai situasi ini dengan muncul 0dan bergerak ke baris kosong, sehingga <sekarang didahului oleh umpan baris.

Jadi, ketika program berakhir pada 1, <masih akan setelah itu 1. Tetapi jika program berakhir pada a 0, itu akan pindah ke baris kosong. Kami dapat dengan mudah mengubah informasi ini menjadi output yang diinginkan dengan tahap pertandingan sederhana:

1<

Ini hanya menghitung kecocokan 1<dalam string. Dengan alasan di atas ini akan terjadi 1jika program diakhiri pada 1, dan 0jika diakhiri pada a 0.


3
Anda Tuan, adalah penyihir.
GamrCorps

Such Regex Mch Wow
Rohan Jhunjhunwala

12

Cembung , 102 95 byte

Nah, bahasa berbasis daftar tumpukan yang dikodekan dalam bahasa berbasis tumpukan ternyata cukup sulit. Tandai kata-kata saya: Saya akan mendapatkan ini hingga 100 byte atau kurang! EDIT: Sukses!

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;;

Cobalah online!

Input program melalui argumen baris perintah. Input 0s dan 1s normal (pada TIO, ini berarti baris baru dipisahkan dalam kotak "input").


Penjelasan:

Semua kode dapat dibagi menjadi tiga bagian:

N/S\+

Bit ini hanya mengambil program input dan mengubahnya menjadi array baris, dan juga menambahkan " "baris ke awal array. Karena array Convex membungkus, hanya memiliki tumpukan kosong di awal akan dilakukan.

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

Bagian ini menentukan garis (atau tumpukan) apa yang akan mulai dieksekusi. Itu mencari melalui setiap baris dan menempatkan nomor tumpukan yang benar ke dalam Mvariabel.

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

Ini bagian yang menyenangkan! Terus loop sampai mencapai garis dengan hanya spasi ( " ") di atasnya (melambangkan tumpukan kosong). Jika saluran tidak kosong, ia melakukan hal berikut:

  1. Pop karakter terakhir dari tumpukan.
  2. Ganti pernyataan:
    1. Jika karakternya adalah ?, ambil input dan tambahkan karakter itu ke baris.
    2. Jika karakter adalah a 0, pindahkan penunjuk garis ke atas.
    3. Jika karakternya adalah 1, pindahkan penunjuk garis ke bawah.
    4. Jika karakter adalah (spasi), cetak item yang baru saja muncul dan akhiri program.

6

Kode mesin x86 32-bit, 70 byte

Dalam hex:

FC89E1565F31D28A07A8DF740B3C3C7511428D5C24FCEB0A5729142484C07405B20147EBE2578B3B8A17F6C2DF7414FF0B923C3F7501AC3C30750383C30883EB04EBE389CCC3

Input adalah string multi-line NULL-dihentikan (dipisahkan linefeed) dilewatkan melalui ESI. Input pengguna diasumsikan sebagai baris pertama. Mengembalikan '0' / '1' di AL.

Membongkar:

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

Dengan asumsi baris baru mengakhiri dalam program

(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++]")

Kurang golf

(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;
}

Uji

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

05AB1E , 58 56 55 53 51 50 46 byte

Disimpan 2 byte berkat Emigna ! Kode:

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

Menggunakan pengkodean CP-1252 . Cobalah online! .


2

Python 3, 147 146 145 144 byte

1 byte terima kasih kepada @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:]

Sebagai program, z menjadi input. Ya, nama variabel saya gila.


1

ES6, 190 byte

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
}

Gunakan seperti f(program, input)


2
Beberapa tip bermain golf umum (ada daftar ini di suatu tempat): gunakan [...o]bukan o.split``, dan gunakan forbukan while, karena itu memungkinkan Anda memindahkan dua ekspresi ke dalam formenyimpan dua byte. Beberapa tips spesifik: Saya pikir para Numberpemain Anda tidak perlu, seperti yang *2akan dilemparkan untuk Anda, dan saya hanya akan membaca imenggunakan j=0dan i[j++]yang saya pikir menghemat 11 byte.
Neil

1
Anda tidak perlu f=, fungsi anonim diizinkan.
gcampbell

0

Java, 256 255 231 219 215 213 byte

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;}

Demo di Ideone.

Mengambil program dan input sebagai argumen dan mengembalikan hasilnya sebagai integer.


@LeakyNun Berubah menjadi satu forlingkaran, tetapi apa arti komentar pertama Anda?
PurkkaKoodari

@ Pietu1998 LeakyNun berarti bisa int f(String[]I)...dan Anda dapat menghindariString[]p=I.split("\n");
kucing

Ini berarti Anda dapat mendeklarasikan fungsinya sebagaiint f(String[]P)
Leaky Nun

1
@cat ninja'd dengan 7 detik: /
Leaky Nun

Juga, jika Anda puas dengan Java 8, Anda dapat memiliki lambda seperti (saya pikir)->(String[]I){...
kucing

0

PHP (<7.0), 195 192 byte

Mengambil program sebagai argumen pertama dan setiap nilai sebagai argumen tambahan.
Perhatikan bahwa saya menguji ini dengan spasi asn split ("", ..) daripada baris baru tetapi seharusnya tetap bekerja.
Memberikan pemberitahuan yang sudah usang jika dijalankan di php> 5.3.
Juga memberikan peringatan jika Anda keluar dari bagian atas program. Namun masih bekerja dan menghasilkan dengan benar sehingga tidak masalah.

<?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 tidak begitu baik dalam memanipulasi string, tetapi ini cukup singkat.

Ini bekerja dengan memindai string untuk kursor ( <), bergerak mundur 1 tempat, membaca perintah, menggantinya dengan tabkarakter, dan bergerak maju atau mundur satu baris. Input dalam bentuk array char C, seperti char array[]="1\n?<\n11\n?\n0";result = f(array);, meskipun carriage return juga diizinkan.

Meskipun string input dimodifikasi, panjangnya tidak berubah.

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;}}}

Program uji

Jalankan program ini dengan setiap test case sebagai parameter terpisah, menggunakan backslash tunggal sebagai pengganti baris baru. Kasing uji akan dipisahkan oleh garis kosong.

#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;
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.