Crea un contatore Geiger


29

Un contatore Geiger è un dispositivo utilizzato per rilevare le radiazioni.

Faremo un programma contatore Geiger.

Come tutti sappiamo, quando la radiazione colpisce un programma per computer rimuove esattamente 1 byte a caso. Quindi un programma contatore Geiger è un programma che di per sé non fa nulla, ma quando viene rimosso un byte viene stampato il programma modificato beep, per indicare la presenza di radiazioni.

Le risposte verranno classificate in byte con un numero inferiore di byte migliori. Le risposte devono essere almeno 1 byte.

Il tuo programma può stampare beepcon una nuova riga finale o stampare una nuova riga per output vuoto, purché lo faccia in modo coerente. Il vostro programma può anche usare un caso diverso per beepcome BEEP, bEEPo Beepfino a quando lo fa in modo coerente.



7
Possiamo usare il carattere di controllo BEL per emettere un segnale acustico?
Jo King,

2
@JoKing Ho giocato con l'idea, è divertente, ma devo dire di no. È troppo sostanzialmente diverso.
Wheat Wizard

2
Voglio vedere una soluzione a Retina.
mbomb007,

3
Sto cercando di capire come farlo in SMBF ... ma l'unico modo per confrontare due celle consiste nel cambiarle. E in SMBF, le celle che devi controllare sono le celle su cui il programma è attualmente in esecuzione. Quindi è come il principio di incertezza di Heisenberg. Quindi devi determinare se qualcosa è cambiato usando solo il flusso di controllo.
mbomb007,

Risposte:


24

Perso , 303 293 263 253 238 228 byte

