Radyasyonla sertleştirilmiş bir irradyatör yazın


17

Görev radyasyonla sertleştirilmiş bir irradyatör yazmaktır. Bununla ne demek istiyorum?

Bir irradiator, bir dize girdi olarak verildiğinde, bir karakter kaldırılarak dizenin tüm olası sürümlerini çıktılayacak bir programdır. Örneğin, girdi göz önüne alındığında Hello, world!, program çıktı vermelidir:

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

Bununla birlikte, bir radyatör radyasyonundan korunmalıdır, bu nedenle yazdığınız radyatör de kendi içinden geçtiğinde hayatta kalmalıdır. Yani, programınızın tek bir baytı kaldırıldığında, programın hala düzgün çalışması gerekir.

Test senaryoları

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;

Özellikler

  • Standart G / Ç kurallarımıza göre kabul edilebilir herhangi bir yöntemle girdi alabilirsiniz
  • Çıktı ya bir karakter listesi ya da bir karakter ya da karakter grubu tarafından ayrılmış basılı bir liste olabilir. Sondaki sınırlayıcı kabul edilebilir
  • Çıktı, olası tüm sürümleri içerdiği sürece herhangi bir sırada olabilir
  • Yinelenen girişler ( Helo, world!ilk örnekteki iki s gibi) filtrelenebilir, ancak bu gerekli değildir
  • Bu , bayt cinsinden en küçük program kazanır

... veya virgül olabilir mi?
Jonathan Allan

4
ile C programı nedeniyle bu gerçekten, golf dilleri lehine olduğu viçinde voidkaldırılır derlemek olmaz
Krzysztof SZEWCZYK

3
@Krzysztof tbh Bence tüm pratik diller olmasa bile, ayrıntı ve sözdizimi nedeniyle radyasyon sertleşmeden kurtulamayacaklar. Sadece bu zorluk değil, TÜM RH zorlukları.
Shieru Asakoto

Yanıtlar:


13

05AB1E , 29 26 bayt

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

Çevrimiçi deneyin! veya tüm ışınlanmış sürümleri deneyin .

Bulabildiğim en kısa ışınlayıcı 5 bayt:

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

Fikir, bunu 3 kez tekrarlamak, sonra çoğunluk oyu yapmak:

