
ذات مرة ، توصل الناس إلى لغة XML ورأوا أنها جيدة. وبدأوا في استخدامه كلما كان ذلك ممكنًا ، وحتى في الأماكن التي لا ينبغي لها ذلك. التنسيقات لتخزين البيانات ونقلها والتكوينات وخدمات الويب وقواعد البيانات ... بدا الأمر وكأننا ننظر إليها - XML و XML في كل مكان. بمرور الوقت ، غيّر الناس رأيهم ، واخترعوا تنسيقات بيانات أخرى مختلفة (أو أخفوا XML داخل الأرشيفات) ، وبدا الجنون في XML وكأنه هادئ. لكن منذ ذلك الحين ، كان أي نظام تقريبًا قادرًا على إكس إم إل ودمج مثل هذه الأنظمة (من قال أباتشي الجمل؟) هي الطريقة الأفضل والأسهل في استخدام مستندات XML.
حيث XML ، هناك XSLT ، لغة مصممة لتحويل مستندات XML. هذه اللغة متخصصة ، ولكنها تمتلك خاصية
الاكتمال وفقًا لتورينج . لذلك ، اللغة مناسبة للاستخدام "غير الطبيعي". هنا ، على سبيل المثال ، هناك
حل لمشكلة 8 ملكات . لذلك ، يمكنك كتابة لعبة.
من أجل الصبر: برنامج عمل على
JSFiddle ، مصادر على
جيثب .
أي برنامج يحول المدخلات إلى الإخراج. يمكن تمييز ثلاثة أجزاء في البرنامج: المعالج الأولي والمعالج والمعالج التالي. يقوم المعالج الأولي بإعداد بيانات الإدخال لمزيد من المعالجة. يشارك المعالج في العمل الرئيسي لتحويل البيانات ، إذا لزم الأمر ، "خلط" إدخال المستخدم والإشارات والأحداث الخارجية ، بما في ذلك في دورة. هناك حاجة إلى postprocessor لتحويل نتائج المعالج إلى نموذج مناسب للإدراك البشري (أو عن طريق برامج أخرى).

