Licznik Geigera to urządzenie służące do wykrywania promieniowania.
Będziemy tworzyć program liczników Geigera.
Jak wszyscy wiemy, gdy promieniowanie uderza w program komputerowy, losowo usuwa dokładnie 1 bajt. Tak więc program licznika Geigera jest programem, który sam nie robi nic, ale po usunięciu dowolnego bajtu drukowany jest zmodyfikowany program beep
, wskazujący obecność promieniowania.
Odpowiedzi będą oceniane w bajtach, przy czym mniej bajtów będzie lepszych. Odpowiedzi muszą mieć co najmniej 1 bajt.
Twój program może drukować beep
z końcowym znakiem nowej linii lub drukować pojedynczy znak nowej linii dla pustych danych wyjściowych, o ile robi to konsekwentnie. Program może również użyć innego przypadek dla beep
takich jak BEEP
, bEEP
lub Beep
tak długo, jak robi to konsekwentnie.
źródło
Odpowiedzi:
Utracone ,
303 293 263 253 238228 bajtówWypróbuj online!
Skrypt weryfikacyjny (zapożyczony z odpowiedzi użytkownika 202729 ). Niestety może to przetestować tylko połowę kodu na raz, ale zapewniam, że przetestowałem cały program.
Och, to było trudne. Zacytuję usuniętą odpowiedź WW:
Niestety, jego odpowiedź nie uwzględniała usuwania nowych linii, co wszystko popsuło.
Wyjaśnienie:
(zwróć uwagę, że kilka bajtów może być tu i tam)
Najpierw porozmawiajmy o ogólnej strukturze kodu:
Wszystko oprócz linii technologicznej musi być całkowicie złożone z jednego
>
lub jednego z nich\/
. Czemu? Na przykład usuńmy nową linię:Pierwsza linia jest teraz znacznie dłuższa niż reszta bloku. Gdyby wskaźnik pojawił się na nie-
>\/
postaci z ruchem pionowym, utknąłby w nieskończonej pętli.Największą częścią detektora promieniowania jest sekcja na końcu każdej linii.
Zwykle IP przechodzący przez to z pierwszej linii wychodziłby z ostatniej linii. Jeśli jednak jakikolwiek znak w linii zostanie usunięty, wówczas linia ta przesuwa się w dół o jeden, np .:
Zamiast tego IP wychodzi z linii, w której brakuje bajtu (z wyjątkiem ostatniej linii, w której wychodzi z drugiej do ostatniej).
Stamtąd każda z pierwszych czterech linii przekieruje do drugiej linii:
Które następnie doprowadzą do jednego z dwóch
beep
ers.Jeśli którykolwiek z bajtów w pierwszym
beep
erie został usunięty, to zamiast tego przechodzi do drugiego:Obaj
beep
prowadzą następnie z powrotem do pierwszej linii i zakończenia@
.Niektóre inne części:
(((((([[[[[[[
Służy do wyczyszczenia stos, gdy wskaźnik zacznie wewnątrz parę cytatów i kończy się przesuwając całą pierwszą linię do stosu. Musi być niestety długi, ponieważ pierwszą linię nowej linii można usunąć, aby pierwsza linia była dwa razy większa. Eksperymentowanie w generowaniu plikubeep
arytmetyki za pomocą cytatów zakończyło się dłużej.\
Y i/
y rozrzucone po liniach są tam golf bajtów w wierszu górnym kodu poprzez przekierowanie wskaźnik do odpowiednich linii. Ponieważ większość dolnych linii jest tylko wypełniaczem, tylko górna linia jest w stanie grać w golfa. Jeśli ktoś ma jakieś pomysły na krótszy stos odporny na promieniowanie, jaśniejszy niż to, co mam teraz, nie krępuj się komentować.źródło
\/
rozdzielićbeep
pchnięcia i fakt, że tylko jeden z cytatów wymagał klauzuli wyjściaSześciokąt , 38 bajtów
Wypróbuj online!
Program weryfikacji.
Wyjaśnienie
Wykorzystujemy tutaj automatyczne wykrywanie sześciokąta przez Hexagony.
Jeśli nie zostaną usunięte żadne bajty, program ma długość boku 4 i wygląda następująco:
Jeśli jednak bajt zostanie usunięty. Istnieją 2 przypadki.
Usunięty bajt następuje po drugim
<
.Wykonanie byłoby następujące:
W
@
piątej linii są 2 kolejne , więc nawet jeśli jeden z nich zostanie usunięty, IP bezpiecznie trafi w@
.Usunięty bajt jest na drugim lub przed drugim
<
.Wtedy druga połowa pozostanie nienaruszona, a adres IP nie będzie już przez to przekierowywany w górę
<
. Obraz przebiegu wykonania:źródło
Sześciokąt ,
3429 bajtówWypróbuj online! Weryfikacja!
Wyjaśnienie:
Oto normalny kod sformatowany w prawidłowy sześciokąt za pomocą HexagonyColorer :
Podwój
//
na początku zapewnia, że ta ścieżka jest zawsze obrana. Jeśli jakikolwiek znak zostanie usunięty,@
zostanie usunięty ze ścieżki, albo zostanie przesunięty do tyłu, albo sam zostanie usunięty:W tym przypadku usunęliśmy znak po znaku
|
, co powoduje, że podąża on tą ścieżką, drukującbeep
:Jeśli zamiast tego usuniemy znak sprzed
|
(lub|
samego), podążamy za drugą drukarką sygnałów:Następnie wzięliśmy pod uwagę wszystkie możliwości i
beep
korzystamy tylko z nienapromieniowanych części programu.źródło
Samomodyfikujący Brainfuck ,
7363 bajtyWypróbuj online! Weryfikacja!
Spacje w środku kodu reprezentują w rzeczywistości bajty NUL.
Wyjaśnienie:
Kod jest podzielony na dwie sekcje przez 3 NUL bajtów pośrodku. Oba drukują w zasadzie,
beep
jeśli druga sekcja jest napromieniowana (z kilkoma wyjątkami).Po pierwsze,
<<[[
na początku należy upewnić się, że wszystkie]
s są dopasowane w dowolnym momencie.[
s nie będzie szukał dopasowania,]
jeśli komórka jest dodatnia, podczas gdy]
s zrobi . Jeśli którykolwiek]
przeskakuje z powrotem do jednego z tych nawiasów, zwykle odskakuje natychmiast, ponieważ komórka jest0
.Następna część
[[<<]]>
sprawdza, czy długość sekcji 2 jest równa. Jeśli tak, wykonuje drugą połowę sekcji 1, która drukujebeep
przy użyciubbeepp
na początku sekcji 2.Następnie usuwa całą sekcję 2, więc nie wykonuje się.
W części 2, sprawdzamy, czy długość sekcji 1 i NUL bajtów jest podzielna przez
3
z+[<<<]>>
.Podobnie drukujemy
beep
.źródło
Z80Golf ,
533634 bajtów-16 bajtów dzięki @Lynn
-2 bajtów dzięki @Neil
Ponieważ jest to tylko kod maszynowy Z80, jest w nim wiele niedrukowalnych elementów, więc należy mieć
xxd -r
odwracalny zrzut heksowy:Wypróbuj online! (wyczerpujący tester w Pythonie)
Wyjaśnienie
z80golf to hipotetyczna maszyna Z80 firmy Anarchy Golf, w której
call $8000
jest putchar,call $8003
jest getchar,halt
powoduje wyjście interpretera, program jest umieszczony$0000
, a cała inna pamięć jest wypełniona zerami. Uczynienie programów odpornymi na promieniowanie w asemblerze jest dość trudne, ale ogólnie użyteczną techniką jest stosowanie jednobajtowych idempotentnych instrukcji. Na przykład,jest tylko jednym bajtem, a
a | c | c == a | c
więc można go zabezpieczyć przed promieniowaniem poprzez powtórzenie instrukcji. W przypadku Z80 8-bitowe natychmiastowe ładowanie to dwa bajty (gdzie natychmiastowe jest w drugim bajcie), więc możesz pewnie ładować niektóre wartości do rejestrów. Tak właśnie zrobiłem na początku programu, więc możesz przeanalizować dłuższe warianty, które zarchiwizowałem na dole odpowiedzi, ale potem zrozumiałem, że istnieje prostszy sposób.Program składa się z dwóch niezależnych ładunków, z których jeden mógł zostać uszkodzony przez promieniowanie. Sprawdzam, czy bajt został usunięty i czy usunięty bajt był przed drugą kopią ładunku, sprawdzając wartości niektórych bezwzględnych adresów pamięci.
Najpierw musimy wyjść, jeśli nie zaobserwowano promieniowania:
Jeśli jakikolwiek bajt został usunięty, wszystkie bajty zostaną przesunięte i
$0020
będą zawierać ostatni76
, więc$0021
będzie to zero. Możemy sobie pozwolić na promieniowanie początku programu, mimo że praktycznie nie ma redundancji:$10
zostanie usunięte, wówczas promieniowanie zostanie poprawnie wykryte, skok nie zostanie wykonany, a przesunięcie nie będzie miało znaczenia. Pierwszy bajt następnej instrukcji zostanie zużyty, ale ponieważ ma on być odporny na usuwanie bajtów, nie ma to znaczenia.$20
zostanie usunięty, wówczas przesunięcie skoku$10
zostanie zdekodowane jakodjnz $ffe4
(pochłanianie następnego bajtu instrukcji jako przesunięcia - patrz wyżej), który jest instrukcją pętli - zmniejszenie B, i przeskoczy, jeśli wynik nie będzie równy zero. Ponieważffe4-ffff
jest wypełniony zeraminop
, a licznik programu się zawija, spowoduje to uruchomienie programu 256 razy, a następnie kontynuację. Dziwi mnie, że to działa.$dd
spowoduje, że reszta kodu zostanie zdekodowana jakoor (hl) / ld ($1020), hl
, a następnie przejdzie do następnej części programu.or
Nie zmieni żadnych ważnych rejestrów, a ponieważ HL wynosi zero w tym momencie zapisu będzie również anulować.$b6
spowoduje, że reszta dekoduje jakold ($1020), ix
i będzie postępować jak wyżej.$21
spowoduje, że dekoder zje$20
, wywołującdjnz
zachowanie.Zauważ, że użycie
or a, (ix+*)
pozwala zaoszczędzić dwa bajtyld a, (**) / and a / and a
dzięki zintegrowanemu sprawdzeniu zera.Teraz musimy zdecydować, którą z dwóch kopii ładunku wykonać:
Dwie kopie są oddzielone znakiem nop, ponieważ do wyboru między nimi używany jest skok względny, a promieniowanie mogło przesunąć program w taki sposób, że skok przeskoczyłby o pierwszy bajt za miejscem docelowym. Dodatkowo nop jest kodowany jako zero, co ułatwia wykrycie przesuniętych bajtów. Zauważ, że nie ma znaczenia, który ładunek zostanie wybrany, jeśli sam przełącznik jest uszkodzony, ponieważ wtedy obie kopie są bezpieczne. Upewnijmy się jednak, że nie wskoczy do niezainicjowanej pamięci:
$dd
spowoduje dekodowanie kolejnych dwóch bajtów jakoor (hl) / dec d
. Clobbers D. Nic wielkiego.$b6
spowoduje utworzenie nieudokumentowanego dłuższego kodowaniadec d
. Tak samo jak powyżej.$15
odczyta$28
zamiast tego przesunięcie, a wykonanie będzie kontynuowane od$0c
, jak poniżej.$28
znika,$0c
dekodowany jest jakoinc c
. Ładowność nie ma znaczeniac
.$0c
- po to jest nop. W przeciwnym razie pierwszy bajt ładunku zostałby odczytany jako przesunięcie skoku, a program wskoczyłby do niezainicjowanej pamięci.Sama ładowność jest dość prosta. Myślę, że mały rozmiar sznurka sprawia, że to podejście jest mniejsze niż pętla i w ten sposób łatwiej jest uniezależnić pozycję.
e
Wbeep
powtórzeń, więc mogę zgolić jednąld a
. Również dlatego, że cała pamięć pomiędzy$0038
i$8000
jest wyzerowany, mogę spaść przez niego i używać krótszyrst
wariantcall
instrukcji, który działa tylko na$0
,$8
,$10
i tak dalej, aż do$38
.Starsze podejścia
64 bajty
58 bajtów
53 bajty
Ten ma wyjaśnienie w historii edycji, ale nie jest inaczej.
Co jeśli: każde niepuste wyjście jest w porządku zamiast sygnału dźwiękowego
1 bajt
halt
s program normalnie, ale jeśli promieniowanie go usunie, pamięć zostanie zapełniona zerami, co spowoduje$8000
wykonanie nieskończonej liczby razy i wydrukowanie dużej liczby bajtów zerowych.źródło
a
zaczyna się od zera, nie możesz użyćor a, (N);
zamiastld a, (N); and a;
? Wygląda na to, że możesz w ten sposób zaoszczędzić kilka bajtów.or a, (ix + N)
?20 19
na początku staje się20 18
, a usunięcie20
tworzy bezwarunkowy skok do tyłu, więc po pierwszym skoku w programie należy dodać nop, odwracając zapisywanie bajtów.> <> , 23 bajty
Wypróbuj online! Weryfikacja.
To naprawdę zaskakujące, jak krótko to dostałem. Kończy się błędem.
Wersja bez błędów, 29 bajtów
Wypróbuj online!
źródło
Klein , jedna z każdej topologii, o łącznej długości 291 bajtów
Po zapoznaniu się z odpowiedzią WW przy użyciu
001
topologii postanowiłem zobaczyć, jak trudno byłoby wykonać Licznik Geigera dla każdej topologii. (Spoiler: bardzo trudny. Trudno ustalić, dokąd pójdzie wskaźnik bez gestów, które sprawiają, że wyglądam, jakbym zastanawiał się, która ręka jest moją lewą)Weryfikacja!
(Myślałem też o napisaniu programu, który jest poprawnym licznikiem Geigera we wszystkich topologiach, ale może to wymagać oczekiwania. Jeśli jednak ktoś chce spróbować, oferuję nagrodę w wysokości 500 powtórzeń)
000 i 010, 21 bajtów
Wypróbuj 000 online! i wypróbuj 010 online!
Jest to przeniesione z mojego
><>
rozwiązania . To oczywiście działa000
, ponieważ jest to domyślna topologia dla większości języków 2D, ale byłem zaskoczony, że to również działa010
.001 i 011, 26 bajtów
Wypróbuj 001 online! i wypróbuj 011 online!
Ten jest kopiowany bezpośrednio z odpowiedzi WW . Dzięki!
100, 21 bajtów
Wypróbuj online!
101, 21 bajtów
Wypróbuj online!
110, 26 bajtów
Wypróbuj online!
111, 24 bajtów
Wypróbuj online!
200, 21 bajtów
Wypróbuj online!
201, 31 bajtów
Wypróbuj online!
Zdecydowanie najbardziej denerwujące.
210, 26 bajtów
Wypróbuj online!
211,27 bajtów
Wypróbuj online!
Jedyny, w którym musiałem poradzić sobie z wejściem do sygnalizatora po prawej stronie.
źródło
Samomodyfikujący Brainfuck ,
144102 bajtówMateriały niedrukowalne są wyświetlane jako sekwencja ucieczki (na przykład
\x01
).Weryfikacja!
źródło
Runiczne Zaklęcia , 29 bajtów
Wypróbuj online!
Zasadniczo taki sam jak odpowiedź Klein 000 lub odpowiedź <<> (zacząłem od Klein). Jedyną konieczną zmianą było włączenie
<
wL
i.
na(tłumaczenie symboli poleceń), wstawienie punktów wejścia IP (potrzeba 2, w przeciwnym razie usunięcie spowodowałoby niekompilację programu) i wstawienie
y
polecenia dela, aby uzyskać dwa adresy IP do scalenia (w ten sposób drukując tylko jedenbeep
), ponownie, wymagając dwóch. Wymagane było również wstawienie dodatkowych NOP, aby zachować takie same długości linii. Klein dogodnie używa również@
do „drukowania i kończenia”.Brak możliwości wykorzystania białych znaków w lewym dolnym rogu, ponieważ wszelkie reflektory zmieniające kierunek hamują zdolność wykrywania promieniowania. np. (26 bajtów, naświetlane
y
):Nie drukuje żadnych danych wyjściowych, ponieważ wygięty segment wejściowy powoduje odbicie z powrotem do terminatora dolnej linii.
źródło
Befunge-93 , 55 bajtów
Wypróbuj online! Weryfikacja!
Miałem nadzieję, że będzie trochę mniejszy, ale wąską szyją jest długość
beep
drukarki.źródło
Wumpus ,
37 34 3231 bajtówWypróbuj online! Weryfikacja!
To rozwiązanie wykorzystuje fakt, że
.
przeskakuje do modułu pozycji na długość programu.Alternatywnie dla tej samej ilości bajtów
Wypróbuj online! Weryfikacja!
Ten wykorzystuje różnicę w kierunku wskaźnika dla nieparzystych i parzystych długości linii. (Naprawdę nie wiem, jak działa pierwsza,
"
gdy nowa linia jest usuwana)źródło
Klein (001), 26 bajtów
Wypróbuj online!
Zweryfikować!
Wyjaśnienie
Ten program wykorzystuje unikalną topologię Kleina, w szczególności 001 topologię , czyli butelkę Kleina.
Bez edycji program podąża ścieżką wykonania:
Usunięcie bajtu z programu może mieć wpływ na program na 4 sposoby (każdy w innym kolorze):
Pierwszą rzeczą, na którą należy zwrócić uwagę, jest to, że na początku
<<
zawsze będzie odchylać ip z lewej strony źródła. Jeśli jeden z nich<
zostanie usunięty, drugi zajmuje jego miejsce. Więc jeśli jakikolwiek bajt zostanie usunięty z czerwonej sekcji, zostanie podana następująca ścieżka wykonania:Jeśli niebieski bajt zostanie usunięty, otrzymamy bardzo prostą ścieżkę:
Jeśli nowa linia zostanie usunięta, otrzymamy ścieżkę:
Żółta ścieżka jest nieco bardziej złożona. Ponieważ dolna linia jest o jeden dłuższa niż górna linia, gdy program zostanie podniesiony do kwadratu na początku wykonywania, na końcu pierwszego wiersza dodawany jest znak wirtualny, aby uzyskać taki sam rozmiar. Jeśli jakikolwiek bajt w drugiej linii zostanie usunięty, linia zostanie skrócona i ten wirtualny znak nie zostanie dodany. Jest to ważne, ponieważ
!
zwykle przeskakuje wirtualną postać, ale pod jej nieobecność przeskakuje/
zamiast niej.źródło
><>
rozwiązanie000
na 21 bajtówBackhand ,
2521 bajtówWypróbuj online! Weryfikacja!
Wykorzystuje to zdolność Backhand do zmiany wartości kroku wskaźnika, aby pomijać instrukcję na każdym kroku i starannie rozwiązać problem redunancji. Następnie używa
j
polecenia, aby sprawdzić, czy kod jest napromieniowany, przeskakując do ostatniego znaku (@
, zatrzymaj), jeśli nie, i przeskakując do ostatniego ostatniego (H
, zatrzymaj i stos wyjściowy), jeśli tak jest.źródło