2.}<@>%?<{>$"/\M!8;
Leggibile:
2 . }
< @ > %
? < { > $
" / \ M
! 8 ;
Provalo online!
Probabilmente questo può essere golfato da un byte o due, ma ciò potrebbe richiedere un layout davvero ingegnoso, che potrebbe essere più facilmente trovato tramite la forza bruta (anche se potrebbe richiedere piuttosto tempo per trovarlo).
Spiegazione di alto livello
Il programma segue principalmente questo pseudocodice:
while (read number is not zero)
{
if (number is even)
print number;
}
Ciò abusa del modo in cui Hexagony tenta di leggere un numero quando STDIN è vuoto (restituisce uno zero). Un grande ringraziamento a Martin per l'aiuto nel trovare questo approccio.
Spiegazione completa
Non ho ancora armeggiato con Mono per far funzionare il fantastico IDE esoterico di Timwi , quindi mi sono appoggiato a Martin per fornirmi alcune belle immagini utili!
Innanzitutto, un piccolo primer sul flusso di controllo di base in Hexagony. Il primo puntatore di istruzione (IP), che è l'unico utilizzato in questo programma, inizia nella parte superiore sinistra del codice sorgente esagonale e inizia a spostarsi verso destra. Ogni volta che l'IP lascia il bordo dell'esagono, sposta le side_length - 1
file verso il centro dell'esagono. Poiché questo programma utilizza un esagono di lunghezza laterale di tre, l'IP si sposterà sempre di due file quando ciò accade. L'unica eccezione è se si sposta al di fuori della riga centrale, dove si sposta in modo condizionale verso la parte superiore o inferiore dell'esagono, a seconda del valore del bordo di memoria corrente.
Ora un po 'di condizionali. Gli unici condizionali in Hexagony di flusso di controllo sono >
, <
e il bordo centrale dell'esagono. Tutti seguono una regola costante: se il valore sul bordo di memoria corrente è zero o il flusso di controllo negativo si sposta a sinistra e se è positivo, il controllo scorre a destra. Le parentesi maggiore di e minore di reindirizzano l'IP ad angoli di sessanta gradi, mentre il bordo dell'esagono controlla a quale riga salta l'IP.
Hexagony ha anche un modello di memoria speciale, in cui tutti i dati sono memorizzati sui bordi di una griglia esagonale infinita. Questo programma utilizza solo tre bordi: uno per memorizzare due, uno per il numero attualmente letto e uno per il numero modulo due. Sembra qualcosa del tipo:
Mod \ / Input
|
2
Non spiegherò attentamente dove siamo in memoria in ogni punto durante la spiegazione del programma, quindi torna qui se rimani confuso da dove siamo in memoria.
Con tutto ciò fuori mano, la vera spiegazione può iniziare. Innanzitutto, popoliamo il bordo "2" in memoria con un 2, quindi eseguiamo un no-op e spostiamo il puntatore della memoria verso destra ( 2.}
).
Successivamente, iniziamo il ciclo principale del programma. Leggiamo il primo numero da STDIN e quindi colpiamo un condizionale ( ?<
). Se non ci sono numeri rimasti in STDIN, questo legge uno zero nel bordo di memoria corrente, quindi giriamo a sinistra su @
, che termina il programma. Altrimenti, rimbalziamo da uno specchio, spostiamo il puntatore della memoria all'indietro ea sinistra, avvolgiamo l'esagono per calcolare il resto della divisione dell'input per 2 e quindi colpiamo un altro condizionale ( /"%>
).
Se il resto era uno (cioè il numero era dispari), giriamo a destra seguendo il percorso blu sopra iniziando eseguendo di nuovo la no-op, quindi ci spostiamo sul fondo dell'esagono, moltiplichiamo il bordo corrente per 10 e quindi aggiungiamo otto, rimbalzare su un paio di specchi, fare di nuovo la stessa moltiplicazione e aggiunta, rimettendo 188 sul bordo corrente, avvolgendosi nuovamente in cima all'esagono, eseguendo di nuovo la no-op e infine terminando il programma ( .8/\8.@
). Questo contorto risultato fu un felice incidente, inizialmente avevo scritto un po 'di logica molto più semplice, ma notai che avrei potuto rimuoverlo a favore della no-op, che pensavo fosse più nello spirito di Hexagony.
Se il resto era zero, giriamo invece a sinistra seguendo il percorso rosso, sopra. Questo ci induce a spostare il puntatore della memoria verso sinistra, quindi a stampare lì il valore (il valore di input) come numero. Lo specchio che incontriamo funge da no-op a causa della direzione in cui ci stiamo muovendo ( {/!
). Quindi colpiamo il bordo dell'esagono che agisce in modo condizionale con un solo risultato, poiché il valore di input di prima era già testato per essere positivo, quindi ci muoviamo sempre verso destra (se immagini di essere rivolto nella direzione dell'IP) . Quindi moltiplichiamo l'input per 10 e ne aggiungiamo due, solo per cambiare direzione, avvolgiamo e sovrascriviamo il nuovo valore con il valore ascii della lettera maiuscola M, 77. Quindi colpiamo alcuni specchi e usciamo dal bordo del centro di l'esagono con un trampolino (2<M\>$
). Poiché 77 è positivo, ci spostiamo a destra verso il fondo dell'esagono e, a causa del trampolino, saltiamo la prima istruzione ( !
). Quindi moltiplichiamo il bordo di memoria corrente per 10 e aggiungiamo 8, ottenendo 778. Quindi produciamo questo valore mod 256 (10) come un carattere ASCII, che risulta essere newline. Finalmente usciamo dall'esagono e torniamo indietro al primo ?
che sovrascrive il 778 con il successivo valore di input.