Axiom - डिग्री बढ़ाएँ!

बूढ़े ग्रे गधा Eeyore जंगल के ऊंचे किनारे कोने में अकेला खड़ा था, पैर अलग और उसके सिर एक तरफ लटक रहे थे, और सीरियस थिंग्स के बारे में सोचा।



ए मिल्ने "विनी द पूह और ऑल-ऑल-ऑल"



- एक गधा देखें? मैं पुलिस वाले से पूछता हूं। - वहाँ पर थोड़ा ग्रे गधा है ... अनुच्छेद 2908. कीमत बत्तीस kopecks है। उसका महान भविष्य है।

"गधा ऐसा करते हैं," पुलिसकर्मी सहमत हैं। - उनका कभी-कभी बहुत शानदार भविष्य होता है।



हेनरी अल्टोव "डोंकी और एक्सोम"





बोर्ड गेम विकसित करने के बारे में सबसे कठिन भाग क्या है? जाहिर है कि बोर्ड के चारों ओर बढ़ते टुकड़ों का एनीमेशन नहीं। उचित और दिलचस्प गेम नियमों के साथ आना मुश्किल है। खेल संतुलन सुनिश्चित करना बहुत मुश्किल हो सकता है। यदि हम कंप्यूटर के विकास में लगे हुए हैं, तो उच्च गुणवत्ता वाले AI (गो या शोगी जैसे गेम के लिए) लागू करना अक्सर मुश्किल होता है, यह समस्या अब तक हल नहीं हुई है। और यहां तक ​​कि अगर हम एक काम करने वाले एआई को लागू करने में कामयाब रहे, तो हमें अपने काम की गुणवत्ता का आकलन करने और कई संभावित विकल्पों में से सर्वश्रेष्ठ का चयन करने के लिए बहुत बड़ी मात्रा में काम करना होगा।



मैं एक ऐसे टूल के बारे में बात करना चाहता हूं जो इन सभी मुद्दों के समाधान को सरल बना सकता है। गेम्स के Zillions को बेहतर बनाने के लिए डेवलपर्स द्वारा Axiom Development Kit की कल्पना की गई थी। विशेष रूप से, यह क्षेत्र की जब्ती (जैसे गो) से संबंधित खेलों के कार्यान्वयन पर केंद्रित है, जो एआई ज़ोग बहुत खराब तरीके से करता है। इसके अलावा, Axiom काफी ZoG डेवलपर्स की क्षमताओं का विस्तार करता है, बहुत सारे अवसर प्रदान करता है जो व्यावहारिक रूप से पारंपरिक ZRF (नियम विवरण भाषा) के ढांचे के भीतर महसूस नहीं किए जाते हैं। इस सब के साथ, एक्सोम पूरी तरह से स्वतंत्र रूप से काम कर सकता है, भले ही ZoG को कभी भी कंप्यूटर पर स्थापित या खरीदा नहीं गया हो। लेकिन, पहली चीजें पहले ...



छवि में



मैंने पहले ही लिखा है कि ZoG में कई कमियां हैं। सौभाग्य से, डेवलपर्स ने उनमें से कुछ के साथ सामना करने के लिए एक तंत्र प्रदान किया है। विस्तार मॉड्यूल (इंजन) एक गतिशील रूप से भरी हुई लाइब्रेरी (DLL) है जो खेल के सभी पहलुओं को नियंत्रित करता है, इसके दृश्य को छोड़कर। यहां आप इस तरह के विस्तार का एक उदाहरण देख सकते हैं।



अपने स्वयं के विस्तार का विकास करना बहुत समय लेने वाला हो सकता है। हमें AI विकसित करना होगा (C ++ में सबसे अधिक संभावना है), क्योंकि जब इंजन जुड़ा होता है, तो नियमित ZoG AI अक्षम होता है। एक्सिओम एक प्रोग्रामेबल इंजन है जो ऐसी चीज़ों को लागू करता है जो एक डेवलपर के लिए मुश्किल होती हैं, जैसे कि एआई एल्गोरिदम, और गेम लॉजिक पर ध्यान केंद्रित करने की क्षमता प्रदान करता है।



आइए उर के रॉयल गेम को लागू करने का प्रयास करें। काम करने के लिए, एक न्यूनतम ZRF फ़ाइल की आवश्यकता है:



इंजन कनेक्शन
(version "2.0") (game (title "Ur") (engine "../Axiom/Ur/axiom.dll") (option "animate captures" false) (option "animate drops" false) (option "show moves list" false) (option "pass turn" forced) (option "highlight goals" false) (option "prevent flipping" true) (option "recycle captures" true) (drop-sound "Audio/Dice_cup.wav") (move-sound "Audio/Clack.wav") (capture-sound "") (players Black White ?Dice) (turn-order White ?Dice ?Dice ?Dice ?Dice Black ?Dice ?Dice ?Dice ?Dice) (board (image "Images\Ur\board.bmp") (grid (start-rectangle -503 -13 -442 79) (dimensions ("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p/q" (67 0)) ; files ("5/4/3/2/1" (0 66)) ; ranks ) ) ) (board-setup (?Dice (wdice q4) (bdice q3 q2) (lock q1) ) (Black (init i5 j5 k5 l5 m5 n5 o5) ) (White (init i1 j1 k1 l1 m1 n1 o1) ) ) (piece (name lock) (image ?Dice "Images\Ur\invisible.bmp" Black "Images\Ur\invisible.bmp" White "Images\Ur\invisible.bmp") ) (piece (name init) (image Black "Images\Ur\binit.bmp" White "Images\Ur\winit.bmp") ) (piece (name prom) (image Black "Images\Ur\bprom.bmp" White "Images\Ur\wprom.bmp") ) (piece (name wdice) (image ?Dice "Images\Ur\wdice.bmp") ) (piece (name bdice) (image ?Dice "Images\Ur\bdice.bmp") ) ; The following dummy piece is required in order to placate the Zillions engine. ; It appears as though Zillions must find at least one "moves" keyword somewhere ; in the zrf in order for it to be happy and thus allow "moves" to work correctly. (piece (name Dummy) (dummy) (moves (from))) )
      
      







यहां खिलाड़ियों का वर्णन है, चालों के क्रम, टुकड़े, लेकिन उन नियमों का कोई वर्णन नहीं है जिनके द्वारा टुकड़े जाते हैं। बोर्ड पर निर्देशों की कोई परिभाषा नहीं है, गेम जोन, खेल को समाप्त करने की शर्तें, और खेल के नियमों से संबंधित अन्य सभी चीजें। यह सब स्वयंसिद्ध लिपियों में समाहित होगा। दुखद बात यह है कि इंजन के साथ ZoG इंटरफ़ेस ZRF फ़ाइल में निहित जानकारी के हस्तांतरण के लिए प्रदान नहीं करता है। इसका मतलब है कि इन सभी विवरणों को Axiom स्क्रिप्ट में डुप्लिकेट करना होगा।



सौभाग्य से, Axiom डेवलपमेंट किट एक उपयोगिता के साथ आता है जो इस प्रक्रिया को स्वचालित करता है। ZRF कन्वर्टर काम में काफी मूडी है। यदि उन्हें ZRF फ़ाइल में कुछ पसंद नहीं है (उदाहरण के लिए, मैक्रो में बोर्ड का वर्णन), तो रूपांतरण प्रक्रिया एक रहस्यमय निदान के साथ बाधित होती है जिससे आप अपना सिर तोड़ लेते हैं। यदि सब कुछ ठीक रहा, तो हमें आउटपुट पर निम्न विवरण मिलता है:



