अपठनीय , 2199 2145 2134 2104 2087 2084 बाइट्स
दोनों का समर्थन करता है k
/ j
साथ ही साथ▲
/▼
सिंटैक्स ।
अच्छी अपठनीय परंपरा में, यहां कार्यक्रम आनुपातिक और दोहरे उद्धरण चिह्नों के बीच अंतर को आगे बढ़ाने के लिए आनुपातिक फ़ॉन्ट में स्वरूपित है:
' "" "" "" "" "" "" "" "" "'" " '" "'" " '" "'" "" ' "" "" "'" "" "" " ' "" ' ""' "" ' ""' "" "" " '" "" "" "'" "" "" " '" "" "" "" "" ""' "" ' " " '" "" "" "" "" "" "" "" "" "'" "" "" "" "" "" "" "" "" "" "" "' "" "" "" "" "" "" ""' "" ' ""' "" ' ""' "" ' "" "'" " '" "" "" "" "" ' ""' "" ' ""' "" ' "" "'" "" "" "" "" ' "" "" "" "" "" "'" " '" "'" " '" " '" ""' "" "" "" "" "" "" "" "" " '" "'" " '" "'" "" ' "" "" "" "" "" '" "'" " '" "'" " '" "'" "" ' "" "" "" "" "'" "" "" "" "" ' ""' "" ' "" ' ""' "" "" "" "" "" "" "" "" "" "" ' ""' "" ' ""' "" ' "" "'" " '" "' "" "" "" "" " '" ""' "" "" "" "" " '" "" "" "" "" "'" " '" "" "" ""'"" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" " '" "" ' "" "" "" "" "'" " '" "" "" "" "" "'" "" "" "" "" ' ""' "" ' ""' "" " "" "" "" " '" "" ""' "" ' "" "'" " '" "" "" "" "" "" "" "" "" ""' ""' "" ' ""' "" ' ""' "" " '" ""' "" ' ""' "" "" "" "" " '" ""' "" "" " "" "" "" "" "" "" "" ' "" "" "" "" "'" " '" "'" "" "" "" "" " '" "" "" "" "" "" ' ""' "" ' ""' "" "" "" "" "" ' "" "" "'" " '" ""' "" ' """ '" "" "" "" "" "" "" "" "" "'" " '" "'" " '" "'" "" ' ""' "" ' "" "'" "" ' "" "" "'" "" "" " '" "'" " '" "'" " '" ""' "" "" "" "" "" "" "" " '" " '" "'" " '" "'" "" ' "" "" "" "" "" "" "" "" "" "" "" "" ""' ""' ""' "" "" "" "" " '" "'" " '" "'" "" ' ""' "" "" "" "" " '" "'" " '" " " '" ""' "" "" "" "" ' ""' "" " '" "'" "" "" "" "" ' ""' "" " '" "" "" " ' ""' "" "" "" "" "" "" "" "" "" ' ""' "" "" "" "" "" "" "" ' "" "'"" "" "" "" "" "" "" "" "" ' "" "" "" "" "" "" ""' "" ' ""' "" ' "" " ' "" "" "" "" "" "" "" "" "'" " '" "'" "" ' "" "" "" "" "'" "" "" "" ' " " '" "'" "" ' "" "" "" ""' "" ' "" "'" "" "" "" "" "" "" "" "" ' ""' "" "" ""' "" "" "" "" ' "" "'" " '" "" "" "" ""' "" " '" "" "" "" " ' "" "" "" "" "" "" "" "" ""' "" ' "" "" "" "" "'" "" ' "" "" "'" "" " "" "" "" "" "" ' ""' "" ' ""' "" " '" "'" "" "" "" "" ' ""' "" ' "" "' "" "" "" "" ""' "" ' "" "'" "" "" "" "" "" "" "" ' ""' "" "" "" "" " ' ""' "" ' "" "'" " '" "" "" "" ""' "" ' "" "'" "" "" ' "" "" "" "" "" " "" "" " '" ""' "" ' "" "" "" "" "'" "" ' "" "" "" "" ""' "" " '" "'"" "" "" "" "" "" "" "" "" ' "" "" "'" "" "" "" "" "" "" "" "" "" "" " '" ""' "" "" "" "" "" "" "" "" "" "" "" "" "" ' "" "" "" "" "" "" " ' "" "'" " '" "" "" "" "" "" "" "" ""' "" "" " '" "'" " '" "" "" "'"" ' ""' "" "" "" "" "" "" "" "" "" "" ' ""' "" " '" "" "" "" "" "" " '" "" "" "'" " '" ""' "" ' ""' "" ' ""' "" ' "" "" ""' "" " '" "'" " '" " ' ""' "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" '" "" "" "" "" "" "" "'" "" "" "" "" "" ' "" "" "" "" "" "" "" ""' " "" "" "" "" "" "" "" "" " '"' "" "" "" "" "" "" "" " '" "'" "" "" " '" "" ' ""' "" ' "" "" "" "" ""' "" "" "" "" "" "" "" " '" "'" "" "" "" '" ""' "" ' ""' "" ' ""' "" ' ""' "" ' ""' "" ' ""' "" ' ""' "" ' ""' "" ' ""' "" ' ""' "" ' ""' "" ' ""' "" "" "" " '" "'" "" "" "" "" "" "" "" "" ' "" "" "" "" "'" "" "" "" "" "" ' ""' "" ' "" "" "" "" ""' " '" """ "" " '" "'" ""
यह एक अद्भुत चुनौती थी। पोस्ट करने के लिए धन्यवाद!
व्याख्या
यह जानने के लिए कि अपठनीय क्या कर सकता है और क्या नहीं कर सकता, दोनों दिशाओं में एक अनंत टेप के साथ ब्रेनफक की कल्पना करें, लेकिन एक समय में एक सेल को चलाने वाले मेमोरी पॉइंटर के बजाय, आप किसी भी मेमोरी सेल को एक पॉइंटर को डेरेफेर करके एक्सेस कर सकते हैं। इस समाधान में यह काफी काम आता है, हालांकि अन्य अंकगणितीय संचालन - जिसमें मोडुलो भी शामिल है - हाथ से किया जाना है।
यहाँ निर्देशक की टिप्पणी के साथ छद्मकोश के रूप में कार्यक्रम है:
// Initialize memory pointer. Why 5 will be explained at the very end!
ptr = 5
// FIRST PASS:
// Read all characters from stdin, store them in memory, and also keep track of the
// current line number at each character.
// We need the +1 here so that EOF, which is -1, ends the loop. We increment ptr by 2
// because we use two memory cells for each input character: one contains the actual
// character (which we store here); the other will contain the line number at which the
// character occurs (updated at the end of this loop body).
while ch = (*(ptr += 2) = read) + 1:
// At this point, ch will be one more than the actual value.
// However, the most code-economical way for the following loop is to
// decrement inside the while condition. This way we get one fewer
// iteration than the value of ch. Thus, the +1 comes in handy.
// We are now going to calculate modulo 4 and 5. Why? Because
// the mod 4 and 5 values of the desired input characters are:
//
// ch %5 %4
// ^ 1
// v 2
// k 3
// j 4
// ▲ 0 2
// ▼ 0 0
//
// As you can see, %5 allows us to differentiate all of them except ▲/▼,
// so we use %4 to differentiate between those two.
mod4 = 0 // read Update 2 to find out why mod5 = 0 is missing
while --ch:
mod5 = mod5 ? mod5 + 1 : -4
mod4 = mod4 ? mod4 + 1 : -3
// At the end of this loop, the value of mod5 is ch % 5, except that it
// uses negative numbers: -4 instead of 1, -3 instead of 2, etc. up to 0.
// Similarly, mod4 is ch % 4 with negative numbers.
// How many lines do we need to go up or down?
// We deliberately store a value 1 higher here, which serves two purposes.
// One, as already stated, while loops are shorter in code if the decrement
// happens inside the while condition. Secondly, the number 1 ('""") is
// much shorter than 0 ('""""""""'""").
up = (mod5 ? mod5+1 ? mod5+3 ? 1 : 3 : 2 : mod4 ? 3 : 1)
dn = (mod5 ? mod5+2 ? mod5+4 ? 1 : 3 : 2 : mod4 ? 1 : 3)
// As an aside, here’s the reason I made the modulos negative. The -1 instruction
// is much longer than the +1 instruction. In the above while loop, we only have
// two negative numbers (-3 and -4). If they were positive, then the conditions in
// the above ternaries, such as mod5+3, would have to be mod5-3 etc. instead. There
// are many more of those, so the code would be longer.
// Update the line numbers. The variables updated here are:
// curLine = current line number (initially 0)
// minLine = smallest linenum so far, relative to curLine (always non-positive)
// maxLine = highest linenum so far, relative to curLine (always non-negative)
// This way, we will know the vertical extent of our foray at the end.
while --up:
curLine--
minLine ? minLine++ : no-op
maxLine++
while --dn:
curLine++
minLine--
maxLine ? maxLine-- : no-op
// Store the current line number in memory, but +1 (for a later while loop)
*(ptr + 1) = curLine + 1
// At the end of this, minLine and maxLine are still relative to curLine.
// The real minimum line number is curLine + minLine.
// The real maximum line number is curLine + maxLine.
// The total number of lines to output is maxLine - minLine.
// Calculate the number of lines (into maxLine) and the real minimum
// line number (into curLine) in a single loop. Note that maxLine is
// now off by 1 because it started at 0 and thus the very line in which
// everything began was never counted.
while (++minLine) - 1:
curLine--
maxLine++
// Make all the row numbers in memory positive by adding curLine to all of them.
while (++curLine) - 1:
ptr2 = ptr + 1
while (ptr2 -= 2) - 2: // Why -2? Read until end!
*ptr2++
// Finally, output line by line. At each line, we go through the memory, output the
// characters whose the line number is 0, and decrement that line number. This way,
// characters “come into view” in each line by passing across the line number 0.
while (--maxLine) + 2: // +2 because maxLine is off by 1
ptr3 = 5
while (ptr -= 2) - 5:
print (*((ptr3 += 2) + 1) = *(ptr3 + 1) - 1) ? 32 : *ptr3 // 32 = space
ptr = ptr3 + 2
print 10 // newline
कार्यक्रम तर्क के लिए इतना। अब हमें इसे बिना पढ़े अनुवाद करने की आवश्यकता है और कुछ और दिलचस्प गोल्फिंग ट्रिक्स का उपयोग करना होगा।
वेरिएबल्स को हमेशा संख्यात्मक रूप से अपठनीय (जैसे a = 1
कुछ हो जाता है *(1) = 1
) में विभाजित किया जाता है । कुछ संख्यात्मक शाब्दिक दूसरों की तुलना में लंबे हैं; सबसे कम 1 है, 2 से पीछा किया जाता है, आदि यह दिखाने के लिए कि नकारात्मक संख्या कितनी लंबी है, यहां संख्या -1 से 7 है:
-1 '""""""""'""""""""'""" 22
0 '""""""""'""" 13
1 '""" 4
2 '""'""" 7
3 '""'""'""" 10
4 '""'""'""'""" 13
5 '""'""'""'""'""" 16
6 '""'""'""'""'""'""" 19
7 '""'""'""'""'""'""'""" 22
स्पष्ट रूप से, हम उस चर # 1 को आवंटित करना चाहते हैं जो सबसे अधिक बार होता है जो कोड में । पहली बार लूप में, यह निश्चित रूप से है mod5
, जो 10 बार आता है। लेकिन mod5
पहले लूप के बाद हमें अब और ज़रूरत नहीं है, इसलिए हम उसी मेमोरी लोकेशन को दूसरे वेरिएबल्स पर फिर से आबंटित कर सकते हैं जो हम बाद में इस्तेमाल करते हैं। ये हैं ptr2
और ptr3
। अब चर को कुल 21 बार संदर्भित किया जाता है। (यदि आप स्वयं घटनाओं की संख्या की गणना करने की कोशिश कर रहे हैं, तो a++
दो बार कुछ गणना करना याद रखें , एक बार मूल्य प्राप्त करने के लिए और एक बार इसे सेट करने के लिए।)
केवल एक अन्य चर है जिसे हम फिर से उपयोग कर सकते हैं; हमने modulo मानों की गणना के बाद,ch
अब जरूरत नहीं है। up
और dn
कई बार एक ही संख्या में आते हैं, इसलिए या तो ठीक है। के ch
साथ विलय करते हैं up
।
यह कुल 8 अद्वितीय चर छोड़ता है। हम चर 0 से 7 आवंटित कर सकते हैं और फिर मेमोरी ब्लॉक (अक्षर और लाइन नंबर से युक्त) को 8 पर शुरू कर सकते हैं। लेकिन! चूंकि length1 के रूप में कोड में 7 की लंबाई है, इसलिए हम वैरिएबल the1 से 6 का उपयोग कर सकते हैं और मेमोरी ब्लॉक को 7. पर शुरू कर सकते हैं। इस तरह, मेमोरी ब्लॉक की शुरुआत की स्थिति का हर संदर्भ कोड में थोड़ा छोटा है! यह हमें निम्नलिखित कार्य के साथ छोड़ देता है:
-1 dn
0 ← ptr or minLine?
1 mod5, ptr2, ptr3
2 curLine
3 maxLine
4 ← ptr or minLine?
5 ch, up
6 mod4
7... [data block]
अभी व यह बहुत ऊपर से इनिशियलाइज़ेशन की व्याख्या करता है: यह 5 है क्योंकि यह 7 (मेमोरी ब्लॉक की शुरुआत) माइनस 2 (पहली स्थिति में अनिवार्य वेतन वृद्धि) है। वही पिछले लूप में 5 की अन्य दो घटनाओं के लिए जाता है।
ध्यान दें कि, 0 और 4 कोड में समान लंबाई हैं, ptr
औरminLine
उन्हें किसी भी तरह से आवंटित किया जा सकता है। ... या वे कर सकते थे?
लूप के दौरान दूसरे-आखिरी में रहस्यमय 2 के बारे में क्या?यह एक 6 नहीं होना चाहिए? हम केवल डेटा ब्लॉक में संख्याओं को कम करना चाहते हैं, है ना? एक बार जब हम 6 तक पहुँच जाते हैं, तो हम डेटा ब्लॉक से बाहर हो जाते हैं और हमें रुक जाना चाहिए! यह एक बफर अतिप्रवाह बग त्रुटि विफलता सुरक्षा भेद्यता होगी!
ठीक है, सोचें कि अगर हम नहीं रुकते हैं तो क्या होगा। हम 6 और 4 चर चर करते हैं mod4
। यह केवल पहली बार लूप में उपयोग किया जाता है और अब इसकी आवश्यकता नहीं है, इसलिए कोई नुकसान नहीं हुआ है। चर 4 के बारे में क्या? आपको क्या लगता है, चर 4 होना ptr
चाहिए या यह होना चाहिए minLine
? यह सही है, minLine
अब इस बिंदु पर भी उपयोग नहीं किया जाता है! इस प्रकार, चर # 4 हैminLine
और हम सुरक्षित रूप से इसे घटा सकते हैं और कोई नुकसान नहीं कर सकते हैं!
अद्यतन 1! 2199 से 2145 तक बाइट्स को यह महसूस करके गोल्फिंग किया जाता है कि dn
इसके साथ विलय भी किया जा सकता है mod5
, भले ही इसके mod5
लिए अभी भी मूल्य की गणना में उपयोग किया जाता है dn
! नया चर असाइनमेंट अब है:
0 ptr
1 mod5, dn, ptr2, ptr3
2 curLine
3 maxLine
4 minLine
5 ch, up
6 mod4
7... [data block]
अद्यतन 2! 2145 से 2134 बाइट्स के लिए गोल्फ को साकार करने के बाद, चूंकि mod5
अब एक ही चर में है dn
, जिसे कुछ समय में 0 पर गिना जाता है, mod5
अब इसे स्पष्ट रूप से 0 से शुरू करने की आवश्यकता नहीं है।
अद्यतन 3! दो चीजों को साकार करके 2134 से 2104 बाइट तक पहुंचा। सबसे पहले, हालांकि "नकारात्मक मोडुलो" विचार इसके लिए लायक था mod5
, वही तर्क लागू नहीं होता है mod4
क्योंकि हम कभी भी mod4+2
आदि के खिलाफ परीक्षण नहीं करते हैं , इसलिए हमें 2110 बाइट्स में बदलना mod4 ? mod4+1 : -3
चाहिए mod4 ? mod4-1 : 3
। दूसरा, चूँकि mod4
हमेशा 0 या 2 होता है, हम mod4
0 के बजाय 2 को इनिशियलाइज़ कर सकते हैं और दो टर्नरीज़ ( mod4 ? 3 : 1
बदले में mod4 ? 1 : 3
) को उल्टा कर सकते हैं ।
अद्यतन 4! 2104 से 2087 बाइट्स तक यह महसूस करते हुए कि मॉड्युलो मानों की गणना करने वाला लूप हमेशा कम से कम एक बार चलता है, और इस तरह के मामले में, अपठनीय आपको अंतिम कथन के मूल्य को दूसरी अभिव्यक्ति में फिर से उपयोग करने की अनुमति देता है। इस प्रकार, हमारे बजाय while --ch: [...]; up = (mod5 ? mod5+1 ? [...]
अब up = ((while --ch: [...]) ? mod5+1 ? [...]
(और अंदर है कि लूप करते समय, हम mod4
पहले गणना करते हैं , इसलिए यह mod5
अंतिम कथन है)।
अद्यतन 5! २० from that से २० by४ बाइट्स तक यह महसूस करते हुए कि मुझे स्थिरांक 32
और 10
(स्पेस और न्यूलाइन) लिखने के बजाय , मैं १० नंबर (अब अप्रयुक्त) चर # २ में स्टोर कर सकता हूं (चलो इसे कॉल करें ten
)। इसके बजाय ptr3 = 5
हम लिखते हैं ten = (ptr3 = 5) + 5
, फिर 32
बन जाता है ten+22
और print 10
बन जाता है print ten
।