الجمعة JS: وهو ملحي يلعب دور التشنج اللاإرادي

أحيي الجميع في بلدي القسم التقليدي الكامل للجنون Lovecraftian.

في عملية كتابة أحد المقالات السابقة (لا تبدو ، لم تكن جيدة على وجه الخصوص) ، فكرت في حقيقة أن كيوين ... نعم ، فقط في الحالة ، أذكركم: كيوين هو برنامج يعرض نصه الخاص ، ويفعله "بأمانة" ( دون النظر ، على سبيل المثال ، هذا النص في ملف على القرص الصلب الخاص بك). بشكل عام ، فإن puzomerka التقليدية لا معنى لها من المبرمجين.

لذلك ، فكرت في حقيقة أن الماء المالح ، من حيث المبدأ ، يمكن أن يحمل حمولة تعسفية. وهذا هو ، لفعل أي شيء آخر إلى جانب وظيفتها الرئيسية. وكإثبات للمفهوم ، قررت أن أكتب ملجأ يلعب دور التشنج اللاإرادي. وكتب. تفاصيل القذرة تحت خفض.

الصورة

"ولكن كيف يمكن أن يفعل أي شيء آخر غير عرض نصه؟" - ربما تسأل. و سهل. بالإضافة إلى الإخراج ، يحتوي البرنامج أيضًا على مدخلات. إذا كان البرنامج يعرض نصه في حالة عدم وجود مدخلات - فسيكون ذلك مناسبًا. إذا كان البرنامج يفعل شيئًا آخر عند توفر الإدخال ، فمن نحن لإدانته؟

ربما سأضع على الفور البطاقات على الطاولة. هنا رابط لخلقي. هناك ثلاثة كيانات في الملف حسب المرجع:

  1. وظيفة quine هو ما أتحدث عنه.
  2. وظيفة evalAndCall هي المساعد.
  3. فئة اللعبة - حتى أكثر المساعد

أولاً ، سنتحدث عن كيفية العمل مع الدالة quine ، ثم كيف تعمل.

كيفية العمل معها


في بداية الدالة quine ، يمكنك رؤية ما يلي:

function quine(input){/* |1|2|3| |4|x|6| |7|8|9| !  - ,     -. ,   .     ,    ,     .             ,    . :   - 0   - 0  - 0 */ 

التعليق في بداية الوظيفة هو واجهة المستخدم. من خلاله ، ستتواصل الوظيفة مع من يستخدمونها للعبة. في البداية ، فكرت في القيام بذلك من خلال وحدة التحكم ، ولكن بعد ذلك قررت أنه سيكون من الأصح الحفاظ على الوظيفة نظيفة .

دعونا نتحقق من أن الوظيفة هي حقاً ملحة. هنا ، للراحة ، قمت بنشر صفحة HTML فارغة (تقريبًا) مع النص البرمجي quine.js المرفق. عند فتح أدوات المطور ، يمكنك قيادة الكود التالي بدون انتقائية:

 const quineText = quine(); const evaluatedQuine = eval("(" + quineText + ")"); // ,     eval       //  undefined,   const evaluatedQuineText = evaluatedQuine(); quineText == evaluatedQuineText; // true 

تتحمل وزارة الدفاع
في الواقع ، بالطبع ، لقد تحققنا فقط من أن الدالة quine تُرجع نص quine ، وليس أنها هي نفسها quine. ولكي نكون دقيقين تمامًا - لقد تحققنا فقط من أن الدالة quine تُرجع نص الدالة ، والتي تعمل في حالتنا مثل quine. لا توجد ضمانات بأن الداخل لا يحتوي على شيء مثل:

 if(Math.random() < 0.99){ beAGoodQuine(); }else{ haltAndCatchFire(); } 


الآن يمكننا محاولة اللعب معها. دعنا نقول أننا نقوم بالانتقال الأول إلى الزاوية اليسرى العليا من الحقل.

 let quineText = quine(1); 

الآن "واجهة المستخدم" هي كما يلي:

 function quine(input){/* |o|x|3| |4|x|6| |7|8|9| !  - ,     -. ,   .     ,    ,     .             ,    . :   - 0   - 0  - 0 */ 

أخذ كين في الاعتبار تحركنا وجعل استجابة في الحقل المركزي العلوي. بالمناسبة ، فإن الدالة الناتجة هي أيضًا مملوءة بالحيوية - تسمى بدون وسيطات ، وستُرجع نصها الجديد ، وليس نص الوظيفة الأصلية. يمكننا أن نلعب اللعبة بأكملها ، ولكن للراحة سنستخدم الوظيفة الإضافية evalAndCall.

 let quineText = quine(); //         ,    . /* |1|2|3| |4|x|6| |7|8|9| */ quineText = evalAndCall(quineText, 1) /* |x|o|3| |4|x|6| |7|8|9| */ quineText = evalAndCall(quineText, 3) /* |x|o|o| |4|x|6| |7|8|x|     .    ,   0    */ quineText = evalAndCall(quineText, 0) /* |1|2|3| |4|x|6| |7|8|9| :   - 0   - 1  - 0 */ 

فويلا! مسرحيات كين ، يفوز وحتى عشرات. يمكنك اللعب معها لفترة أطول ، ولكن لمزيد من الراحة ، أوصي باستخدام فئة اللعبة ، التي اختبرت بها اللعبة بنفسي. أعتقد أنه إذا قرأت هذه النقطة ، فلست بحاجة إلى شرح كيفية استخدامها.

كيف يعمل


بشكل عام ، كانت المهمة تتألف من جزأين: كتابة ، إن أمكن ، وظيفة مختصرة للعبة تيك تاك تو ، ثم دفعها إلى الماء. لنبدأ مع تيك تاك تو.

يقع جوهر "الذكاء الاصطناعي" على الخطوط 66-90 وتشبه صورة ظلية السنجاب العنيد:

  const rules = { "o___x____": "ox__x__!_", "ox__x__o_": "ox!_x_xo_", "oxo_x_xo_": "oxo!xxxo_", "oxooxxxo_": "oxooxxxoxd", "_o__x____": "xo__x___!", "xo__x___o": "xo_xx!!_o" }; const next = (field, move) => { if(!~"!_".indexOf(field[--move])){ return null; } field[move] = "o"; const win = field.indexOf("!"); if(~win){ field[win] = "x"; return [...field, "w"]; } for(let n = 0; n < 4; n++){ field = field.map((_, i) => field[[2, 5, 8, 1, 4, 7, 0, 3, 6][i]]); rules[field.join("")] && (field = rules[field.join("")].split("")); } return field; } 

تبدو هذه الشفرة غامضة بعض الشيء لأنني كنت مهتمًا بجعلها قصيرة قدر الإمكان. جوهرها هو هذا: عند إدخال الوظيفة التالية ، يتم استلام حالة الحقل - مجموعة من تسعة عناصر - وعدد الخلية التي يقوم بها اللاعب - الشخص (يتحقق التالي من صحة هذه الخطوة). يمكن أن يكون كل عنصر من عناصر الحقل عبارة عن علامة تبادلية أو صفر أو تسطير أسفل السطر (خلية فارغة) أو علامة تعجب (خلية فارغة لوضع عليها علامة تقاطع عند أول فرصة). إذا كانت هناك علامة تعجب في الحقل ، فإننا نتحرك فورًا ونفوز. خلاف ذلك ، فإننا نلصق المصفوفة في سلسلة ونبحث عن القاعدة المقابلة في كائن القواعد. لتوفير مساحة ، تكون القواعد دقيقة للتناوب ؛ لذلك ، للبحث ، يتم تدوير الحقل أربع مرات. عند العثور على القاعدة المطلوبة ، يتم استبدال حالة الحقل بقيمة القاعدة ، مقسمة إلى أحرف. بعد ذلك ، ترجع الدالة التالية الحالة الجديدة للحقل. في الوقت نفسه ، قد تنضم إليها شخصية العاشرة الإضافية: "w" - إذا فاز AI ، "d" - إذا كان هناك تعادل.

بفضل علامات التعجب و "التلميحات" وتناوب الحقل ، وأيضًا ، نظرًا لحقيقة أن الذكاء الاصطناعي يبدأ أولاً ، تم وصف الاستراتيجية المثلى في 6 قواعد فقط.

باستخدام الوظيفة التالية ، تقوم الدالة quine بمعالجة الإدخال وكتابة بعض الحقول إلى كائن magicHash. وهنا ننتقل بسلاسة إلى الجزء الثاني: كيف يعمل مكون "quayne". كل السحر موجود في كائن magicHash وخاصيته magicString.

يحتوي خط magicString ، كما ترون بسهولة ، على نص برنامج مكرر تقريبًا بالكامل. ومع ذلك ، كما يعلم كل من حاول كتابة خط فاصل في أي وقت ، لا يمكنك دفع نص كامل تمامًا فيه - لأنه سيتعين عليه حينئذٍ احتواء نفسه بشكل صارم ، وهو أمر مستحيل بالنسبة للسلاسل ذات الطول المحدود. لذلك ، بالإضافة إلى النص "العادي" ، فإنه يحتوي أيضًا على سلاسل أحرف البدل "السحرية" المحددة على كلا الجانبين بحرف "$".

عندما يحين الوقت X وعلينا أن نعيد نص الوظيفة ، فإننا نأخذ magicString ونستبدل تسلسل أحرف البدل فيه بالخصائص المقابلة لكائن magicHash. يمكن أن تكون هذه الخصائص ثابتة (backtick) أو تتغير في وقت التشغيل (الحقل) أو يمكن إضافتها في وقت التشغيل (message) - لا يهم. من المهم أن يكون لكل خاصية "إشكالية" من التعليمات البرمجية لا يمكن ببساطة تكرارها في سطر ما ، خاصية "سحرية" لكائن magicHash. آخر واحد يستبدل magicString نفسه. هذا الأخير - لأنه بخلاف ذلك ، سيكون هناك تسلسل أحرف بدل إضافي سيتم استبداله أيضًا.

ملخص


راجعت من تجربتي الخاصة أنه يمكنك وضع أي شيء في ملجأ. من حيث المبدأ ، إذا كنت تهتم ، فيمكنك إنشاء مولد quine - وهي وظيفة تحول أي وظيفة نقية أخرى إلى quine وتسمح لك بتخزين حالة تعسفية يمكن الوصول إليها من خلال وظيفة pure الخالصة. ومع ذلك ، فإن هوامش هذه المخطوطة ضيقة جدًا ...

بشكل عام ، أنا لا أدعي للحداثة الخاصة لـ "اكتشافي". يجب على الموظفين المتشددين قراءة هذا النص بابتسامة التميز. ولكن كان من المثير للاهتمام بالنسبة لي أن أستلمها بيدي ، لأضع أصابعي في الجروح ، إذا جاز التعبير. وآمل أن تكونوا مهتمين بالقراءة عنه.

وداعا ، والفتيان والفتيان. اراك مجددا

Source: https://habr.com/ru/post/ar435732/


All Articles