Z80Golf , 53 36 34 byte
-16 byte nhờ @Lynn
-2 byte nhờ @Neil
Vì đây chỉ là mã máy Z80, nên có rất nhiều thứ không thể in được trong cái này, do đó, có một xxd -r
hexdump có thể đảo ngược:
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
Hãy thử trực tuyến! (người kiểm tra toàn diện trong Python)
Giải trình
z80golf là máy Z80 giả thuyết của Anarchy Golf, trong đó call $8000
một putar, call $8003
là một getar, halt
làm cho trình thông dịch thoát ra, chương trình của bạn được đặt tại$0000
và tất cả các bộ nhớ khác chứa đầy số không. Làm cho các chương trình chống bức xạ trong lắp ráp khá khó khăn, nhưng một kỹ thuật hữu ích chung là sử dụng các hướng dẫn tạm thời một byte. Ví dụ,
or c ; b1 ; a = a | c
chỉ là một byte và a | c | c == a | c
do đó, nó có thể được chống bức xạ bằng cách lặp lại hướng dẫn. Trên Z80, tải tức thời 8 bit là hai byte (trong đó tức thời là byte thứ hai), vì vậy bạn có thể tải một số giá trị vào các thanh ghi một cách đáng tin cậy. Đây là những gì tôi đã làm ban đầu khi bắt đầu chương trình, vì vậy bạn có thể phân tích các biến thể dài hơn mà tôi đã lưu trữ ở cuối câu trả lời, nhưng sau đó tôi nhận ra rằng có một cách đơn giản hơn.
Chương trình bao gồm hai tải trọng độc lập, trong đó một trong số chúng có thể đã bị hư hại do phóng xạ. Tôi kiểm tra xem một byte có bị xóa hay không và liệu byte bị loại bỏ có trước bản sao thứ hai của tải trọng hay không, bằng cách kiểm tra các giá trị của một số địa chỉ bộ nhớ tuyệt đối.
Đầu tiên, chúng ta cần thoát ra nếu không quan sát thấy bức xạ:
or a, (ix+endbyte) ; dd b6 21 ; a |= memory[ix+0x0021]
jr nz, midbyte ; 20 10 ; jump to a halt instruction if not zero
Nếu bất kỳ byte nào bị loại bỏ, thì tất cả các byte sẽ thay đổi và $0020
sẽ chứa cuối cùng 76
, do đó $0021
sẽ là một số không. Chúng tôi có thể đủ khả năng tỏa ra sự khởi đầu của chương trình, mặc dù hầu như không có sự dư thừa:
- Nếu phần bù nhảy
$10
được loại bỏ, thì bức xạ sẽ được phát hiện chính xác, bước nhảy sẽ không được thực hiện và phần bù sẽ không thành vấn đề. Byte đầu tiên của lệnh tiếp theo sẽ được sử dụng, nhưng vì nó được thiết kế để chống lại việc loại bỏ byte, nên điều này không thành vấn đề.
- Nếu opcode nhảy
$20
bị loại bỏ, thì offset offset $10
sẽ giải mã thành djnz $ffe4
(sử dụng byte lệnh tiếp theo làm offset - xem ở trên), đó là một lệnh lặp - giảm B và nhảy nếu kết quả không bằng 0. Bởi vì ffe4-ffff
được lấp đầy bằng số không (nop
và bộ đếm chương trình bao quanh, điều này sẽ chạy phần đầu của chương trình 256 lần, và cuối cùng tiếp tục. Tôi ngạc nhiên công trình này.
- Việc xóa
$dd
sẽ làm cho phần còn lại của đoạn mã giải mã thành or (hl) / ld ($1020), hl
, và sau đó trượt vào phần tiếp theo của chương trình. Việc or
này sẽ không thay đổi bất kỳ thanh ghi quan trọng nào và vì tại thời điểm này, số 0 bằng 0 nên việc ghi cũng sẽ bị hủy.
- Loại bỏ
$b6
sẽ làm cho phần còn lại giải mã làld ($1020), ix
và tiến hành như trên.
- Loại bỏ
$21
sẽ làm cho bộ giải mã ăn $20
, kích hoạt djnz
hành vi.
Lưu ý rằng việc sử dụng or a, (ix+*)
tiết kiệm hai byte ld a, (**) / and a / and a
nhờ kiểm tra tích hợp cho số không.
Bây giờ chúng ta cần quyết định bản sao nào trong hai bản tải trọng được thực thi:
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
Hai bản sao được phân tách bằng một nop, vì một bước nhảy tương đối được sử dụng để chọn giữa chúng và bức xạ có thể đã thay đổi chương trình theo cách làm cho bước nhảy bỏ qua byte đầu tiên sau đích đến. Ngoài ra, nop được mã hóa thành số 0, giúp dễ dàng phát hiện các byte bị dịch chuyển. Lưu ý rằng việc tải trọng được chọn không thành vấn đề nếu bản thân công tắc bị hỏng, vì sau đó cả hai bản sao đều an toàn. Mặc dù vậy, hãy đảm bảo rằng nó sẽ không nhảy vào bộ nhớ chưa được khởi tạo:
- Xóa
$dd
sẽ làm cho hai byte tiếp theo giải mã thànhor (hl) / dec d
. Clobbers D. Không có vấn đề lớn.
- Xóa
$b6
sẽ tạo ra một mã hóa dài hơn không có giấy tờ cho dec d
. Giống như trên.
- Việc xóa
$15
sẽ đọc $28
thay vào đó là phần bù và việc thực thi sẽ được tiến hành tại $0c
, như bên dưới.
- Khi
$28
biến mất, $0c
được giải mã là inc c
. Tải trọng không quan tâm c
.
- Xóa
$0c
- đó là những gì nop dành cho. Mặt khác, byte đầu tiên của tải trọng sẽ được đọc là phần bù nhảy và chương trình sẽ nhảy vào bộ nhớ chưa được khởi tạo.
Bản thân trọng tải khá đơn giản. Tôi nghĩ rằng kích thước nhỏ của chuỗi làm cho cách tiếp cận này nhỏ hơn một vòng lặp và việc tạo ra vị trí độc lập theo cách này sẽ dễ dàng hơn. Các e
trong beep
lặp đi lặp lại, vì vậy tôi có thể cạo một ld a
. Ngoài ra, bởi vì tất cả bộ nhớ giữa $0038
và $8000
được zeroed, tôi có thể lọt qua nó và sử dụng một ngắn hơn rst
biến thể của call
hướng dẫn, mà chỉ hoạt động cho $0
, $8
, $10
và như vậy, lên đến $38
.
Phương pháp cũ hơn
64 byte
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 byte
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 byte
Điều này có một lời giải thích trong lịch sử chỉnh sửa, nhưng nó không quá khác biệt.
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
Điều gì xảy ra nếu: bất kỳ đầu ra không trống nào cũng tốt thay vì tiếng bíp
1 byte
v
halt
Là chương trình bình thường, nhưng nếu bức xạ loại bỏ nó, thì bộ nhớ sẽ chứa đầy số 0, $8000
thực hiện vô số lần, in rất nhiều byte rỗng.