Prindeal (pronunciato prin-dee-al ) è un nuovo linguaggio di programmazione esoterico che ha solo quattro comandi: pr int , in crement , de crement e al ias . Nonostante il suo minimalismo, in Prindeal è possibile eseguire complesse operazioni matematiche combinando abilmente i quattro comandi.
Il tuo compito in questa sfida di golf del codice è quello di scrivere il programma più breve in grado di eseguire il codice Prindeal.
Le specifiche sono lunghe ma ho cercato di renderlo il più chiaro possibile e credo che se fai lo sforzo di imparare Prindeal lo troverai abbastanza elegante!
Intrepreting Prindeal
Pre-elaborazione
Prima che un programma Prindeal possa essere interpretato, queste cose devono essere rimosse da esso in questo ordine:
- Qualunque cosa dopo un
#
segno alla fine della linea è attiva, più lo#
stesso. (Questi sono commenti.) - Spazio bianco finale su qualsiasi riga.
- Linee completamente vuote.
Ad esempio, il programma Prindeal
p cat #The next line has 7 trailing spaces.
p dog
#p mouse
verrebbe preelaborato
p cat
p dog
D'ora in poi supponiamo che questo passaggio di preelaborazione sia stato eseguito.
variabili
Dobbiamo rapidamente definire le variabili prima di mostrare come vengono utilizzate.
Le variabili (e i riferimenti alle variabili) sono quelli che vengono passati agli argomenti dei comandi Prindeal. Le variabili sono sempre globali , quindi le modifiche a una variabile, indipendentemente da dove si verificano, si riflettono ovunque.
Ogni variabile contiene un numero intero di precisione arbitraria non negativa (0, 1, 2, 3, ...). Non è necessario pre-inizializzare le variabili: iniziano sempre con il valore 0 la prima volta che vengono utilizzate o richieste.
Un nome di variabile può essere qualsiasi stringa non vuota di caratteri alfanumerici e di sottolineatura che non inizia con una cifra - [a-zA-Z_][0-9a-zA-Z_]*
in regex . Sono case sensitive, quindi spiny_lumpsuck3r
e Spiny_lumpsuck3r
sono variabili diverse.
Esecuzione
Prindeal è un linguaggio di programmazione imperativo . Quando viene eseguito un programma Prindeal, le sue istruzioni vengono eseguite dall'alto verso il basso in ordine e quindi il programma termina.
Ogni riga non indentata in un programma Prindeal è un'istruzione che comporta l'esecuzione di un singolo comando che può o meno accettare argomenti.
Le linee rientrate si verificano solo dopo i comandi alias . In particolare, dopo ogni comando alias si verificano esattamente tre righe rientrate con spazi singoli e sono considerate parte di esso. Quindi le dichiarazioni alias sono davvero lunghe quattro righe. (Potrebbero essere una riga, quattro è semplicemente più leggibile.)
Dichiarazioni non alias
Con l'eccezione di alias , ogni affermazione in un programma Prindeal ha la forma:
[command name] [argument 1] [argument 2] [argument 3] ...
Potrebbe esserci un numero arbitrario di argomenti (incluso nessuno). Ogni argomento è sempre una variabile o (come vedremo quando discuteremo di alias ) un riferimento a una variabile .
Una volta eseguita l'esecuzione, ogni istruzione viene contrassegnata come un errore o un successo a seconda che si siano verificati errori o meno. (Questo è davvero importante solo quando usiamo l' alias .)
La stampa , l' incremento e il decremento integrati sono istruzioni con il modulo precedente. Ecco cosa fanno:
print ha il nome del comando
p
e accetta un argomento. Stampa il nome della variabile passata e il suo valore (in decimale) separato da "=", quindi una nuova riga. Viene sempre segnalato come un successo .Ad esempio, il programma Prindeal
p _MyVariable_321 p screaming_hairy_armadillo
sarebbe uscita
_MyVariable_321 = 0 screaming_hairy_armadillo = 0
perché tutte le variabili iniziano da 0. (Sono richiesti gli spazi prima e dopo il segno di uguale.)
increment ha il nome del comando
i
e accetta un argomento. Aumenta il valore della variabile passata di 1. Viene sempre contrassegnato come un successo .Ad esempio, il programma
i alpaca p alpaca i alpaca p alpaca
sarebbe uscita
alpaca = 1 alpaca = 2
Nota come è
alpaca
stato incrementato da 0 a 1 anche se non era mai stato effettuato prima.decrement ha il nome del comando
d
e accetta un argomento. Se la variabile passata è diversa da zero il suo valore viene decrementato di 1 e l'istruzione viene contrassegnata come riuscita . Se la variabile passata è 0, non viene fatto nulla e l'istruzione viene contrassegnata come un errore .Ad esempio, il programma
i malamute p malamute d malamute #success p malamute d malamute #failure p malamute d akita #failure p akita
sarebbe uscita
malamute = 1 malamute = 0 malamute = 0 akita = 0
Si noti che il decremento di una variabile con valore 0 è l'unico modo per produrre un errore .
L' istruzione alias e i comandi con alias
Il comando alias ha una sintassi speciale ed è il più potente perché può essere utilizzato per definire nuovi comandi. Il nome del comando alias è a
e un'istruzione alias ha la forma:
a [name of new command]
[statement A]
[statement B]
[statement C]
Dove ognuno [statement X]
rappresenta una qualsiasi dichiarazione non alias , ovvero qualcosa con il modulo [command name] [argument 1] [argument 2] [argument 3] ...
.
Il nome del comando con alias [name of new command]
può essere qualsiasi stringa non vuota di caratteri alfanumerici e di sottolineatura che non inizia con una cifra - [a-zA-Z_][0-9a-zA-Z_]*
in regex.
(Questo è lo stesso set di nomi delle variabili ma i comandi e le variabili con alias sono cose diverse utilizzate in luoghi diversi . Una variabile può essere denominata come un comando senza conseguenze negative.)
Quando viene eseguita un'istruzione alias , viene aggiunto un nuovo comando accanto ai quattro p
i
d
a
comandi originali . Il nuovo comando può essere utilizzato come [command name]
istruzioni in e chiamato con argomenti proprio come qualsiasi altro comando non alias .
Quando viene eseguita un'istruzione con un nome di comando alias, vengono eseguite esattamente altre due istruzioni dalla sua istruzione alias originale :
[statement A]
è sempre gestito[statement B]
viene eseguito se è[statement A]
stato un successo[statement C]
viene eseguito se si[statement A]
è verificato un errore
Le dichiarazioni A, B e C vengono sempre eseguite pigramente , ovvero vengono valutate al volo nel momento in cui vengono eseguite.
Al termine dell'esecuzione, il comando alias viene contrassegnato con lo stesso flag di esito positivo o negativo dell'istruzione B o C, a prescindere dal fatto che uno sia stato eseguito . (le stesse dichiarazioni alias non devono essere contrassegnate in quanto non possono verificarsi all'interno di se stesse).
Alias Esempio 1
Supponiamo di voler un nuovo comando che incrementi la variabile
frog
due volte. Questa affermazione alias lo raggiunge:a increment_frog_twice i frog i frog d frog
L'istruzione A (
i frog
) viene sempre eseguita e sempre contrassegnata come un successo, quindi anche l'istruzione B (i frog
) viene sempre eseguita e la variabilefrog
viene quindi incrementata di 2. Ilincrement_frog_twice
comando viene sempre contrassegnato come un successo perché l'istruzione B viene sempre eseguita e B è sempre un successo . L'istruzione C (d frog
) non viene mai eseguita.Quindi l'output a
a increment_frog_twice i frog i frog d frog p frog increment_frog_twice p frog
sarebbe
frog = 0 frog = 2
Possiamo generalizzare questo esempio in modo che ogni variabile possa essere incrementata due volte dando al comando alias un argomento.
All'interno di un'istruzione alias gli interi positivi 1, 2, 3, ecc. Rappresentano gli argomenti 1st, 2nd, 3rd, ecc. Passati nel comando alias. (Questi argomenti potrebbero essere semplici variabili o riferimenti a variabili stesse). Questi numeri possono apparire solo all'interno degli argomenti delle dichiarazioni A, B e C in un'istruzione alias . Non ha senso che appaiano altrove.
Alias Esempio 2
Questo generalizza l'ultimo esempio: ogni variabile passata
increment_twice
verrà incrementata di 2 perché1
è un riferimento al primo argomento passato:a increment_twice i 1 i 1 d 1 #never reached p toad increment_twice toad p toad
L'output di questo programma sarebbe
toad = 0 toad = 2
Potremmo quindi alias un altro comando che accetta due argomenti e li chiama
increment_twice
entrambi: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
L'output qui sarebbe
platypus = 2 duck = 2
È importante rendersi conto che i comandi con alias possono essere ricorsivi, poiché è qui che sta il loro vero potere. Ad esempio, possiamo eseguire un comando che imposta qualsiasi variabile passata su 0:
Alias Esempio 3
Il
set_to_zero
comando accetta un argomento e imposta la sua variabile su 0 e viene contrassegnato come successo al termine: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
L'output di questo programma sarebbe
oryx = 3 oryx = 0
Quello che sta succedendo è che quando
set_to_zero oryx
viene eseguito,d 1
diminuisce con successooryx
da 3 a 2, quindiset_to_zero 1
viene chiamato, il che equivale a richiamare diset_to_zero oryx
nuovo. Quindi il processo si ripete fino a quando nond 1
si verifica un errore , arrestando la ricorsione e incrementando la_dummy_
variabile in modo da produrre un successo .
Sfida
Scrivi un programma in grado di eseguire il codice Prindeal esattamente come descritto sopra. Prendi il codice Prindeal in via stdin, dalla riga di comando o come file di testo. Stampa l'output del programma Prindeal su stdout o l'alternativa più vicina alla tua lingua.
In alternativa, è possibile scrivere una funzione che accetta il codice come stringa e stampa o restituisce la stringa di output.
Inoltre, puoi presumere che:
- Il codice Prindeal di input conterrà solo nuove righe e ASCII stampabili e (facoltativamente) che termina con una riga vuota.
- Il codice di input sarà Prindeal valido, ben formato e sintatticamente corretto.
- L'esecuzione del codice non produrrà loop infiniti né riferimenti non validi a comandi che non sono stati definiti o argomenti che non sono stati forniti.
- I nomi dei comandi
p
,i
,d
, ea
non saranno mai alias sopra. (Si può non supporre che le variabili non avranno questi nomi.)
Inoltre, non importa se i valori delle variabili non sono numeri interi di precisione arbitraria poiché verranno testati solo numeri inferiori a circa 1000. Va anche bene se la tua lingua ha limiti di ricorsione (come Python ) che i programmi Prindeal più complessi potrebbero incontrare finché il programma di test qui sotto funziona.
Programma di test
Ecco un grande programma Prindeal che costruisce le operazioni di addizione, moltiplicazione ed esponenziazione attraverso l'uso di variabili fittizie (a partire _
dalla convenzione) e molti alias helper:
#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
(Se stai giocando con questo codice, tieni presente che molti dei comandi falliranno se la stessa variabile viene fornita più volte come argomento. Questo può essere facilmente risolto ma il codice risultante è più lungo.)
L'interprete Prindeal dovrebbe essere in grado di produrre l'output esatto:
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
punteggio
Vince il codice più breve in byte. Tiebreaker va inoltrato prima.
Bonus brownie: scrivi un programma interessante in Prindeal. Ho implementato addizione e moltiplicazione, puoi fare sottrazione o divisione?
p
, e quindip p
, quale stamperebbe 1, giusto?