Mor Yorumlayıcı Golf


13

Mor Yorumlayıcı Golf

Mor , iki ana amaç için tasarlanmış bir esolang:

  • Patlıcanın en aza indirilmesi için, etrafında sadece kendi kendini değiştiren tek talimat dilleri yoktur.
  • Korkunç derecede küçük golfçü tercümanlar olasılığını kabul etmek . Makul tam özellikli bir Python 2 yorumlayıcısında ilk geçişim sadece 702 bayt ve eminim daha deneyimli bir golfçü bundan biraz tıraş olabilir.

Amacınız bu dil için bir tercüman yazmaktır.

Mor hakkında bilgi:

Mor program, programın ilk karakteri sıfır adrese yerleştirilecek şekilde sonsuz, adreslenebilir bir bellek dizisine yerleştirilen bir karakter dizisidir. Dizinin geri kalanı (Mor programın depolanmasından önce ve sonra) sıfıra başlatılır.

Purple'da a ve b ve i adında üç kayıt vardır; bunların her biri işaretli bir tamsayıyı tutabilir ve sıfıra sıfırlanır. i aynı zamanda komut göstergesidir ve her zaman yürütülmekte olan Mor talimatı gösterir.

Her döngü, yorumlayıcı, talimat işaretçisi tarafından belirtilen bellek konumundan başlayarak üç bitişik karakterden oluşan bir sekans okuyacak ve bu sekansı Mor talimat olarak yürütmeye çalışacaktır. Daha sonra, talimat işaretçisi her zaman 3 arttırılır.

Sözdizimsel olarak, Mor komutu arka arkaya " xyz " gibi üç karakterden (veya kodlamalarından) oluşur .

İlk x karakteri aşağıdakilerden herhangi biri olabilir:

abABio

Bu semboller şu anlama gelir:

a - Place the result in register a.
b - Place the result in register b.
A - Place the result in the location in memory referred to by register a.
B - Place the result in the location in memory referred to by register b.
i - Set the instruction pointer to the result.
o - Output the result to stdout.

Diğer iki bayt y ve z aşağıdakilerden herhangi biri olabilir:

abABio1

Bu sembollerin her biri şu anlama gelir:

a - Return the contents of register a.
b - Return the contents of register b.
A - Return the contents of the memory array at the address stored in register a.
B - Return the contents of the memory array at the address stored in register b.
i - Return the contents of register i (the instruction pointer).
o - Return the value of a single character read from stdin.
1 - Return the literal numeric value 1.

Talimatı getirdikten sonra, Mor yorumlayıcı y ve sonra z'yi değerlendirir , z'nin sonucunu y sonucundan çıkarır ve sonra fark üzerinde x ile belirtilen eylemi gerçekleştirir .

Üç karakter dizisi (veya kodlamaları) geçerli bir Mor talimat değilse, yorumlayıcı herhangi bir hata vermeden hemen durur.

Tercümanınız:

  • İşlev değil, tam bir program olun.
  • EOF okunmadıkça asla stderr'e çıkış yapmayın .
  • Aşağıda verilen test programları da dahil olmak üzere çok büyük sayı içermeyen tüm iyi oluşturulmuş girdilerdeki referans uygulamasına aynı şekilde davranın. (Eh, aynı zamanlamaya kadar - daha yavaş çalışabilir, ancak çok fazla değil!)

Programı tercümana istediğiniz herhangi bir biçimde sağlayabilirsiniz: bir dosyadan okuyun, programa bir dize olarak gömün veya stdin'den okuyun.

Test senaryoları:

Program

ooo

girdi ile çalıştırıldığında

z!

vermeli

Y

Program

bbboobiii

girdi ile çalıştırıldığında

It's a cat program.

(veya başka herhangi bir girdi)

It's a cat program.

(veya aldığı her giriş) ve ardından baştan başlayın ve aynı şeyi tekrar yapın .


Program

Aoab11bi1bABoAaiba

girdi ile çalıştırıldığında

0

vermeli

0

ve sonra durun, ancak girdi ile çalıştırıldığında

1

çıktı almaya devam etmeli

1

sonsuza dek.


Program

b1bbb1oAbabaa1ab1Ab1Bi1b

vermeli

b1bbb1oAbabaa1ab1Ab1Bi1b

Program

aA1aa1bb1oAbbi1bb1bbAb1Bi1b Purple is the awesomest! Why haven't you tried it yet?
!dlroW ,olleG

vermeli

Hello, World!

puanlama:

Bu , aşağıdaki bonus tarafından potansiyel olarak değiştirildiği gibi, bayt cinsinden en kısa kaynak kazanır.

Bonus:

  • Tercümanınız stdin'den veya komut satırı bağımsız değişkeninden bir dosya adı okuyor ve programı dosyadan yüklüyorsa% -10.

