Напишіть опромінений радіатором


17

Завдання полягає в тому, щоб написати опромінений радіатор. Що саме я маю на увазі під цим?

Опромінювач - це програма, яка при введенні рядка в якості вхідного сигналу видасть усі можливі версії рядка з видаленим одним символом. Наприклад, враховуючи вхідні дані Hello, world!, програма повинна виводити:

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

Однак опромінювач повинен бути захищений від його випромінювання, тому опромінювач, який ви пишете, також повинен виживати, коли проходить через себе. Тобто, коли будь-який байт вашої програми видалений, програма все одно повинна функціонувати належним чином.

Тестові справи

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;

Технічні умови

  • Ви можете взяти інформацію будь-яким прийнятним методом за нашими Стандартними правилами вводу / виводу
  • Вихід може бути або списком рядків, або друкованим списком, обмеженим символом або групою символів. Додатковий роздільник є прийнятним
  • Вихід може бути в будь-якому порядку, якщо він містить усі можливі версії
  • Дублікати записів (наприклад, два Helo, world!s у першому прикладі) можуть бути відфільтровані, але це не обов'язково
  • Оскільки це , виграє найменша програма в байтах

... чи кома, можливо?
Джонатан Аллан

4
це один дійсно користь мов грати в гольф, так як програма C з vв voidне видаляються компілюватиметься
Кшиштоф Шевчик

3
@Krzysztof tbh Я думаю, що більшість, якщо не всі практичні мови, не переживуть радіаційне загартування через багатослів’я та синтаксиси. Не лише цей виклик, але і ВСІ проблеми.
Шиеру Асакото

Відповіді:


13

05AB1E , 29 26 байт

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

Спробуйте в Інтернеті! або спробуйте всі опромінені версії .

Найкоротший опромінювач, який я міг знайти, - 5 байт:

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

Ідея полягає в тому, щоб повторити це 3 рази, після чого проголосуйте більшістю:

æ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

Åє префіксом для 2-байтних команд, але немає Å`команди, через що Åігнорується. Це нам знадобиться пізніше.

Сортування гарантує, що більшість голосів знаходиться в середині масиву. Якщо демпфірувати, а потім поміняти, це значення отримає у верхній частині стека.

Будь-яке опромінення в початковій частині призводить лише до помилки в глобальному масиві, яку вирішує більшість голосів. Опромінення в заключному {Å`sбіті набагато складніше, ніж про:

  • Å все одно ігнорується, тому добре його опромінювати

  • Якщо backtick опромінюється, Å`sстає Ås, що є розширеною командою "отримати середину масиву".

  • Якщо {або sопромінюється, це означає, що нічого іншого немає, тож глобальний масив має три рази однакове значення. У такому випадку нам не потрібна сортування / заміна, будь-яке значення буде працювати.


3
Дуже вражає! Я не думав, що побачу відповідь 05AB1E на виклик RH. Я додам щедрості, щоб винагородити за цю відповідь (і, як я думаю, дам виклик трохи більше викриття). Ви зіграли стільки моїх відповідей, тож ви заслуговуєте на них і безліч кредитів! :)
Кевін Кройсейсен

3
Насправді я раніше бачив відповіді 05AB1E на виклик RH . Все-таки дуже вражаюче!
Kevin Cruijssen

5

8086 машинного коду (MS-DOS .COM), 83 байти

Працює в DOSBox або улюбленому обчислювальному двигуні на пару. Рядок для опромінення задається як аргумент командного рядка.

Двійковий:

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                                        : ...

Читає:

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

Спуститися

Активна частина дублюється так, що завжди є одна, не торкнута радіацією. Ми вибираємо здорову версію за допомогою стрибків. Кожен стрибок - це короткий стрибок, і так це лише два байти, де другий байт - це переміщення (тобто відстань до стрибка, зі знаком, що визначає напрям).

Ми можемо розділити код на чотири частини, які можна опромінити: стрибок 1, код 1, стрибок 2 та код 2. Ідея полягає у тому, щоб завжди використовувати чисту кодову частину. Якщо одна з частин коду опромінена, інша повинна бути обрана, але якщо один із стрибків опромінений, обидві частини коду будуть чистими, тому не має значення, яку з них обрано.

Причиною наявності двох частин стрибка є виявлення опромінення в першій частині, перестрибуючи його. Якщо перша частина коду опромінена, це означає, що ми вийдемо на один байт від позначки. Якщо ми переконаємося, що такий збір посадки вибирає код 2, а правильна посадка вибирає код 1, ми золото.

Для обох стрибків ми дублюємо байт зміщення, роблячи кожну частину стрибка 3 байтами. Це гарантує, що опромінення в одному з двох останніх байтів все-таки зробить стрибок дійсним. Опромінення в першому байті перешкоджає переходу стрибка взагалі, оскільки останні два байти формуватимуть зовсім іншу інструкцію.

Зробіть перший стрибок:

EB 28 28        jmp +0x28 / db 0x28

Якщо будь-який з 0x28байтів буде видалений, він все одно перескочить на те саме місце. Якщо 0xEBбайт буде видалено, ми замість цього закінчимо

28 28           sub [bx + si], ch

що є доброякісною інструкцією щодо MS-DOS (інші аромати можуть не погоджуватися), і тоді ми переходимо до коду 1, який повинен бути чистим, оскільки шкода була в стрибку 1.

Якщо стрибок зроблений, ми приземляємось при другому стрибку:

EB D7 D7        jmp -0x29 / db 0xd7

Якщо ця послідовність байтів є недоторканою, і ми приземляємось прямо на позначку, це означає, що код 1 був чистим, і ця інструкція переходить до тієї частини. Дублюваний байт переміщення гарантує це, навіть якщо це був один із цих байтів переміщення, які були пошкоджені. Якщо ми або висадимо один байт (через пошкоджений код 1 або стрибок 1), або 0xEBбайт пошкоджений, два рейтингових байта також тут будуть доброякісними:

D7 D7           xlatb / xlatb

Незалежно від випадку, якщо ми закінчимо виконання цих двох інструкцій, ми знаємо, що або стрибок 1, код 1, або стрибок 2 були опромінені, що робить прохід до коду 2 безпечним.

Тестування

Наступна програма була використана для автоматичного створення всіх версій файлу .COM. Він також створює BAT-файл, який можна запустити в цільовому середовищі, який запускає кожне опромінене бінарне, і передає їхні виводи на окремі текстові файли. Порівнювати вихідні файли для перевірки досить просто, але DOSBox не має fc, тому його не додавали до файлу 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);
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.