Stackylogic'i çalıştır


45

Stackylogic ben o take oluşan bir mantık tabanlı programlama dilidir 0'ler ve 1giriş için' ler ve tek çıkışı 0veya 1üzerine tamamlanmasını.

Bir Stackylogic programı sadece üç karakter içerebilir hatları oluşur 01?zamanda tam bir şekilde <hatlarının birinin sonunda. Çizgiler boş olmayabilir ve hattı <en az birine sahip olması gerekir 0, 1ya da ?ondan önce.

İşte (açıklayacağım gibi) iki bitin NAND değerini hesaplayan örnek bir program :

1
?<
11
?
0

Stackylogic programındaki her satır , altta solda ve sağda sağda bir yığın olarak kabul edilir . Örtülü, programdaki ilk satırdan önce ve son satırdan sonra boş bir yığın var.

<Biz diyeceğiz ki imleci bir Stackylogic program çalıştırıldığında, işaretler yığın günü başlayacak. Stackylogic programının yürütülmesi şu şekilde devam eder:

  1. İmlecin gösterdiği yığından en üstteki karakteri çıkar.

    • Karakter ise ?, kullanıcıdan bir 0veya a 1isteyin ve karaktermiş gibi davranın.
    • Karakter ise 0, imleci bir yığın yukarı (geçerli çizginin üstündeki satıra) hareket ettirin.
    • Karakter ise 1, imleci bir yığın aşağı (geçerli çizginin altındaki satıra) getirin.
  2. İmleç boşa hareket ederse, yığıntan çıkan son değeri (her zaman a 0veya 1) çıkartın ve programı sonlandırın.

  3. Aksi takdirde, imleç hareket ettiği yığın boş değilse, 1. adıma geri dönün ve işlemi tekrarlayın.

Stackylogic programlarının her zaman sona erdiğine dikkat edin, çünkü sonunda yığınlarını tüketmeleri gerekir.

NAND Örneği

NAND programında imleç a ile başlar ?:

1
?<
11
?
0

Bir 1kez ?açıldığında kullanıcı girişlerini varsayacağız , yani imleç aşağı hareket eder, böylece program şöyle görünür:

1

11<
?
0

Şimdi 1imleç yığınının en üstünde bir düz var. Usulüne uygun şekilde fırlatılır ve imleç tekrar hareket eder:

1

1
?<
0

Şimdi kullanıcı girişlerini varsayalım 0için ?imleci yukarı hareket edecek demektir:

1

1<

0

Yine, a 1imleç yığınının üzerindedir, böylece imleç açılır ve aşağı hareket eder:

1


<
0

Sonunda imleç yığını boştur, bu nedenle en son açılan değer,, çıkılır 1ve program sona erer.

Bunun nedeni NAND geçidi için doğrudur 1 NAND 0olduğunu 1. Elbette, kontrol etmek istiyorsanız diğer iki iki bitli girişler için çalışır.

VEYA Örnek

Bu Stackylogic programı bir OR kapısını simüle eder :

?
?<

Bir ilk girişin 1, imleci son satırın altındaki örtük boş yığına iterek, programı sonlandırarak ve 1bunun sadece girilen çıktıyı verdiğini görmek kolaydır .

Bir girişi için 00diğer taraftan, imleç programı biten ve son çıkışı, üstündeki örtük boş yığınına yolunda yapacak 0girdi olmak.

Meydan okuma

Baskı veya sonuçlanımını dönen, bir dize olarak bir Stackylogic programında alır ve onu çalıştıran bir program veya fonksiyon yazın 0veya 1.

Upon ?'s, bir kullanıcıdan isteyebilir 0veya 1giriş, ya önceden belirlenmiş bir dizesinden değerini okumak 0' ler ve 1ayrıca girdi olarak alması 'ın. (Bu, programınıza / işlevinize başka bir dize girişi olabilir veya yalnızca program dizesinin ilk veya son satırının girdi akışı olacağını varsayabilirsiniz).

