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

"लेकिन वह अपने पाठ को प्रदर्शित करने के अलावा और कुछ कैसे कर सकता है?" - शायद आप पूछें। और आसान है। आउटपुट के अलावा, प्रोग्राम में इनपुट भी है। यदि कार्यक्रम इनपुट के अभाव में अपने पाठ को प्रदर्शित करता है - तो यह क्वीन है। यदि इनपुट उपलब्ध होने पर प्रोग्राम कुछ और करता है, तो हम इसकी निंदा करने वाले कौन हैं?
शायद मैं तुरंत मेज पर कार्ड बिछा दूंगा।
यहाँ मेरी रचना की एक कड़ी है। संदर्भ में फ़ाइल में तीन इकाइयाँ हैं:
- क्वीन फंक्शन मैं किस बारे में बात कर रहा हूं।
- EvalAndCall फ़ंक्शन सहायक है।
- खेल वर्ग - और भी अधिक सहायक
पहले, हम इस बारे में बात करेंगे कि क्वीन फ़ंक्शन के साथ कैसे काम करना है, और फिर यह कैसे काम करता है।
उसके साथ कैसे काम करना है
क्वीन फ़ंक्शन की शुरुआत में, आप निम्नलिखित देख सकते हैं:
function quine(input){
फ़ंक्शन की शुरुआत में टिप्पणी उपयोगकर्ता इंटरफ़ेस है। इसके माध्यम से, फ़ंक्शन उन लोगों के साथ संवाद करेगा जो खेल के लिए इसका उपयोग करते हैं। पहले, मैंने इसे कंसोल के माध्यम से करने के बारे में सोचा, लेकिन फिर मैंने फैसला किया कि
फ़ंक्शन को साफ रखने के लिए यह अधिक सही होगा।
आइए देखें कि फ़ंक्शन वास्तव में क्वीन है।
यहां, सुविधा के लिए, मैंने quine.js स्क्रिप्ट के साथ एक (लगभग) खाली HTML पृष्ठ पोस्ट किया है। डेवलपर के टूल खोलते हुए, आप निम्न कोड को गैर-चुनिंदा तरीके से चला सकते हैं:
const quineText = quine(); const evaluatedQuine = eval("(" + quineText + ")");
बोर मॉडवास्तव में, निश्चित रूप से, हमने केवल यह जाँच की कि क्वीन फ़ंक्शन क्वीन का पाठ लौटाता है, और यह नहीं कि यह स्वयं ही क्वीन है। और बिल्कुल सटीक होने के लिए - हमने केवल यह जाँच की कि क्वीन फ़ंक्शन फ़ंक्शन का पाठ लौटाता है, जो हमारे मामले में क्वीन की तरह काम करता है। कोई गारंटी नहीं है कि अंदर कुछ शामिल नहीं है:
if(Math.random() < 0.99){ beAGoodQuine(); }else{ haltAndCatchFire(); }
अब हम उसके साथ खेलने की कोशिश कर सकते हैं। मान लीजिए कि हम मैदान के ऊपरी बाएँ कोने में पहली चाल बनाते हैं।
let quineText = quine(1);
अब "यूजर इंटरफेस" इस प्रकार है:
function quine(input){
क्वीन ने हमारे कदम को ध्यान में रखा और ऊपरी केंद्रीय क्षेत्र में प्रतिक्रिया दी। वैसे, परिणामी फ़ंक्शन भी क्वीन है - बिना तर्कों के कहा जाता है, यह अपना नया पाठ लौटाएगा, न कि मूल फ़ंक्शन का पाठ। हम पूरे गेम खेल सकते हैं, लेकिन सुविधा के लिए हम सहायक फ़ंक्शन evalAndCall का उपयोग करेंगे।
let quineText = quine();
देखा! शांत खेलता है, जीतता है और स्कोर भी करता है। आप इसके साथ लंबे समय तक खेल सकते हैं, लेकिन अधिक सुविधा के लिए, मैं गेम क्लास का उपयोग करने की सलाह देता हूं, जिसके साथ मैंने खुद गेम का परीक्षण किया। मुझे लगता है कि यदि आप इस बिंदु तक पढ़ते हैं, तो मुझे यह समझाने की आवश्यकता नहीं है कि इसका उपयोग कैसे किया जाए।
यह कैसे काम करता है
सामान्य तौर पर, कार्य में दो भाग होते हैं: लिखने के लिए, यदि संभव हो, टिक-टैक-टो के खेल का एक संक्षिप्त कार्य, तो इसे क्वीन में बंद कर दें। चलो टिक-टैक-टो से शुरू करते हैं।
"कृत्रिम बुद्धिमत्ता" का मूल 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; }
यह कोड थोड़ा अस्पष्ट लगता है क्योंकि मैं इसे यथासंभव छोटा बनाने में रुचि रखता था। इसका सार इस प्रकार है: फ़ील्ड की स्थिति - नौ तत्वों की एक सरणी - और उस सेल की संख्या जहां खिलाड़ी-व्यक्ति एक चाल बनाता है (अगला इस चाल की वैधता की जांच करता है), अगले फ़ंक्शन में प्रवेश करता है। फ़ील्ड का प्रत्येक तत्व एक क्रॉस, एक शून्य, एक अंडरस्कोर (खाली सेल) या एक विस्मयादिबोधक चिह्न (एक खाली सेल, जिस पर पहले अवसर पर एक क्रॉस डाल सकता है) हो सकता है। यदि मैदान पर कोई विस्मयादिबोधक चिह्न है, तो हम तुरंत वहां कदम रखते हैं और जीतते हैं। अन्यथा, हम सरणी को एक स्ट्रिंग में गोंद करते हैं और नियम ऑब्जेक्ट में संबंधित नियम की तलाश करते हैं। अंतरिक्ष को बचाने के लिए, नियम रोटेशन के लिए सटीक हैं, इसलिए खोज करने के लिए, क्षेत्र को चार बार घुमाया जाता है। जब वांछित नियम पाया जाता है, तो फ़ील्ड के राज्य को नियम के मान से बदल दिया जाता है, पात्रों में तोड़ दिया जाता है। अगला, अगला फ़ंक्शन फ़ील्ड की नई स्थिति लौटाता है। उसी समय, एक अतिरिक्त दसवां चरित्र इसमें शामिल हो सकता है: "डब्ल्यू" - यदि एआई जीता, "डी" - अगर कोई ड्रॉ था।
विस्मयादिबोधक चिह्न, "संकेत" और क्षेत्र के रोटेशन के लिए धन्यवाद, और यह भी, निश्चित रूप से, इस तथ्य के कारण कि एआई पहले चलता है, इष्टतम रणनीति को केवल 6 नियमों में वर्णित किया गया था।
अगले फ़ंक्शन का उपयोग करते हुए, क्वीन फ़ंक्शन इनपुट को संसाधित करता है और मैजिकहैश ऑब्जेक्ट के लिए कुछ फ़ील्ड लिखता है। और यहां हम आसानी से दूसरे भाग पर जाते हैं: "क्वैने" घटक कैसे काम करता है। सभी जादू मैजिक हैश ऑब्जेक्ट और इसकी मैजिकस्ट्रिंग प्रॉपर्टी में है।
मैजिकस्ट्रिंग लाइन, जैसा कि आप आसानी से देख सकते हैं, इसमें लगभग पूरी तरह से डुप्लिकेट प्रोग्राम टेक्स्ट शामिल है। हालाँकि, जिस किसी ने कभी भी एक क्वीन लिखने की कोशिश की है, वह जानता है, आप इसमें एक पूरी तरह से पाठ को आगे नहीं बढ़ा सकते हैं - क्योंकि तब इसमें खुद को सख्ती से रखना होगा, जो परिमित लंबाई के लिए असंभव है। इसलिए, "प्लेन" टेक्स्ट के अलावा, इसमें "मैजिक" वाइल्डकार्ड सीक्वेंस भी होते हैं, जो "$" कैरेक्टर द्वारा दोनों तरफ सीमांकित होते हैं।
जब समय एक्स आता है और हमें फ़ंक्शन का पाठ वापस करना पड़ता है, तो हम बस मैजिकस्ट्रिंग लेते हैं और इसमें वाइल्डकार्ड अनुक्रम को मैजिकहैश ऑब्जेक्ट के संबंधित गुणों के साथ बदल देते हैं। ये गुण स्थैतिक (बैकटिक) हो सकते हैं, रनटाइम (क्षेत्र) में परिवर्तन या यहां तक कि रनटाइम (संदेश) में जोड़ा जा सकता है - यह कोई फर्क नहीं पड़ता। यह महत्वपूर्ण है कि कोड के प्रत्येक "समस्याग्रस्त" टुकड़े के लिए जिसे केवल एक पंक्ति में डुप्लिकेट नहीं किया जा सकता है, हमारे पास मैजिक हैश ऑब्जेक्ट की "मैजिक" संपत्ति है। पिछले एक ही MagicString विकल्प। उत्तरार्द्ध - क्योंकि अन्यथा अतिरिक्त वाइल्डकार्ड अनुक्रम होंगे जो प्रतिस्थापित भी किए जाएंगे।
परिणाम
मैंने अपने अनुभव से जाँच की कि आप किसी भी चीज़ को क्वीन में भर सकते हैं। सिद्धांत रूप में, यदि आप परेशान करते हैं, तो आप एक क्वीन जनरेटर बना सकते हैं - एक फ़ंक्शन जो किसी अन्य शुद्ध फ़ंक्शन को क्वीन में बदल देता है और आपको एक मनमाना राज्य संग्रहीत करने की अनुमति देता है जो उपरोक्त शुद्ध फ़ंक्शन का उपयोग कर सकता है। हालांकि, इस पांडुलिपि के मार्जिन बहुत संकीर्ण हैं ...
सामान्य तौर पर, मैं अपनी "खोज" की विशेष नवीनता का ढोंग नहीं करता। कट्टर पदाधिकारियों ने उत्कृष्टता की मुस्कान के साथ इस पाठ को पढ़ा होगा। लेकिन यह मेरे लिए दिलचस्प था कि मैं इसे अपने हाथों से उठाऊं, डालूं, बोलने के लिए, उंगलियों को घाव में डाल दूं। और मुझे आशा है कि आप इसके बारे में पढ़ने में रुचि रखते थे।
अलविदा, लड़कियों और लड़कों। फिर मिलते हैं।