Prindeal (ausgesprochen prin-dee-al ) ist eine neue esoterische Programmiersprache, die nur vier Befehle enthält: pr int , in crement , de crement und al ias . Trotz seines Minimalismus können komplexe mathematische Operationen in Prindeal durchgeführt werden, indem die vier Befehle geschickt kombiniert werden.
Ihre Aufgabe bei dieser Code-Golf- Herausforderung ist es, das kürzeste Programm zu schreiben, das Prindeal-Code ausführen kann.
Die Spezifikation ist lang, aber ich habe versucht, sie so deutlich wie möglich zu machen, und ich glaube, wenn Sie sich die Mühe machen, Prindeal zu lernen, werden Sie feststellen, dass es ziemlich elegant ist!
Prindeal interpretieren
Vorverarbeitung
Bevor ein Prindeal-Programm interpretiert werden kann, müssen diese Dinge in dieser Reihenfolge entfernt werden:
- Alles, was nach einem
#
Zeichen bis zum Ende der Zeile steht, ist eingeschaltet, plus das#
Selbst. (Dies sind Kommentare.) - Leerzeichen in jeder Zeile nachstellen.
- Völlig leere Zeilen.
Zum Beispiel das Prindeal-Programm
p cat #The next line has 7 trailing spaces.
p dog
#p mouse
würde vorverarbeitet werden
p cat
p dog
Ab hier gehen wir davon aus, dass dieser Vorverarbeitungsschritt abgeschlossen ist.
Variablen
Wir müssen schnell Variablen definieren, bevor wir zeigen, wie sie verwendet werden.
Variablen (und Verweise auf Variablen) werden an die Argumente von Prindeal-Befehlen übergeben. Variablen sind immer global , sodass Änderungen an einer Variablen, unabhängig davon, wo sie auftreten, überall wiedergegeben werden.
Jede Variable enthält eine nicht negative Ganzzahl mit beliebiger Genauigkeit (0, 1, 2, 3, ...). Variablen müssen nicht vorinitialisiert werden - sie beginnen immer mit dem Wert 0, wenn sie zum ersten Mal verwendet oder aufgerufen werden.
Ein Variablenname kann eine beliebige nicht leere Zeichenfolge aus alphanumerischen Zeichen und Unterstrichen sein, die nicht mit einer Ziffer beginnt - [a-zA-Z_][0-9a-zA-Z_]*
in Regex . Es wird zwischen Groß- und Kleinschreibung unterschieden, spiny_lumpsuck3r
und Spiny_lumpsuck3r
es handelt sich um verschiedene Variablen.
Ausführung
Prindeal ist eine zwingende Programmiersprache. Wenn ein Prindeal-Programm ausgeführt wird, werden seine Anweisungen der Reihe nach von oben nach unten ausgeführt und das Programm endet.
Jede nicht eingerückte Zeile in einem Prindeal-Programm ist eine Anweisung, die die Ausführung eines einzelnen Befehls beinhaltet, der Argumente annehmen kann oder nicht.
Indented Linien treten erst nach Alias - Befehle. Insbesondere treten genau drei Zeilen, die mit einzelnen Leerzeichen eingerückt sind, nach jedem Alias- Befehl auf und werden als Teil davon betrachtet. So alias Aussagen sind wirklich lange vier Linien. (Es kann sich um eine Zeile handeln, vier sind lediglich lesbarer.)
Non- Alias- Anweisungen
Mit Ausnahme des Alias hat jede Anweisung in einem Prindeal-Programm die Form:
[command name] [argument 1] [argument 2] [argument 3] ...
Es kann eine beliebige Anzahl von Argumenten geben (einschließlich überhaupt keiner). Jedes Argument ist immer eine Variable oder (wie wir bei der Beschreibung des Alias sehen werden ) ein Verweis auf eine Variable .
Sobald die Ausführung abgeschlossen ist, wird jede Anweisung als fehlgeschlagen oder erfolgreich markiert, je nachdem, ob Fehler aufgetreten sind oder nicht. (Dies ist nur dann wirklich wichtig, wenn wir uns mit der Verwendung von Alias befassen .)
Die integrierten Funktionen print , increment und decrement sind Anweisungen mit der obigen Form. Folgendes machen sie:
print hat einen Befehlsnamen
p
und akzeptiert ein Argument. Es gibt den Namen der übergebenen Variablen und ihren Wert (in Dezimalzahl) aus, getrennt durch "=", gefolgt von einer neuen Zeile. Es wird immer als Erfolg gewertet .Zum Beispiel das Prindeal-Programm
p _MyVariable_321 p screaming_hairy_armadillo
würde ausgeben
_MyVariable_321 = 0 screaming_hairy_armadillo = 0
weil alle Variablen bei 0 beginnen. (Die Leerzeichen vor und nach dem Gleichheitszeichen sind erforderlich.)
increment hat den Befehlsnamen
i
und nimmt ein Argument entgegen. Es erhöht den Wert der übergebenen Variablen um 1. Es wird immer als Erfolg gewertet.Zum Beispiel das Programm
i alpaca p alpaca i alpaca p alpaca
würde ausgeben
alpaca = 1 alpaca = 2
Beachten Sie, wie
alpaca
von 0 auf 1 inkrementiert wurde, obwohl noch nie zuvor darauf zugegriffen wurde.decrement hat einen Befehlsnamen
d
und benötigt ein Argument. Wenn die Variablen übergeben ist ungleich Null sein Wert um 1 verringert wird und die Anweisung wird als markiert Erfolg . Wenn die übergebene Variable 0 ist, wird nichts unternommen und die Anweisung als fehlerhaft gekennzeichnet .Zum Beispiel das Programm
i malamute p malamute d malamute #success p malamute d malamute #failure p malamute d akita #failure p akita
würde ausgeben
malamute = 1 malamute = 0 malamute = 0 akita = 0
Beachten Sie, dass das Dekrementieren einer Variablen mit dem Wert 0 die einzige Möglichkeit ist, einen Fehler zu erzeugen .
Die Alias- Anweisung und die Alias-Befehle
Der Alias- Befehl hat eine spezielle Syntax und ist am leistungsfähigsten, da er zum Definieren neuer Befehle verwendet werden kann. Der Name des Aliasbefehls lautet a
und eine Aliasanweisung hat die Form:
a [name of new command]
[statement A]
[statement B]
[statement C]
Wobei jedes [statement X]
eine Nicht- Alias- Anweisung darstellt, dh etwas mit der Form [command name] [argument 1] [argument 2] [argument 3] ...
.
Der Name des Befehls mit Alias [name of new command]
kann eine beliebige nicht leere Zeichenfolge aus alphanumerischen Zeichen und Unterstrichen sein, die nicht mit einer Ziffer beginnt - [a-zA-Z_][0-9a-zA-Z_]*
in Regex.
(Dies ist der gleiche Satz von Namen wie Variablen, aber Alias- Befehle und Variablen werden an verschiedenen Stellen unterschiedlich verwendet . Eine Variable kann den gleichen Namen wie ein Befehl haben, ohne dass dies negative Folgen hat.)
Wenn eine Alias- Anweisung ausgeführt wird, wird neben den ursprünglichen vier p
i
d
a
Befehlen ein neuer Befehl hinzugefügt . Der neue Befehl kann [command name]
wie jeder andere Nicht- Alias- Befehl als in-Anweisung verwendet und mit Argumenten aufgerufen werden .
Wenn eine Anweisung mit einem Alias-Befehlsnamen ausgeführt wird, werden genau zwei weitere Anweisungen aus der ursprünglichen Alias- Anweisung ausgeführt:
[statement A]
wird immer ausgeführt[statement B]
wird ausgeführt, wenn[statement A]
ein Erfolg war[statement C]
wird ausgeführt, wenn[statement A]
ein Fehler aufgetreten ist
Anweisungen A, B und C werden immer träge ausgeführt , dh sie werden sofort zum Zeitpunkt der Ausführung ausgewertet.
Wenn Sie fertig ausgeführt wird , wird der Alias - Befehl mit dem gleichen gekennzeichnet Erfolg oder Versagen Flagge als Aussage B oder C, je nachdem , welche ausgeführt wurde . ( Alias- Anweisungen selbst müssen nicht markiert werden, da sie nicht in sich selbst vorkommen können.)
Alias Beispiel 1
Angenommen, wir möchten einen neuen Befehl, der die Variable
frog
zweimal inkrementiert . Diese Alias-Anweisung erreicht es:a increment_frog_twice i frog i frog d frog
Anweisung A (
i frog
) wird immer ausgeführt und immer als Erfolg gekennzeichnet, daher wird auch Anweisung B (i frog
) ausgeführt und die Variablefrog
wird daher um 2 erhöht. Derincrement_frog_twice
Befehl wird immer als Erfolg gekennzeichnet, da Anweisung B immer ausgeführt wird und B immer a ist erfolg . Anweisung C (d frog
) wird niemals ausgeführt.Also die Ausgabe an
a increment_frog_twice i frog i frog d frog p frog increment_frog_twice p frog
wäre
frog = 0 frog = 2
Wir können dieses Beispiel so verallgemeinern, dass jede Variable zweimal inkrementiert werden kann, indem Sie dem Alias-Befehl ein Argument geben.
In einer Alias- Anweisung stehen die positiven Ganzzahlen 1, 2, 3 usw. für die Argumente 1, 2, 3 usw., die an den Alias-Befehl übergeben werden. (Diese Argumente können einfache Variablen oder Verweise auf Variablen selbst sein.) Diese Zahlen können nur in den Argumenten von Anweisung A, B und C in einer Alias- Anweisung vorkommen. Es macht keinen Sinn, wenn sie woanders auftauchen.
Alias Beispiel 2
Dies verallgemeinert das letzte Beispiel: Jede Variable, an die übergeben
increment_twice
wird, wird um 2 inkrementiert, da1
es sich um einen Verweis auf das erste übergebene Argument handelt:a increment_twice i 1 i 1 d 1 #never reached p toad increment_twice toad p toad
Die Ausgabe dieses Programms wäre
toad = 0 toad = 2
Wir könnten dann einen anderen Befehl aliasen, der zwei Argumente aufnimmt und
increment_twice
beide aufruft :a increment_twice i 1 i 1 d 1 #never reached a increment_both_twice increment_twice 1 increment_twice 2 d 1 #never reached increment_both_twice platypus duck p platypus p duck
Die Ausgabe hier wäre
platypus = 2 duck = 2
Es ist wichtig zu wissen, dass Alias-Befehle rekursiv sein können, da hier ihre wahre Kraft liegt. Zum Beispiel können wir einen Befehl erstellen, der jede übergebene Variable auf 0 setzt:
Alias Beispiel 3
Der
set_to_zero
Befehl akzeptiert ein Argument und setzt seine Variable auf 0. Wenn er fertig ist, wird er als erfolgreich markiert :a set_to_zero d 1 set_to_zero 1 i _dummy_ i oryx i oryx i oryx p oryx set_to_zero oryx p oryx
Die Ausgabe dieses Programms wäre
oryx = 3 oryx = 0
Was passiert ist, dass, wenn ausgeführt
set_to_zero oryx
wird,d 1
erfolgreichoryx
von 3 auf 2 dekrementiert wird , dannset_to_zero 1
aufgerufen wird, was dasselbe ist wie einset_to_zero oryx
erneuter Aufruf . Der Prozess wird wiederholt, bisd 1
ein Fehler aufgetreten ist. Die Rekursion wird gestoppt und die_dummy_
Variable erhöht , sodass ein Erfolg erzielt wird.
Herausforderung
Schreiben Sie ein Programm, das Prindeal-Code genau wie oben beschrieben ausführen kann. Übernehmen Sie den Prindeal-Code über stdin, die Befehlszeile oder als Textdatei. Drucken Sie die Ausgabe des Prindeal-Programms auf stdout oder die nächstgelegene Alternative Ihrer Sprache.
Alternativ können Sie eine Funktion schreiben, die den Code als Zeichenfolge aufnimmt und die Ausgabezeichenfolge ausgibt oder zurückgibt.
Darüber hinaus können Sie davon ausgehen, dass:
- Der eingegebene Prindeal-Code enthält nur Zeilenumbrüche und druckbare ASCII-Zeichen und endet (optional) mit einer Leerzeile.
- Der eingegebene Code ist gültig Prindeal - wohlgeformt und syntaktisch korrekt.
- Das Ausführen des Codes führt weder zu Endlosschleifen noch zu ungültigen Verweisen auf Befehle, die nicht definiert wurden, oder auf Argumente, die nicht angegeben wurden.
- Die Befehlsnamen
p
,i
,d
, unda
werden nie über aliased werden. (Sie können nicht davon ausgehen, dass Variablen diese Namen nicht haben.)
Außerdem spielt es keine Rolle, ob Ihre Variablenwerte wirklich Ganzzahlen mit willkürlicher Genauigkeit sind, da nur Zahlen mit weniger als etwa 1000 getestet werden. Es ist auch in Ordnung, wenn Ihre Sprache über Rekursionsbeschränkungen (wie Python ) verfügt, auf die komplexere Prindeal-Programme möglicherweise stoßen, solange das folgende Testprogramm funktioniert.
Testprogramm
Hier ist ein großes Prindeal-Programm, das die Operationen Addition, Multiplikation und Exponentiation durch die Verwendung von Dummy-Variablen (beginnend mit _
Konvention) und vielen Helfer-Aliasen aufbaut :
#Command Definitions:
a s #flag as a success
i _
d _
d _
a f #flag as a failure
d _
d _
d _
a z #1 = zero
d 1
z 1
s
a n #1 = one
z 1
i 1
s
a move #2 += 1, 1 = zero
moveH 1 2
move 1 2
s
a moveH #move helper
d 1
i 2
f
a dupe #2 += 1, 3 += 1, 1 = zero
dupeH1 1 2 3
dupe 1 2 3
s
a dupeH1 #dupe helper
d 1
dupeH2 2 3
f
a dupeH2 #dupe helper
i 1
i 2
s
a copy #2 = 1
z 2
copyH 1 2
s
a copyH #copy helper
dupe 1 2 _copy
move _copy 1
s
a addTo #1 += 2
copy 2 _add
#testing comments #
move _add 1#in weird places # just because #
s
#it's a g##d idea
###
a add #1 = 2 + 3
#its a good idea
z 1
addH 1 2 3
s
##
#
a addH #add helper
#this is a comment
addTo 1 2 #as is this
addTo 1 3
s
a mul #1 = 2 * 3
mulH1 1 2
mulH2 1 3
s
a mulH1 #mul helper
z 1
copy 2 _mul
s
a mulH2 #mul helper
mulH3 1 2
mulH2 1 2
s
a mulH3 #mul helper
d _mul
addTo 1 2
f
a mulBy #1 *= 2
mul _mulBy 1 2
copy _mulBy 1
s
a pow #1 = 2^3
powH1 1 3
powH2 1 2
s
a powH1 #pow helper
n 1
copy 2 _pow
s
a powH2 #pow helper
powH3 1 2
powH2 1 2
s
a powH3 #pow helper
d _pow
mulBy 1 2
f
#Running Tests:
p A
p B
p C
n A #A = 1
n B #B = 1
add C A B #C = A + B = 1 + 1 = 2
p ____
p A
p B
p C
add B A C #B = A + C = 1 + 2 = 3
p ____
p A
p B
p C
mul d B C #d = B * C = 3 * 2 = 6
p ____
p d
mulBy d B #d = d * B = 6 * 3 = 18
p ____
p d
d A #A = A - 1 = 1 - 1 = 0
mulBy d A #d = d * A = 18 * 0 = 0
p ____
p d
pow A C B #A = C ^ B = 2 ^ 3 = 8
p ____
p A
p B
p C
pow A B C #A = B ^ C = 3 ^ 2 = 9
p ____
p A
p B
p C
pow C A B #C = A ^ B = 9 ^ 3 = 729
p ____
p A
p B
p C
(Wenn Sie mit diesem Code herumspielen, beachten Sie, dass viele der Befehle fehlschlagen, wenn dieselbe Variable mehrmals als Argument angegeben wird. Dies kann leicht behoben werden, der resultierende Code ist jedoch länger.)
Ihr Prindeal-Interpreter sollte in der Lage sein, die genaue Ausgabe zu erstellen:
A = 0
B = 0
C = 0
____ = 0
A = 1
B = 1
C = 2
____ = 0
A = 1
B = 3
C = 2
____ = 0
d = 6
____ = 0
d = 18
____ = 0
d = 0
____ = 0
A = 8
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 2
____ = 0
A = 9
B = 3
C = 729
Wertung
Der kürzeste Code in Bytes gewinnt. Tiebreaker geht auf frühere Vorlage.
Brownie Bonus: Schreiben Sie ein cooles Programm in Prindeal. Ich habe Addition und Multiplikation implementiert. Können Sie subtrahieren oder dividieren?
quelle
p
, undp p
was würde dann 1 ausgeben, richtig?Antworten:
Pyth,
162136 BytesDemonstration.
26 Zeichen durch Inlining von Variablen und Ändern von
I
undE
basierendem Kontrollfluss zu?
und.x
basierendem Kontrollfluss herausgearbeitet.Zum ersten Mal gingen mir in Pyth die Variablen aus. Jede einzelne Variable in Pyth (
bdkGHNTY
undJK
) wurde verwendet, und ich wollte verwendenb
als Zeilenumbruch verwenden. Zum Glück konnte ich verwendenN
zwei völlig verschiedene Dinge in verschiedenen Teilen des Programms bedeuten, und so funktioniert es immer noch.Ungolfed (laufen mit -m):
quelle
Python 2,
600584397373 BytesDies ist meine eigene Referenzlösung für den Golfsport. Jeder ist willkommen, es zu verbessern oder seiner Logik in seiner eigenen Antwort zu folgen, solange die Zuschreibung erfolgt.
Das Schöne daran ist, dass keine Rekursion durchgeführt wird, sodass es nie Probleme mit der Rekursionsgrenze von Python geben wird. Beispielsweise kann das Countup Prindeal-Programm von Sp auf unbestimmte Zeit ausgeführt werden.
Es ist ein Programm, das die angegebene Programmzeichenfolge mit Zeilenumbrüchen einliest, z
'p _MyVariable_321\np screaming_hairy_armadillo'
.Aus den Antworten von Sp und Pietu habe ich verschiedene Hinweise zum Golfen entnommen . Danke Leute :)
quelle
Python 3,
345336335328 Bytes(-6 Bytes dank @orlp)
Immer noch Golf spielen. Angenommen, das Programm ist in einer Datei mit dem Namen gespeichert
P
.Die Anrufe ins
f
Lambda steckend
würde einige Bytes sparen, aber der letzte Testfall würde die maximale Rekursionstiefe erreichen.Einige Prindeal-Programme
Das nutzlose Subtraktionsprogramm
Hier ist ein nutzloses Subtraktionsprogramm . Es ist nutzlos, weil es Erfolg / Misserfolg nicht entsprechend zurückgibt, obwohl es richtig subtrahiert.
Die Ausgabe sollte sein:
Zusammenzählen
Zählt nach oben und druckt
n
für immer. Könnte möglicherweise als Test für die Interpretergeschwindigkeit dienen (Vorsicht vor den langen Tracebacks bei Tastatur-Interrupts).quelle
l[:(l+"#").find("#")]
und alle seine Variationen können durch eine einfache ersetzt werdenl.split('#')[0]
.find
dass ich vergessen habe, dass man es könnte,split
auch wenn#
es nicht da wäre. Vielen Dank :)JavaScript (ES6), 273
258Behobene Fehler bearbeiten und eine echte Testsuite hinzugefügt.
Ohne führende Leerzeichen und Zeilenumbrüche.
Sicher kann man ein bisschen mehr golfen.
Ich bin zu müde, jetzt eine Erklärung zu schreiben, und denke, es ist ein gutes Beispiel für die Verwendung von Closures, um temporäre Werte (Parameter) am Leben zu erhalten.
Testlauf des Snippets in jedem EcmaScript 6-kompatiblen Browser (insbesondere nicht in Chrome und nicht in MSIE. Ich habe es in Firefox getestet, Safari 9 könnte funktionieren)
quelle
C # 6, 653 Bytes
Hier ist mein Eintrag, inmitten eines Meeres von Python ...
Erweitert und kommentiert:
Um es zu verwenden, instanziieren Sie einfach die Klasse und rufen Sie die
R()
Methode auf, zum Beispiel:quelle
Gemeines Lisp,
758646619Geben Sie dies ein
file.lisp
und rufen Sie zum Beispiel ansbcl --script file.lisp
; Die Eingabe wird aus dem Standardeingabestream gelesen.Diese Version analysiert eine Obermenge von Prindeal: Ohne große Schwierigkeiten können Sie von einer Prindeal-Quelle aus auf alle Common Lisp zugreifen. Ich halte dies für ein Merkmal des Interpreters.
Kommentierte Version
Beispiel
Wenn wir in der Lese- / Bewertungsschleife
eval
durch ersetzenprint
, können wir sehen, was ausgewertet wird:Makroexpansion
Wenn wir die folgende Aliasdefinition auswählen:
... wir können Verweise auf eine Variable mit dem Namen sehen,
g
die im lexikalischen Bereich nirgends zu finden ist. Aber nach der Makroexpansion wird hier der eigentliche Code ausgewertet:Nun
g
bezieht sich auf die Argumentliste der Funktion definiert ist.quelle
Python 2, 486 Bytes
Dies ist die Referenzlösung, mit der ich mehr Golf gespielt habe (derzeit -98 Bytes).
Änderungen (an die ich mich erinnere):
[l,l[:l.find('#')]]['#'in l]
).V[k]=-~V[k]if k in V else 1
)k=s[1]
)print
Leerzeichen automatisch hinzufügen (print k,'=',V.get(k,0)
)'0'<t[0]<':'
)r
um, umreturn
s zu sparenmap(str.split,c[:3]))
)quelle
Python 3, 1322 Bytes
Golf gespielt:
Ungolfed:
Verwendung:
Wo
c
ist der Textinhalt.Beispiele:
Einzeilige Zeichenfolgen werden akzeptiert:
P("p cat")
P("p dog\ni dog\np dog")
Mehrzeilige Zeichenfolgen werden ebenfalls akzeptiert:
Oder:
Etc.
Anmerkungen:
Dies funktioniert ordnungsgemäß für alle Testfälle, erreicht jedoch die Rekursionsgrenze für:
Daher die
sys.setrecursionlimit(2000)
.quelle
Python -
695688 Bytes<TAB>
ist ein wörtliches Tabulatorzeichen.quelle
C ++, 1111 Bytes
Dieser ist C ++ - so idiomatisch wie ich es machen könnte.
Das bedeutet, es mehr C ++ - und weniger C-ish zu machen.
Das bedeutet auch, dass es größer als das entsprechende C-Programm ist.
Ich denke, C ++ konkurriert mit Java um eine ausführliche Standardbibliothek.
Kompiliert mit VS2013 und g ++ 4.9.2 (mit -std = c ++ 11)
Unten ist das Original. Wenn jemand eine Möglichkeit finden sollte, es gleichzeitig idiomatischer und kürzer zu gestalten, lassen Sie es mich bitte wissen.
quelle
Haskell, 1009
Ich habe mein Bestes gegeben, um Golf zu spielen. Mein ungolfed Code bestand aus über 3.000 Zeichen. An diesem Punkt kann ich mich nicht erinnern, was alle Funktionen tun, wenn ich Golf spiele, heißt das erraten, was es kaputt macht und was nicht.
quelle