مشروع: لعبة إكس-أو
الفكرة: أنت X والحاسوب O. يقرأ البرنامج حركاتك من الإدخال (رقم خانة من 1 إلى 9 في كل سطر)، والحاسوب يبحث في كل الاحتمالات (minimax) فلا يخسر.
البرنامج
رابط إلى قسم «البرنامج»في هذا التشغيل كُتبت الحركات مسبقاً في الإدخال، ومنها «س» وخانات مشغولة لترى رسائل التحقق:
# تطبيق تعليمي: لعبة إكس-أو في الطرفية، اللاعب ضد الحاسوب (بحث minimax كامل)# يقرأ حركات اللاعب من الإدخال (رقم الخانة 1–9 في كل سطر)
تعداد خانة: فارغة انا حاسوب
هيكل لوح: خانات مصفوفة[خانة, 9]
ثابت خطوط_الفوز = "012345678036147258048246"
داله رمز_خانة(خ خانة, رقم عدد) نص: حالات خ: حاله خانة.فارغة: ارجع نص(رقم) حاله خانة.انا: ارجع "X" حاله خانة.حاسوب: ارجع "O"
داله ارسم(ل لوح) فراغ: لكل ص في مدى(0, 3): اطبع(" ", رمز_خانة(ل.خانات[3 * ص], 3 * ص + 1), " | ", رمز_خانة(ل.خانات[3 * ص + 1], 3 * ص + 2), " | ", رمز_خانة(ل.خانات[3 * ص + 2], 3 * ص + 3)) اذا ص < 2: اطبع("---+---+---")
داله رقم_في(ن نص, موضع عدد) عدد: ارجع عدد(جزء(ن, موضع, موضع + 1)) والا 0
داله الفائز(ل لوح) خانة: لكل خط في مدى(0, 8): ا = رقم_في(خطوط_الفوز, 3 * خط) ب = رقم_في(خطوط_الفوز, 3 * خط + 1) ج = رقم_في(خطوط_الفوز, 3 * خط + 2) اذا ل.خانات[ا] != خانة.فارغة و ل.خانات[ا] == ل.خانات[ب] و ل.خانات[ب] == ل.خانات[ج]: ارجع ل.خانات[ا] ارجع خانة.فارغة
داله ممتلئ(ل لوح) منطقي: لكل خ في ل.خانات: اذا خ == خانة.فارغة: ارجع خطاء ارجع صواب
عقد_مفحوصة = 0
داله قيمة(ل لوح, دور خانة, عمق عدد) عدد: عام عقد_مفحوصة عقد_مفحوصة += 1 ف = الفائز(ل) اذا ف == خانة.حاسوب: ارجع 10 - عمق اذا ف == خانة.انا: ارجع عمق - 10 اذا ممتلئ(ل): ارجع 0 افضل = 100 اذا دور == خانة.حاسوب: افضل = -100 لكل ع في مدى(0, 9): اذا ل.خانات[ع] != خانة.فارغة: تجاوز ل.خانات[ع] = دور # الهيكل بالقيمة: نسخة لا تمس لوح المستدعي اذا دور == خانة.حاسوب: ق = قيمة(ل, خانة.انا, عمق + 1) اذا ق > افضل: افضل = ق غير ذلك: ق = قيمة(ل, خانة.حاسوب, عمق + 1) اذا ق < افضل: افضل = ق ل.خانات[ع] = خانة.فارغة ارجع افضل
داله حركة_الحاسوب(ل لوح) عدد: افضل = -100 موضع = -1 لكل ع في مدى(0, 9): اذا ل.خانات[ع] == خانة.فارغة: ل.خانات[ع] = خانة.حاسوب ق = قيمة(ل, خانة.انا, 1) ل.خانات[ع] = خانة.فارغة اذا ق > افضل: افضل = ق موضع = ع ارجع موضع
داله اقرأ_حركة(ل لوح) عدد: طالما !انتهى_الدخل(): سطر = قص_الفراغات(اقرأ("حركتك (1-9): ")) ر = عدد(سطر) والا خ: اطبع("«", سطر, "» ليس رقماً") تجاوز اذا ر < 1 او ر > 9: اطبع("الخانة بين 1 و9") تجاوز اذا ل.خانات[ر - 1] != خانة.فارغة: اطبع("الخانة مشغولة") تجاوز ارجع ر - 1 ارجع -1
ل = لوح([خانة.فارغة, خانة.فارغة, خانة.فارغة, خانة.فارغة, خانة.فارغة, خانة.فارغة, خانة.فارغة, خانة.فارغة, خانة.فارغة])اطبع("أنت X والحاسوب O")طالما الفائز(ل) == خانة.فارغة و !ممتلئ(ل): ارسم(ل) م = اقرأ_حركة(ل) اذا م < 0: اطبع("انتهى الإدخال") توقف ل.خانات[م] = خانة.انا اذا الفائز(ل) != خانة.فارغة او ممتلئ(ل): توقف ح = حركة_الحاسوب(ل) اطبع("الحاسوب يلعب ", ح + 1) ل.خانات[ح] = خانة.حاسوبارسم(ل)حالات الفائز(ل): حاله خانة.انا: اطبع("فزت!") حاله خانة.حاسوب: اطبع("فاز الحاسوب") حاله خانة.فارغة: اطبع("تعادل")اطبع("عقد مفحوصة: ", عقد_مفحوصة)الإدخال
5س153489
بُني أيضاً بـ meem build عند بناء الموقع: ملف ساكن حجمه 47.2 ك.ب، شُغّل وحده وطابق مخرجه المخرج أعلاه.
خطوة خطوة
رابط إلى قسم «خطوة خطوة»- التعداد
خانة: فارغة أو أنا أو حاسوب. وحالاتعلى التعداد تُفحص عند الترجمة: نسيان حالة خطأ. - اللوح هيكل بمصفوفة ثابتة:
مصفوفة[خانة, 9]. والهيكل يُمرَّر بالقيمة، فكل استدعاء لـقيمةيعمل على نسخته. - minimax:
قيمةتجرّب كل خانة فارغة وتستدعي نفسها للاعب الآخر، وتفضّل الفوز الأقرب (10 - عمق). - الإدخال:
اقرأ_حركةتقرأ حتى ينتهي الإدخال (انتهى_الدخل())، وعدد(سطر) والا خ:ترفض ما ليس رقماً، وتتحقق من المدى ومن أن الخانة فارغة.
ما كان صعباً
رابط إلى قسم «ما كان صعباً»- نسخ خفية في الدالة الساخنة (في 0.9.1):
رقم_فيتكتبعدد(جزء(ن, موضع, موضع + 1)). في 0.9.1 كانعدد()على العرض يحجز نسخة لا تُعاد في كل نداء، وminimax يناديها عشرات الآلاف من المرات، فأبقى هذا السطر وحده في التقرير 1.1 مليون كتلة (20 م.ب) حتى الخروج، وكشفها--debug-memبالسطر. في 0.10.0 أُزيلت هذه النسخ: البرنامج نفسه بـ--debug-memلا يذكر هذا السطر في تقريره. - الحل الالتفافي (غير مشغَّل هنا): أن تُحسب خطوط الفوز أعداداً مرة واحدة في قائمة، بدل تحويل الأحرف في كل نداء.
ما تعلّمناه
رابط إلى قسم «ما تعلّمناه»- التعداد مع
حالاتالمكتملة يجعل منطق اللعبة واضحاً ومفحوصاً. - الهيكل بالقيمة يغني عن التراجع اليدوي في بحث كهذا.
- عُدّت 56490 عقدة في هذه اللعبة، والزمن في التقرير 0.24 ث مبنياً.