
مهمة مفتعلة أخرى للبرمجة غير الطبيعية في JavaScript . هذه المرة بمناسبة العام الجديد القادم 2019. آمل أن يكون من المثير للاهتمام أن تقرر مدى الاهتمام بالنسبة لي. أطلب فضولي تحت القط. كل الشمبانيا وكلها سعيدة!
المهام السابقة:
على مدار العام الماضي ، جمعت سانتا كلوز قائمة جيدة بأسماء المطورين العاديين وتخطط الآن لكتابة برنامج للتهنئة. التنسيق هو: happy new year, ${username}!
. ولكن إليك الحظ السيئ: تعطل لوحة المفاتيح ولا يسمح لك بإدخال العديد من الأحرف اللاتينية. بعد فحص العيب ، أبدت الجان ملاحظة مهمة أنه من بين Snowing day
الأخرى التي يمكنك إضافتها إلى Snowing day
. يمكن تحديد مصدر الإخراج حسب تقديرك.
لذلك ، عند الإدخال - بعض الصفيف من السلاسل غير الفارغة (لا يمكن أن يكون الاسم فارغًا). يجب كتابة برنامج باستخدام أحرف لاتينية فقط: S
و n
و o
و w
و i
و g
و d
و a
و y
(أي ما مجموعه 9 أحرف ، أحدها كبير). يجب أن يتحول البرنامج إلى الصفيف الذي تم تمريره وإخراج عبارة happy new year, ${username}!
لكل اسم happy new year, ${username}!
باستخدام نوع من مصدر الإخراج: alert ، console.log أو أي شيء يتبادر إلى الذهن. حسنًا ، سيكون من الجيد عدم تلويث السياق العالمي.
الحل المعتاد
إذا لم تخترع أي شيء ، فسيكون كل شيء بسيطًا جدًا:
function happy(users) { for (let i = 0; i !== users.length; i += 1) { console.log(`happy new year, ${users[i]}!`); } }
أو الأفضل من ذلك:
function happy(users) { users.forEach(user => console.log(`happy new year, ${user}!`)); }
نحن نستخدم مع مجموعة لدينا ، فليكن المستخدمين :
let users = ['John', 'Jack', 'James']; happy(users);
ولكن هنا يكون بعيد المنال: لاستخدام الأحرف المسموح بها فقط في تطبيق اللاتينية. حاول أن تتعامل معه بنفسك أولاً ، ثم انضم إلى المناقشة.
قرار ترفيهي
الصبر يمكن أن يرى الحل أدناه في JSFiddle الآن.
لحل المشكلة ، تحتاج إلى التخلص من اللاتينية الزائدة في ما يلي:
- وظيفة الكلمة الرئيسية في إعلان الوظيفة .
- الكلمة الأساسية let (أو var ) للتصريح عن المتغيرات.
- الكلمات الأساسية عند تنظيم حلقة لتكرارها على صفيف مرت.
- تشكيل نص الرسالة.
- استدعاء بعض وظيفة لإخراج النتيجة.
سوف تساعدنا وظائف السهم بسهولة في المشكلة الأولى:
(arr => el.forEach())(users);
لن ننتبه إلى أسماء المتغيرات في الوقت الحالي ، حيث يمكننا بسهولة إعادة تسميتها في النهاية.
نستخدم "الأسهم" مع IIFE أينما دعت الحاجة إلى وظيفة أو نتيجتها على الفور. بالإضافة إلى ذلك ، تسمح لك الوظائف بالتخلص من توجيهات السماح و var بطريقتين:
(param => )(value); ((param = value) => )();
في كلتا الحالتين ، نعلن متغير في معلمات الدالة. في الحالة الأولى فقط نمرر القيمة عند استدعاء الوظيفة ، وفي الحالة الثانية - نستخدم معلمة الوظيفة الافتراضية.
في الواقع ، تبدأ المشاكل في النقطة الثالثة . ليس لدينا عدد كافٍ من الأحرف للـ الكلاسيكية لـ ، والقيام ، أثناء الحلقات ، ولا لخيارات اجتياز خلال لـ .. في و .. من أجل ، ولا لأساليب الصفيف لكل ، الخريطة ، التصفية (حيث يمكنك تمرير رد الاتصال). ولكن يمكننا تنفيذ وظيفة التكرار لدينا على مجموعة:
function iterate(arr, consume) { function iter(i) { if (arr[i]) { consume(arr[i]); iter(++i); } } iter(0); }
نحن نعبر العناصر بشكل متكرر حتى يتحقق التحقق من الحالة الحالية. لماذا يمكننا الاعتماد على التحول المنطقي هنا؟ نظرًا لأن عنصر الصفيف الخاص بنا ليس سلسلة فارغة (إلا أنه يلف كاذب ) ، ولكن عندما نخرج من الصفيف خلال زيادة الفهرس ، فإننا نحصل على غير معرف (يتم تحويله إلى خطأ ).
نعيد كتابة الوظيفة باستخدام تعبيرات السهم:
let iterate = (arr, consume) => ( (iter = i => { if (arr[i]) { consume(arr[i]); iter(++i); } }) => iter(0) )();
لكن لا يمكننا استخدام if statement ، لأننا لا نملك الحرف f
. لكي نفي بوظيفتنا ، نحتاج إلى التخلص منها:
let iterate = (arr, consume) => ( (iter = i => arr[i] ? (consume(arr[i]), iter(++i)) : 0) => iter(0) )();
ساعدنا المشغل الثلاثي والقدرة على الجمع بين تعبيرين في واحد من خلال المشغل فاصلة في هذا. سوف نستخدم هذه الوظيفة في وقت لاحق في تخطيط الحل.
المشكلة الرابعة هي أننا في أي حال نحتاج إلى الحصول على سلسلة مع الأحرف المفقودة. من الواضح أننا سوف نستخدم الأرقام لتمثيل الشخصيات. هناك العديد من الخيارات:
- دالة String.fromCharCode تتوقع عدد الأعداد الصحيحة لإرجاع وإرجاع سلسلة تم إنشاؤها من تسلسل Unicode المحدد.
- يتيح
\uhhhh
تسلسل \uhhhh
إخراج أي حرف Unicode باستخدام الكود السداسي عشر المحدد. - التنسيق
&#dddd;
بالنسبة إلى أحرف html ، تسمح لك بعرض رمز في مستند الصفحة باستخدام الكود العشري المحدد. - تحتوي الدالة toString الخاصة بالكائن النموذج الأولي على معلمة جذرية إضافية - أساس نظام الأرقام.
- ربما هناك شيء آخر ...
يمكنك حفر نفسك في اتجاه الخيارات الثلاثة الأولى ، ويمكنك الآن التفكير في أسهل هذه المهمة: Number.prototype.toString . القيمة القصوى للمعلمة radix هي 36 (10 أرقام + 26 حرفًا لاتينيًا صغيرًا):
let symb = sn => (sn + 9).toString(36);
وبالتالي ، يمكننا الحصول على أي حرف لاتيني من خلال الرقم في الأبجدية ، بدءًا من 1. والقيد الوحيد هو أن جميع الأحرف صغيرة. نعم ، هذا يكفي بالنسبة لنا لعرض النص في الرسالة ، لكن لا يمكننا إضافة بعض الأساليب والوظائف (نفس لكل منها ).
ولكن من المبكر جدًا أن نفرح ، فأنت بحاجة أولاً إلى التخلص من toString في إدخال الوظيفة. أولاً ، ننتقل إلى الطريقة كما يلي:
let symb = sn => (sn + 9)['toString'](36);
إذا نظرت عن كثب ، toString
للسلسلة إلى السلسلة ، نحتاج فقط إلى حرفين: t
و r
: كل الباقي في كلمة Snowing
. الحصول عليها بسيط للغاية ، لأن ترتيبها يشير بالفعل إلى true
. باستخدام تحويلات الكتابة الضمنية ، يمكننا الحصول على هذه السلسلة والأحرف التي نحتاجها كما يلي:
!0+'';
نحقق وظيفة الحصول على أي خطاب لاتيني:
let symb = sn => (sn + 9)[(!0+'')[0] + 'oS' + (!0+'')[0] + (!0+'')[1] + 'ing'](36);
للحصول على كلمات من مجموعة من أرقام تسلسل الحروف باستخدام symb ، نستخدم الدالة Array.prototype.reduce القياسية:
[1,2,3].reduce((res, sn) => res += symb(sn), '');
نعم ، هذا لا يناسبنا. لكن في حلنا ، يمكننا أن نفعل شيئًا مشابهًا مع وظيفة التكرار :
let word = chars => (res => (iterate(chars, ch => res += symb(ch)), res))(''); word([1,2,3]);
يلاحظ الأشخاص المهتمون أننا طورنا وظيفة التكرار لمجموعة من السلاسل ، لكننا نستخدمها هنا بأرقام. هذا هو السبب في أن الفهرس الأولي للأبجدية لدينا هو 1 ، وليس 0. وإلا ، فإن دورة مرتجلة ستنتهي عندما تقابل 0 (حرف a
).
لسهولة تعيين الأحرف إلى أرقامها التسلسلية ، يمكنك الحصول على قاموس:
[...Array(26).keys()].reduce((map, i) => (map[symb(i + 1)] = i + 1, map), {});
لكن من الحكمة أن تفعل أبسط وأن تكتب وظيفة تحول الكلمة العكسي ككل:
let reword = str => str.split('').map(s => parseInt(s, 36) - 9); reword('happy');
نكمل وظيفة تشكيل الرسالة نفسها:
let message = name => word([8,1,16,16,25]) + ' ' + word([14,5,23]) + ' ' + word([25,5,1,18]) + ', ' + name + '!';
لم يتبق سوى القليل للغاية لمعالجة خاتمة المشكلة الخامسة . وحدة التحكم ، والتنبيه ، تأكيد ، موجه ، innerHTML ، document.write تتبادر إلى الذهن. ولكن لا يمكن الوصول إلى أي من الخيارات المدرجة مباشرة.
لقد حصلنا أيضًا على فرصة للحصول على أي كلمة باستخدام دالة الكلمة . هذا يعني أنه يمكننا استدعاء العديد من الوظائف من الكائنات عن طريق الوصول إليها من خلال الأقواس المربعة ، كما كان الحال مع toString .
نظرًا لأننا نستخدم وظائف السهم ، فإن هذا السياق يظل عالميًا (وليس هناك حاجة لإعادة توجيهه). في أي مكان ، يمكننا الوصول إلى العديد من وظائفها من خلال خط:
this[word([1,12,5,18,20])]('hello');
ولكن من أجل "الرسم" this
فإننا نفتقر مرة أخرى إلى الشخصيات. يمكننا استبدالها بـ Window.self ، ولكن مع الأسوأ من حيث الأبجدية المتوفرة. ومع ذلك ، يجدر الانتباه إلى كائن النافذة نفسه ، "الخطوط العريضة" الخاصة به مرضية للغاية بالنسبة لنا ، حتى لو كانت عنزة ، وكانت أطول من ذلك بكثير!
بالمناسبة ، في الإصدار الأول من المهمة ، كانت العبارة الرئيسية هي فقط كلمة Snowing
، ولا يمكن طي window
(بسبب غياب الحرف d
). اعتمد الوصول إلى السياق على إحدى خدع jsfuck :
(_ => 0)['constructor']('return this')()['alert']('hello');
أو يمكنك أيضًا الوصول إلى شيء ما في سياق عالمي مباشرةً:
(_ => 0)['constructor']('return alert')()('hello');
كما ترون ، في الأمثلة اللاتينية كلها في طوابير. هنا نقوم بإنشاء دالة من سلسلة ، ونحصل على الوصول إلى الدالة (المُنشئ) من وظيفة السهم المهدر. ولكن هذا بطريقة أو بأخرى أكثر من اللازم! ربما شخص آخر يعرف كيفية الوصول إلى السياق في ظروفنا؟
وأخيرا ، وضعنا كل ذلك معا! سيطلق نص الدالة "الرئيسية" الخاصة بنا على التكرار للصفيف الذي تم تمريره ، وسيخرج العميل نتيجة وظيفة تجميع الرسائل المدمجة بالفعل. بالنسبة لنص الرسالة والأوامر ، يتم استخدام وظيفة كلمة واحدة ، والتي تحتاج أيضًا إلى تكرارها ، وسوف نحددها بعد ذلك في المعلمات الافتراضية . مثل هذا:
(users => ( (( // firstly we need the iterating function iterate = (array, consume) => ((iter = i => array[i] ? (consume(array[i]), iter(++i)) : 0) => iter(0))(),
إعادة تسمية المتغيرات باستخدام الأبجدية المسموح بها:
(_10 => ( (( _123 = (ann, snow) => ((_12 = i => ann[i] ? (snow(ann[i]), _12(++i)) : 0) => _12(0))(), wo = ann => (w => (_123(ann, an => w += (an + 9)[(!0+'')[0] + 'oS' + (!0+'')[0] + (!0+'')[1] + 'ing'](36) ), w) )('') ) => _123(_10, _1 => window[wo([3,15,14,19,15,12,5])][wo([12,15,7])]( wo([8,1,16,16,25]) + ' ' + wo([14,5,23]) + ' ' + wo([25,5,1,18]) + ', ' + _1 + '!' ) ))() ))(users);
متغير | الوصف |
---|
_123 {function} | وظيفة التكرار للتكرار على عناصر الصفيف. |
_12 {function} | الدالة iter المحلية التي تكرار المكالمات بشكل متكرر. |
الثلج {function} | تستهلك وظيفة كرد اتصال للتكرار . |
ann {Array<Any>} | صفيف المعلمة. |
{Any} | معلمة عنصر الصفيف. |
wo {function} | وظيفة الكلمة لتشكيل الكلمات. |
w {string} | المتغير المحلي لتجميع سلسلة في كلمة . |
_10 {Array<string>} | مجموعة الأصلي من المستخدمين. |
_1 {string} | المستخدم من مجموعة المصدر ، اسمه. |
هذا كل شيء. اكتب أفكارك وأفكارك حول هذا الأمر ، حيث توجد العديد من الخيارات للقيام بشيء مختلف أو لا تفعله على الإطلاق.
الخاتمة
ومن المثير للاهتمام أن الخروج بكلمة أو عبارة لظروف المشكلة تحولت إلى اختبار حقيقي. أردت أن تكون قصيرة وليس موحية للغاية ، ومناسبة لحل موجزة أكثر أو أقل.
تم توفير مصدر إلهام لهذه المهمة من خلال وظيفة جافا سكريبت ووتروتيس من 6 أحرف معروفة للكثيرين. كما تمت مناقشته سابقًا ، قد يكون لهذا الأمر العديد من الاختلافات حول الموضوع وليس الحل الوحيد. يكفي الخروج بصياغة بسيطة وعبارة رئيسية. أراك في العام الجديد!