في حالة وجود لعبة تفاعلية على XSLT ، سيكون كل جزء من الأجزاء الثلاثة للبرنامج ملف XSLT منفصل. سيقوم المعالج الأولي بإعداد الملعب. سيقوم المعالج بتطبيق حركة اللاعب البشري ، ويقوم بنقل مشغل الكمبيوتر وتحديد الفائز. سوف postprocessor تقديم حالة اللعبة.
يحتاج برنامج XSLT إلى وقت تشغيل. وقت التشغيل الأكثر شيوعًا القادر على تنفيذ XSLT هو أي
متصفح حديث . سوف نستخدم الإصدار 1.0 من XSLT ، لأنه مدعوم من المتصفحات خارج الصندوق.
قليلا عن XSLT و XPath
XSLT هي لغة تحويل مستند XML. يستخدم XPath للوصول إلى أجزاء من مستند XML. يتم نشر مواصفات هذه اللغات على w3.org:
XSLT الإصدار 1.0 و
XPath الإصدار 1.0 .
من السهل البحث على الأساسيات وأمثلة الاستخدام لـ XSLT و XPath على الشبكة. أود هنا أن ألفت الانتباه إلى الميزات التي يجب مراعاتها عند محاولة استخدام XSLT كلغة برمجة عالية المستوى "عامة" للأغراض العامة.
قامت XSLT بتسمية الوظائف. أعلنوا عنصرا.
<xsl:template name="function_name"/>
وتسمى بهذه الطريقة:
<xsl:call-template name="function_name"/>
قد يكون لها وظائف المعلمات.
إعلان:
<xsl:template name="add"> <xsl:param name="x"/> <xsl:param name="y"/> <xsl:value-of select="$x + $y"/> </xsl:template>
استدعاء وظيفة مع المعلمات:
<xsl:call-template name="add"> <xsl:with-param name="x" select="1"/> <xsl:with-param name="y" select="2"/> </xsl:call-template>
يمكن أن تحتوي المعلمات على القيم الافتراضية.
يمكن أن تكون المعلمات "عالمية" قادمة من الخارج. باستخدام هذه المعلمات ، سيتم نقل إدخال المستخدم إلى البرنامج.
تسمح لك اللغة أيضًا بتعريف المتغيرات التي قد ترتبط بقيمة. المعلمات والمتغيرات غير قابلة للتغيير ويمكن تعيين القيم لها مرة واحدة (تمامًا مثل Erlang ، على سبيل المثال).
يحدد XPath أربعة أنواع من البيانات الأساسية: السلسلة والرقم والمنطق المنطقي ومجموعة العقدة. يضيف XSLT نوعًا خامسًا - جزء شجرة نتيجة. يبدو هذا الجزء وكأنه مجموعة عقدة ، لكن مع ذلك يمكنك تنفيذ مجموعة محدودة من العمليات. يمكن نسخها بالكامل إلى مستند إخراج XML ، لكن لا يمكنك الوصول إلى العقد الفرعية.
<xsl:variable name="board"> <cell>1</cell> <cell>2</cell> <cell>3</cell> <cell>4</cell> </xsl:variable>
يحتوي متغير اللوحة على جزء من مستند XML. لكن لا يمكن الوصول إلى العقد التابعة. هذا الرمز غير صحيح:
<xsl:for-each select="$board/cell"/>
أفضل ما يمكنك الحصول عليه هو الوصول إلى العقد النصية للجزء والعمل معها كسلسلة:
<xsl:value-of select="substring(string($board), 2, 1)"/>
سيعود "2".
لهذا السبب ، في لعبتنا ، سيتم تقديم اللوحة (أو ساحة اللعب) كسلسلة بحيث يمكن التلاعب بها بشكل تعسفي.
XSLT يسمح لك بتكرار مجموعة عقدة باستخدام xsl: for-each build. لكن اللغة لا تحتوي على الحلقات المعتادة أو أثناءها. بدلاً من ذلك ، يمكنك استخدام استدعاء دالة تكرارية (التكرار والانتقال متساويان). سيتم تنظيم حلقة من النموذج لـ x في a..b مثل هذا:
<xsl:call-template name="for_loop"> <xsl:with-param name="x" select="$a"/> <xsl:with-param name="to" select="$b"/> </xsl:call-template> <xsl:template name="for_loop"> <xsl:param name="x"/> <xsl:param name="to"/> <xsl:if test="$x < $to"> <xsl:call-template name="for_loop"> <xsl:with-param name="x" select="$x + 1"/> <xsl:with-param name="to" select="$to"/> </xsl:call-template> </xsl:if> </xsl:template>
كتابة وقت التشغيل
لكي يعمل البرنامج ، تحتاج إلى: 3 XSLT ، مصدر XML ، إدخال المستخدم (معلمات) ، XML الحالة الداخلية ، وإخراج XML.
نضع الحقول النصية ذات المعرفات في
ملف html : "preprocessor-xslt" ، "processor-xslt" ، "postprocessor-xslt" ، "input-xml" ، "المعلمات" ، "output-xml" ، "postprocessed-xml". نحن أيضًا نضع /> لتضمين النتيجة في الصفحة (للتصور).
أضف زرين: التهيئة والاستدعاء (خطوة) للمعالج.
دعنا نكتب بعض كود JavaScript
الميزة الرئيسية هي استخدام تحويل XSLT. function transform(xslt, xml, params) { var processor = new XSLTProcessor(); var parser = new DOMParser(); var xsltDom = parser.parseFromString(xslt, "application/xml");
وظائف لتنفيذ المعالج ، والمعالج ، و postprocessor: function doPreprocessing() { var xslt = document.getElementById("preprocessor-xslt").value; var xml = document.getElementById("input-xml").value; var result = transform(xslt, xml); document.getElementById("output-xml").value = result; } function doProcessing() { var params = parseParams(document.getElementById("parameters").value); var xslt = document.getElementById("processor-xslt").value; var xml = document.getElementById("output-xml").value; var result = transform(xslt, xml, params); document.getElementById("output-xml").value = result; } function doPostprocessing() { var xslt = document.getElementById("postprocessor-xslt").value; var xml = document.getElementById("output-xml").value; var result = transform(xslt, xml); document.getElementById("postprocessed-xml").value = result; document.getElementById("output").innerHTML = result; }
دالة المساعد parseParams () بتوزيع إدخال المستخدم في أزواج القيمة = المفتاح.
زر التهيئة يستدعي function onInit() { doPreprocessing(); doPostprocessing(); }
زر بدء المعالج function onStep() { doProcessing(); doPostprocessing(); }
وقت التشغيل الأساسي جاهز.
كيفية استخدامها. أدخل ثلاثة مستندات XSLT في الحقول المناسبة. إدراج مستند إدخال XML. اضغط على زر "التهيئة". إذا لزم الأمر ، أدخل القيم المطلوبة في حقل المعلمة. انقر فوق زر الخطوة.
كتابة لعبة
إذا لم يخمن شخص آخر ، فإن اللعبة التفاعلية من العنوان هي اللعبة الكلاسيكية 3 إلى 3 tic-tac-toe.
ساحة اللعب عبارة عن طاولة 3 × 3 ، يتم ترقيم خلاياها من 1 إلى 9.
يعبر اللاعب البشري دائمًا (الرمز "X") ، والكمبيوتر - الأصفار ("O"). إذا كانت الخلية مشغولة بصليب أو صفر ، فسيتم استبدال الرقم المقابل بالرمز "X" أو "O".
يتم تضمين حالة اللعبة في مستند XML من هذا النموذج:
<game> <board>123456789</board> <state></state> <beginner></beginner> <message></message> </game>
يحتوي العنصر <board /> على الملعب؛ <الحالة /> - حالة اللعبة (الفوز بأحد اللاعبين أو السحب أو الخطأ) ؛ يتم استخدام العنصر <مبتدئ /> لتحديد من بدأ اللعبة الحالية (بحيث يبدأ لاعب آخر اللعبة التالية) ؛ <message /> - رسالة للاعب.
ينشئ
المعالج الأولي حالة أولية (حقل فارغ) من مستند XML تعسفي.
يقوم المعالج بالتحقق من صحة إدخال المستخدم ، ويطبق حركته ، ويحسب حالة اللعبة ، ويحسب ويطبق نقل الكمبيوتر.
على الكود الزائف ، يبدو مثل هذا fn do_move() { let board_after_human_move = apply_move(board, "X", param) let state_after_human_move = get_board_state(board_after_human_move) if state_after_human_move = "" { let board_after_computer_move = make_computer_move(board_after_human_move) let state_after_computer_move = get_board_state(board_after_computer_move) return (board_after_computer_move, state_after_computer_move) } else { return (board_after_human_move, state_after_human_move) } } fn apply_move(board, player, index) { // board index player } fn get_board_state(board) { // "X", , "O", , "tie" } fn make_computer_move(board) { let position = get_the_best_move(board) return apply_move(board, "O", position) } fn get_the_best_move(board) { return get_the_best_move_loop(board, 1, 1, -1000) } fn get_the_best_move_loop(board, index, position, score) { if index > 9 { return position } else if cell_is_free(board, index) { let new_board = apply_move(board, "O", index) let new_score = minimax(new_board, "X", 0) if score < new_score { return get_the_best_move_loop(board, index + 1, index, new_score) } else { return get_the_best_move_loop(board, index + 1, position, score) } } else { return get_the_best_move_loop(board, index + 1, position, score) } } fn cell_is_free(board, index) { // true, board index ( ) } fn minimax(board, player, depth) { let state = get_board_state(board) if state = "X" { // return -10 + depth } else if state = "O" { // return 10 - depth } else if state = "tie" { // return 0 } else { let score = if player = "X" { 1000 } else { -1000 } return minimax_loop(board, player, depth, 1, score) } } fn minimax_loop(board, player, depth, index, score) { if index > 9 { return score } else if cell_is_free(board, index) { // , let new_board = apply_move(board, player, index) let new_score = minimax(new_board, switch_player(player), depth + 1) let the_best_score = if player = "X" { // if new_score < score { new_score } else { score } } else { // if new_score > score { new_score } else { score } } return minimax_loop(board, player, depth, index + 1, the_best_score) } else { // return minimax_loop(board, player, depth, index + 1, score) } } fn switch_player(player) { // ; X -> O, O -> X }
تستخدم وظيفة اختيار تحرك الكمبيوتر خوارزمية minimax ، حيث يزيد الكمبيوتر من نقاطه ، ويقوم الشخص بتصغيرها. هناك حاجة إلى المعلمة عمق الدالة minimax لتحديد الخطوة التي تؤدي إلى النصر في أقل عدد من التحركات.
تستخدم هذه الخوارزمية عددًا كبيرًا من المكالمات المتكررة وتُحسب الخطوة الأولى من الكمبيوتر على جهازي حتى 2-3 ثواني. يجب علينا تسريع بطريقة أو بأخرى. يمكنك ببساطة إجراء أفضل حركات الكمبيوتر والقيام بحسابها المسبق لجميع الظروف الممكنة لمجال المقامرة. تحولت مثل هذه الحالات إلى 886. من الممكن تقليل هذا العدد بسبب التناوب وانعكاسات الحقل ، لكن هذا ليس ضروريًا.
النسخة الجديدة سريعة.
حان الوقت لعرض ملعب جميل. ما يجب استخدامه إذا كان هذا شيئًا ما) يجب أن يرسم رسومات (القرن الحادي والعشرين في الفناء ، ما نوع اللعبة بدون رسومات؟!) و ب) من المستحسن أن يكون هناك تنسيق XML؟ بالطبع SVG!
يرسم
المعالج التالي حقلاً متقلبًا ويرتب الصلبان الخضراء والأصفار الزرقاء
والفساتين السوداء الصغيرة
فيه . كما يعرض رسائل حول نهاية اللعبة.
والآن يبدو أن اللعبة جاهزة. لكن شيئا ما ليس صحيحا. للعب ، تحتاج إلى القيام بالكثير من الإجراءات غير الضرورية والمملة والمزعجة: أدخل رقم الخلية في حقل الرمز التالي واضغط على الزر. فقط انقر على الخلية المطلوبة!
نحن بصدد الانتهاء من
وقت التشغيل و
postprocessor .
في وقت التشغيل ، أضف وظيفة استجابة النقر فوق عنصر SVG:
function onSvgClick(arg) { document.getElementById("parameters").value = arg; onStep(); }
في postprocessor نضيف مربعًا فوق كل خلية (يتم تحديد الشفافية بنمط rect.btn) ، وعند النقر فوقها ، تُدعى دالة برقم الخلية:
<rect class="btn" x="-23" y="-23" width="45" height="45" onclick="onSvgClick({$index})"/>
بعد اكتمال الدفعة ، يؤدي النقر فوق أي خلية إلى بدء خلية جديدة. يجب الضغط على زر "Init" مرة واحدة فقط في البداية.
الآن يمكنك اعتبار اللعبة منتهية. الشيء صغير: إخفاء الدواخل ، وتعبئتها في تطبيق الإلكترون ، ووضعها على ستيم ، ؟؟؟ ، استيقظ الغنية والغنية.
الخاتمة
يمكن للمبرمج القوي التفكير كتابة أي شيء على أي شيء
حتى في JavaScript . لكن من الأفضل استخدام أداة مناسبة لكل مهمة.