Viết một máy chiếu xạ làm cứng bức xạ


17

Nhiệm vụ là viết một máy chiếu xạ làm cứng bức xạ. Chính xác thì tôi có ý gì?

Bộ chiếu xạ là một chương trình, khi được cung cấp một chuỗi làm đầu vào, sẽ xuất tất cả các phiên bản có thể có của chuỗi với một ký tự được loại bỏ. Ví dụ, được cung cấp đầu vào Hello, world!, chương trình sẽ xuất ra:

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

Tuy nhiên, một máy chiếu xạ phải được bảo vệ khỏi bức xạ của nó, vì vậy máy chiếu xạ bạn viết cũng phải tồn tại khi được đặt qua chính nó. Đó là, khi bất kỳ byte đơn nào của chương trình của bạn bị xóa, chương trình vẫn phải hoạt động đúng.

Các trường hợp thử nghiệm

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;

Thông số kỹ thuật

  • Bạn có thể nhận đầu vào theo bất kỳ phương thức có thể chấp nhận nào theo quy tắc I / O tiêu chuẩn của chúng tôi
  • Đầu ra có thể là danh sách các chuỗi hoặc danh sách in được phân tách bằng ký tự hoặc nhóm ký tự. Một dấu phân cách là chấp nhận được
  • Đầu ra có thể theo bất kỳ thứ tự nào miễn là nó chứa tất cả các phiên bản có thể
  • Các mục trùng lặp (chẳng hạn như hai Helo, world!s trong ví dụ đầu tiên) có thể được lọc ra, nhưng điều này là không cần thiết
  • Vì đây là , chương trình nhỏ nhất, tính bằng byte, thắng

... hoặc dấu phẩy có lẽ?
Jonathan Allan

4
cái này thực sự là thiên ngôn ngữ chơi golf, bởi vì chương trình với C vtrong voidloại bỏ sẽ không biên dịch
Krzysztof Szewczyk

3
@Krzysztof tbh Tôi nghĩ rằng hầu hết các ngôn ngữ thực tế sẽ không tồn tại quá trình làm cứng bức xạ vì tính dài dòng và các cú pháp. Không chỉ thử thách này, mà TẤT CẢ những thách thức.
Shieru Asakoto

Câu trả lời:


13

05AB1E , 29 26 byte

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

Hãy thử trực tuyến! hoặc thử tất cả các phiên bản chiếu xạ .

Bộ chiếu xạ ngắn nhất tôi có thể tìm thấy là 5 byte:

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

Ý tưởng là lặp lại 3 lần, sau đó bỏ phiếu đa số:

æ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

