เขียนตัวรับรังสีที่ชุบแข็งด้วยรังสี


17

ภารกิจคือการเขียนผู้ฉายรังสีที่ชุบแข็งด้วยรังสี ฉันหมายความว่ายังไงกันแน่?

irradiator เป็นโปรแกรมที่เมื่อได้รับสตริงเป็นอินพุตจะส่งออกเวอร์ชันที่เป็นไปได้ทั้งหมดของสตริงโดยลบหนึ่งอักขระ ตัวอย่างเช่นเมื่อได้รับอินพุท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;

ข้อมูลจำเพาะ

  • คุณสามารถรับข้อมูลด้วยวิธีการที่ยอมรับได้ตามกฎมาตรฐาน I / Oของเรา
  • ผลลัพธ์อาจเป็นรายการของสตริงหรือรายการที่พิมพ์โดยคั่นด้วยอักขระหรือกลุ่มของอักขระ ยอมรับตัวคั่นต่อท้าย
  • ผลลัพธ์อาจอยู่ในลำดับใดก็ได้ตราบใดที่มีเวอร์ชันที่เป็นไปได้ทั้งหมด
  • รายการที่ซ้ำกัน (เช่นทั้งสองรายการHelo, world!ในตัวอย่างแรก) อาจถูกกรองออก แต่ไม่จำเป็น
  • เช่นนี้เป็นโปรแกรมที่เล็กที่สุดเป็นไบต์ชนะ

... หรืออาจเป็นจุลภาค?
Jonathan Allan

4
อันนี้เป็นที่นิยมมากภาษากอล์ฟเพราะโปรแกรม C กับvในvoidจะถูกลบออกจะไม่รวบรวม
Krzysztof Szewczyk

3
@Krzysztof tbh ฉันคิดว่ามากที่สุดถ้าไม่ใช่ภาษาที่ใช้งานได้จริง ๆ จะไม่รอดจากการแผ่รังสีความแข็งเนื่องจากความฟุ่มเฟื่อยและวากยสัมพันธ์ ไม่เพียงแค่ความท้าทายนี้ แต่ความท้าทายทั้งหมด RH
Shieru Asakoto

คำตอบ:


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 ฉันจะเพิ่มรางวัลเพื่อให้รางวัลคำตอบนี้ (และให้ความท้าทายเพิ่มขึ้นอีกเล็กน้อยเช่นกันฉันเดา) ทันที คุณเล่นกอล์ฟกับคำตอบมากมายของฉันดังนั้นคุณควรได้รับเครดิตมากมายสำหรับผู้เล่นเช่นกัน! :)
Kevin Cruijssen

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

rundown

ส่วนที่ใช้งานอยู่จะถูกทำซ้ำเพื่อให้ไม่มีการสัมผัสกับรังสีหนึ่งครั้ง เราเลือกเวอร์ชั่นที่สมบูรณ์โดยการข้าม การกระโดดแต่ละครั้งเป็นการกระโดดสั้น ๆ และมีความยาวเพียงสองไบต์ซึ่งไบต์ที่สองคือการกระจัด (เช่นระยะทางที่จะกระโดดด้วยเครื่องหมายกำหนดทิศทาง)

เราสามารถแบ่งรหัสออกเป็นสี่ส่วนซึ่งอาจได้รับการฉายรังสี: กระโดด 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);
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.