Scrivi un irradiatore indurito dalle radiazioni


17

Il compito è scrivere un irradiatore indurito dalle radiazioni. Cosa intendo esattamente con questo?

Un irradiatore è un programma che, quando viene fornita una stringa come input, produrrà tutte le possibili versioni della stringa con un carattere rimosso. Ad esempio, dato l'input Hello, world!, il programma dovrebbe produrre:

ello, world!
Hllo, world!
Helo, world!
Helo, world!
Hell, world!
Hello world!
Hello,world!
Hello, orld!
Hello, wrld!
Hello, wold!
Hello, word!
Hello, worl!
Hello, world

Un irradiatore, tuttavia, deve essere protetto dalle sue radiazioni, quindi anche l'irradiatore che scrivi deve sopravvivere se sottoposto a se stesso. Cioè, quando viene rimosso un singolo byte del programma, il programma deve ancora funzionare correttamente.

Casi test

abc -> bc; ac; ab
foo bar -> oo bar:fo bar:fo bar:foobar:foo ar:foo br:foo ba
source -> ource;surce;sorce;souce;soure;sourc;

specificazioni

  • È possibile accettare input con qualsiasi metodo accettabile dalle nostre regole I / O standard
  • L'output può essere un elenco di stringhe o un elenco stampato delimitato da un carattere o un gruppo di caratteri. Un delimitatore finale è accettabile
  • L'output può essere in qualsiasi ordine purché contenga tutte le versioni possibili
  • Le voci duplicate (come le due Helo, world!s nel primo esempio) possono essere filtrate, ma ciò non è necessario
  • Dato che si tratta di , vince il programma più piccolo, in byte

... o virgola forse?
Jonathan Allan,

4
questo favorisce davvero le lingue del golf, perché il programma C con vin voidrimosso non verrà compilato
Krzysztof Szewczyk

3
@Krzysztof tbh Penso che la maggior parte, se non tutte le lingue pratiche, non sopravviveranno all'indurimento delle radiazioni a causa della verbosità e delle sintassi. Non solo questa sfida, ma TUTTE le sfide di UR.
Shieru Asakoto,

Risposte:


13

05AB1E , 29 26 byte