Ålà tiền tố cho các lệnh 2 byte, nhưng không có Å`lệnh nào , đó là lý do tại sao Åbị bỏ qua. Chúng tôi sẽ cần nó sau, mặc dù.

Sắp xếp đảm bảo bỏ phiếu đa số ở giữa mảng. Bán phá giá sau đó hoán đổi được giá trị đó lên đầu ngăn xếp.

Bất kỳ sự chiếu xạ nào trong phần ban đầu chỉ dẫn đến một lỗi trong mảng toàn cầu, được giải quyết bằng đa số phiếu. Các bức xạ trong {Å`sbit cuối cùng khó hơn nhiều để lý do về:

  • Å dù sao cũng bị bỏ qua, vì vậy không sao khi chiếu xạ nó

  • Nếu backtick được chiếu xạ, Å`strở thành Åslệnh mở rộng "get middle of the Array".

  • Nếu {hoặc sđược chiếu xạ, điều đó có nghĩa là không có gì khác, vì vậy mảng toàn cầu có cùng giá trị ba lần. Trong trường hợp đó, chúng tôi không cần sắp xếp / hoán đổi, mọi giá trị sẽ hoạt động.


3
Rất ấn tượng! Tôi không nghĩ rằng tôi đã thấy câu trả lời 05AB1E về thử thách SKSS. Tôi sẽ thêm một tiền thưởng để thưởng cho câu trả lời này (và đưa ra thử thách tiếp xúc nhiều hơn một chút như tôi đoán) ngay lập tức. Bạn đã chơi rất nhiều câu trả lời của tôi, vì vậy bạn cũng xứng đáng nhận được rất nhiều tín dụng cho những câu trả lời đó! :)
Kevin Cruijssen

3
Trên thực tế, tôi đã thấy 05AB1E câu trả lời về một thách thức RH trước đây . Tuy nhiên, rất ấn tượng!
Kevin Cruijssen

5

Mã máy 8086 (MS-DOS .COM), 83 byte

Có thể chạy trong DOSBox hoặc công cụ tính toán chạy bằng hơi nước yêu thích của bạn. Chuỗi để chiếu xạ được đưa ra dưới dạng đối số dòng lệnh.

Nhị phân:

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

Có thể đọc được

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

Chạy xuống

Phần hoạt động được nhân đôi để luôn luôn không bị ảnh hưởng bởi bức xạ. Chúng tôi chọn phiên bản lành mạnh bằng cách nhảy. Mỗi bước nhảy là một bước nhảy ngắn và do đó chỉ dài hai byte, trong đó byte thứ hai là độ dịch chuyển (tức là khoảng cách để nhảy, với hướng xác định dấu hiệu).

Chúng ta có thể chia mã thành bốn phần có thể được chiếu xạ: nhảy 1, mã 1, nhảy 2 và mã 2. Ý tưởng là đảm bảo một phần mã sạch luôn được sử dụng. Nếu một trong các phần mã được chiếu xạ, phần khác phải được chọn, nhưng nếu một trong các bước nhảy được chiếu xạ, cả hai phần mã sẽ sạch, vì vậy sẽ không có vấn đề nào được chọn.

Lý do để có hai phần nhảy là để phát hiện chiếu xạ trong phần đầu tiên bằng cách nhảy qua nó. Nếu phần mã đầu tiên được chiếu xạ, điều đó có nghĩa là chúng ta sẽ đến một byte khỏi dấu. Nếu chúng tôi đảm bảo rằng việc hạ cánh được khắc phục như vậy sẽ chọn mã 2 và hạ cánh phù hợp sẽ chọn mã 1, chúng tôi sẽ rất tuyệt vời.

Đối với cả hai lần nhảy, chúng tôi nhân đôi byte dịch chuyển, làm cho mỗi phần nhảy dài 3 byte. Điều này đảm bảo rằng chiếu xạ ở một trong hai byte cuối cùng vẫn sẽ khiến bước nhảy hợp lệ. Chiếu xạ trong byte đầu tiên sẽ ngăn chặn bước nhảy xảy ra, vì hai byte cuối cùng sẽ tạo thành một hướng dẫn hoàn toàn khác nhau.

Bước nhảy đầu tiên:

EB 28 28        jmp +0x28 / db 0x28

Nếu một trong hai 0x28byte bị loại bỏ, nó vẫn sẽ nhảy đến cùng một vị trí. Nếu 0xEBbyte bị loại bỏ, thay vào đó chúng ta sẽ kết thúc bằng

28 28           sub [bx + si], ch

đó là một hướng dẫn lành tính trên MS-DOS (các hương vị khác có thể không đồng ý), và sau đó chúng tôi rơi vào mã 1, phải sạch, vì thiệt hại nằm ở bước 1.

Nếu bước nhảy được thực hiện, chúng ta sẽ hạ cánh ở lần nhảy thứ hai:

EB D7 D7        jmp -0x29 / db 0xd7

Nếu chuỗi byte này còn nguyên vẹn và chúng ta hạ cánh ngay trên nhãn hiệu, điều đó có nghĩa là mã 1 đã sạch và hướng dẫn này nhảy trở lại phần đó. Byte dịch chuyển trùng lặp đảm bảo điều này, ngay cả khi đó là một trong những byte dịch chuyển bị hỏng. Nếu chúng ta hoặc hạ một byte (vì mã 1 bị hỏng hoặc nhảy 1) hoặc 0xEBbyte là một byte bị hỏng, hai byte còn lại cũng sẽ ở đây là lành tính:

D7 D7           xlatb / xlatb

Bất kể trường hợp nào, nếu chúng ta kết thúc việc thực hiện hai hướng dẫn đó, chúng ta đều biết rằng bước nhảy 1, mã 1 hoặc bước 2 đã được chiếu xạ, điều này làm cho việc chuyển sang mã 2 trở nên an toàn.

Kiểm tra

Chương trình sau đây được sử dụng để tự động tạo tất cả các phiên bản của tệp .COM. Nó cũng tạo ra một tệp BAT có thể chạy trong môi trường đích, chạy từng tệp nhị phân được chiếu xạ và chuyển các kết quả đầu ra của chúng sang các tệp văn bản riêng biệt. So sánh các tệp đầu ra để xác thực là đủ dễ dàng, nhưng DOSBox không có fc, vì vậy nó không được thêm vào tệp 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);
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.