æ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 baytlık komutların önekidir, ancak Å`komut yoktur , bu yüzden Åyok sayılır. Yine de buna ihtiyacımız olacak.

Sıralama, çoğunluk oyunun dizinin ortasında olmasını sağlar. Damping ve swapping bu değeri yığının en üstüne alır.

İlk kısımdaki herhangi bir ışınlama, küresel dizide yalnızca çoğunluk oyu ile çözülen bir hatayla sonuçlanır. Son bitdeki ışınlamalar, aşağıdakiler {Å`shakkında akıl yürütmek için daha zordur:

  • Å yine de yok sayılır, bu yüzden onu ışınlamak uygun

  • Ters tırnak ışınlanmış ise, Å`solur Åsgenişletilmiş komuta "dizisinin orta olsun" olan.

  • Işınlanırsa {veya sışınlanırsa, başka bir şey olmadığı anlamına gelir, bu nedenle genel dizi üç kez aynı değerdedir. Bu durumda sıralama / değiştirmeye ihtiyacımız yoktur, herhangi bir değer işe yarayacaktır.


3
Çok etkileyici! Bir RH meydan okumasında 05AB1E cevabı göreceğimi düşünmemiştim. Bu cevabı ödüllendirmek için bir ödül ekleyeceğim (ve meydan okumayı sanırım biraz daha fazla pozlama vereceğim). Benim pek çok cevabımı golf oynadınız, bu yüzden onlar için de bir sürü krediyi hak ediyorsunuz! :)
Kevin Cruijssen

3
Aslında, daha önce bir RH zorluğuna 05AB1E cevapları gördüm . Yine de çok etkileyici!
Kevin Cruijssen

5

8086 makine kodu (MS-DOS .COM), 83 bayt

DOSBox'ta veya favori buharla çalışan bilgi işlem motorunuzda çalıştırılabilir. Işınlanacak dize bir komut satırı argümanı olarak verilir.

İkili:

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

Okunabilir:

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

Bitkin

Aktif kısım çoğaltılır, böylece her zaman radyasyon tarafından dokunulmaz. Sağlıklı versiyonu atlamalarla seçiyoruz. Her atlama kısa bir atlamadır ve bu nedenle sadece iki bayt uzunluğundadır, burada ikinci bayt yer değiştirmedir (yani atlama mesafesi, işaret belirleme yönü ile).

Kodu ışınlanabilecek dört bölüme ayırabiliriz: atlama 1, kod 1, atlama 2 ve kod 2. Fikir her zaman temiz bir kod parçasının kullanıldığından emin olmaktır. Kod parçalarından biri ışınlanırsa, diğeri seçilmelidir, ancak atlamalardan biri ışınlanırsa, her iki kod parçası temiz olur, bu yüzden hangisinin seçildiği önemli değildir.

İki atlama parçasına sahip olmanın nedeni, ilk kısımdaki ışınlamayı üstünden atlayarak tespit etmektir. İlk kod parçası ışınlanırsa, işaretten bir bayt ulaşacağımız anlamına gelir. Böyle bir botlu inişin kod 2'yi ve uygun bir inişin kod 1'i seçtiğinden emin olursak, biz altınız.

Her iki sıçrama için de, her atlama parçasını 3 bayt uzunluğunda olacak şekilde deplasman baytını çoğaltırız. Bu, son iki bayttan birindeki ışınlamanın atlamayı hala geçerli kılmasını sağlar. İlk bayttaki ışınlama, sıçramanın gerçekleşmesini durduracaktır, çünkü son iki bayt tamamen farklı bir talimat oluşturacaktır.

İlk atlamayı yap:

EB 28 28        jmp +0x28 / db 0x28

Birini ise 0x28bayt kaldırılır, hala aynı yere atlayacaktır. Eğer 0xEBbayt kaldırılır, bunun yerine ile sona erecek

28 28           sub [bx + si], ch

Bu MS-DOS (diğer tatlar katılmayabilir) iyi huylu bir talimattır ve daha sonra hasar atlama 1 olduğu için temiz olması gereken kod 1'e düşer.

Atlama yapılırsa, ikinci atlamaya iniyoruz:

EB D7 D7        jmp -0x29 / db 0xd7

Bu bayt dizisi bozulmamışsa ve doğrudan işaretin üzerine indiğimizde, kod 1'in temiz olduğu ve bu talimatın bu kısma geri atladığı anlamına gelir. Çoğaltılmış yer değiştirme baytı, hasar gören bu yer değiştirme baytlarından biri olsa bile bunu garanti eder. Bir bayt çıkarırsak (hasarlı kod 1 veya atlama 1 nedeniyle) veya 0xEBbayt hasarlı olan ise, kalan iki bayt da iyi huylu olacaktır:

D7 D7           xlatb / xlatb

Hangi durumda olursa olsun, bu iki talimatı uygularsak, atlama 1, kod 1 veya atlama 2'nin ışınlandığını biliyoruz, bu da kod 2'ye güvenli bir geçiş sağlıyor.

Test yapmak

Aşağıdaki program .COM dosyasının tüm sürümlerini otomatik olarak oluşturmak için kullanıldı. Ayrıca, her ışınlanmış ikili dosyayı çalıştıran ve çıktılarını ayrı metin dosyalarına bağlayan hedef ortamda çalıştırılabilen bir BAT dosyası oluşturur. Doğrulamak için çıktı dosyalarını karşılaştırmak yeterince kolaydır, ancak DOSBox yoktur fc, bu nedenle BAT dosyasına eklenmemiştir.

#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);
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.