1
Bellek hücrelerinin boyutu nedir? bayt, karakterler (unicode olanlar?), (keyfi) büyük tamsayılar? Görünüşe göre aynı anlama gelen "karakter" ve "bayt" kullanıyorsunuz.
Paŭlo Ebermann

@ PaŭloEbermann Benim tahminim uygulamaya özgü; örneğin uint32karakterler için ve INTS için MAXINT kullanmalıyım
cat

2
@sysreq Bu gerçekten bir engelleyici mi? Uygulamanızın biri negatif diğeri pozitif endeksler için olmak üzere iki bandı olabilir. (Evet, bu biraz daha kod alacak, ama o kadar da değil, sanırım.)
Paŭlo Ebermann

1
@sysreq temel olarak, Mor kendi kendine yorumlayıcı, stdin'den bir Mor programı okuyan ve daha sonra bu programın yapacağı her şeyi yapan bir program olacaktır. İlk Purple programı (tercüman) istediğiniz tercümanda çalışabilir. Giriş ile tamamen en düşük bellek adreslerinin üzerine yazan bir program, daha sonra bir şekilde okuma koduna geçmeden önce kendini siler (ancak bunun gerçekten mümkün olduğunu düşünmüyorum).
quintopia

2
Kendini yorumlayabilecek bir çalışma süresine sahip olmaya çok yaklaştım, ama çok geç kaldım.
kedi

Yanıtlar:


7

Pyth, 148 128 121 bayt (ya da 124 * .9 = 111.6, alt bakınız)

J,00=kjb.z .eXHkCbz#=b-Fm?=zx"oabABi1"C@H+Zd@s[0Jm.x@Hk0JZ1H)zCh~tkS2 ?hKx"abAB"=YC@HZ?PKXH@JKbXJKb?qY\i=Zb?qY\opCbvN=+Z3

Test odası

STDIN'in ilk satırında verilen kod, STDIN'nin geri kalanındaki Purple programına girin. Yeni satırlarla kod kullanmak için alt kısımdaki alternatif sürümü kullanın.

Makul golf. İşte netlik için çizgi ve girinti ile:

J,00
=kjb.z
 .eXHkCbz
#
  =b-Fm
    ?=zx"oabABi1"C@H+Zd
      @
        s[0Jm.x@Hk0JZ1H)
        z
      Ch~tk
    S2
   ?hKx"abAB"=YC@HZ
    ?PK
      XH@JKb
      XJKb
  ?qY\i=Zb
  ?qY\opCb
  vN
  =+Z3

Temel olarak, bir #döngü yürütmeyi ve durdurmayı hata sonu yoluyla yapar.

ave btek bir değişken halinde birleştirilir J,. Zyönerge işaretçisi. kPurple programına girilir. Hsözlük olarak gösterilen kasettir. bşimdiki sonuçtur. Ykomutun geçerli ilk baytıdır.

Dosyadan okuma:

J,00=kjb.z .eXHkCbjb'z#=b-Fm?q\o=zC@H+ZdCh~tk@s[Jm.x@Hk0JZ1H)x"abABi1"zS2 ?hKx"abAB"=YC@HZ?PKXH@JKbXJKb?qY\i=Zb?qY\opCbvN=+Z3

STDIN'in ilk satırı olarak dosya adını verin. Test sürüşü:

$ cat purple-final.pyth 
J,00=kjb.z .eXHkCbjb'z#=b-Fm?=zx"oabABi1"C@H+Zd@s[0Jm.x@Hk0JZ1H)zCh~tkS2 ?hKx"abAB"=YC@HZ?PKXH@JKbXJKb?qY\i=Zb?qY\opCbvN=+Z3
$ cat purple-code.txt 
aA1aa1bb1oAbbi1bb1bbAb1Bi1b Purple is the awesomest! Why haven't you tried it yet?
!dlroW ,olleG
$ pyth purple-final.pyth <<< 'purple-code.txt' 
Hello, World!

5

JavaScript (ES6), 292 bayt

eval(`a=b=i=d=0;v=n=>(x=m[i+n])==97?a_98?b_65?m[a]_66?m[b]_105?i_111?p()[c]()_49?1:d=1;for(m=[...(p=prompt)()].map(b=>b[c="charCodeAt"]());!d;i+=3)(y=v(1),d)||(z=v(2),d)?1:(x=m[r=y-z,i])==97?a=r_98?b=r_65?m[a]=r_66?m[b]=r_105?i=r-3_111?alert(String.fromCharCode(r)):d=1`.replace(/_/g,":x=="))

açıklama

JavaScript cevapları her zaman gariptir STDINve STDOUTgerektiğinde ...

