অপঠনযোগ্য , 2199 2145 2134 2104 2087 2084 বাইট
উভয় সমর্থন k
/ j
সেইসাথে▲
/ ▼
সিনট্যাক্স ।
ভাল অপঠনযোগ্য traditionতিহ্যে, অ্যাপোস্ট্রোফস এবং ডাবল-কোটের মধ্যে পার্থক্য নিরস্ত করার জন্য এখানে প্রোগ্রামটি আনুপাতিক ফন্টে ফর্ম্যাট করা হয়েছে:
' "" "" ""' "" "" "" "" ' "" "'" " '" "'" " '" "'" "" ' "" "" "'" "" "" " ' "" ' ""' "" ' ""' "" " '" "'" "" "" " '" "" "" "'" "" "" "" " '" ""' "" ' " " '" "" "" ""' "" "" "" "" ' "" "'" "" "" "" "" " '" "" "'" "" " '" "" "' "" ""' "" "" ' "" "" ""' "" ' ""' "" ' ""' "" ' "" "'" " '" ""' "" "" "" ' ""' "" ' ""' "" ' "" "'" "" "" "" "" ' "" "" "'" "" "" " '" "'" " '" "'" " '" ""' "" "" "" "" ' "" "" "" "'" " '" "'" " '" "'" "" ' "" ""' "" "" "" '" "'" " '" "'" " '" "'" "" ' "" "" "" "" "'" "" "" "" ' ""' "" ' ""' "" ' ""' "" " '" "" "" "" "'" "" "" "" ' ""' "" ' ""' "" ' ""' "" " '" "'" " ' "" " '" "" "" "'" "" ' "" "" "" "" "'" "" "" "" ' "" "'" " '" "" "" ""'"" " '" "" "" "" "'" "" "" "" " '" "" "" "" "'" "" "" "" " '" "" "" "" "'" "" ' "" "" "" "" "'" " '" "" "" ""' "" " '" "" "" "" ""' "" ' ""' "" ' "" " "" "" ' "" "'" "" ' ""' "" ' "" "'" " '" ""' "" "" "" "" " '" "" "" ""' ""' "" ' ""' "" ' ""' "" " '" ""' "" ' ""' "" " '" "" "" "'" "" ' "" "" " "" "" ' "" "" "" "'" "" ' "" "" "" "" "'" " '" "'" "" "" "" ' "" "'" "" "" "" "" ' ""' "" ' ""' "" ' "" "" "" "'" "" ' "" "'" " '" "'" "" ' ""' """ '" "" "" "" ""' "" "" "" " '" "'" " '" "'" " '" "'" "" ' ""' "" ' "" "'" "" ' "" "" "'" "" "" " '" "'" " '" "'" " '" ""' "" "" "" "" ' "" "" "" "'" " '" "'" " '" "'" "" ' "" ""' "" "" ' "" "" "" "" "'" "" "" "" ' ""' ""' ""' "" " '" "" "" "'" " '" "'" " '" ""' "" ' "" "" "" "'" " '" "'" " '" " " '" ""' "" "" "" ' ""' "" ' "" "'" " '" "" "" ""' "" ' ""' "" " '" "" "" " ' ""' "" " '" "" "" "" "'" "" "" "" ' ""' "" " '" "" ""' "" "" "" ' "" "'"" "" "" "" ' "" "" "" "'" "" ' "" ""' "" "" ' "" "" ""' "" ' ""' "" ' "" " ' "" "" "" ""' "" "" "" " '" "'" " '" "'" "" ' "" "" "" "" "'" "" "" "" ' " " '" "'" "" ' "" "" ""' "" ' ""' "" " '" "" "" "" "'" "" "" "" ' ""' ""' "" "'" "" ' "" "" ""' "" ' "" "'" " '" "" "" ""' "" ' "" "'" "" "" " '" " ' "" "" "" "'" "" "" "" " '" ""' "" ' "" "" "" "'" " '" ""' "" "" " '" "" " "" "" ' "" "" ""' "" ' ""' "" ' "" "'" " '" "" "" ""' "" ' ""' "" ' "" "' "" ""' "" "" "" ' ""' "" " '" "" "" "" "'" "" "" "" ' ""' "" " '" "" "" " ' ""' "" ' "" "'" " '" "" "" ""' "" ' ""' "" " '" "" ""' "" "" "" "" ' "" " "" " '" "'" "" ' ""' "" "" "" " '" "'" "" ' "" ""' "" "" "" ' "" "'" " '"" "" "" " '" "" "" "" "'" "" ' "" "" "'" "" "" "" " '" "" "" "" "'" "" "" " '" ""' "" "" "" "" ' "" "" "" ""' "" "" "" " '" ""' "" "" "" ' "" "" "" " ' "" "'" " '" "" "" ""' "" "" "" " '" ""' "" "" " '" "'" " '" "" "" "'"" ' ""' "" " '" "" "" "" "'" "" "" "" ' ""' "" ' "" "'" "" " '" "" "'" "" " '" "" "" "'" " '" ""' "" ' ""' "" ' ""' "" ' "" "" ""' "" " '" "'" " '" " ' ""' "" " '" "" ""' "" "" "" "" ' "" "" "" ""' "" "" "" "" ' "" "" "" "" '" "" "" "" "'" "" "" " '" "" "" "" "'" "" ' "" "" "" ""' "" "" "" "" ' " "" "" "" ' "" "" "" ""' "" " '"' "" "" "" "" " '" "" "" "'" " '" "" "" "'" "" ' ""' "" ' "" "" "" "'" "" ' "" "" "" ""' "" "" "" " '" "'" "" "" "" '" ""' "" ' ""' "" ' ""' "" ' ""' "" ' ""' "" ' ""' "" ' ""' "" ' ""' "" ' ""' "" ' ""' "" ' ""' "" ' ""' "" "" "" " '" "'" "" ' "" "" "" "'" "" "" "" ' "" "'" "" "" " '" "" "" "" "'" "" ' ""' "" ' "" "" "" "'" "" ' "'" """ "" " '" "'" ""
এটি একটি আশ্চর্যজনক চ্যালেঞ্জ ছিল। পোস্ট করার জন্য আপনাকে ধন্যবাদ!
ব্যাখ্যা
অপঠনযোগ্য যা করতে পারে এবং কী করতে পারে না তার অনুভূতি পেতে ব্রেইনফাককে দু'দিকেই অসীম টেপ দিয়ে কল্পনা করুন, তবে মেমোরি পয়েন্টারটির পরিবর্তে একবারে একটি কক্ষ সরিয়ে আপনি কোনও পয়েন্টারকে ডিফারেন্স করে কোনও মেমরি সেল অ্যাক্সেস করতে পারবেন। এটি এই সমাধানটিতে যথেষ্ট কার্যকর, যদিও অন্যান্য গাণিতিক অপারেশনগুলি - মডিউলো সহ - হাতে হাতে করতে হবে।
পরিচালকের ভাষ্য সহ সিউডোকোড হিসাবে প্রোগ্রামটি এখানে:
// 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, ইত্যাদি negativeণাত্মক সংখ্যা কত দীর্ঘ রয়েছে তা দেখানোর জন্য এখানে -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++
একবার মূল্য হিসাবে একবার এবং একবার সেট করার জন্য দু'বারের না))
আর একটি মাত্র পরিবর্তনশীল রয়েছে যা আমরা আবার ব্যবহার করতে পারি; আমরা মডুলোর মান গণনা করার পরে, ch
আর প্রয়োজন হয় না। up
এবং dn
একই সংখ্যক বার আসুন, তাই হয় ঠিক আছে। আসুন একত্রীকরণ ch
সঙ্গে up
।
এটি মোট 8 অনন্য ভেরিয়েবল ছেড়ে যায়। আমরা 0 থেকে 7 ভেরিয়েবল বরাদ্দ করতে পারি এবং তারপরে 8 এ মেমরি ব্লক (অক্ষর এবং রেখা সংখ্যা সহ) শুরু করতে পারি But তবে! যেহেতু code১ কোডের সমান দৈর্ঘ্য −1, আমরা পাশাপাশি ভেরিয়েবলগুলি to1 থেকে 6 ব্যবহার করতে পারি এবং মেমরি ব্লকটি 7 এ শুরু করতে পারি way এইভাবে, মেমরি ব্লকের প্রারম্ভিক অবস্থানের প্রতিটি রেফারেন্স কোডে কিছুটা ছোট হয়! এটি আমাদের নিম্নোক্ত কার্যাদি সহ ছেড়ে দেয়:
-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. চলক 6 হ্রাস mod4
। এটি কেবল প্রথমদিকে ব্যবহৃত হয়েছিল যখন লুপ এবং এখানে আর প্রয়োজন হয় না, সুতরাং কোনও ক্ষতি করা হয়নি। চলক 4 সম্পর্কে কী? আপনার কী মনে হয়, ভেরিয়েবল 4 হওয়া ptr
উচিত বা হওয়া উচিত minLine
? এটা ঠিক, minLine
এখন আর এই সময়ে ব্যবহার করা হয় না! সুতরাং, পরিবর্তনশীল # 4 minLine
এবং আমরা নিরাপদে এটি হ্রাস করতে পারি এবং কোনও ক্ষতি করতে পারি না!
আপডেট 1! নিরূপক যে 2145 বাইট 2199 থেকে Golfed 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
, যা কিছুক্ষণের মধ্যে লুপ হিসাবে গণনা করা হয়, mod5
এখন আর স্পষ্টভাবে 0 তে আরম্ভ করার দরকার নেই।
আপডেট 3! দুটি জিনিস বুঝতে পেরে 2134 থেকে 2104 বাইট গল্ফ করা হয়েছে। প্রথমত, যদিও "নেতিবাচক মডিউল" ধারণা জন্য এটি ছিল মূল্য mod5
, একই যুক্তি প্রযোজ্য নয় mod4
আমরা কখনোই বিরুদ্ধে পরীক্ষা কারণ mod4+2
ইত্যাদি অতএব, পরিবর্তন mod4 ? mod4+1 : -3
করার জন্য mod4 ? mod4-1 : 3
2110 বাইট আমাদের লাগে। দ্বিতীয়ত, যেহেতু 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! 2087 থেকে 2084 বাইটে গল্ফ করে বুঝতে পেরেছি যে ধ্রুবকগুলি 32
এবং 10
(স্পেস এবং নিউলাইন) লেখার পরিবর্তে , আমি 10 নম্বরটি (বর্তমানে অব্যবহৃত) ভেরিয়েবল # 2 এ সঞ্চয় করতে পারি (আসুন এটি কল করুন ten
)। বদলে ptr3 = 5
আমরা লিখতে ten = (ptr3 = 5) + 5
, তারপর 32
হয়ে ওঠে ten+22
এবং print 10
হয়ে print ten
।