v^"peeb"<\>"beepvv"((>@@>>%%>>(((((([[[[[[\
>>>>>>>>>//>>>>>>>>>>>>>>/>>/>>>>>>>>>>>>>\\
>>>>>>>>//>>>>\>>>>>>>>>>/>>>>>>>>>>>>>>>>>\\
>/>>>>>>>/>>>>>>>>>>>>\>>>>>>>>>>>>>>>>>>>>>\\
>>>>>>>>>>>>>>>>>>>>>>\\>>>>\>>>>>>>>>>>>>>>>\

Provalo online!

Script di verifica (preso in prestito dalla risposta dell'utente 202729 ). Sfortunatamente questo può solo testare metà del codice alla volta, ma state certi che ho testato l'intero programma.

Ahi, questo è stato difficile. Citerò la risposta cancellata da WW:

Lost è forse la lingua più interessante per questa sfida. In Lost la posizione iniziale e la direzione del puntatore sono del tutto casuali, quindi per creare programmi deterministici è necessario tenere conto di ogni possibile posizione e direzione iniziale. Allo stesso tempo, per la natura di questa sfida, devi anche tenere conto della rimozione di ogni singolo byte.

Sfortunatamente, la sua risposta non ha tenuto conto della rimozione di nuove righe, il che ha rovinato tutto.

Spiegazione:

(nota che alcuni byte potrebbero essere spenti qua e là)

Innanzitutto parliamo della struttura generale del codice:

v^^"peeb"<<\/"beepvv"((>>>@@>>%%>>(((((([[[[[[[\       Processing line
>>>>>>>>>>>//>>>>>>>>>>>>>>>>>>>/>>>>>>>>>>>>>>\\      Beep line
>>>>>>>>>//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\\     Back-up beep line
>//>>>>>>>>>>>>>>>>>>>>\\>>>>>>>>>>>>>>>>>>>>>>>>\\    Back-up return line
>>>>>>>>>>>>>>>>>>>>>>>>\\>>>>>>\>>>>>>>>>>>>>>>>>\    Return line

Tutto tranne la linea di elaborazione deve essere interamente composto da uno >o da uno \/. Perché? Bene, ad esempio, rimuoviamo una nuova riga:

v^^"peeb"<<\/"beepvv"((>>>@@>>%%>>(((((([[[[[[[\>>>>>>>>>>>//>>>>>>>>>>>>>>>>>>>/>>>>>>>>>>>>>>\\
>>>>>>>>>//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\\
>//>>>>>>>>>>>>>>>>>>>>\\>>>>>>>>>>>>>>>>>>>>>>>>\\
>>>>>>>>>>>>>>>>>>>>>>>>\\>>>>>>\>>>>>>>>>>>>>>>>>\

La prima riga è ora molto più lunga del resto del blocco. Se un puntatore si generasse su un non >\/personaggio con movimento verticale, si bloccherebbe in un ciclo infinito.


La parte più grande del rivelatore di radiazioni è la sezione alla fine di ogni linea.

 \
 \\
 >\\
 >>\\
 >>>\

Normalmente un IP che lo attraversa dalla prima riga uscirebbe dall'ultima riga. Tuttavia, se viene rimosso qualsiasi carattere sulla linea, tale linea si sposta di uno in basso, ad esempio:

 \
 \\
 >\\
 >\\
 >>>\

E l'IP invece esce dalla riga mancante di un byte (ad eccezione dell'ultima riga, dove esce dalla penultima).

Da lì, ciascuna delle prime quattro righe reindirizzerà alla seconda riga:

v
>>>>>>>>>>
>>>>>>>>//
>/

Il che porterà quindi a uno dei due beepers.

v^"peeb"<<\/"beepvv"((>
>>>>>>>>>>//

Se uno dei byte nel primo beeper è stato rimosso, passa invece al secondo:

v^^"peb"<<\/"beepvv"((>
>>>>>>>>>>>//

Entrambe beepportano quindi alla prima riga e alla terminazione @.

Alcune altre parti varie:

La (((((([[[[[[[viene utilizzato per cancellare lo stack quando il puntatore inizia all'interno di una coppia di citazioni e finisce per spingere l'intera prima linea a pila. Deve essere purtroppo lungo perché la prima riga nuova può essere rimossa per rendere la prima riga due volte più grande. Sperimentare nel generare l' beeparitmetica usando invece delle virgolette è finito più a lungo.

Le \s e /s sparse tra le linee sono lì per golfare i byte nella riga superiore del codice reindirizzando il puntatore sulle linee corrette. Poiché la maggior parte delle linee di fondo sono solo riempitivi, solo la linea di cima può essere giocata a golf. Se qualcuno ha qualche idea per uno stack più corto a prova di radiazione più chiaro di quello che ho ora, sentiti libero di commentare.


Solo per curiosità, quanto è stata utile la risposta parziale che ho postato in chat? Ho visto alcune somiglianze nelle versioni precedenti e mi piacerebbe sapere se ero sulla strada giusta.
Mago del grano

A quel tempo ci avevo già lavorato, ma il fatto \/di separare le beepspinte e il fatto che solo una delle citazioni necessitasse di una clausola di uscita mi aiutò
Jo King,

20

Esagonia , 38 byte

.....;p;<>b;e;/<b;e;;p...@@.......;@..

Provalo online!

Programma di verifica.


Spiegazione

Facciamo qui il rilevamento automatico di Hexagony della lunghezza laterale esagonale.

Se non vengono rimossi byte, il programma ha una lunghezza laterale 4 e si presenta così:

Programma senza rimuovere alcun byte

Se tuttavia, un byte viene rimosso. Ci sono 2 casi

  1. Il byte rimosso è dopo il secondo <.

    Il flusso di esecuzione sarebbe:

    Programma con l'ultimo byte rimosso

    Ci sono 2 consecutivi @sulla 5a linea, quindi anche se uno di essi viene rimosso, l'IP colpirà in modo sicuro a @.

  2. Il byte rimosso è uguale o precedente al secondo <.

    Quindi la seconda metà rimarrà intatta e l'IP non verrà più reindirizzato verso l'alto da quello <. Immagine del flusso di esecuzione:

    Programma con il secondo <code> <</code> rimosso


19

Esagonia , 34 29 byte

//..>;e;<b@;p;/|/;e;;\.b@;p<@

Provalo online! Verifica!

Spiegazione:

Ecco il normale codice formattato in un esagono corretto usando HexagonyColorer :

Nessun cancro ...

Il doppio //all'inizio assicura che questo percorso sia sempre preso. Se un personaggio viene rimosso, @viene rimosso dal percorso, spostandolo indietro o rimuovendolo:

Cancro!

In questo caso, abbiamo rimosso un carattere dopo il |, che lo fa seguire questo percorso, stampando beep:

Primo segnale acustico

Se invece rimuoviamo un carattere prima del |(o dello |stesso), seguiamo l'altra stampante bip:

Secondo bip

Abbiamo quindi tenuto conto di tutte le possibilità e utilizziamo solo beeple parti non irradiate del programma.


13

Brainfuck automodificante , 73 63 byte

<<[[[[<<]]>[[.>>..>>.[,>]]]]   bbeepp+[<<<]>>[[>]>>>.>>..>>.,+]

Provalo online! Verifica!

Gli spazi nel mezzo del codice rappresentano effettivamente i byte NUL.

Spiegazione:

Il codice è diviso in due sezioni da 3 byte NUL nel mezzo. Entrambi stampano sostanzialmente beepse l'altra sezione è irradiata (con un paio di eccezioni).

Innanzitutto, <<[[all'inizio è garantire che tutti gli ]s siano abbinati in qualsiasi momento. [s non tenterà di cercare una corrispondenza ]se la cella è positiva, mentre ]s lo fa . Se qualche ]salto torna a una di queste parentesi, di solito salta indietro immediatamente perché la cella lo è 0.

La parte successiva, [[<<]]>quindi controlla se la lunghezza della sezione 2 è pari. In tal caso, esegue l'altra metà della sezione 1, che stampa beepusando bbeeppall'inizio della sezione 2.

[[.>>..>>.[,>]]]]

Quindi cancella tutta la sezione 2 in modo che non venga eseguita.

Nella sezione 2, controlliamo se la lunghezza della sezione 1 e il NUL byte è divisibile per 3con +[<<<]>>.

[[>]>>>.>>..>>.,+]

Allo stesso modo, stampiamo beep.


10

Z80Golf , 53 36 34 byte

-16 byte grazie a @Lynn
-2 byte grazie a @Neil

Dato che questo è solo il codice macchina Z80, ci sono molti non stampabili in questo, quindi ha un xxd -rhexdump reversibile:

00000000: ddb6 2120 10dd b615 280c 003e 62ff 3e65  ..! ....(..>b.>e
00000010: ffff 3e70 ff76 003e 62ff 3e65 ffff 3e70  ..>p.v.>b.>e..>p
00000020: ff76                                     .v

Provalo online! (tester esaustivo in Python)

Spiegazione

z80golf è l'ipotetica macchina Z80 di Anarchy Golf, dove call $8000è un putchar, call $8003è un getchar, haltfa uscire l'interprete, il programma è posto in $0000, e tutta la memoria è piena di zero. Rendere i programmi a prova di radiazione nell'assemblaggio è piuttosto difficile, ma una tecnica genericamente utile sta usando istruzioni idempotenti a un byte. Per esempio,

or c        ; b1    ; a = a | c

è solo un byte e a | c | c == a | c, quindi, può essere reso a prova di radiazione semplicemente ripetendo le istruzioni. Sulla Z80, un carico immediato a 8 bit è di due byte (dove l'immediato si trova nel secondo byte), quindi è possibile caricare in modo affidabile anche alcuni valori nei registri. Questo è quello che ho fatto all'inizio del programma, quindi puoi analizzare le varianti più lunghe che ho archiviato in fondo alla risposta, ma poi ho capito che esiste un modo più semplice.

Il programma consiste in due carichi utili indipendenti, in cui uno di essi potrebbe essere stato danneggiato dalle radiazioni. Controllo se un byte è stato rimosso e se il byte rimosso era prima della seconda copia del payload, controllando i valori di alcuni indirizzi di memoria assoluti.

Innanzitutto, dobbiamo uscire se non si osservano radiazioni:

    or a, (ix+endbyte) ; dd b6 21 ; a |= memory[ix+0x0021]
    jr nz, midbyte     ; 20 10    ; jump to a halt instruction if not zero

Se un byte è stato rimosso, tutti i byte si sposteranno e $0020conterranno l'ultimo 76, quindi $0021sarà uno zero. Possiamo permetterci di irradiare l'inizio del programma, anche se praticamente non c'è ridondanza:

  • Se l'offset del salto $10viene rimosso, la radiazione verrà rilevata correttamente, il salto non verrà eseguito e l'offset non avrà importanza. Il primo byte dell'istruzione successiva verrà consumato, ma poiché è progettato per resistere alla rimozione dei byte, questo non ha importanza.
  • Se il codice operativo del salto $20viene rimosso, l'offset del salto $10verrà decodificato come djnz $ffe4(consumando il byte di istruzione successivo come offset - vedere sopra), che è un'istruzione di loop - decrementa B, e salta se il risultato non è zero. Poiché ffe4-ffffè pieno di zero ( nops) e il contatore del programma si avvolge, questo eseguirà l'inizio del programma 256 volte, e infine continuerà. Sono stupito che funzioni.
  • La rimozione $dddi decodificherà il resto del frammento come or (hl) / ld ($1020), hl, quindi scorrerà nella parte successiva del programma. Questo ornon cambierà alcun registro importante e poiché HL è zero a questo punto, anche la scrittura verrà annullata.
  • Rimuovendo $b6, il resto verrà decodificato come ld ($1020), ixe procederà come sopra.
  • La rimozione di $21farà mangiare il decodificatore $20, innescando il djnzcomportamento.

Si noti che l'utilizzo or a, (ix+*)consente di risparmiare due byte ld a, (**) / and a / and agrazie al controllo integrato per zero.

Ora dobbiamo decidere quale delle due copie del payload eseguire:

    or (ix+midbyte)  ; dd b6 15
    jr z, otherimpl  ; 28 0c
    nop              ; 00
    ; first payload
    ld a, 'b'        ; 3e 62
    rst $0038        ; ff
    ld a, 'e'        ; 3e 65
    rst $0038        ; ff
    rst $0038        ; ff
    ld a, 'p'        ; 3e 70
    rst $0038        ; ff
midbyte:
    halt             ; 76
otherimpl:
    nop              ; 00
    ld a, 'b'        ; 3e 62
    ; ...            ; ...
    rst $0038        ; ff
endbyte:
    halt             ; 76

Le due copie sono separate da un nop, poiché un salto relativo viene utilizzato per scegliere tra di esse e la radiazione potrebbe aver spostato il programma in modo tale da far saltare il primo byte dopo la destinazione. Inoltre, il nop è codificato come zero, il che semplifica il rilevamento di byte spostati. Si noti che non importa quale payload viene scelto se lo switch stesso è danneggiato, perché entrambe le copie sono sicure. Assicuriamoci che non salti nella memoria non inizializzata, però:

  • L'eliminazione $ddfarà decodificare i prossimi due byte come or (hl) / dec d. Clobbers D. Nessun grosso problema.
  • L'eliminazione $b6creerà una codifica più lunga non documentata per dec d. Come sopra.
  • L'eliminazione $15leggerà $28invece come offset e l'esecuzione procederà in $0c, come di seguito.
  • Quando $28scompare, $0cviene decodificato come inc c. Al payload non interessa c.
  • Eliminazione $0c: ecco a cosa serve il nop. Altrimenti, il primo byte del payload sarebbe stato letto come offset di salto e il programma sarebbe saltato nella memoria non inizializzata.

Il payload stesso è piuttosto semplice. Penso che le dimensioni ridotte della stringa rendano questo approccio più piccolo di un loop, ed è più facile rendere indipendente dalla posizione in questo modo. L' ea beepripete, così posso radere uno ld a. Inoltre, poiché tutta la memoria tra $0038ed $8000è azzerato, posso cadere attraverso di essa e utilizzare una minore rstvariante della callistruzione, che funziona solo per $0, $8, $10e così via, fino a $38.

Approcci precedenti

64 byte

00000000: 2e3f 3f2e 3f3f 7e7e a7a7 201f 1e2b 2b1e  .??.??~~.. ..++.
00000010: 2b2b 6b00 7ea7 2814 003e 62cd 0080 3e65  ++k.~.(..>b...>e
00000020: cd00 80cd 0080 3e70 cd00 8076 003e 62cd  ......>p...v.>b.
00000030: 0080 3e65 cd00 80cd 0080 3e70 cd00 8076  ..>e......>p...v

58 byte

00000000: 2e39 392e 3939 7e7e a7a7 2019 3a25 00a7  .99.99~~.. .:%..
00000010: 2814 003e 62cd 0080 3e65 cd00 80cd 0080  (..>b...>e......
00000020: 3e70 cd00 8076 003e 62cd 0080 3e65 cd00  >p...v.>b...>e..
00000030: 80cd 0080 3e70 cd00 8076                 ....>p...v

53 byte

Questo ha una spiegazione nella cronologia delle modifiche, ma non è troppo diverso.

00000000: 3a34 00a7 a720 193a 2000 a728 1400 3e62  :4... .: ..(..>b
00000010: cd00 803e 65cd 0080 cd00 803e 70cd 0080  ...>e......>p...
00000020: 7600 3e62 cd00 803e 65cd 0080 cd00 803e  v.>b...>e......>
00000030: 70cd 0080 76                             p...v

Cosa succede se: qualsiasi output non vuoto andava bene invece del segnale acustico

1 byte

v

halts normalmente il programma, ma se la radiazione lo rimuove, allora la memoria sarà piena di zero, facendo $8000eseguire un numero infinito di volte, stampando molti byte nulli.


Poiché ainizia da zero, non puoi usare or a, (N);invece di ld a, (N); and a;? Sembra che tu possa salvare un paio di byte in quel modo.
Neil,

@Neil Buona domanda! Sfortunatamente, sullo Z80, solo le istruzioni di caricamento possono prendere indirizzi come questo.
NieDzejkob,

Ugh, è passato troppo tempo da quando ho fatto una programmazione Z80 ... forse ci stavo pensando or a, (ix + N)?
Neil

@Neil in realtà, quello esiste, e anche IX inizia da zero ... sfortunatamente, salvare un byte in quell'area fa spostare i byte in modo tale che 20 19all'inizio diventi 20 18, e rimuovendo 20crea un salto incondizionato all'indietro, quindi un nop deve essere aggiunto dopo il primo salto nel programma, invertendo il salvataggio del byte.
NieDzejkob,

Ah, è un peccato. Grazie per aver controllato!
Neil,


4

Klein , una per ogni topologia, per un totale di 291 byte

Dopo aver visto la risposta di WW usando la 001topologia, ho deciso di vedere quanto sarebbe stato difficile fare un contatore Geiger per ogni topologia. (Spoiler: molto difficile. È difficile capire dove andrà il puntatore senza i gesti delle mani che mi fanno sembrare che sto capendo quale mano è la mia sinistra)

Verifica!

(Ho anche pensato di scrivere un programma che è un contatore Geiger valido su tutte le topologie, ma che potrebbe dover aspettare. Se qualcun altro vuole provare, sto offrendo una ricompensa di 500 rep)

000 e 010, 21 byte

<<@"peeb"/
.@"peeb"<\

Prova 000 online! e prova 010 online!

Questo è portato dalla mia ><>soluzione . Questo ovviamente funziona 000, dato che è la topologia predefinita per la maggior parte dei linguaggi 2D, ma sono rimasto sorpreso dal fatto che funzioni anche 010.

001 e 011, 26 byte

!.<<@"peeb"/
.@"peeb"..<..

Prova 001 online! e prova 011 online!

Questo è copiato direttamente dalla risposta di WW . Grazie!

100, 21 byte

//@"peeb"\
@"peeb".</

Provalo online!

101, 21 byte

//@"peeb"/
@"peeb".<!

Provalo online!

110, 26 byte

<.<@"peeb"\\
.\@."peeb".\<

Provalo online!

111, 24 byte

<<@"peeb"<\
...@"peeb"//

Provalo online!

200, 21 byte

<<@"peeb"\
@"peeb".!/

Provalo online!

201, 31 byte

\\.\.@"peeb"</./
./...@"peeb"<\

Provalo online!

Di gran lunga il più fastidioso.

210, 26 byte

/\\@"peeb"</\
/@.."peeb"<\

Provalo online!

211, 27 byte

\\."peeb"((</
!/@@<"peeb"<\

Provalo online!

L'unico in cui ho dovuto gestire l'ingresso del segnale acustico attraverso il lato destro.


Sarò felicemente secondo a quel dono.
Mago del grano

3

Brainfuck automodificante , 144 102 byte

Gli stampabili non vengono visualizzati come sequenza di escape (ad esempio \x01).

\xa8<<[[<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<[[[.<-]>[>-]\x01qffb\x00\x00beep\x00]]]<[>]<<[>[-<+>]+<<]>[[>]>>[.>]]\x01

Verifica!


2

Incantesimi runici , 29 byte

>>yyLL@"peeb"/
     @"peeb"L\

Provalo online!

Sostanzialmente uguale alla risposta Klein 000 o> <> (ho iniziato con quella Klein). L'unica modifica realmente necessaria era trasformare <in Le .in  (traduzione dei simboli di comando), inserendo i punti di ingresso IP (necessità 2, altrimenti una cancellazione comporterebbe un programma non di compilazione) e l'inserimento del ycomando dela per ottenere il due IP da unire (quindi stampandone solo uno beep), ancora una volta, ne occorrono due. È inoltre richiesto l'inserimento di ulteriori NOP per mantenere le lunghezze delle linee uguali. Klein utilizza convenientemente anche @per "stampa e termina".

Nessuna capacità di utilizzare lo spazio bianco in basso a sinistra, poiché qualsiasi riflettore per cambiare direzione inibisce la capacità di rilevare le radiazioni. ad es. (26 byte, irradiato y):

/yLL@"peeb"/
\<<  @"peeb"L\

Non stampa alcun output, a causa del segmento di entrata piegato che causa un riflesso indietro al terminatore della linea inferiore.



1

Wumpus , 37 34 32 31 byte

777*7..@ $o&4"beep"|"@peeb"4&o@

Provalo online! Verifica!

Questa soluzione utilizza il fatto che .salta su un modulo di posizione per la lunghezza del programma.

In alternativa per la stessa quantità di byte


" @o&4"beep"}@
@o&4"beep"}$}  

Provalo online! Verifica!

Questo utilizza la differenza nella direzione del puntatore per lunghezze pari e dispari. (Non so davvero come funziona il primo "quando viene rimossa la nuova riga)


1

Klein (001), 26 byte

!.<<@"peeb"/
.@"peeb"..<..

Provalo online!

Verificare!

Spiegazione

Questo programma sfrutta la topologia unica di Klein, in particolare la topologia 001 , che è una bottiglia di Klein.

Inedito il programma segue il percorso di esecuzione:

Percorso arancione

La rimozione di un byte dal programma può avere effetto sul programma in 4 modi (ognuno con un colore diverso):

Sezioni del programma

La prima cosa da notare è che all'inizio <<deverà sempre l'ip a sinistra dell'origine. Se una delle <s viene eliminata, l'altra prende il suo posto. Quindi se un byte viene rimosso dalla sezione rossa verrà seguito il seguente percorso di esecuzione:

Percorso rosso

Se il byte blu viene rimosso otteniamo il percorso molto semplice:

inserisci qui la descrizione dell'immagine

Se la nuova riga viene rimossa otteniamo il percorso:

Percorso verde

Il percorso giallo è un po 'più complesso. Poiché la linea di fondo è una più lunga della linea superiore, quando il programma viene quadrato all'inizio dell'esecuzione, un carattere virtuale viene aggiunto alla fine della prima linea per renderle della stessa dimensione. Se viene rimosso qualsiasi byte sulla seconda riga, la riga viene accorciata e quel carattere virtuale non viene aggiunto. Questo è importante perché !normalmente salta sul personaggio virtuale, ma in sua assenza salta /invece.

Percorso giallo


1
Puoi trasferire la mia ><>soluzione 000per 21 byte
Jo King il

@JoKing Penso che sarebbe meglio come risposta.
Wheat Wizard

1

Rovescio , 25 21 byte

vv""ppeeeebb""jjHH@

Provalo online! Verifica!

Questo utilizza la capacità di Backhand di modificare il valore del passo del puntatore per saltare un'istruzione ad ogni passo e risolvere ordinatamente il problema della ridondanza. Quindi utilizza il jcomando per verificare se il codice viene irradiato saltando all'ultimo carattere ( @, halt) in caso contrario, e saltando al secondo ultimo ( H, halt e output stack) in tal caso.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.