Programın ve girişin her zaman iyi oluşturulduğunu varsayabilirsiniz. İsteğe bağlı olarak, girdi programlarının tek bir izleyen yeni satır ile geldiğini varsayabilirsiniz (sonunda her zaman gizli bir yığın olduğunu unutmayın).

Bayt cinsinden en kısa kod kazanır.

Diğer Örnek Programlar

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

Medyan programlar için teşekkürler Martin .


Eğer bir 3 girişli işlev eklemek isterseniz, buraya medyan uygulamak için tek yolu şudur: ?\1?<\??. Alternatif olarak, işte simetrik 5 hatlı bir uygulama:?\?0\?<\?1\?
Martin Ender

Oh, bir hatta daha düzgün uygulanmasını bulundu: 1\???<\0.
Martin Ender

2
@ MartinEnder'ın 3-giriş medyan fonksiyonunun düzgün bir şekilde uygulanması (eşit olarak, çoğunluk-kurallar fonksiyonu) güzel bir şekilde genellenir. Örneğin, 7 giriş çoğunluk kuralları işlevi 111\???????<\000.
Greg Martin,

Stackylogic programının $ P $ 'ı tuhaflaştırın, orijinal programların satırlarının sırasını tersine çevirerek ve tüm 1'leri 0'larla değiştirerek (ancak? $ B_1, b_2, \ dots $ girdilerinde $ BP $ çıktısının $! B_1,! B_2, \ dots $ girişlerinde $ P çıktı olmadığına benziyor. Verilen AND ve OR uygulamalarının NAND ve NOR ve XOR / XNOR'un iki versiyonunda olduğu gibi tuhaf bir şekilde ilişkili olduğuna dikkat edin. Bazı programlar kendi tuhaflıklarıdır (BUFFER, NOT, MEDIAN (v1)).
Greg Martin,

1
@GregMartin Yep. Teknik terimin dualite olduğuna inanıyorum .
Calvin'in Hobileri

Yanıtlar:


15

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

Bayt sayısı, ISO 8859-1 kodlamasını varsayar.

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

Giriş, STDIN üzerinden yapılır ve kaynak kodundan iki satır besleme ile ayrılmış kullanıcı girişi olması beklenir.

Çevrimiçi deneyin! (İlk iki satır, her bir satırın /satır besleme yerine ayrı bir test durumu olduğu bir test paketi sağlar .)

Burada ne olduğundan tam olarak emin değilim. Bu gerçekten tıkanmış bir çözüm gibi geliyor ve bu gerçekten Retina için yapılan bir tür sorun değil, yine de bir nedenden dolayı mevcut tüm cevapları aştı.

açıklama

Bunun son versiyonu aslında oldukça basit bir hale geldi.

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

İlk aşama, sadece +dilin gerçek yorumunu yapan (seçenek nedeniyle) bir döngüdür . Aşama, tek bir regex ikamesidir, ancak gerçekte, kullanılmayan dallardan grupların yakalanması, ikame sırasında sadece boş sayılır.

  1. İşleme ?:

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

    Bu basitçe girişin ilk karakterini alır, sonra bulana kadar rastgele karakterleri eşleştirir ?<ve ilk karakteri <(silme ?) önüne koyar .

  2. İşleme 0:

    (¶.*)0<
    <$1
    

    Bu önceki satırı ile eşleştiğini 0<sonra ve koyar onu <çıkarmadan, 0. (Etkili, bu sadece siler 0ve <bir satır yukarı taşır .)

  3. İşleme 1:

    1<(¶.+)
    $1<
    

    Hemen hemen aynı şey, <a silerken bir satır aşağı hareket etmemiz dışında 1. Dikkat edilmesi gereken önemli bir ayrıntı, +bunun yerine *, bir sonraki satırın boş olmamasını kullanmaktır.