æIg<ùˆ\æIg<ùˆ\æIg<ùˆ¯¯{Å`s

Provalo online! oppure prova tutte le versioni irradiate .

L'irradiatore più corto che ho trovato è di 5 byte:

æ        # powerset of the input
 Ig      # length of the input
   <     # - 1
    ù    # elements of a with length b

L'idea è di ripeterlo 3 volte, quindi vota a maggioranza:

æIg<ù         # irradiate
     ˆ        # add the result to the global array
      \       # pop (in case the above instruction gets irradiated)
æIg<ùˆ\       # idem
æIg<ùˆ        # no pop, it's okay to dirty the stack at this point
¯             # push global array
 ¯            # and again, so at least one goes through
  {           # sort
   Å          # conveniently ignored by the parser
    `         # dump
     s        # swap
              # and implicitly output

Åè un prefisso per i comandi a 2 byte, ma non esiste alcun Å`comando, motivo per cui Åviene ignorato. Ne avremo bisogno in seguito, però.

L'ordinamento si assicura che il voto della maggioranza sia al centro dell'array. Dumping e poi scambio porta quel valore in cima allo stack.

Qualsiasi irradiazione nella parte iniziale provoca solo un errore nell'array globale, che viene risolto dal voto della maggioranza. Le irradiazioni nell'ultima {Å`sparte sono molto più difficili da ragionare su:

  • Å viene comunque ignorato, quindi va bene irradiarlo

  • Se il backtick è irradiato, Å`sdiventa Ås, che è il comando esteso "get middle of the array".

  • Se {o ssono irradiati, ciò significa che nient'altro lo è, quindi l'array globale ha lo stesso valore tre volte. In tal caso non abbiamo bisogno di smistamento / scambio, qualsiasi valore funzionerà.


3
Molto impressionante! Non pensavo di vedere una risposta 05AB1E su una sfida RH. Aggiungerò una generosità per premiare questa risposta (e darò alla sfida un po 'più di visibilità, anche immagino) subito. Hai raccolto così tante mie risposte, quindi meriti un sacco di credito anche per quelle! :)
Kevin Cruijssen,

3
In realtà, ho già visto 05AB1E risposte su una sfida RH . Comunque, molto impressionante!
Kevin Cruijssen,

5

8086 codice macchina (MS-DOS .COM), 83 byte

Eseguibile in DOSBox o il tuo motore di elaborazione preferito alimentato a vapore. La stringa da irradiare viene fornita come argomento della riga di comando.

Binario:

00000000 : EB 28 28 8A 0E 80 00 49 BD 83 00 B4 02 51 8A 0E : .((....I.....Q..
00000010 : 80 00 BE 82 00 AC 39 EE 74 04 88 C2 CD 21 E2 F5 : ......9.t....!..
00000020 : 59 45 B2 0A CD 21 E2 E5 C3 90 EB D7 D7 8A 0E 80 : YE...!..........
00000030 : 00 49 BD 83 00 B4 02 51 8A 0E 80 00 BE 82 00 AC : .I.....Q........
00000040 : 39 EE 74 04 88 C2 CD 21 E2 F5 59 45 B2 0A CD 21 : 9.t....!..YE...!
00000050 : E2 E5 C3                                        : ...

Leggibile:

cpu 8086
org 0x100
    jmp part2
    db 0x28

part1:
    mov cl, [0x80]
    dec cx
    mov bp, 0x83
    mov ah, 0x02

.l:
    push cx
    mov cl, [0x80]
    mov si, 0x82
.k:
    lodsb
    cmp si, bp
    je .skip
    mov dl, al
    int 0x21
.skip:
    loop .k
    pop cx
    inc bp
    mov dl, 10
    int 0x21
    loop .l
    ret

    nop
part2:
    jmp part1
    db 0xd7
    mov cl, [0x80]
    dec cx
    mov bp, 0x83
    mov ah, 0x02

.l:
    push cx
    mov cl, [0x80]
    mov si, 0x82
.k:
    lodsb
    cmp si, bp
    je .skip
    mov dl, al
    int 0x21
.skip:
    loop .k
    pop cx
    inc bp
    mov dl, 10
    int 0x21
    loop .l
    ret

Corri giù

La parte attiva viene duplicata in modo tale che ne rimanga sempre una non trattata dalle radiazioni. Selezioniamo la versione sana per mezzo di salti. Ogni salto è un salto breve, e quindi è lungo solo due byte, dove il secondo byte è lo spostamento (ovvero la distanza da saltare, con segno che determina la direzione).

Possiamo dividere il codice in quattro parti che potrebbero essere irradiate: salto 1, codice 1, salto 2 e codice 2. L'idea è quella di assicurarsi che venga sempre usata una parte pulita del codice. Se una delle parti del codice viene irradiata, l'altra deve essere scelta, ma se uno dei salti viene irradiato, entrambe le parti del codice saranno pulite, quindi non importa quale verrà scelta.

La ragione per avere due parti di salto è rilevare l'irradiazione nella prima parte saltandola. Se la prima parte di codice viene irradiata, significa che arriveremo a un byte fuori dal segno. Se ci assicuriamo che un atterraggio di questo tipo selezioni il codice 2 e un atterraggio corretto selezioni il codice 1, siamo d'oro.

Per entrambi i salti, dupliciamo il byte di spostamento, rendendo ogni salto parte di 3 byte. Ciò garantisce che l'irradiazione in uno degli ultimi due byte renderà comunque valido il salto. L'irradiazione nel primo byte impedirà che si verifichi il salto, poiché gli ultimi due byte formeranno un'istruzione completamente diversa.

Fai il primo salto:

EB 28 28        jmp +0x28 / db 0x28

Se uno dei 0x28byte viene rimosso, salterà comunque nella stessa posizione. Se il 0xEBbyte viene rimosso, finiremo invece con

28 28           sub [bx + si], ch

che è un'istruzione benigna su MS-DOS (altri gusti potrebbero non essere d'accordo), e quindi passiamo al codice 1, che deve essere pulito, poiché il danno era nel salto 1.

Se il salto viene eseguito, atterriamo al secondo salto:

EB D7 D7        jmp -0x29 / db 0xd7

Se questa sequenza di byte è intatta e atterriamo sul segno, significa che il codice 1 era pulito e questa istruzione torna a quella parte. Il byte di spostamento duplicato lo garantisce, anche se è uno di questi byte di spostamento che sono stati danneggiati. Se atterriamo un byte fuori (a causa di un codice danneggiato 1 o salta 1) o il 0xEBbyte è quello danneggiato, anche i due byte rimanenti saranno benigni:

D7 D7           xlatb / xlatb

In ogni caso, se finiamo per eseguire queste due istruzioni, sappiamo che il salto 1, il codice 1 o il salto 2 sono stati irradiati, il che rende sicuro il passaggio al codice 2.

analisi

Il seguente programma è stato utilizzato per creare automaticamente tutte le versioni del file .COM. Crea inoltre un file BAT che può essere eseguito nell'ambiente di destinazione, che esegue ogni binario irradiato e convoglia i loro output in file di testo separati. Confrontare i file di output da convalidare è abbastanza semplice, ma DOSBox non ha fc, quindi non è stato aggiunto al file BAT.

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
    FILE *fin, *fout, *fbat;
    int fsize;
    char *data;

    if (!(fin = fopen(argv[1], "rb")))
    {
        fprintf(stderr, "Could not open input file \"%s\".\n", argv[1]);
        exit(1);
    }

    if (!(fbat = fopen("tester.bat", "w")))
    {
        fprintf(stderr, "Could not create BAT test file.\n");
        exit(2);
    }

    fseek(fin, 0L, SEEK_END);
    fsize = ftell(fin);
    fseek(fin, 0L, SEEK_SET);

    if (!(data = malloc(fsize)))
    {
        fprintf(stderr, "Could not allocate memory.\n");
        exit(3);
    }

    fread(data, 1, fsize, fin);

    fprintf(fbat, "@echo off\n");

    for (int i = 0; i < fsize; i++)
    {
        char fname[512];

        sprintf(fname, "%03d.com", i);
        fprintf(fbat, "%s Hello, world! > %03d.txt\n", fname, i);

        fout = fopen(fname, "wb");

        fwrite(data, 1, i, fout);
        fwrite(data + i + 1, 1, fsize - i - 1, fout);

        fclose(fout);
    }

    free(data);
    fclose(fin);
    fclose(fbat);
}
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.