Questo è stato sorprendentemente complicato, e non sono convinto che sia ottimale ...
<.@!$?
Dopo aver riempito e spiegato il codice, questo rappresenta la seguente griglia esadecimale:
Questo utilizza un flusso di controllo simile a quello del mio recente programma cat privo di errori , che si muove lungo anti-diagonali. Per ottenere ciò, iniziamo deviando il puntatore dell'istruzione (IP) a sinistra, dove il percorso viola si avvolge nell'angolo in basso a sinistra.
?
legge l'input come numero intero. !
lo stampa indietro. .
è solo una no-op. Ora l'angolo della griglia funge da ramo:
Se l'input era 0
, l'IP continuerà lungo il percorso rosso, che termina semplicemente con il programma @
.
Se l'input era 1
, l'IP continuerà sul percorso verde. Ancora una volta, .
è solo una no-op, ma $
è l'equivalente del trampolino di Befunge: salta la prossima istruzione. Dopo il wrapping, l'istruzione successiva sarebbe la ?
, ma a causa $
dell'esecuzione in realtà continua sul percorso blu, iniziando con la !
stampa di un'altra copia del file 1
. Questo ciclo che contiene solo !..$
ora viene ripetuto indefinitamente.
Uno studio del flusso di controllo in esagonia ...
Credo che la soluzione di cui sopra sia ottimale. Ho scritto un bruto forcer, che controlla tutti i programmi Hexagony a 6 byte, che contengono almeno uno ciascuno ?!@
(che sono necessari; ho anche controllato :
e %
al posto di @
terminare con un errore di divisione per zero, ma neanche quello ha aiutato). Il controllo stampa tutti i programmi che a) producono un 0
input 0
e terminano eb) producono almeno due 1
s (e nient'altro) e non terminano entro i primi 60 tick del programma (200 tick per soluzioni a 5 byte) . Dubito che qualsiasi soluzione valida richiederebbe più di 200 tick per stampare correttamente la prima 0
o la seconda 1
su una griglia così piccola, quindi non credo di aver perso nessuna potenziale soluzione.
La ricerca non ha prodotto alcun risultato per 5 byte, ma 57 risultati per 6 byte (utilizzando @
; non è necessario terminare con un errore se possiamo risolverlo in modo pulito nella stessa quantità di byte). Di questi 57 solo 6 erano falsi positivi che in realtà stampavano solo due se 1
poi entravano in un ciclo infinito senza più stampare. Una soluzione è stata elencata due volte perché conteneva due !
comandi. Ciò lascia esattamente 50 soluzioni valide.
Esiste un certo grado di degenerazione tra le soluzioni in cui uno o due personaggi non sono sostanziali, ad esempio perché sono effettivamente inoperabili comunque. Le soluzioni possono essere raggruppate in 23 serie di programmi veramente distinti (in alcuni casi, esiste una sola differenza di carattere tra due serie, ma cambia sostanzialmente il flusso di controllo, quindi le ho contate separatamente). Due dei gruppi usano persino più puntatori di istruzioni in un modo molto inaspettato. Dato che non avrei mai escogitato la maggior parte di questi modi per utilizzare i rami e gli specchi, fanno uno studio molto interessante su quali tipi di flusso di controllo sono possibili in Hexagony e ho sicuramente imparato alcuni nuovi trucchi per i golf futuri.
Il flusso di controllo complessivo è quasi sempre lo stesso: leggi un numero, stampalo. Se 0
trova un modo per il @
, se non continuare a scorrere il !
mentre mantenendo un valore limite di 1
. Esistono quattro eccezioni notevoli:
- Una soluzione (quella con due
!
) stampa due 1
s per iterazione attraverso la griglia, quindi stampa circa due volte più veloce della maggior parte dei programmi. Ho segnato questo con x2
sotto.
- Alcune soluzioni (quelle che contengono una
o
) sostituiscono la 1
con una 111
(il codice carattere di o
), quindi stampano tre 1
s per iterazione, facendole stampare circa tre volte più velocemente della maggior parte dei programmi. Ho segnato questi con x3
sotto.
- Due soluzioni aggiungono un
1
al valore di bordo in ogni iterazione (così 1
-> 11
-> 111
-> ...). Quelli stampano molto velocemente, ma finiranno per esaurire la memoria. Ho segnato questi con OoM
sotto.
- Due soluzioni entrano in un circuito molto stretto che rimbalza semplicemente avanti e indietro su
!
, stampando su ogni altro segno di spunta (invece di ogni 5 o giù di lì), il che le rende leggermente più veloci (e più ordinate). Ho segnato questi con ><
sotto.
Quindi ecco l'intero zoo:
#1 #5 #12 #19
?!/$.@ ?$!>$@ .?!/$@ |!|?$@ # ><
?!/$1@ # OoM ?$!|$@ =?!/$@
?!/$=@ #20
?!/$\@ #6 #13 $@.?<!
?!/$o@ # x3 ?/!<|@ .?/!$@ $@1?<! # OoM
?!/$!@ # x2 =?/!$@ $@=?<!
#7 $@o?<! # x3
#2 ?\!<|@ #14
?!>$)@ \!?__@ #21
?!>$1@ #8 _>_!?@
?!>$o@ # x3 ?<!>$@ # >< #15
?!|$)@ \_?!$@ #22
?!|$1@ #9 <!@.$?
?!|$o@ # x3 ?\$!@$ #16 <!@/$?
\_?!_@ <!@=$?
#3 #10 <$@!$?
?!|)$@ ?~#!@) #17 <.@!$?
?!|1$@ ?~#!@1 $$?\@! </@!$?
?!|o$@ # x3 <=@!$?
#11 #18
#4 ?$)\@! \$?\@! #23
?_!<@> ?$1\@! <<@]!?
?$o\@! # x3
Quella che segue è una breve procedura dettagliata per una manciata di gruppi più rappresentativi. In particolare vale la pena dare un'occhiata ai gruppi 10 e 23. Ci sono molti altri percorsi interessanti e talvolta contorti negli altri gruppi, ma penso di averti annoiato abbastanza alla fine di questo. Per chiunque voglia davvero imparare l'esagonia, vale sicuramente la pena indagare su questi, poiché esibiscono usi ancora più possibili degli specchi e $
.
Gruppo 1
Questo non è molto più elaborato della mia soluzione originale, ma i percorsi vanno in direzioni diverse. Inoltre, consente il maggior numero di variazioni in una singola cella, in quanto la no-op più a destra può essere sostituita con 5 diversi comandi che lo rendono ancora valido senza modificare la struttura:
Gruppo 2
Questo è piuttosto interessante, perché si muove solo in orizzontale. Dopo aver eseguito il wrapping su >
, l'IP si inverte immediatamente, prendendo il ramo nell'angolo. Il diagramma non è del tutto ben visibile, ma nel caso di 1
attraversiamo di nuovo la prima fila, ma questa volta al contrario . Questo significa anche che ci imbattiamo di ?
nuovo, che ora ritorna 0
(EOF). Questo problema è stato risolto con )
(incremento) per continuare a stampare 1
s. Questo ha anche 5 varianti, come )
potrebbe anche essere 1
o o
, e >
potrebbe anche essere |
:
Gruppo 3
Questo sembra quasi identico al precedente ma è disordinato da morire. Colpire |
e poi attraversare la riga inferiore o superiore è lo stesso. Ma nel caso di un ciclo, l' $
ora salta sul )
sul specchio. Quindi seguiamo il percorso turchese a destra, ora colpiamo l'incremento, saltiamo sopra @
prima di avvolgere di |
nuovo il percorso e poi torniamo al percorso verde in alto.
Gruppo 4
Ho pensato che questo fosse particolarmente elegante:
Lo _
specchio nell'angolo in alto a destra è inizialmente un non-op, quindi stampiamo con !
e premiamo il <
. Il 0
percorso ora colpisce lo specchio orizzontale e termina. Tuttavia, il 1
percorso assume una traiettoria davvero interessante: devia verso il basso, si avvolge verso il basso !
, viene reindirizzato verso l'orizzontale e poi torna indietro verso il !
nuovo . Continua quindi a muoversi in questa forma di rombo, stampando due volte per iterazione (ogni terzo segno di spunta).
Gruppo 8
Questa è una delle due soluzioni con un ciclo di stampa davvero stretto:
I <
funge da ramo. Dopo aver avvolto due volte, 0
colpisce @
. 1
d'altra parte, prima salta il ?
, quindi lo >
invia di $
nuovo sul, in modo che salti il @
. Quindi l'IP si avvolge nel percorso turchese, dove rimbalza avanti e indietro tra >
e <
(avvolgendosi attorno al bordo in mezzo).
Gruppo 10
Uno dei due gruppi che usano altri puntatori di istruzioni ed è assolutamente bello. Hexagony ha 6 - ognuno inizia da un angolo diverso lungo il bordo in senso orario, ma solo uno di essi è attivo alla volta.
Come al solito, leggiamo con ?
. Ora ~
è negazione unaria: trasforma la 1
in a -1
. Successivamente, abbiamo colpito il #
. Questo è un modo per passare da un IP all'altro: prende l'attuale valore di bordo modulo 6 e passa all'IP corrispondente (gli IP sono numerati 0
in senso orario). Quindi, se l'input è stato 0
, allora l'IP rimane semplicemente lo stesso, e viaggia noiosamente dritto in avanti !@
. Ma se l'input era 1
, allora il valore corrente è -1
quale è 5 (mod 6)
. Quindi passiamo all'IP che inizia sulla stessa cella (il percorso verde). Ora #
è una no-op e ?
imposta il limite della memoria su 0
. )
incrementi così !
stampa a 1
. Ora premiamo di ~
nuovo per assicurarlo#
è ancora una no-op (al contrario di passare a IP 1 che terminerebbe il programma). È strabiliante quanto bene tutto si combini in questo piccolo programma.
Gruppo 22
Solo per notare, questo è il gruppo in cui si trova la mia soluzione originale. Capita anche di essere il gruppo più grande, perché il no-op può trovarsi in due posti diversi e ci sono diverse scelte per il comando effettivo (no-op effettivo).
Gruppo 23
Questo è l'altro gruppo che utilizza più IP. In realtà questo utilizza 3 IP diversi. L'angolo in alto a destra è un po 'un casino, ma proverò a guidarti attraverso questo:
Quindi, l'inizio che hai visto prima: <
devia il Nord-Est, ?
legge l'input. Ora ]
è un altro modo per passare da un IP all'altro: passa il controllo al successivo IP in senso orario. Quindi passiamo al controllo del percorso turchese che (so che è difficile da vedere) inizia nell'angolo nord-est andando a sud-est. Si riflette immediatamente nel <
modo in cui si avvolge nell'angolo sud-est, andando a nord-ovest. E ' anche colpisce il ]
modo si passa al successivo IP. Questo è il sentiero grigio che inizia nell'angolo est, in direzione sud-ovest. Stampa l'input, quindi si avvolge nell'angolo nord-est. <
devia il percorso in orizzontale, dove viene riflesso dall'altro <
. Ora la mano destra<
agisce come una diramazione: se l'input era 0
, l'IP si sposta a nord-est e si sposta su @
. Se l'input era 1
, l'IP si sposta su !
, si avvolge sul lef-thand <
dove si riflette ... ora nell'angolo, si avvolge di nuovo su !
, viene deviato da destra <
, riflesso da sinistra <
e inizia il percorso al di sopra di...
Piuttosto un casino, ma un bel casino. :)
Diagrammi generati con l' incredibile HexagonyColorer di Timwi .