İlginç olan, bunun neden işe yaradığını ve neden son çıktıyı belirlemek için attığımız son değeri takip etmek zorunda olmadığımızı bulmak. Bunu yapmak için yukarıdaki döngünün nasıl sonlanabileceğini düşünmemiz gerekir. Her olası eşleşme dizgiyi değiştirdiğinden (en az bir karakter ondan çıkarıldığından) yalnızca eşleşmenin tamamen başarısız olduğu durumları düşünmemiz gerekir.

Önünde karakteri ise <bir ?maç başarısız tek yolu, önünde olmayan satır besleme karakteri yerde olmadığını, ama biz her zaman yeterli girdi var olduğunu garanti çünkü bu olamaz.

Önündeki karakter <ise 0, regex her zaman eşleşir, çünkü geçerli satırın üstünde her zaman başka bir satır vardır (girişi satırdan kaynak kodundan ayıran boş satır olabilir).

Önündeki karakter <ise 1, son satırda olursak ( eşleşme başarısız olacağından) veya sonraki satır boşsa ( .+eşleşme başarısız olduğundan) başarısız olur. Bu durumların her ikisinin de bir patlamadan sonra programı sonlandırmaya karşılık geldiğine dikkat edin 1.

Son olarak, <hiçbirinden önce gelmeyen bir olasılık da var ?01. Görünüşe göre bu duruma ancak a 0ile boş bir çizgiye geçerek ulaşabiliriz , böylece bundan <önce bir satır beslemesinden önce gelir.

Yani, program sonlandırıldığında a 1, <bundan sonra olacak 1. Ancak eğer program sonlandırılırsa, 0boş bir satıra taşınacaktır. Bu bilgiyi basit bir eşleşme aşaması ile kolayca istenen çıktıya dönüştürebiliriz:

1<

Bu sadece 1<dizedeki eşleşmeleri sayar . Bu akıl yürütme üzerinde olacaktır By 1program üzerinde sonlandırdıysanız 1ve, 0o üzerinde sonlandırdıysanız 0.


3
Siz bayım, büyücüsünüz.
GamrCorps

Böyle Regex Mch Vay
Rohan Jhunjhunwala

12

Dışbükey , 102 95 bayt

Yığın tabanlı bir dilde kodlanmış yığın listesi tabanlı bir dilin oldukça zor olduğu ortaya çıktı. Sözlerimi işaretleyin: Bunu 100 bayt veya daha azına ulaştıracağım! EDIT: Başarı!

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

Çevrimiçi deneyin!

Program girişi komut satırı argümanları üzerindendir. Normalde 0s ve 1s girişleri (TIO'da bu, "giriş" kutusuna yeni satır ayrılmış) anlamına gelir.


Açıklama:

Kodun tamamı üç parçaya bölünebilir:

N/S\+

Bu bit sadece girdi programını alır ve onu bir dizi dizisine dönüştürür ve ayrıca " "dizinin başına çizgiler ekler . Convex'in dizileri sarıldığından, başlangıçta yalnızca boş bir istifleme yapacaktır.

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

Bu bölüm, hangi satırın (veya yığının) yürütmeye başlayacağını belirler. Her satır boyunca arama yapar ve doğru yığın numarasını Mdeğişkene yerleştirir.

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

Bu eğlenceli bir parça! " "Üzerinde sadece ( ) bulunan (boş bir yığını simgeleyen) bir boşluk ( ) bulunan bir çizgiye ulaşana kadar sürekli döngülenir . Satır boş değilse, aşağıdakileri yapar:

  1. Yığındaki son karakteri aç.
  2. Anahtar deyimi:
    1. Karakter a ise ?, girişi alın ve bu karakteri çizgiye ekleyin.
    2. Karakter a ise 0, çizgi işaretçisini birer yukarı hareket ettirin.
    3. Karakter a ise 1, çizgi işaretçisini bir aşağı hareket ettirin.
    4. Karakter bir (boşluk) ise, en son açılan öğeyi yazdırın ve programı sonlandırın.

6

32 bit x86 makine kodu, 70 bayt

Onaltılı olarak:

FC89E1565F31D28A07A8DF740B3C3C7511428D5C24FCEB0A5729142484C07405B20147EBE2578B3B8A17F6C2DF7414FF0B923C3F7501AC3C30750383C30883EB04EBE389CCC3

Giriş, ESI aracılığıyla geçirilen, NULL sonlandırılmış çok satırlı bir dizedir (satır besleme ayrılmış). Kullanıcı girişi ilk satır olarak kabul edilir. AL'de '0' / '1' değerini döndürür.

demontaj:

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

Programda sonlanan bir yeni satır varsayarak

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

Daha az golf oynadı

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

Ölçek

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 bayt

Emigna sayesinde 2 bayt kaydedildi ! Kod:

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

CP-1252 kodlamasını kullanır . Çevrimiçi deneyin! .


2

Python 3, 147 146 145 144 bayt

@Lynn sayesinde 1 bayt teşekkürler.

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 program, z giriş. Evet, değişken isimlerim çıldırmış.


1

ES6, 190 bayt

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
}