İlk bilgi istemi, program dizesinin girdisidir. Bir otalimattan kaynaklanan her komut istemi yalnızca ilk karakteri okuyacaktır.

eval, birkaç bayt kaydeden ortak bir ifadenin yerine kullanılır. Ungolfed ve evalprogram olmadan şöyle görünür:

// Initialisation
a=b=i=                            // initialise registers to 0
  d=0;                            // d is set to true when the program should die

// Gets the result of Y or Z
v=n=>                             // n = offset from i
  (x=m[i+n])==97?a:               // x = value of instruction
  x==98?b:
  x==65?m[a]:
  x==66?m[b]:
  x==105?i:
  x==111?p()[c]():
  x==49?1:
  d=1;                            // if it was none of the valid values, die

// Execution loop
for(
  m=                              // m = memory array
    [...(p=prompt)()]             // receive the program
    .map(b=>b[c="charCodeAt"]()); // initialise m to the ASCII values of the program
  !d;                             // finish if an error occured
  i+=3                            // increment i
)
  (y=v(1),d)||                    // get the value of Y and check for errors
  (z=v(2),d)?1:                   // get the value of Z and check for errors

    // Get the result of X
    (x=m[r=y-z,i])==97?a=r:       // r = result of y - z
    x==98?b=r:
    x==65?m[a]=r:
    x==66?m[b]=r:
    x==105?i=r-3:
    x==111?alert(String.fromCharCode(r)):
    d=1

2
İkincisi c="charCodeAt"sadece ile değiştirilebilir cmi?
Dendrobium

Negatif dizinlerle dizi erişimi JavaScript'te çalışıyor mu?
nimi

@Dendrobium Vay be, bunu nasıl özlediğimi bilmiyorum haha! Teşekkürler.
user81655

2
@nimi Çalışıyor. Dizilerin kendileri negatif indeksleri desteklemez, ancak bu aynı zamanda nesne olarak davrandıklarından yararlanır. array[-1] = 1ile aynıdır array = { "-1": 1 }. Her ikisine de ile erişilebilir array[-1].
user81655

@ user81655: Ah güzel, bilmiyordum.
nimi

3

Seylan, 827 792 671 bayt

import ceylon.language{l=variable,I=Integer,x=nothing,p=process,m=map}shared void run(){try{if(exists d=p.arguments[0]){l value t=m{*d*.hash.indexed};l I a=0;l I b=0;l I i=0;I g(I j)=>t[j]else 0;l{I*}c=[];I o{if(c==[]){if(exists e=p.readLine()){c=e*.hash.chain{10};}else{c={-1}.cycled;}}assert(is I r=c.first);c=c.rest;return r;}value f=m{97->{a},98->{b},65->{g(a)},66->{g(b)},105->{i},111->{o},49->{1}};value s=m{97->((I v)=>a=v),98->((I v)=>b=v),65->((I v)=>t=m{a->v,*t}),66->((I v)=>t=m{b->v,*t}),105->((I v)=>i=v),111->((I v)=>p.write("``v.character``"))};I h(I v)=>f[v]?.first else x;while(0<1){(s[g(i)]else x)(h(g(i+1))-h(g(i+2)));i+=3;}}}catch(AssertionError e){}}

Program EOF'daki girdiyi okumaya çalıştığında referans uygulamasından biraz farklı davranır - referans uygulaması, burada (ve muhtemelen bir hata) çoğaltmak için çok pahalı olan bir TypeError ile çöker, bu yüzden bunun yerine -1 döndürür ( gerekirse tekrar tekrar).

(Bu -1'i stdout'a yazmaya çalışırken, yorumlayıcı bir OverflowError ile biter. Unicode aralığının dışındaki bir Tamsayı çıkarılırsa benzer olur.)

Tercüman programı ilk komut satırı argümanı olarak alır (boşluk veya başka ilginç şeyler içerdiğinde kabuğunuz için alıntı yaptığınızdan emin olun).

Ceylon'da sadece giriş satırına göre kolayca okuyabiliriz (sanırım bu sonraki sürümlerden birinde değişecektir), bu nedenle ookuma için kullanıldığında, tüm bir satırı okuyorum ve gelecekteki kullanımlar için parçaları arabelleğe alıyorum. Sanırım bir terminale bağlandığında Python uygulamasında benzer şekilde çalışıyor.


Geçerli karakterlerden biri olmayan bir komutu (parçayı) yürütmeye çalışırken, nothingbir AssertionError öğesinin atılmasına neden olur, bu da daha sonra ana döngü etrafındaki catch bloğunda yakalanır.

Bu tercihen özel bir İstisna türü olması gerektiğini düşünüyorum (AssertionError bir hata varsa başka yerlerde de meydana gelebilir gibi), ancak bu ilk sürümden yaptığım çoğu iyileştirmeyi yiyerek çok daha fazla yer kaplayacaktır.