Ur.4th
 {board {position} a5 {position} b5 {position} c5 {position} d5 {position} e5 {position} f5 {position} g5 {position} h5 {position} i5 {position} j5 {position} k5 {position} l5 {position} m5 {position} n5 {position} o5 {position} p5 {position} q5 {position} a4 {position} b4 {position} c4 {position} d4 {position} e4 {position} f4 {position} g4 {position} h4 {position} i4 {position} j4 {position} k4 {position} l4 {position} m4 {position} n4 {position} o4 {position} p4 {position} q4 {position} a3 {position} b3 {position} c3 {position} d3 {position} e3 {position} f3 {position} g3 {position} h3 {position} i3 {position} j3 {position} k3 {position} l3 {position} m3 {position} n3 {position} o3 {position} p3 {position} q3 {position} a2 {position} b2 {position} c2 {position} d2 {position} e2 {position} f2 {position} g2 {position} h2 {position} i2 {position} j2 {position} k2 {position} l2 {position} m2 {position} n2 {position} o2 {position} p2 {position} q2 {position} a1 {position} b1 {position} c1 {position} d1 {position} e1 {position} f1 {position} g1 {position} h1 {position} i1 {position} j1 {position} k1 {position} l1 {position} m1 {position} n1 {position} o1 {position} p1 {position} q1 board} {players {player} Black {player} White {player} ?Dice {random} players} {pieces {piece} lock {piece} init {piece} prom {piece} wdice {piece} bdice {piece} Dummy pieces} {turn-order {repeat} {turn} White {turn} ?Dice {turn} ?Dice {turn} ?Dice {turn} ?Dice {turn} Black {turn} ?Dice {turn} ?Dice {turn} ?Dice {turn} ?Dice turn-order} {board-setup {setup} ?Dice wdice q4 {setup} ?Dice bdice q3 {setup} ?Dice bdice q2 {setup} ?Dice lock q1 {setup} Black init i5 {setup} Black init j5 {setup} Black init k5 {setup} Black init l5 {setup} Black init m5 {setup} Black init n5 {setup} Black init o5 {setup} White init i1 {setup} White init j1 {setup} White init k1 {setup} White init l1 {setup} White init m1 {setup} White init n1 {setup} White init o1 board-setup}
      
      







यहां पहले आश्चर्य ने हमारा इंतजार किया। Axiom आपको बोर्ड को अधिक कॉम्पैक्ट रूप से वर्णन करने की अनुमति देता है, लेकिन गंभीर सीमाओं के साथ। ग्रिड डिज़ाइन आपको "मानक" सेल नाम के साथ केवल आयताकार बोर्डों का वर्णन करने की अनुमति देता है (इसके अलावा, बोर्ड विवरण में केवल एक ग्रिड का उपयोग किया जा सकता है)। यदि आपको अधिक जटिल आकार के बोर्ड (उदाहरण के लिए, त्रि-आयामी) का वर्णन करने की आवश्यकता है, तो आपको प्रत्येक स्थिति का उसी तरह से स्पष्ट रूप से वर्णन करना होगा जैसे ZRF कन्वर्टर ने किया था। चूंकि, हमारे मामले में, सभी प्रतिबंधों का सम्मान किया जाता है (मुझे ZRF कार्यान्वयन की तुलना में बोर्ड के कॉलम और पंक्तियों का नाम बदलना पड़ा), हम एक अधिक कॉम्पैक्ट रिकॉर्ड का उपयोग करते हैं:



 {board 5 17 {grid} board}
      
      





अगला, आपको उस दिशा को निर्धारित करने की आवश्यकता है जिसमें आंकड़े स्थानांतरित हो सकते हैं। शतरंज या चेकर्स जैसे खेलों में, हम एक संकेतन संकेतन का उपयोग कर सकते हैं जो निर्देशांक बढ़ाने के संदर्भ में दिशाओं को परिभाषित करता है:



 {directions -1 0 {direction} North 1 0 {direction} South 0 1 {direction} East 0 -1 {direction} West -1 1 {direction} Northeast 1 1 {direction} Southeast -1 -1 {direction} Northwest 1 -1 {direction} Southwest directions}
      
      





काश, हमारे मामले में, यह विधि उपयुक्त नहीं है। बोर्ड पर चिप्स के आंदोलन की गति के बाद से, खेल यूआर में, काफी विचित्र है, आपको पदों के बीच कनेक्शन को स्पष्ट रूप से निर्धारित करना होगा:



दिशाओं
 {directions ( Anext ) {link} Anext i1 l2 {link} Anext j1 l2 {link} Anext k1 l2 {link} Anext l1 l2 {link} Anext m1 l2 {link} Anext n1 l2 {link} Anext o1 l2 {link} Anext l2 k2 {link} Anext k2 j2 {link} Anext j2 i2 {link} Anext i2 i3 {link} Anext i3 j3 {link} Anext j3 k3 {link} Anext k3 l3 {link} Anext l3 m3 {link} Anext m3 n3 {link} Anext n3 o3 {link} Anext o3 o2 {link} Anext o2 p2 {link} Anext p2 p3 {link} Anext p3 p4 {link} Anext p4 o4 {link} Anext o4 o3 ( Bnext ) {link} Bnext i5 l4 {link} Bnext j5 l4 {link} Bnext k5 l4 {link} Bnext l5 l4 {link} Bnext m5 l4 {link} Bnext n5 l4 {link} Bnext o5 l4 {link} Bnext l4 k4 {link} Bnext k4 j4 {link} Bnext j4 i4 {link} Bnext i4 i3 {link} Bnext i3 j3 {link} Bnext j3 k3 {link} Bnext k3 l3 {link} Bnext l3 m3 {link} Bnext m3 n3 {link} Bnext n3 o3 {link} Bnext o3 o4 {link} Bnext o4 p4 {link} Bnext p4 p3 {link} Bnext p3 p2 {link} Bnext p2 o2 {link} Bnext o2 o3 ( Cnext ) {link} Cnext p3 p4 {link} Cnext p4 o4 {link} Cnext o4 o3 {link} Cnext o3 n3 {link} Cnext n3 m3 {link} Cnext m3 l3 {link} Cnext l3 k3 {link} Cnext k3 j3 {link} Cnext j3 i3 {link} Cnext i3 h3 ( Dnext ) {link} Dnext p3 p2 {link} Dnext p2 o2 {link} Dnext o2 o3 {link} Dnext o3 n3 {link} Dnext n3 m3 {link} Dnext m3 l3 {link} Dnext l3 k3 {link} Dnext k3 j3 {link} Dnext j3 i3 {link} Dnext i3 h3 directions}
      
      







काले और सफेद चिप्स अलग-अलग तरीकों से चलते हैं, इसलिए मुझे काले टुकड़ों के लिए सफेद और Bnext के लिए दिशा Anext निर्धारित करना पड़ा। इसके अलावा, परिवर्तन क्षेत्र से गुजरने वाले चिप्स के लिए, Cnext और Dnext की दिशा निर्धारित करना आवश्यक है। यदि ऐसा नहीं किया जाता है, तो ओ 3 फ़ील्ड पर एक कांटा बनता है और सभी चिप्स एक छोटे से ब्लॉक में एक सर्कल में स्पिन करेंगे, जो पहले उपलब्ध मार्गों को चुनते हैं।



 {symmetries Black {symmetry} Anext Bnext Black {symmetry} Cnext Dnext symmetries}
      
      