Gibi kullanın f(program, input)


2
Birkaç genel golf ipucu (bir yerlerde bunların bir listesi var): [...o]yerine iki ifadeyi tasarruf eden iki bayta taşımanıza izin veren yerine o.split``kullanın ve kullanın . Özel ipuçları bir çift: Ben senin düşünüyorum dökme olarak, gereksizdir sizin için irade döküm ve sadece okurdum kullanarak ve bence 11 bayt kaydeder. forwhileforNumber*2ij=0i[j++]
Neil,

1
İhtiyacınız yok f=, isimsiz fonksiyonlara izin verilir.
gcampbell

0

Java, 256 255 231 219 215 213 bayt

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

İdeone Demo.

Programı ve girişi argüman olarak alır ve sonucu bir tamsayı olarak döndürür.


@LeakyNun Bir fordöngüye değiştirildi , ancak ilk yorumunuz ne anlama geliyor?
PurkkaKoodari

@ Pietu1998 LeakyNun olabileceği int f(String[]I)...ve kaçınabileceği anlamına gelirString[]p=I.split("\n");
kedi

İşlevi olarak ilan edebileceğiniz anlamına gelirint f(String[]P)
Leaky Nun

1
@ cat ninja'd 7 saniye ile: /
Leaky Nun

Ayrıca, eğer Java 8'e razıysanız (sanırım) bir lambdaya sahip olabilirsiniz->(String[]I){...
kedi

0

PHP (<7.0), 195 192 bayt

Programı ilk argüman ve her değeri ek argüman olarak alır.
Bunu newlines yerine split ("", ..) gibi boşluklarla test ettiğime dikkat edin ama yine de çalışması gerekir.
Php> 5.3'te çalıştırıldığında, kullanımdan kaldırılmış bir bildirim verir.
Ayrıca programın üstünden çıkarsanız bir uyarı verir. Ancak yine de çalışır ve doğru şekilde çalışır.

<?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 dizeleri işlemekle pek başarılı olmuyor, fakat bu oldukça kısa.

İmleci ( <) dizesini tarayarak, 1 basamak geri hareket ettirerek, komutu okuyarak, bir tabkarakterle değiştirerek ve bir satır ileri veya geri hareket ettirerek çalışır. Girdiye, char array[]="1\n?<\n11\n?\n0";result = f(array);satır başı da izin verilse de , C karakter dizisi biçimindedir .

Giriş dizesi değiştirilse de, uzunluk değişmez.

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

Test programı

Yeni bir program yerine tek bir ters eğik çizgi kullanarak her bir test senaryosunda ayrı bir parametre olarak bu programı çalıştırın. Test durumları boş bir satırla ayrılacaktır.

#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;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.