Golf için kullanılan bazı hileler:

  • Önceki sürümlerde bir ceylon.collection.HashMap kullanıyorduk - bunun yerine artık mapişlev tarafından oluşturulduğu gibi değişmez bir harita kullanıyoruz ve her seferinde yeni bir tane oluşturuyoruz Aveya xB olarak kullanılıyor .
  • Birden çok kez kullanılan ( variableşimdi ek açıklama dahil) ceylon.language tanımlayıcıları için takma ad ithalatı kullanıyorum l.
  • Sınıftan E(çevre için) ve s(adım) yönteminden kurtuldum - şimdi her şey runfonksiyonun içinde gerçekleşiyor .
  • .integerBir karakterin kod noktasını almak için kullanmak yerine .hash, aynı sonucu verir. Böylece string*.hashaynıdır string.map(Character.integer)(bir dizeden kod noktalarını yineleyerek verir).
  • Bir tür diğer addan içe aktarıldığında, is I ...daha kısadır exists ....
  • Bir şeyi (örneğin x) bir dizeye dönüştürürken, (veya bir karakter için kullandığımdan) "``t``"daha kısadır .t.stringString{t}
  • sadece bir kez kullanılan fonksiyonlar genellikle satır içine alınabilir.

Biçimlendirilmiş (ve yorumlanmış) sürüm:

// Purple – a self-modifying, "one-instruction" language.
//
// Question:  http://codegolf.stackexchange.com/q/65411/2338
// My answer: http://codegolf.stackexchange.com/a/65492/2338

import ceylon.language {
    l=variable,
    I=Integer,
    x=nothing,
    p=process,
    m=map
}

shared void run() {
    try {
        // Reading code from file certainly takes more than 73 characters,
        // this isn't worth the 10% bonus.
        if (exists d = p.arguments[0]) {

            // The memory tape, as a Map<Integer, Integer>.
            // We can't modify the map itself, but we
            // can replace it by a new map when update is needed.
            l value t = m {
                // It is initialized with the code converted to Integers.
                // We use `.hash` instead of `.integer` because it is shorter.
                *d*.hash.indexed };

            // three registers
            l I a = 0;
            l I b = 0;
            l I i = 0;

            // get value from memory
            I g(I j) =>
                    t[j] else 0;

            // cached input which is still to be read
            l {I*} c = [];

            // get value from stdin.
            // we can only comfortably access stdin by line, so we read a whole line
            // and cache the rest for later.
            I o {
                if (c == []) {
                    if (exists e = p.readLine()) {
                        c = e*.hash.chain { 10 }; // convert string into ints, append \n
                    } else {
                        // EOF – return just -1 from now on.
                        c = { -1 }.cycled;
                    }
                }
                assert (is I r = c.first);
                c = c.rest;
                return r;
            }


            // Map of "functions" for fetching values.
            // We wrap the values in iterable constructors for lazy evaluation
            //  – this is shorter than using (() => ...).
            // The keys are the (Unicode/ASCII) code points of the mapped
            // source code characters.
            value f = m {
                // a
                97 -> { a },
                // b
                98 -> { b },
                // A
                65 -> { g(a) },
                // B
                66 -> { g(b) },
                // i
                105 -> { i },
                // o
                111 -> { o },
                // 1
                49 -> { 1 }
            };

            // Map of functions for "storing" results.
            // The values are void functions taking an Integer,
            // the keys are the ASCII/Unicode code points of the corresponding
            // source code characters.
            value s = m {
                // a
                97 -> ((I v) => a = v),
                // b
                98 -> ((I v) => b = v),
                // Modification of the memory works by replacing the map with a new one.
                // This is certainly not runtime-efficient, but shorter than importing
                // ceylon.collections.HashMap.
                // A
                65 -> ((I v) => t = m { a->v, *t }),
                // B
                66 -> ((I v) => t = m { b->v, *t }),
                // i
                105 -> ((I v) => i = v),
                // o – output as a character.
                111 -> ((I v) => p.write("``v.character``"))
            };

            // accessor function for the f map
            I h(I v) =>
                    f[v]?.first else x;

            // the main loop, can only be left by exception
            while (0 < 1) {
                (s[g(i)] else x)(h(g(i + 1)) - h(g(i + 2)));
                i += 3;
            }
        }
    } catch (AssertionError e) {
        // abort silently
    }
}

Tüm durma programlarını bulmaya çalışan bir "paralel yorumlayıcı" için bu kodun bir kısmını tekrar kullandım . (Birçoğu var.) (Orada I / O çok yer kapladığı ve bu görevde kullanılmadığı için Purple'ın I / O olmayan bir versiyonunu kullandım.)
Paŭlo Ebermann
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.