Z80Golf , 53 36 34 बाइट्स
-16 बाइट्स धन्यवाद @Lynn
-2 बाइट थैंक्यू @Neil
चूँकि यह सिर्फ Z80 मशीन कोड है, इसलिए इस में बहुत सारे xxd -r
unprintables हैं, इसलिए एक-के- बाद एक विषमताएं हैं:
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
इसे ऑनलाइन आज़माएं! (पायथन में संपूर्ण परीक्षक)
व्याख्या
z80golf अराजकता गोल्फ के काल्पनिक Z80 मशीन, जहां call $8000
एक putchar है, call $8003
एक getchar है, halt
दुभाषिया से बाहर निकलें बनाता है, अपने कार्यक्रम पर रखा गया है $0000
, और सभी अन्य स्मृति शून्य से भर जाता है। असेंबली में रेडिएशन प्रूफ बनाना काफी कठिन है, लेकिन एक पीढ़ी-दर-पीढ़ी उपयोगी तकनीक एक-एक बेतुके निर्देशों का उपयोग कर रही है। उदाहरण के लिए,
or c ; b1 ; a = a | c
सिर्फ एक बाइट है, और a | c | c == a | c
, इसलिए इसे केवल निर्देश दोहराकर विकिरण-सबूत बनाया जा सकता है। Z80 पर, एक 8-बिट तत्काल लोड दो बाइट्स है (जहां तत्काल दूसरी बाइट में है), इसलिए आप कुछ मानों को रजिस्टर में भी मज़बूती से लोड कर सकते हैं। यह वही है जो मैंने मूल रूप से कार्यक्रम की शुरुआत में किया था, इसलिए आप उत्तर के निचले भाग में संग्रहीत किए गए लंबे वेरिएंट का विश्लेषण कर सकते हैं, लेकिन तब मुझे महसूस हुआ कि एक सरल तरीका है।
कार्यक्रम में दो स्वतंत्र पेलोड होते हैं, जहां उनमें से एक विकिरण से क्षतिग्रस्त हो सकता था। मैं जांच करता हूं कि क्या एक बाइट को हटा दिया गया था, और क्या हटाए गए बाइट पेलोड की दूसरी प्रति से पहले था, कुछ निरपेक्ष स्मृति पतों के मूल्यों की जांच करके।
अगर कोई विकिरण नहीं देखा गया था, तो सबसे पहले हमें बाहर निकलने की जरूरत है:
or a, (ix+endbyte) ; dd b6 21 ; a |= memory[ix+0x0021]
jr nz, midbyte ; 20 10 ; jump to a halt instruction if not zero
यदि किसी भी बाइट को हटा दिया गया था, तो सभी बाइट्स शिफ्ट $0020
हो जाएंगे और अंतिम होगा 76
, इसलिए $0021
एक शून्य होगा। वस्तुतः कोई अतिरेक नहीं होने पर भी हम कार्यक्रम की शुरुआत को विकीर्ण कर सकते हैं:
- यदि जंप ऑफसेट
$10
हटा दिया जाता है, तो विकिरण सही ढंग से पता लगाया जाएगा, कूद नहीं लिया जाएगा और ऑफसेट कोई फर्क नहीं पड़ेगा। अगले निर्देश के पहले बाइट का उपभोग किया जाएगा, लेकिन चूंकि यह बाइट हटाने के लिए प्रतिरोधी होने के लिए डिज़ाइन किया गया है, इसलिए यह कोई फर्क नहीं पड़ता।
- यदि जम्प ओपकोड
$20
को हटा दिया जाता है, तो जंप ऑफ़सेट के $10
रूप में डिकोड हो जाएगा djnz $ffe4
(अगले निर्देश बाइट का उपयोग ऑफ़सेट के रूप में - ऊपर देखें), जो कि लूप इंस्ट्रक्शन है - डीक्रिमेंट बी, और परिणाम शून्य न होने पर कूदें। क्योंकि ffe4-ffff
शून्य ( nop
एस) से भरा है , और कार्यक्रम काउंटर चारों ओर घूमता है, यह कार्यक्रम की शुरुआत को 256 बार चलाएगा, और फिर अंत में जारी रहेगा। मैं इस काम से चकित हूं।
$dd
वसीयत को हटाने से स्निपेट के बाकी डिकोड जैसे हो जाएंगे or (hl) / ld ($1020), hl
, और फिर कार्यक्रम के अगले भाग में स्लाइड करें। or
किसी भी महत्वपूर्ण रजिस्टरों में परिवर्तन नहीं होगा, और क्योंकि HL इस बिंदु पर शून्य है, लिखने भी रद्द हो जाएगा।
$b6
वसीयत को हटाने से बाकी डिकोड हो जाएगा ld ($1020), ix
और ऊपर के रूप में आगे बढ़ेगा।
$21
विल को हटाने से डिकोडर को खा जाएगा $20
, djnz
व्यवहार को ट्रिगर करेगा ।
ध्यान दें कि शून्य के लिए एकीकृत चेक के लिए धन्यवाद or a, (ix+*)
पर दो बाइट्स का उपयोग करना सहेजता ld a, (**) / and a / and a
है।
अब हमें यह तय करने की आवश्यकता है कि निष्पादित करने के लिए पेलोड की दो प्रतियों में से कौन सी है:
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
दो प्रतियों को एक एनओपी द्वारा अलग किया जाता है, क्योंकि एक रिश्तेदार कूद का उपयोग उनके बीच चयन करने के लिए किया जाता है, और विकिरण कार्यक्रम को इस तरह से स्थानांतरित कर सकता है जो गंतव्य के बाद पहले बाइट को छोड़ देगा। इसके अतिरिक्त, एनओपी को एक शून्य के रूप में एन्कोड किया गया है, जिससे शिफ्ट बाइट्स का पता लगाना आसान हो जाता है। ध्यान दें कि यदि स्विच स्वयं ही दूषित है, तो इससे कोई फर्क नहीं पड़ता कि कौन सा पेलोड चुना गया है, क्योंकि तब दोनों प्रतियां सुरक्षित हैं। चलो यह सुनिश्चित करते हैं कि यह एकतरफा स्मृति में नहीं जाएगा, हालांकि:
- हटाया जा रहा है
$dd
से अगले दो बाइट्स डिकोड हो जाएंगे or (hl) / dec d
। क्लोबर्स डी। कोई बड़ी बात नहीं है।
- हटाने के
$b6
लिए एक अनिर्दिष्ट अब एन्कोडिंग पैदा करेगाdec d
। ऊपर की तरह।
- हटाने
$15
के $28
बजाय ऑफसेट के रूप में पढ़ा जाएगा , और निष्पादन नीचे के रूप में आगे बढ़ेगा $0c
।
- जब
$28
गायब हो जाता है, के $0c
रूप में डिकोड किया जाता है inc c
। पेलोड की परवाह नहीं है c
।
- हटाना
$0c
- यही nop के लिए है। अन्यथा, पेलोड के पहले बाइट को जंप ऑफसेट के रूप में पढ़ा गया होगा, और यह कार्यक्रम एकतरफा मेमोरी में कूद जाएगा।
पेलोड अपने आप में बहुत सरल है। मुझे लगता है कि स्ट्रिंग का छोटा आकार इस दृष्टिकोण को लूप से छोटा बनाता है, और इस तरह से स्थिति-स्वतंत्र करना आसान है। e
में beep
दोहराता है, इसलिए मैं दूर एक दाढ़ी कर सकते हैं ld a
। इसके अलावा, क्योंकि बीच सभी स्मृति $0038
और $8000
ध्यान केंद्रित किया है, मैं इसे माध्यम से आते हैं और एक छोटी उपयोग कर सकते हैं rst
के संस्करण call
अनुदेश, जो केवल के लिए काम करता है $0
, $8
, $10
और इतने पर, अप करने के लिए $38
।
पुराना दृष्टिकोण
64 बाइट्स
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 बाइट्स
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 बाइट्स
यह संपादित इतिहास में एक व्याख्या है, लेकिन यह बहुत अलग नहीं है।
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
क्या होगा अगर: बीप के बजाय कोई भी गैर-खाली आउटपुट ठीक था
1 बाइट
v
halt
कार्यक्रम को सामान्य रूप से करें, लेकिन यदि विकिरण इसे हटा देता है, तो मेमोरी शून्य से भरी होगी, $8000
कई बार अनंत संख्या में निष्पादित होती है, बहुत सारे नल बाइट्स को प्रिंट करती है।