यह डिज़ाइन आपको "समरूपता" को परिभाषित करने की अनुमति देता है। एक अच्छा चित्रण शतरंज में प्यादों का आंदोलन है। पाव हमेशा आगे बढ़ते हैं, लेकिन सफेद के लिए यह बोर्ड को ऊपर ले जाता है, और काले रंग के लिए यह विपरीत दिशा में है। समरूपता के अधिक जटिल रूप हैं। उदाहरण के लिए, शतरंज के चार-पक्षीय वेरिएंट में, रंग के आधार पर "फॉरवर्ड" आंदोलन, चार "कार्डिनल पॉइंट्स" में से किसी की दिशा में हो सकता है। "समरूपता" परिभाषित करने के बाद, हम हमेशा एक ही दिशा (उदाहरण के लिए, Anext ) का उपयोग कर सकते हैं, आकृति के रंग पर ध्यान नहीं दे रहे हैं। काले रंग के लिए, यह स्वचालित रूप से सममित ( बेनेक्स ) में परिवर्तित हो जाएगा।



दुर्ग



फोर्ट के साथ मेरा परिचय जल्दी था, लेकिन बहुत लंबे समय तक यह बहुत ही शानदार रहा। मैंने पहली बार फोर्ट को बीसी-शेख और मिक्रोश के समय देखा था। मेरे मित्र के पास वेक्टर ०६ सी था , जिससे हम सभी माता-पिता के संयुक्त प्रयासों से, केवल हमारे कानों में सफल हुए। वेकटोर के लिए, समय-समय पर, खेलों के साथ कैसेट खरीदे गए थे, और समय-समय पर उन पर "बेहिसाब" के लिए खोज की गई थी। ऐसे बेहिसाब परिणामों के बीच, हमने किले के कार्यान्वयन को पाया। स्टैक के साथ पर्याप्त खेलने के बाद, मैंने और मेरे दोस्त ने "अहा" कहा और संख्या प्रणाली के लिए आधार को शून्य पर सेट किया (फोर्ट में ऐसा एक मजेदार अवसर है)। किला स्वाभाविक रूप से यह सहन नहीं कर सका और हम इसके बारे में कुछ समय के लिए भूल गए।



बाद में, पहले से ही संस्थान में, फोर्ट बार-बार मेरे ध्यान की सतह पर उभरा, लेकिन वे गंभीरता से इससे निपट नहीं सके। वास्तव में, मुझे कभी भी किसी भी माइक्रोकंट्रोलर प्रोग्रामिंग या फोर्ट के किसी अन्य उपयोगी अनुप्रयोग का सामना करने का मौका नहीं मिला। और अब, Axiom डेवलपर्स के लिए धन्यवाद, मेरे पास ऐसा अवसर है! तथ्य यह है कि फोर्थ शब्द एक कारण से उनके फोर्थस्क्रिप्ट में दिखाई देता है। वास्तव में, दोनों Axiom और ForthScript के भाग को Fort पर लागू किया गया है, और axiom.dll में एक दुभाषिया है जो उन्हें उपयोग करने की अनुमति देता है। यदि आवश्यक हो, तो axiom.4th और CORE.4TH में आप कार्यान्वयन विवरण देख सकते हैं, और संभवतः कुछ ठीक कर सकते हैं।



इसलिए, सभी गेम लॉजिक की प्रोग्रामिंग फोर्ट को करनी होगी। लेकिन विकास कहाँ से शुरू करें? शुरुआत के लिए, बोर्ड पर टुकड़ों के एक साधारण आंदोलन को प्राप्त करना अच्छा होगा। प्रत्येक आंकड़ा 1, 2, 3 या 4 कोशिकाओं को अपने स्वयं के प्रक्षेपवक्र के साथ स्थानांतरित करने में सक्षम होना चाहिए (जब तक कि हम "हड्डियों" पर यादृच्छिक बिंदुओं को फेंकने से विचलित न हों):



