Z80Golf , 53 36 34 Bytes
-16 Bytes dank @Lynn
-2 Bytes dank @Neil
Da es sich nur um Z80-Maschinencode handelt, sind in diesem Code viele nicht druckbare Dateien enthalten. Verwenden Sie also einen xxd -rumkehrbaren Hexdump:
00000000: ddb6 2120 10dd b615 280c 003e 62ff 3e65 ..! ....(..>b.>e
00000010: ffff 3e70 ff76 003e 62ff 3e65 ffff 3e70 ..>p.v.>b.>e..>p
00000020: ff76 .v
Probieren Sie es online! (ausführlicher Tester in Python)
Erläuterung
z80golf ist Anarchy Golfs hypothetische Z80-Maschine, bei der call $8000es sich um einen Putchar handelt.call $8003 einen Getchar handelt, haltder den Interpreter beendet, Ihr Programm abgelegt $0000wird und der gesamte andere Speicher mit Nullen gefüllt ist. Es ist ziemlich schwierig, Programme in der Assembly strahlungssicher zu machen, aber eine allgemein nützliche Technik ist die Verwendung von Anweisungen mit einem Byte im Idempotenten. Beispielsweise,
or c ; b1 ; a = a | c
ist nur ein Byte und a | c | c == a | c kann daher durch einfaches Wiederholen des Befehls strahlungssicher gemacht werden. Beim Z80 besteht ein 8-Bit-Sofortladevorgang aus zwei Bytes (wobei der Sofortladevorgang sich im zweiten Byte befindet), sodass Sie auch einige Werte zuverlässig in Register laden können. Das habe ich ursprünglich zu Beginn des Programms getan, damit Sie die längeren Varianten analysieren können, die ich am Ende der Antwort archiviert habe, aber dann habe ich festgestellt, dass es einen einfacheren Weg gibt.
Das Programm besteht aus zwei unabhängigen Nutzlasten, von denen eine durch Strahlung beschädigt worden sein könnte. Ich überprüfe, ob ein Byte entfernt wurde und ob das entfernte Byte vor der zweiten Kopie der Nutzdaten lag, indem ich die Werte einiger absoluter Speicheradressen überprüfe.
Zuerst müssen wir gehen, wenn keine Strahlung beobachtet wurde:
or a, (ix+endbyte) ; dd b6 21 ; a |= memory[ix+0x0021]
jr nz, midbyte ; 20 10 ; jump to a halt instruction if not zero
Wenn irgendein Byte entfernt wurde, dann alle werden die Bytes verschieben und $0020die letzte enthalten 76, so$0021 eine Null. Wir können es uns leisten, den Beginn des Programms zu strahlen, obwohl es praktisch keine Redundanz gibt:
- Ist der Sprung versetzt
$10 entfernt wird, wird die Strahlung korrekt erfasst, der Sprung wird nicht ausgeführt, und der Versatz spielt keine Rolle. Das erste Byte des nächsten Befehls wird verbraucht, aber da es so konzipiert ist, dass es resistent gegen das Entfernen von Bytes ist, spielt dies keine Rolle.
- Wenn der Sprung - Opcode
$20entfernt wird, dann versetzte der Sprung $10wird als dekodieren djnz $ffe4(raubend das nächste Befehlsbyte als Offset - siehe oben), die eine Schleifenanweisung ist - Dekrement - B, und zu springen , wenn das Ergebnis nicht null ist. Weil ffe4-ffffmit Nullen gefüllt ist (nop ist und der Programmzähler einen Zeilenumbruch durchführt, wird der Programmanfang 256-mal ausgeführt und anschließend fortgesetzt. Ich bin erstaunt, dass dies funktioniert.
- Wenn Sie das entfernen,
$ddwird der Rest des Snippets als dekodiert or (hl) / ld ($1020), hlund dann in den nächsten Teil des Programms verschoben. Das orändert keine wichtigen Register, und da HL zu diesem Zeitpunkt Null ist, wird das Schreiben ebenfalls abgebrochen.
- Wenn Sie das entfernen,
$b6wird der Rest ld ($1020), ixwie oben beschrieben dekodiert .
- Wenn Sie den entfernen
$21, frisst der Decoder den $20und löst das djnzVerhalten aus.
Beachten Sie, dass durch die Verwendung von or a, (ix+*)zwei Bytes ld a, (**) / and a / and adurch die integrierte Prüfung auf Null gespart wird .
Wir müssen jetzt entscheiden, welche der beiden Kopien der Nutzlast ausgeführt werden soll:
or (ix+midbyte) ; dd b6 15
jr z, otherimpl ; 28 0c
nop ; 00
; first payload
ld a, 'b' ; 3e 62
rst $0038 ; ff
ld a, 'e' ; 3e 65
rst $0038 ; ff
rst $0038 ; ff
ld a, 'p' ; 3e 70
rst $0038 ; ff
midbyte:
halt ; 76
otherimpl:
nop ; 00
ld a, 'b' ; 3e 62
; ... ; ...
rst $0038 ; ff
endbyte:
halt ; 76
Die zwei Kopien sind durch ein NOP getrennt, da ein relativer Sprung verwendet wird, um zwischen ihnen zu wählen, und Strahlung das Programm auf eine Weise hätte verschieben können, die den Sprung zum Überspringen des ersten Bytes nach dem Ziel führen würde. Zusätzlich wird der NOP als Null codiert, wodurch es einfach ist, verschobene Bytes zu erkennen. Beachten Sie, dass es keine Rolle spielt, welche Nutzdaten ausgewählt werden, wenn der Switch selbst beschädigt ist, da dann beide Kopien sicher sind. Stellen wir aber sicher, dass es nicht in den nicht initialisierten Speicher springt:
- Durch Löschen
$ddwerden die nächsten zwei Bytes als dekodiertor (hl) / dec d . Clobbers D. Keine große Sache.
- Durch das Löschen
$b6wird eine undokumentierte längere Codierung für erstellt dec d. Das gleiche wie oben.
- Beim Löschen
$15wird $28stattdessen der Wert als Versatz gelesen , und die Ausführung erfolgt $0cwie unten beschrieben.
- Wenn
$28verschwindet, wird der $0cals dekodiert inc c. Die Nutzlast kümmert sich nicht darum c.
- Löschen
$0c- dafür ist der NOP da. Andernfalls wäre das erste Byte der Nutzlast als Sprungoffset gelesen worden, und das Programm würde in den nicht initialisierten Speicher springen.
Die Nutzlast selbst ist ziemlich einfach. Ich denke, die geringe Größe der Zeichenfolge macht diesen Ansatz kleiner als eine Schleife, und es ist einfacher, auf diese Weise positionsunabhängig zu machen. Die ein beepWiederholungen, so kann ich ein abrasieren ld a. Auch, weil alle Speicher zwischen $0038und auf $8000Null gesetzt wird, kann ich durch sie fallen und eine kürzere verwenden rstVariante der callAnweisung, die nur funktioniert für $0, $8, $10und so weiter, bis zu$38 .
Ältere Ansätze
64 Bytes
00000000: 2e3f 3f2e 3f3f 7e7e a7a7 201f 1e2b 2b1e .??.??~~.. ..++.
00000010: 2b2b 6b00 7ea7 2814 003e 62cd 0080 3e65 ++k.~.(..>b...>e
00000020: cd00 80cd 0080 3e70 cd00 8076 003e 62cd ......>p...v.>b.
00000030: 0080 3e65 cd00 80cd 0080 3e70 cd00 8076 ..>e......>p...v
58 Bytes
00000000: 2e39 392e 3939 7e7e a7a7 2019 3a25 00a7 .99.99~~.. .:%..
00000010: 2814 003e 62cd 0080 3e65 cd00 80cd 0080 (..>b...>e......
00000020: 3e70 cd00 8076 003e 62cd 0080 3e65 cd00 >p...v.>b...>e..
00000030: 80cd 0080 3e70 cd00 8076 ....>p...v
53 Bytes
Dieser hat eine Erklärung in der Bearbeitungshistorie, aber es ist nicht zu unterschiedlich.
00000000: 3a34 00a7 a720 193a 2000 a728 1400 3e62 :4... .: ..(..>b
00000010: cd00 803e 65cd 0080 cd00 803e 70cd 0080 ...>e......>p...
00000020: 7600 3e62 cd00 803e 65cd 0080 cd00 803e v.>b...>e......>
00000030: 70cd 0080 76 p...v
Was ist, wenn: eine nicht leere Ausgabe in Ordnung war anstelle eines Pieptons
1 Byte
v
halts das Programm normalerweise, aber wenn Strahlung es entfernt, dann ist der Speicher voll von Nullen, so $8000dass unendlich oft ausgeführt wird und viele Null-Bytes gedruckt werden.