आंकड़ों की चाल
 : common-move ( 'dir n -- ) SWAP BEGIN DUP EXECUTE verify SWAP 1- DUP 0= IF DROP TRUE ELSE SWAP FALSE ENDIF UNTIL empty? IF from here move add-move ENDIF ; : i-move-1 ( -- ) ['] Anext 1 common-move ; : i-move-2 ( -- ) ['] Anext 2 common-move ; : i-move-3 ( -- ) ['] Anext 3 common-move ; : i-move-4 ( -- ) ['] Anext 4 common-move ; : p-move-1 ( -- ) ['] Cnext 1 common-move ; : p-move-2 ( -- ) ['] Cnext 2 common-move ; : p-move-3 ( -- ) ['] Cnext 3 common-move ; : p-move-4 ( -- ) ['] Cnext 4 common-move ; {moves i-moves {move} i-move-1 {move} i-move-2 {move} i-move-3 {move} i-move-4 moves} {moves p-moves {move} p-move-1 {move} p-move-2 {move} p-move-3 {move} p-move-4 moves} {pieces {piece} init {moves} i-moves {piece} prom {moves} p-moves pieces}
      
      







निष्पादन पर ZRF-ku चलाना, आप यह सुनिश्चित कर सकते हैं कि अब आंकड़े स्थानांतरित किए जा सकते हैं। यह सब कैसे काम करता है? आइए आम-चाल के कार्यान्वयन को देखें। नाम के तुरंत बाद स्थित (फोर्ट शैली में) एक टिप्पणी से पता चलता है कि यह स्टैक पर दो मापदंडों को लेता है - एक संकलित दिशा संक्रमण आदेश और आंदोलन चरणों की संख्या। कार्यान्वयन में दो भाग होते हैं। सबसे पहले, एक चक्र में, एक निर्दिष्ट संख्या में, एक दिशा संक्रमण किया जाता है, फिर, यह जांचने के बाद कि लक्ष्य फ़ील्ड खाली है, Axiom कमांड के एक अनुक्रम को निष्पादित किया जाता है जो इस कदम (चिप को स्थानांतरित करते हुए) का निर्माण करता है। सबसे महत्वपूर्ण बात, यह सब संतुलन बनाने के दौरान - स्टैक को नष्ट करने के लिए नहीं!



निष्पादित की जा सकने वाली प्रत्येक कमांड का विवरण फोर्थस्क्रिप्ट और असिओम मैनुअल में पाया जा सकता है, जो एय्योम डेवलपमेंट किट के साथ बंडल किए गए हैं, लेकिन मैं इस कोड के बीच कुछ महत्वपूर्ण अंतरों पर आपका ध्यान आकर्षित करना चाहता हूं और जेडआरएफ का उपयोग करके क्या लिखा जा सकता है:





कुछ समय के लिए इस संस्करण के साथ खेलने के बाद, आप देख सकते हैं कि चिप्स, छोटे ब्लॉक तक पहुंचते हुए, एक सर्कल में चलना शुरू करते हैं। एक चिप के लिए इस "संसार के चक्र" से बचने के लिए, इसे खत्म कर दिया जाना चाहिए ( बदले हुए चिप्स के लिए, दिशा Cnext और Dnext की ओर अग्रसर होते हैं)। आपको याद दिला दूं कि उर के खेल में चिप्स को तोड़ना मुश्किल है। चिप को परिवर्तन क्षेत्र पर खड़े नहीं किया जाता है, लेकिन इसके माध्यम से गुजर रहा है। इसके अलावा, चूंकि अब चिप्स अंत तक सभी तरह से जाने में सक्षम होंगे, इसलिए बोर्ड से चिप्स को हटाने के बारे में मत भूलना जो खत्म हो गए हैं:



चिपटते हुए चिप्स
 VARIABLE isPromouted : common-move ( 'dir n -- ) FALSE isPromouted ! SWAP BEGIN current-player White = IF here p2 ELSE here p4 ENDIF = IF TRUE isPromouted ! ENDIF DUP EXECUTE verify SWAP 1- DUP 0= IF DROP TRUE ELSE SWAP FALSE ENDIF UNTIL empty? IF from here move here h3 = IF capture ENDIF isPromouted @ IF current-piece-type 1+ change-type ENDIF add-move ENDIF ;
      
      







किले में चर के बारे में कुछ शब्द इस प्रकार हैं। हम VARIABLE कीवर्ड का उपयोग करते हुए isPromouted चर को परिभाषित करते हैं। एक चर को परिभाषित करने के बाद, कोड में इसका कोई भी उल्लेख स्टैक पर इस चर के पते को धक्का देता है। निर्दिष्ट पते पर स्थित मान को पुनः प्राप्त करने के लिए, @ कमांड, कमांड का उपयोग करें ! चर का मान अधिलेखित करता है।



Axiom में कुछ जटिलता, आकार के प्रकारों के हेरफेर द्वारा दर्शाया गया है। तथ्य यह है कि आंकड़ों की परिभाषा कोड के बाद स्थित होती है जो उनके आंदोलन को नियंत्रित करती है (क्योंकि वे इसका उपयोग करते हैं)। इस कारण से, हम कोड में आकृतियों के प्रकारों के नामों का उपयोग नहीं कर सकते हैं (क्योंकि इस बिंदु पर वे अभी तक परिभाषित नहीं हैं)। एक नियम के रूप में, आप इस अप्रिय स्थिति से बाहर निकल सकते हैं। उदाहरण के लिए, हमारे कोड में, चिप्स को फ्लिप करने के लिए, हम बस उस प्रकार के टुकड़े को बढ़ाते हैं जो चाल को निष्पादित करता है।



गेमप्ले का एक महत्वपूर्ण हिस्सा खिलाड़ियों द्वारा एक चाल को छोड़ने की क्षमता है। खिलाड़ी को इस कदम को पूरा करना चाहिए, यदि संभव हो, और इस कदम को छोड़ दें, अन्यथा। यदि आप इस उद्देश्य पर ध्यान नहीं देते हैं, तो खेल किसी भी खिलाड़ी द्वारा कदम की पहली असंभवता पर स्वचालित रूप से एक ड्रॉ में पूरा हो जाएगा। इसके अलावा, प्रतिद्वंद्वी की बारी को छोड़ कर, "आउटलेट" पर जाने के बाद खिलाड़ी के दूसरे कदम को लागू करना तर्कसंगत है। चलो इसे करते हैं:



प्रगति को छोड़ दें
 : is-rosette? ( -- ? ) here i2 = here i4 = OR here l3 = OR here o2 = OR here o4 = OR ; : common-move ( 'dir n -- ) q5 enemy-at? NOT IF FALSE isPromouted ! SWAP BEGIN current-player White = IF here p2 ELSE here p4 ENDIF = IF TRUE isPromouted ! ENDIF DUP EXECUTE verify SWAP 1- DUP 0= IF DROP TRUE ELSE SWAP FALSE ENDIF UNTIL empty? IF from here move here h3 = IF capture ENDIF isPromouted @ IF current-piece-type 1+ change-type ENDIF is-rosette? IF q1 piece-type-at q5 create-piece-type-at ELSE q5 capture-at ENDIF add-move ENDIF ENDIF ; : pass-move ( -- ) q5 capture-at Pass add-move ; {moves i-moves {move} i-move-1 {move-type} normal-type {move} i-move-2 {move-type} normal-type {move} i-move-3 {move-type} normal-type {move} i-move-4 {move-type} normal-type {move} pass-move {move-type} pass-type moves} {moves p-moves {move} p-move-1 {move-type} normal-type {move} p-move-2 {move-type} normal-type {move} p-move-3 {move-type} normal-type {move} p-move-4 {move-type} normal-type {move} pass-move {move-type} pass-type moves} {move-priorities {move-priority} normal-type {move-priority} pass-type move-priorities}
      
      







क्या आप सबसे पहले आइस-रोसेट की आकर्षक परिभाषा को पकड़ते हैं? । दुर्भाग्य से, Axiom में, ZRF के विपरीत, गेम ज़ोन को परिभाषित करने का कोई तरीका नहीं है। सभी क्षेत्रों को व्यक्तिगत रूप से जांचना होगा।



स्किप कार्यान्वयन ZRF में उपयोग किए गए दृष्टिकोण से भी भिन्न होता है। " पास टर्न " विकल्प सेट करना Axiom द्वारा अनदेखा किया गया है। इसके बजाय, एक स्किप पास कमांड द्वारा स्पष्ट रूप से कॉन्फ़िगर किया जाना चाहिए। यह ZSG चालन रिकॉर्डिंग नोटेशन सुविधाओं के पूर्ण उपयोग का एक उदाहरण है (इसका उपयोग इंजन से ZoG में स्थानांतरण स्थानांतरित करने के लिए किया जाता है)। इस तरह का एक और उदाहरण ZRF में लागू नहीं होने पर, आंशिक चाल प्रदर्शन करते समय ड्रॉप्स कमांड का उपयोग करने की क्षमता है।



टिप्पणी
अपने स्वयं के विस्तार मॉड्यूल ( इंजन ) को विकसित करते समय ZSG संकेतन को समझना बहुत महत्वपूर्ण है। ZoG में एक चाल प्रदर्शन करने की क्षमता पूरी तरह से निर्धारित होती है कि क्या इसे ZSG संकेतन में लिखा जा सकता है। ZoG इस प्रारूप का दस्तावेजीकरण नहीं करता है, लेकिन Axiom प्रलेखन में इसका वर्णन करने वाला एक खंड है (परिशिष्ट B)। इस खंड से परिचित ZSG संकेतन की विशेषताओं को स्पष्ट करने के लिए डेवलपर को लंबे प्रयोगों से बचा सकता है।



पास के लिए केवल किसी अन्य कदम की संभावना के अभाव में काम करने के लिए, प्राथमिकताओं का उपयोग करना आवश्यक है। कम प्राथमिकता के साथ एक कदम केवल तभी प्रदर्शन किया जा सकता है जब उच्च प्राथमिकता वाले कदम की कोई संभावना नहीं है। दुर्भाग्य से, बल के लिए " पास टर्न " विकल्प सेट करते समय एज़िओम-स्टाइल स्किपिंग कार्यात्मक रूप से पूरी तरह से ZoG व्यवहार के बराबर नहीं है। ZRF कार्यान्वयन में, स्किपिंग स्वचालित रूप से की जाती है, Axiom के मामले में, आपको एक बटन दबाना होगा:







मुझे कहना होगा, यह बहुत भ्रम की बात है।



"आउटलेट" के लिए एक कदम के बाद एक लंघन कदम को लागू करने के लिए, एक अदृश्य ताला आंकड़ा q5 स्थिति में रखा जाता है जो खेल में उपयोग नहीं किया जाता है। आम-चाल की शुरुआत में, इस क्षेत्र में एक दुश्मन की उपस्थिति की उपस्थिति के लिए एक चेक बनाया जाता है। यदि क्षेत्र पर दुश्मन का कब्जा है, तो कोई चाल संभव नहीं है।



अब, यह सीखने का समय है कि पासा कैसे चलाया जाए:



हड्डी फेंकना
 {players {player} White {player} Black {player} ?Dice {random} players} {turn-order {turn} White {turn} ?Dice {of-type} clear-type {turn} ?Dice {turn} ?Dice {turn} ?Dice {turn} Black {turn} ?Dice {of-type} clear-type {turn} ?Dice {turn} ?Dice {turn} ?Dice turn-order} : drop-dices ( -- ) q2 here = q3 here = OR q4 here = OR empty? AND IF drop add-move ENDIF ; : count-dices ( -- n ) q2 piece-at piece-value q3 piece-at piece-value + q4 piece-at piece-value + DUP 0= IF DROP 4 ENDIF ; : clear-dices ( -- ) q1 here = verify q2 not-empty-at? q3 not-empty-at? q4 not-empty-at? AND AND IF drop q2 capture-at q3 capture-at q4 capture-at add-move ENDIF ; : i-move ( -- ) ['] Anext count-dices common-move ; : p-move ( -- ) ['] Cnext count-dices common-move ; {moves p-moves {move} p-move {move-type} normal-type {move} pass-move {move-type} pass-type moves} {moves drops {move} drop-dices {move-type} normal-type {move} pass-move {move-type} pass-type moves} {moves clears {move} clear-dices {move-type} clear-type moves} {pieces {piece} lock {moves} clears {piece} init {moves} i-moves {piece} prom {moves} p-moves {piece} wdice {drops} drops 1 {value} {piece} bdice {drops} drops 0 {value} pieces}
      
      







"हड्डियों" ( ड्रॉप-डाइस ) को फेंकने का कार्य प्राथमिक रूप से किया जाता है। बस जांचें कि लक्ष्य फ़ील्ड पासा फेंकने के लिए है, ड्रॉप कमांड के साथ आकृति डालें और ऐड-मूव कमांड के साथ चाल को समाप्त करें। क्लियर-डाइस थोड़ा और अधिक जटिल हैं। ZoG में, बोर्ड से एक टुकड़ा निकालने में केवल एक चाल बनाने का कोई तरीका नहीं है। हम एक अदृश्य आकृति को q1 फ़ील्ड में रीसेट करने के साथ सफाई प्रक्रिया को जोड़ते हैं जो खेल में उपयोग नहीं किया जाता है। बोर्ड से "हड्डियों" को हटाना इस कदम का एक दुष्प्रभाव है। यह गिराए गए बिंदुओं ( गिनती- बिंदुओं) को गिनने और इस मान को सामान्य-चाल में पास करने के लिए बना हुआ है



खेल को समाप्त करने के लिए स्थिति निर्धारित करने के लिए, उन चिप्स को गिनना आवश्यक है जो बोर्ड छोड़ चुके हैं। पूर्ण जाँच स्वयं को ओवरऑसम शब्द OnIsGameOver कहकर Axiom द्वारा किया जाता है। प्रारंभिक क्रियाएं करने के लिए, खेल की शुरुआत में (उदाहरण के लिए, छद्म यादृच्छिक संख्या जनरेटर को आरंभीकृत करना), आपको OnNewGame को ओवरराइड करना होगा:



समाप्ति की स्थिति
 {board 5 17 {grid} {variable} WhitePieces {variable} BlackPieces board} : WhitePieces++ WhitePieces ++ ; : BlackPieces++ BlackPieces ++ ; : common-move ( 'dir n -- ) q5 enemy-at? NOT IF FALSE isPromouted ! SWAP BEGIN current-player White = IF here p2 ELSE here p4 ENDIF = IF TRUE isPromouted ! ENDIF DUP EXECUTE verify SWAP 1- DUP 0= IF DROP TRUE ELSE SWAP FALSE ENDIF UNTIL empty? IF from here move here h3 = IF current-player White = IF COMPILE WhitePieces++ ELSE COMPILE BlackPieces++ ENDIF capture ENDIF isPromouted @ IF current-piece-type 1+ change-type ENDIF is-rosette? IF q1 piece-type-at q5 create-piece-type-at ELSE q5 capture-at ENDIF add-move ENDIF ENDIF ; : OnNewGame ( -- ) RANDOMIZE ; : OnIsGameOver ( -- gameResult ) repetition-reset #UnknownScore current-player White = IF BlackPieces @ 7 - 0= IF DROP #LossScore ENDIF ENDIF current-player Black = IF WhitePieces @ 7 - 0= IF DROP #LossScore ENDIF ENDIF ;
      
      







टिप्पणी
ऑन-बोर्ड वेरिएबल्स का उपयोग, एक्सीओम डॉक्यूमेंटेशन की धारा 3.9.4, "अपडेटिंग बोर्ड वेरिएबल्स" में वर्णित है।



एक पूर्ण खेल प्राप्त करने के लिए, यह आंकड़ों की लड़ाई और विशेष क्षेत्रों के प्रसंस्करण को लागू करने के लिए बनी हुई है। मैं इन विवरणों के साथ लेख को अव्यवस्थित नहीं करूंगा, क्योंकि वे अपने आप में कुछ नया नहीं करते हैं। जो इच्छुक हैं, वे GitHub पर "उर के रॉयल गेम" का पूर्ण कार्यान्वयन देख सकते हैं।



मूल वृत्ति



ZoG का मुख्य आकर्षण इसकी बहुमुखी प्रतिभा है। ZRF आपको बस अपने नियमों की घोषणा करके एक नया गेम बनाने (या किसी मौजूदा का वर्णन करने) की अनुमति देता है। हां, यह विशेष कार्यक्रमों की तुलना में काफी खराब है, लेकिन लगभग किसी भी खेल का एक प्रोटोटाइप बनाने के लिए इस तरह का अवसर बहुत लायक है! ZoG के लिए विकसित किए गए अनुप्रयोगों की संख्या अपने लिए बोलती है।



स्वयंसिद्ध भी सार्वभौमिक है। यह ZoG की कई अप्रिय सीमाओं को दूर करता है और आपको ऐसे बोर्ड गेम का वर्णन करने की अनुमति देता है जो ZoG के साथ सामना नहीं करता है। बूलियन झंडे में हेरफेर करने के बजाय पूर्ण विकसित अंकगणित का उपयोग करने की एक संभावना, इस उत्पाद को गुणात्मक रूप से उच्च स्तर पर ले जाती है, लेकिन यह Axiom का मुख्य लाभ नहीं है! ZoG अच्छा या बुरी तरह से खेलता है, लेकिन हमारे लिए, इसका AI एक ब्लैक बॉक्स है। हम उसके खेल की गुणवत्ता को प्रभावित नहीं कर सकते हैं! Axiom हमें इष्टतम कदम चुनने के लिए एल्गोरिदम के विकास में भाग लेने का अवसर देता है (लेकिन इसकी आवश्यकता नहीं है)।



एआई एक्सिओम के काम में हस्तक्षेप करने की सबसे स्पष्ट संभावना वजन फ़ंक्शन का विकल्प है जिसके द्वारा प्रत्येक स्थिति का मूल्यांकन किया जाता है। हम सभी की आवश्यकता है कि OnEvaluce को फिर से परिभाषित करना है । चलो शुरू से अंत तक चिप्स के कुल प्रचार के आधार के रूप में एक बहुत ही सरल मूल्यांकन समारोह बनाने की कोशिश करते हैं। हम 0 के वजन के साथ शुरुआती स्थिति में चिप्स के स्थान का मूल्यांकन करेंगे, और जिन चिप्स ने पूर्ण पथ पास किया है उनका मूल्यांकन कुछ बड़ी संख्या के साथ किया जाएगा, उदाहरण के लिए 100। जाहिर है, अगर एक चिप लिया जाता है, तो रेटिंग मूल्य तेजी से घट जाएगा (अधिक, आगे चिप समय है आगे बढ़ो)। बेशक, दुश्मन के लिए हम विपरीत संकेत के साथ उठाए गए एक ही अनुमान का उपयोग करेंगे। दुश्मन की स्थिति जितनी अच्छी होगी, हमारी स्थिति उतनी ही खराब होगी:



सरल मूल्यांकन समारोह
 VARIABLE whiteScored VARIABLE blackScored : Score ( value piece-type player pos -- score ) DUP not-empty-at? IF DUP player-at White = IF whiteScored -- ELSE blackScored -- ENDIF DUP ROT SWAP player-at = ROT ROT piece-type-at = AND NOT IF DROP 0 ENDIF ELSE DROP DROP DROP DROP 0 ENDIF ; : OnEvaluate ( -- score ) 7 whiteScored ! 7 blackScored ! 0 1 White i1 Score 0 1 White j1 Score + 0 1 White k1 Score + 0 1 White l1 Score + 0 1 White m1 Score + 0 1 White n1 Score + 0 1 White o1 Score + 0 1 Black i5 Score + 0 1 Black j5 Score + 0 1 Black k5 Score + 0 1 Black l5 Score + 0 1 Black m5 Score + 0 1 Black n5 Score + 0 1 Black o5 Score + 1 1 White l2 Score + -1 1 Black l4 Score + 2 1 White k2 Score + -2 1 Black k4 Score + 3 1 White j2 Score + -3 1 Black j4 Score + 4 1 White i2 Score + -4 1 Black i4 Score + 5 1 White i3 Score + -5 1 Black i3 Score + 6 1 White j3 Score + -6 1 Black j3 Score + 7 1 White k3 Score + -7 1 Black k3 Score + 8 1 White l3 Score + -8 1 Black l3 Score + 9 1 White m3 Score + -9 1 Black m3 Score + 10 1 White n3 Score + -10 1 Black n3 Score + 11 1 White o3 Score + -11 1 Black o3 Score + 12 1 White o2 Score + -12 1 Black o4 Score + 13 1 White p2 Score + -13 1 Black p4 Score + 14 2 White p3 Score + -14 2 Black p3 Score + 15 2 White p4 Score + -15 2 Black p2 Score + 16 2 White o4 Score + -16 2 Black o2 Score + 17 2 White o3 Score + -17 2 Black o3 Score + 18 2 White n3 Score + -18 2 Black n3 Score + 19 2 White m3 Score + -19 2 Black m3 Score + 20 2 White l3 Score + -20 2 Black l3 Score + 21 2 White k3 Score + -21 2 Black k3 Score + 22 2 White j3 Score + -22 2 Black j3 Score + 23 2 White i3 Score + -23 2 Black i3 Score + 1 1 White c2 Score + 1 1 White c3 Score + 1 1 White c4 Score + -1 1 Black d2 Score + -1 1 Black d3 Score + -1 1 Black d4 Score + 3 1 White a2 Score + 3 1 White a3 Score + 3 1 White a4 Score + -3 1 Black b2 Score + -3 1 Black b3 Score + -3 1 Black b4 Score + 7 1 White f2 Score + 7 1 White f3 Score + 7 1 White f4 Score + -7 1 Black f2 Score + -7 1 Black f3 Score + -7 1 Black f4 Score + 10 1 White g2 Score + 10 1 White g3 Score + 10 1 White g4 Score + -10 1 Black g2 Score + -10 1 Black g3 Score + -10 1 Black g4 Score + 11 1 White e2 Score + 11 1 White e3 Score + 11 1 White e4 Score + -11 1 Black e2 Score + -11 1 Black e3 Score + -11 1 Black e4 Score + 17 2 White e2 Score + 17 2 White e3 Score + 17 2 White e4 Score + -17 2 Black e2 Score + -17 2 Black e3 Score + -17 2 Black e4 Score + 18 2 White g2 Score + 18 2 White g3 Score + 18 2 White g4 Score + -18 2 Black g2 Score + -18 2 Black g3 Score + -18 2 Black g4 Score + 21 2 White f2 Score + 21 2 White f3 Score + 21 2 White f4 Score + -21 2 Black f2 Score + -21 2 Black f3 Score + -21 2 Black f4 Score + whiteScored @ 100 * + blackScored @ 100 * - current-player Black = IF NEGATE ENDIF ;
      
      







निश्चित रूप से, Axiom हमें मूल्यांकन समारोह विकसित करते समय किले के साथ आमने-सामने नहीं छोड़ता है। सामग्री और स्थिति दोनों घटकों का मूल्यांकन करने के लिए हमारे लिए सुविधाजनक प्राइमेटिव प्रदान किए जाते हैं। उदाहरण के लिए, आधिकारिक गाइड से लिया गया निम्न मूल्यांकन फ़ंक्शन (ऑड्स के लिए सटीक), अधिकांश गेम के लिए अच्छा काम करेगा, जैसे चेकर्स और शतरंज:



 : Mobility ( -- mobilityScore ) move-count \ Number of moves available to us. current-player TRUE 0 $GenerateMoves \ Generate moves for opponent move-count \ Number of moves available to opponent. - \ #friendlyMoves - #unfriendlyMoves $DeallocateMoves \ Deallocate the opponent's move list ; : OnEvaluate ( -- score ) Mobility current-player material-balance 3 * + ;
      
      





यहाँ, चाल-गणना कॉल वर्तमान स्थिति से संभावित चालों की संख्या की गणना करता है , और सामग्री-संतुलन {मान} विशेषता का उपयोग करके टुकड़ों को सौंपे गए भार की राशि की गणना करता है (हमारे कोड में, हम इसका उपयोग "हड्डियों" के लिए संख्यात्मक मान सेट करने के लिए करते हैं)।



यह सब ठीक है, लेकिन क्या होगा जब मिनिमैक्स एल्गोरिथ्म का बहुत उपयोग बेमानी है? जिस खेल को हम लागू करने की कोशिश कर रहे हैं, उसमें एक से अधिक कदमों की तलाश में केवल कंप्यूटिंग संसाधनों की बर्बादी का नेतृत्व करने की संभावना है। जैसा कि मैंने लिखा है, यहां हमें "आर्टिफिशियल इंटेलिजेंस" नहीं, बल्कि "आर्टिफिशियल इंस्टिंक्ट" की जरूरत है! Axiom हमें एक गहरे स्तर पर कदम चयन एल्गोरिथ्म में हस्तक्षेप करने का अवसर देता है:



मनमानी चाल चयन एल्गोरिथ्म
 VARIABLE BestScore \ Keep track of the best score found so far by our search engine. VARIABLE Nodes \ The number of possibilities explored by our search engine. VARIABLE Eated VARIABLE Rosettes : enemy-value-at ( pos -- value ) DUP empty-at? IF DROP 0 ELSE 0 SWAP player-at current-player <> IF DROP 1 ENDIF ENDIF ; : friend-value-at ( pos -- value ) DUP empty-at? IF DROP 0 ELSE 1 SWAP player-at current-player <> IF DROP 0 ENDIF ENDIF ; : Make_enemy_p ( pos -- ) <BUILDS , DOES> @ enemy-value-at ; : Make_friend_p ( pos -- ) <BUILDS , DOES> @ enemy-value-at ; i1 Make_enemy_p e0 j1 Make_enemy_p e1 k1 Make_enemy_p e2 l1 Make_enemy_p e3 m1 Make_enemy_p e4 n1 Make_enemy_p e5 o1 Make_enemy_p e6 i5 Make_enemy_p e7 j5 Make_enemy_p e8 k5 Make_enemy_p e9 l5 Make_enemy_p e10 m5 Make_enemy_p e11 n5 Make_enemy_p e12 o5 Make_enemy_p e13 i2 Make_friend_p r0 i4 Make_friend_p r1 l3 Make_friend_p r2 o2 Make_friend_p r3 o4 Make_friend_p r4 : CountEated ( -- count ) e0 e1 + e2 + e3 + e4 + e5 + e6 + e7 + e8 + e9 + e10 + e11 + e12 + e13 + ; : CountRosettes ( -- count ) r0 r1 + r2 + r3 + r4 + ; : Score ( -- score ) Eated @ CountEated < IF 10 ELSE 0 ENDIF Rosettes @ CountRosettes < IF 5 ELSE 0 ENDIF + ; : Custom-Engine ( -- ) -1000 BestScore ! \ Keep track of the best score. 0 Nodes ! \ Count the number of possibilities explored. CountEated Eated ! CountRosettes Rosettes ! ( Notes: 1 - We do not need to invoke $GenerateMoves since they have already been generated for the current player { since ZoG has called DLL_GenerateMoves prior to calling DLL_Search}. 2 - ZoG does not invoke the search engine if there are no moves, so we can safely assume. that at least one move exists. Thus we can use BEGIN..UNTIL instead of BEGIN...WHILE..REPEAT for iterating moves. ) $FirstMove \ Obtain the address of the first move. BEGIN $CloneBoard \ Create a temporary copy of the current board. DUP $MoveString CurrentMove! \ Inform ZoG of the current move being examined. DUP .moveCFA EXECUTE \ Apply the move to the board by executing its code. Score \ Calculate the score for the new board. BestScore @ OVER < \ Have we found a better score? IF DUP BestScore ! \ Save the improved score. Score! \ Inform ZoG of the improved score. DUP $MoveString BestMove! ELSE DROP \ We didn't find a better move, drop the score. ENDIF $DeallocateBoard \ Done with the revised board. Nodes ++ \ Count one more node explored. Nodes @ Nodes! \ Inform ZoG of the node count. $Yield \ Allow ZoG to dispatch Windows messages. $NextMove \ Advance to the next move. DUP NOT \ No more moves? UNTIL DROP ; {players {player} White {search-engine} Custom-Engine {player} Black {search-engine} Custom-Engine {player} ?Dice {random} players}
      
      







इस कोड का अधिकांश प्रलेखन से लिया गया है। जैसा कि आप टिप्पणियों से देख सकते हैं, हम सभी संभावित चालों से गुजरते हैं और मूल्यांकन कार्य को अस्थायी अस्थायी पदों पर लागू करते हैं। मूल्यांकन समारोह के रूप में, हम वही फ़ंक्शन ले सकते हैं जो हमने OnEvaluate के लिए लिखा था , लेकिन यह दिलचस्प नहीं होगा। मैंने कुछ बेहद आक्रामक खेल रणनीति तैयार करने की कोशिश की। यदि शत्रु का टुकड़ा लेना या "आउटलेट" पर खड़ा होना संभव है, तो इस कदम को बेहतर माना जाता है, यदि यह संभव नहीं है, तो पहली चाल जो सामने आई है वह चयनित है।



वैसे, Axiom ने प्राथमिक गेम {{}} और {random} को पूर्वनिर्धारित किया है। यहाँ बताया गया है कि वे स्वयंसिद्ध में कैसे वर्णित हैं।



आदिम खेल की रणनीतियाँ
 : $RandomMoveEngine $FirstMove 0 $movesList @ CELLSIZE + @ 1- $RAND-WITHIN BEGIN DUP 0> WHILE SWAP @ SWAP $Yield 1- REPEAT DROP ( move ) $MoveString DUP CurrentMove! BestMove! 1 Nodes! 0 Score! 0 Depth! ; : {random} ['] $RandomMoveEngine $CompileEngine ; : $FirstMoveEngine $FirstMove $MoveString DUP CurrentMove! BestMove! $Yield ; : {first} ['] $FirstMoveEngine $CompileEngine ;
      
      







जैसा कि मैंने कहा, ओपन सोर्स (आंशिक रूप से भी) सोर्स कोड बढ़िया है!



झूठ, ज़बरदस्त झूठ और आंकड़े



खैर, हमने एक नया गेम बनाया और हम इसे ZoG का उपयोग करके खेल सकते हैं। हमने विभिन्न चालन चयन एल्गोरिदम के साथ कई खेल विकल्प लागू किए हैं, लेकिन हम यह कैसे निर्धारित करते हैं कि कौन सा बेहतर है? बेशक, आप एक दर्जन "विशेषज्ञ" एकत्र कर सकते हैं और उनमें से प्रत्येक को प्रत्येक विकल्प के साथ सौ बार खेलने के लिए कह सकते हैं। जैसा कि मेरे एक दोस्त ने कहा, "यह वर्षों तक रह सकता है।" एक बेहतर तरीका है!



Axiom परीक्षण प्रक्रिया को स्वचालित करने के लिए AutoPlay उपयोगिता प्रदान करता है। स्वचालन के मार्ग का अनुसरण करते हुए हमें सबसे पहला काम करना चाहिए, खेल विकल्प बनाना :



 (variant (title "Ur [random]")) (variant (title "Ur [simple evaluation]")) (variant (title "Ur [aggressive]"))
      
      





ZRF फ़ाइल के अंत में इन पंक्तियों को जोड़ने के बाद, हम खेल का चौथा संस्करण प्राप्त करने के लिए ZRF कनवर्टर को फिर से लॉन्च करेंगे। प्रोग्राम द्वारा उपयोग की जाने वाली रणनीति को प्रभावित करने वाली इन फ़ाइलों में परिवर्तन करना आवश्यक है। यहाँ, उदाहरण के लिए, सबसे सरल विकल्पों में से एक दिखता है:



 LOAD Ur.4th ( Load the base Ur game ) {players {player} White {random} {player} Black {random} {player} ?Dice {random} players}
      
      





जैसा कि यह देखना आसान है, हम विवरण के अलग-अलग वर्गों को फिर से परिभाषित कर सकते हैं, सभी साझा कोड को भरी हुई स्क्रिप्ट फ़ाइलों में ले जा सकते हैं।



विकल्प तैयार होने के बाद, हम गेम को दूसरे के खिलाफ एक विकल्प के गेम मोड में शुरू कर सकते हैं। यह ऑटोप्ले का मुख्य लाभ है! यह विकल्प बनाने के लिए आवश्यक नहीं है जिसमें खिलाड़ी विभिन्न रणनीतियों का उपयोग करके खेलते हैं यह निम्नलिखित आदेश देने के लिए पर्याप्त है:



 AutoPlay Ur-[random] Ur-[random] 100
      
      





सब कुछ यथासंभव सरल है। हम पहले और दूसरे खिलाड़ियों के लिए विकल्प सेट करते हैं (ऑटोप्ले के वर्तमान कार्यान्वयन में, अधिक खिलाड़ी समर्थित नहीं हैं) और गेम की संख्या। फिर कार्यक्रम अपने आप काम करता है। और अगर वह इन खेलों को ZoG का उपयोग करके खेला जाता है, तो वह उससे भी ज्यादा तेजी से करती है! आउटपुट एक बड़ी टेक्स्ट फ़ाइल है जिसमें ZSG नोटेशन में खेले गए सभी गेमों का वर्णन है। सबसे अंत में, अंतिम आंकड़े प्रदर्शित किए जाते हैं, जिसके अनुसार यह देखा जा सकता है कि, बशर्ते कि चालों को बेतरतीब ढंग से चुना जाता है, पहला कदम बनाने वाले खिलाड़ी को थोड़ा फायदा होता है (यहां तक ​​कि इस तथ्य को ध्यान में रखते हुए कि वह हमेशा "इकाई" में जाता है):



 Final results: Player 1 "Ur-[random]", wins = 52. Player 2 "Ur-[random]", wins = 48. Draws = 0 100 game(s) played
      
      





एक पूर्ण ZSG विवरण होने से, हमें थोड़ा प्रसंस्करण के बाद, किसी भी बैच को ZoG में लोड करने और चरण दर चरण इसकी समीक्षा करने की अनुमति मिलती है। वैसे, यह है कि कार्यान्वयन में इन त्रुटियों को कैसे खोजा गया और सही किया गया (मुझे नहीं पता कि मैंने क्या सोचा था जब मैंने इसे जांचने के बजाय संक्रमण परिणाम को छोड़ने का फैसला किया था)।



एक पूर्ण ZSG विवरण होने का एक और लाभ यह है कि, डेटा को संसाधित करने के बाद, हम किसी भी आवश्यक आंकड़े एकत्र कर सकते हैं यदि हम जीते / खोए गए खेलों की संख्या के सरल अनुपात से संतुष्ट नहीं हैं। निम्नलिखित स्क्रिप्ट खेल की अवधि पर डेटा प्रदर्शित करता है, खेल के अंत में अंतिम स्कोर, मिस्ड चाल की संख्या और प्रत्येक खिलाड़ियों द्वारा चिप्स "गिर" की संख्या:



डेटा प्रोसेसिंग स्क्रिप्ट
 #!/usr/bin/perl -w my @S = (0, 0, 0, 0, 0, 0); my $ix = 0; my $T; while (<>) { if (/results/) { my $d = $S[0] - $S[1]; print "$T, $d, $S[3], $S[2], $S[4], $S[5]\n"; @S = (0, 0, 0, 0, 0, 0); $ix = 0; } else { if (/^(\d+)\.\s+[^?].*$/) { $T = $1; if (/x h3/) { $S[$ix]++; } if (/Pass|^(\d+)\.\s+x\s+q5\s*$/) { $S[$ix + 2]++; } if (/Black init [ijklmno]5/) { $S[4]++; } if (/White init [ijklmno]1/) { $S[5]++; } $ix++; if ($ix > 1) { $ix = 0; } } } }
      
      







अब हमारे पास सब कुछ है जो हमें विकसित किए गए विकल्पों की गेम गुणवत्ता की तुलना करने की आवश्यकता है। हम तीन विकल्पों पर विचार करेंगे:





यादृच्छिक बनाम यादृच्छिक
पार्टी की अवधि (विरोधियों, खेल मजबूत करने के लिए औसतन, स्ट्रोक थोड़ा 150 से अधिक नहीं की कोशिश कर रहे हैं):







चिप्स बोर्ड पर छोड़ दिया की राशि (एक नकारात्मक मूल्य - पहले खिलाड़ी की हानि):







एक ही के बारे में खिलाड़ियों चिप "नीचे कट" की संख्या:







हम देख सकते हैं कि खिलाड़ी अभी शुरुआत है सबसे पहले, यह एक मामूली लाभ है:



 Final results: Player 1 "Ur-[random]", wins = 52. Player 2 "Ur-[random]", wins = 48. Draws = 0 100 game(s) played
      
      







यादृच्छिक बनाम सरल
:







:



 Final results: Player 1 "Ur-[random]", wins = 50. Player 2 "Ur-[simple-evaluation]", wins = 50. Draws = 0 100 game(s) played
      
      







सरल बनाम यादृच्छिक
:







«» :







 Final results: Player 1 "Ur-[simple-evaluation]", wins = 87. Player 2 "Ur-[random]", wins = 13. Draws = 0 100 game(s) played
      
      







यादृच्छिक बनाम आक्रामक
:







random ( ):







, , «» :







«» , !



 Final results: Player 1 "Ur-[random]", wins = 25. Player 2 "Ur-[aggressive]", wins = 75. Draws = 0 100 game(s) played
      
      







एग्रेसिव बनाम रैंडम
:







«» «» !







, «» , :







 Final results: Player 1 "Ur-[aggressive]", wins = 90. Player 2 "Ur-[random]", wins = 10. Draws = 0 100 game(s) played
      
      







सरल बनाम आक्रामक
, . , simple :







!







 Final results: Player 1 "Ur-[simple-evaluation]", wins = 73. Player 2 "Ur-[aggressive]", wins = 27. Draws = 0 100 game(s) played
      
      







एग्रेसिव बनाम सरल
, agressive :







«» , , «»:







 Final results: Player 1 "Ur-[aggressive]", wins = 64. Player 2 "Ur-[simple-evaluation]", wins = 36. Draws = 0 100 game(s) played
      
      







वैसे, निम्नलिखित अद्भुत रेखा पर ध्यान दें:



 Draws = 0
      
      





तथ्य यह है कि Axiom "3-समय पुनरावृत्ति ड्रा!" से निपटने का एक तरीका प्रदान करता है। मैंने दस्तावेज़ के संबंधित अनुभाग का सावधानीपूर्वक अध्ययन किया और सभी आवश्यक कार्रवाई की। समस्या यह है कि ZoG में यह स्थिति अभी भी पैदा होती है। यह आमतौर पर तब होता है जब सफेद और काले चिप्स की लंबी श्रृंखलाएं (एक पंक्ति में 3-4 चिप्स) एक दूसरे को अवरुद्ध करती हैं। "रॉयल उर" में, सुरक्षित क्षेत्रों के लिए धन्यवाद, हमेशा उनके लिए फैलाने का एक तरीका है, लेकिन ZoG (यहां तक ​​कि Axiom के नियंत्रण में) चिप्स के फैलने तक इंतजार नहीं करता है! और यहाँ AutoPlay है, अंत तक सभी गेम खेल रहा है। सिद्धांत रूप में, जैसा कि मैंने पहले ही कहा था, इसे ZoG स्थापित और खरीदे बिना भी लॉन्च किया जा सकता है, बस कोई ग्राफ़िकल इंटरफ़ेस नहीं होगा।



... और एक हजार हाथी!



बेशक, सिर्फ एक लेख में इस तरह के एक जटिल और बहुमुखी उत्पाद के बारे में सभी को बताना असंभव है, जैसे कि Axiom Development Kit। देखें कि डेवलपर्स ने क्या विशेषताएं घोषित की हैं:



Axiom इंजन की विशेषताएं
  • Contains a universal game engine designed to play a large variety of games. The search engine is not optimized for any particular class of games.
  • Allows (actually requires) the game programmer to specify a custom game AI. This is one of the main benefits of Axiom. Some 'built-in' AI helpers are provided. For example, one helper is simply the difference between the number of available moves for each player, another takes into consideration material advantage. The list is expected to grow over time.
  • «Minimax with Alpha-Beta pruning» search algorithm.
  • Iterative deepening with transposition table.
  • Zobrist hashing
  • Limited move reordering based on 'best move from previous iteration' stored in the transposition table.
  • Full width searching.
  • Support for 'partial' and 'pass' moves.
  • Supports 'teams'.
  • Time management.
  • Supports additional user-supplied custom engines.
  • Programmer controlled quiescence (currently experimental)


समय प्रबंधन के लिए समर्थन भी है, और टीम प्ले के लिए समर्थन, जो कि ZoG में कमी थी। Axiom "कनेक्शन" और "क्षेत्र पर कब्जा करने" के लिए खेलों के विकास के लिए एक विशेष डेटा संरचना (रिंग बफर) प्रदान करता है। कुछ हद तक निराशा की बात यह है कि टुकड़ों की विशेषताओं का समर्थन नहीं किया जाता है (उदाहरण के लिए, जोओजी का उपयोग करके, शतरंज कास्टिंग को लागू करता है), लेकिन एक्सिओम इस कष्टप्रद सीमा के आसपास पाने के लिए पर्याप्त अवसर प्रदान करता है।



अलग और बहुत गर्म शब्द प्रलेखन और उदाहरणों की गुणवत्ता के लायक हैं। बहुत जटिल सामग्री प्रस्तुत की गई ताकि इसका आत्मसात किसी भी कठिनाइयों से जुड़ा न हो। और यहां तक ​​कि अगर यह सामग्री पर्याप्त नहीं है, तो ZoG वेबसाइट में Axiom का उपयोग करके विकसित 60 से अधिक दिलचस्प एप्लिकेशन हैं, जो विश्लेषण और अध्ययन के लिए उपलब्ध हैं।




All Articles