शुरुआती लोगों के लिए चरण-दर-चरण गाइड
आपको क्या चाहिए
- एक FlipSight खाता। साइन इन करने के बाद आप बॉट पंजीकृत कर सकते हैं और कनेक्टर डाउनलोड कर सकते हैं।
- बॉट की एक तस्वीर: 5 MB या उससे छोटी GIF, JPG या PNG फ़ाइल, जिसकी चौड़ाई और ऊँचाई कम से कम 175 px हो।
- बॉट चलाने के लिए अपना कंप्यूटर आपके बॉट की चालें उसी कंप्यूटर पर गिनी जाती हैं जिस पर कनेक्टर चल रहा है। एक ही इंजन होने पर भी कंप्यूटर की क्षमता और इंजन की सेटिंग के हिसाब से ताकत अलग हो सकती है, और कंप्यूटर या सेटिंग बदलने पर रेटिंग भी उसी के अनुसार बदल सकती है।
- Python 3, एक मुफ़्त प्रोग्राम जो कनेक्टर चलाता है। संस्करण 3.9 या नया काम करता है; 3.11 या नया सुझाया जाता है। आप इसे चरण 5 में जाँचेंगे।
- आपके बॉट का इंजन। कनेक्शन प्रोग्राम के साथ परीक्षण के लिए एक अभ्यास इंजन शामिल है।
1. अपना बॉट पंजीकृत करें
साइन इन करें और बॉट पेज (othelloclub.com/hi/flipsight/bot) खोलें। ऊपर के अपना बॉट पंजीकृत करें बॉक्स में बॉट का नाम (2–24 अक्षर) में नाम लिखें। समर्थित खेल में अभी केवल स्टैंडर्ड चुना रहने दें। बॉट की तस्वीर अपलोड करें में तस्वीर चुनें, फिर अपना बॉट पंजीकृत करें बटन दबाएँ।
सफल होने पर ऐसा दिखता है: कनेक्शन टोकन (केवल एक बार दिखेगा) बॉक्स दिखाई देता है, जिसमें fsbm_ से शुरू होने वाला लंबा टेक्स्ट होता है।
2. टोकन सँभालकर रखें
यह लंबा टेक्स्ट टोकन है, यानी सिर्फ़ आपके बॉट का पासवर्ड। कनेक्टर इसी से सर्वर को साबित करता है कि वह इस बॉट की ओर से बोल रहा है। पूरा टेक्स्ट कॉपी करें और कुछ समय के लिए कहीं चिपकाएँ, जैसे किसी टेक्स्ट एडिटर में। बॉक्स बंद करने के बाद वही टोकन फिर नहीं देख सकते।
टोकन को पासवर्ड की तरह रखें। इसे किसी को न दिखाएँ और इसका स्क्रीनशॉट पोस्ट न करें। अगर यह खो जाए या कोई इसे देख ले, तो बॉट सूची में प्रबंधन खोलें और कनेक्शन टोकन बनाएँ दबाएँ। नया टोकन मिलते ही पुराना तुरंत काम करना बंद कर देता है।
3. कनेक्टर डाउनलोड करें
ZIP फ़ाइल डाउनलोड करने के लिए Python उदाहरण डाउनलोड करें दबाएँ और उसे एक्सट्रैक्ट करें। इस गाइड में एक्सट्रैक्ट किए गए फ़ोल्डर को "बॉट फ़ोल्डर" कहा गया है। इसे किसी आसानी से मिलने वाली जगह रखें, जैसे डेस्कटॉप पर।
सफल होने पर ऐसा दिखता है: बॉट फ़ोल्डर में README.md फ़ाइल और tools फ़ोल्डर है।
4. बॉट फ़ोल्डर में टर्मिनल खोलें
टर्मिनल एक विंडो है जिसमें आप कमांड टाइप करते हैं। अपने सिस्टम के अनुसार इसे नीचे बताए तरीके से खोलें।
macOS: Command+Space दबाएँ, Terminal टाइप करें और उसे खोलें। cd और एक स्पेस टाइप करें, बॉट फ़ोल्डर को खींचकर विंडो में छोड़ें, फिर Enter दबाएँ।
Linux: फ़ाइल मैनेजर में बॉट फ़ोल्डर पर राइट-क्लिक करें और "टर्मिनल में खोलें" (Open in Terminal) चुनें। मेन्यू का नाम हर डिस्ट्रीब्यूशन में अलग हो सकता है। अगर ऐसा मेन्यू नहीं है, तो टर्मिनल खोलें और macOS की तरह cd उपयोग करें।
Windows: फ़ाइल एक्सप्लोरर में बॉट फ़ोल्डर खोलें। ऊपर एड्रेस बार में powershell टाइप करें और Enter दबाएँ। उसी फ़ोल्डर में एक PowerShell विंडो खुलती है।
जाँच: नीचे का कमांड टाइप करें और Enter दबाएँ। सूची में README.md और tools दिखें तो सफल है। यह कमांड macOS, Linux और Windows PowerShell में एक जैसा है।
ls5. Python जाँचें
उसी विंडो में अपने सिस्टम वाला एक कमांड कॉपी करें, चिपकाएँ और Enter दबाएँ। हर कोड बॉक्स के ऊपर दाईं ओर का कॉपी बटन उपयोग कर सकते हैं।
macOS / Linux
python3 --versionWindows PowerShell
py --versionसफल होने पर ऐसा दिखता है: 3 से शुरू होने वाला संस्करण, जैसे Python 3.11.9। संस्करण 3.9 या नया काम करता है। अगर कमांड नहीं मिलता, तो नीचे बताए अनुसार Python इंस्टॉल करें, विंडो बंद करें और चरण 4 से फिर शुरू करें।
macOS: python.org से macOS इंस्टॉलर (.pkg) डाउनलोड करके इंस्टॉल करें। फिर Applications के Python फ़ोल्डर से Install Certificates.command एक बार चलाएँ। इससे सुरक्षित (HTTPS) कनेक्शन के लिए ज़रूरी प्रमाणपत्र तैयार होते हैं।
Linux: अपने डिस्ट्रीब्यूशन के सॉफ़्टवेयर मैनेजर या पैकेज मैनेजर से python3 इंस्टॉल करें।
Windows: python.org से Python install manager इंस्टॉल करें।
6. टोकन डालें
टोकन को एक एनवायरनमेंट वेरिएबल में रखें। यह एक अस्थायी सेटिंग है जो केवल इसी टर्मिनल विंडो के अंदर रहती है। इसका नाम FS_BOT_TOKEN है। नीचे अपने सिस्टम वाला एक पंक्ति का कमांड कॉपी करें, चिपकाएँ और एक बार Enter दबाएँ। फिर Bot token दिखेगा और आपके इनपुट का इंतज़ार करेगा। अब चरण 2 में कॉपी किया टोकन चिपकाएँ और Enter दबाएँ।
macOS / Linux
printf 'Bot token: '; read -r -s FS_BOT_TOKEN; printf '\n'; export FS_BOT_TOKENWindows PowerShell
$env:FS_BOT_TOKEN = [Net.NetworkCredential]::new('', (Read-Host 'Bot token' -AsSecureString)).PasswordmacOS और Linux पर चिपकाया गया टोकन नहीं दिखता, और Windows पर उसके अक्षरों की जगह * दिखते हैं। दोनों सामान्य हैं। टोकन कमांड में नहीं लिखा जाता, इसलिए वह कमांड इतिहास में नहीं रहता। यह सेटिंग केवल इसी विंडो में रहती है। अगर आपने विंडो बंद कर दी या नई विंडो खोली, तो चरण 4 और 6 दोहराएँ।
Windows: PowerShell में Ctrl+V या राइट-क्लिक से चिपकाएँ। यह एक पंक्ति का कमांड ऐसे लिखा गया है कि Windows के साथ आने वाले Windows PowerShell 5.1 और नए PowerShell 7 दोनों में चले, लेकिन इसे अभी किसी असली Windows कंप्यूटर पर नहीं जाँचा गया है।
सफल होने पर ऐसा दिखता है: बिना किसी त्रुटि के अगले कमांड का प्रॉम्प्ट वापस आ जाता है।
7. कनेक्टर शुरू करें
उसी विंडो में नीचे का कमांड जैसा है वैसा ही कॉपी करें, चिपकाएँ और Enter दबाएँ। इसमें फ़ाइलों के नाम न बदलें। आपका बॉट अभ्यास इंजन के साथ जुड़ता है। यह बहुत कमज़ोर इंजन है जो सबसे छोटे नंबर वाले वैध खाने पर चलता है।
macOS / Linux
python3 tools/bot_match_client.py --engine 'python3 tools/bot_match_example_engine.py'Windows PowerShell
py tools/bot_match_client.py --engine 'py tools/bot_match_example_engine.py'चलते समय कमांड का कोई पाठ न दिखाना और अगला इनपुट प्रॉम्प्ट न लौटना सामान्य है। बॉट को ऑनलाइन रखने के लिए यह विंडो खुली रखें, कनेक्शन प्रोग्राम और इंजन चलाते रहें तथा कंप्यूटर को स्लीप में न जाने दें। विंडो बंद करने या Ctrl+C दबाने से दोनों प्रोग्राम बंद हो जाते हैं और बॉट ऑफलाइन हो जाता है। दोबारा ऑनलाइन लाने के लिए ऊपर दिया कमांड फिर चलाएं। कनेक्शन प्रोग्राम दूसरे बॉट के मैच अनुरोध अपने आप स्वीकार करता है।
जब तक बॉट अभ्यास इंजन से चल रहा है, उसे अपने-आप मुकाबले नहीं मिलते, और दूसरे बॉट के साथ उसके मुकाबले, आपके खुद भेजे गए भी, रेटिंग में नहीं गिने जाते। अपने इंजन से दोबारा चालू करें (चरण 10), तब से उसे जोड़ी मिलेगी और रेटिंग गिनी जाएगी।
सफल होने पर ऐसा दिखता है: बॉट पेज की पंजीकृत बॉट सूची में आपके बॉट के नाम के दाईं ओर का बिंदु हरा है। उस पर माउस ले जाने पर ऑनलाइन दिखता है। अगर वह स्लेटी (ऑफ़लाइन) है, तो ताज़ा करें दबाएँ।
8. पहले खेल से जाँचें
बॉट पेज पर मेरा खेलने वाला बॉट में अपना बॉट चुनें। FlipSight बॉट सूची में कोई भी बॉट चुनें, चुनौती दें दबाएँ और खुलने वाली विंडो में पुष्टि करें। सभी तरह के खेलों में FlipSight बॉट की चालें सर्वर गिनता है, इसलिए गेम रूम खुला रखने की ज़रूरत नहीं है। अपने-आप जोड़ी चालू रहने पर (डिफ़ॉल्ट), कनेक्टर चलते समय साइट आपके लिए बॉट मुकाबले भी तय करती है।
सफल होने पर ऐसा दिखता है: गेम रूम में दो बोर्ड दिखते हैं, और आपके बॉट की हर बारी पर एक गोटी रखी जाती है। अभ्यास इंजन बहुत कमज़ोर है, इसलिए हारना सामान्य है।
9. विंडो बंद करने के बाद भी चलाते रहें (वैकल्पिक)
चरण 7 के बजाय नीचे के कमांड से शुरू करें, तो विंडो बंद करने के बाद भी बॉट चलता रहेगा। इसे उसी विंडो में चलाएँ जिसमें आपने टोकन डाला था (चरण 6)। कंप्यूटर बंद होने या स्लीप में जाने पर यह रुक जाता है। खेल के दौरान रोकने पर वह खेल समय समाप्त होने या कनेक्शन टूटने से हार जाता है।
macOS / Linux
macOS / Linux: शुरू करने वाला कमांड चलाने के बाद आप विंडो बंद कर सकते हैं। संदेश बॉट फ़ोल्डर की bot.log फ़ाइल में लिखे जाते हैं। रोकने के लिए नया टर्मिनल खोलें और रोकने वाला कमांड चलाएँ। सिर्फ़ वही बॉक्स कॉपी करें जिसकी ज़रूरत है: दोनों बॉक्स एक साथ चिपकाने पर बॉट शुरू होते ही रुक जाता है।
शुरू करें
nohup python3 tools/bot_match_client.py --engine 'python3 tools/bot_match_example_engine.py' > bot.log 2>&1 &रोकें
pkill -f bot_match_client.pyWindows PowerShell
Windows: टास्कबार में एक छोटी की गई (minimized) विंडो दिखती है और बॉट उसी में चलता है। आप मौजूदा PowerShell विंडो बंद कर सकते हैं। रोकने के लिए छोटी की गई विंडो खोलें और Ctrl+C दबाएँ, या उस विंडो को बंद करें।
शुरू करें
Start-Process py -ArgumentList 'tools/bot_match_client.py --engine "py tools/bot_match_example_engine.py"' -WorkingDirectory $PWD -WindowStyle Minimized10. अपने इंजन पर जाएँ
अभ्यास इंजन से कनेक्शन जाँचने के बाद अपने इंजन पर जाएँ। Edax या Egaroucid के लिए नीचे के विशेष विकल्प, दूसरे संगत इंजन के लिए --nboard और अपने इंजन के लिए JSON उपयोग करें। टोकन वही रखें।
कोई अन्य रूप वाला खेल (एंटी, 10x10, अष्टकोण, क्लासिक रिवर्सी) समर्थित खेल में तभी चुनें जब आपका इंजन उसके नियम जानता हो। दूसरे बॉट और लोग आपके बॉट को हर चुने गए खेल में चुनौती दे सकते हैं। इसे बदलने के लिए बॉट सूची में प्रबंधन खोलें, समर्थित खेल बदलें और सहेजें दबाएँ। कोई खेल चल रहा हो या चुनौती प्रतीक्षा में हो, तो इसे नहीं बदल सकते।
खेल के अनुसार इंजन अनुरोध के उदाहरण
Edax जैसे NBoard-संगत इंजन से कनेक्ट करें
NBoard एक ग्राफिकल Othello प्रोग्राम है जिसे NTest के साथ इस्तेमाल किया जा सकता है। NBoard प्रोटोकॉल इस प्रोग्राम और इंजन के बीच संवाद का सार्वजनिक प्रारूप है और NTest तथा Edax जैसे इसे समर्थन देने वाले इंजन के साथ काम करता है।
नीचे दिए गए इंस्टॉलेशन और चलाने के उदाहरण Edax 4.6 और Egaroucid for Console 7.8.2 पर आधारित हैं।
Edax 4.6 कनेक्शन प्रोग्राम में शामिल नहीं है। Edax 4.6 के Assets से अपने ऑपरेटिंग सिस्टम की फ़ाइल डाउनलोड करें, बॉट फ़ोल्डर में रखें और नीचे दिए तैयारी कमांड से खोलें। Windows और Linux कमांड x86-64 कंप्यूटर के लिए हैं।
Windows PowerShell (x86-64): edax-4.6-MS-windows-x86.zip
तैयारी (केवल पहली बार)
Expand-Archive -LiteralPath edax-4.6-MS-windows-x86.zip -DestinationPath edax-4.6शुरू करें
py tools/bot_match_client.py --edax "edax-4.6\wEdax-x86-64.exe"Linux (x86-64): edax-4.6-linux-x86.tar.gz
तैयारी (केवल पहली बार)
mkdir -p edax-4.6
tar -xzf edax-4.6-linux-x86.tar.gz -C edax-4.6
chmod +x edax-4.6/lEdax-x86-64शुरू करें
python3 tools/bot_match_client.py --edax "edax-4.6/lEdax-x86-64"macOS: edax-reversi-4.6.tar.gz
Edax 4.6 का आधिकारिक macOS निष्पादन योग्य प्रोग्राम उपलब्ध नहीं है। उसी रिलीज से Source code (tar.gz) और edax-4.6-linux-x86.tar.gz डाउनलोड करें। Mac प्रोग्राम को स्रोत से बनाएं; Linux संग्रह से केवल साझा मूल्यांकन फ़ाइल data/eval.dat निकालें। Xcode Command Line Tools जरूरी हैं। तैयारी कमांड स्रोत को संकलित करते हैं।
तैयारी (केवल पहली बार)
xcode-select --installtar -xzf edax-reversi-4.6.tar.gz
mv edax-reversi-4.6 edax-4.6
mkdir -p edax-4.6/bin
tar -xzf edax-4.6-linux-x86.tar.gz -C edax-4.6 data/eval.dat
(cd edax-4.6/src && make build ARCH=native OS=osx)शुरू करें
python3 tools/bot_match_client.py --edax "edax-4.6/bin/mEdax-native"Edax को नीचे --edax में केवल निष्पादन योग्य फ़ाइल का पथ देकर भी जोड़ सकते हैं। अलग अडैप्टर नहीं चाहिए; कनेक्टर बची हुई खेल घड़ी के अनुसार हर चाल का सोचने का समय बाँटता है।
कमांड के पथ को अपने प्रोग्राम के पूरे पथ से बदलें। पथ में खाली जगह हो तो डबल कोट लगाएँ। मूल्यांकन फ़ाइल अपने आप न मिले तो --edax-eval से eval.dat का पथ दें।
NBoard कनेक्शन केवल सामान्य 8×8 खेल खेलता है। इस बॉट के समर्थित खेल में केवल स्टैंडर्ड चुना रखें। अगर कोई अन्य रूप वाला खेल आता है, तो कनेक्टर इंजन से नहीं पूछता, कोई चाल नहीं चली जाती, और खेल रद्द हो जाता है या समय समाप्त होने से हार जाता है।
Egaroucid: --egaroucid
Egaroucid for Console तैयार करें। ग्राफिकल ऐप के बजाय कंसोल प्रोग्राम चुनें और resources फ़ोल्डर उसकी जगह रखें। macOS और Linux पर आधिकारिक निर्देशों से बना प्रोग्राम उपयोग करें। कनेक्टर setboard, settime और go से स्थिति और बचा समय भेजता है, इसलिए अडैप्टर नहीं चाहिए।
Windows PowerShell
py tools/bot_match_client.py --egaroucid "egaroucid\Egaroucid_for_console.exe"macOS / Linux
python3 tools/bot_match_client.py --egaroucid "egaroucid/bin/Egaroucid_for_Console.out"दोनों तरीके केवल सामान्य 8×8 का समर्थन करते हैं और एक साथ दो खेलों में हर खेल के लिए एक इंजन चलता है। --max-think-seconds प्रति चाल सुरक्षा सीमा है (डिफ़ॉल्ट 10 सेकंड)। Egaroucid सीमा पर पहुँचे तो खोज रोककर एक वैध वैकल्पिक चाल चली जाती है और अगली बारी में इंजन फिर शुरू होता है।
खुद बनाया इंजन: JSON से जोड़ें
यह भाग तभी पढ़ें जब आप अपना खुद का लिखा इंजन जोड़ना चाहते हों। अगर आप Edax, Egaroucid या कोई और NBoard इंजन इस्तेमाल करते हैं, तो आपका काम ऊपर ही पूरा हो चुका है और आप इसे छोड़ सकते हैं।
जब भी आपके बॉट की बारी आती है, कनेक्टर my_adapter.py को एक बार चलाता है। वह मौजूदा स्थिति एक पंक्ति में देता है (गोटियाँ कहाँ हैं, किसकी बारी है, कौन से खाने वैध हैं, कितना समय बचा है), my_adapter.py एक पंक्ति में एक खाना जवाब में देता है, और कनेक्टर वह चाल सर्वर पर चल देता है। my_adapter.py बीच की एक छोटी Python फ़ाइल है जो आपके इंजन से चाल पूछती है। सर्वर से जुड़ना, टोकन और चाल भेजना कनेक्टर सँभालता है, इसलिए इस फ़ाइल को इनसे कभी कोई मतलब नहीं रहता।
bot_match_client.py→ my_adapter.pybot_match_client.py← my_adapter.pyआपका इंजन किस तरह का है?
- ऐसा इंजन जो Python कोड में अपनी चाल चुनता है: नीचे का उदाहरण A इस्तेमाल करें।
- ऐसी प्रोग्राम फ़ाइल जो हर बार चलने पर जवाब की एक पंक्ति छापकर बंद हो जाती है: नीचे का उदाहरण B इस्तेमाल करें।
- चालू रहकर लगातार कमांड का आदान-प्रदान करने वाली प्रोग्राम फ़ाइल: अगर वह NBoard समर्थित है तो ऊपर --nboard से जोड़ें। किसी दूसरे प्रोटोकॉल के लिए उदाहरण B को उस प्रोटोकॉल के अनुसार बदलें और my_adapter.py को इंजन चालू रखकर एक-एक पंक्ति का लूप में आदान-प्रदान करने दें।
चरण 1: ऐसी फ़ाइल जो सिर्फ़ कनेक्शन जाँचती है (my_adapter.py)
बॉट फ़ोल्डर में (जहाँ README.md और tools हैं) my_adapter.py नाम की फ़ाइल बनाएँ, नीचे का कोड जैसा है वैसा ही चिपकाएँ और सहेजें। यह फ़ाइल कोई इंजन इस्तेमाल नहीं करती और बस पहले वैध खाने से जवाब देती है। इसका काम यह पक्का करना है कि आपका इंजन जोड़ने से पहले कनेक्शन ठीक चल रहा है।
import json
import sys
def choose_move(position):
legal = position["legal_moves"]
return legal[0] if legal else -1
line = sys.stdin.readline()
position = json.loads(line)
move = choose_move(position)
print(json.dumps({"move": move}), flush=True)
जोड़ने से पहले इनपुट और आउटपुट जाँचें
बॉक्स 1 का कमांड उदाहरण स्थिति सीधे अडैप्टर में डालता है। इसे एक पंक्ति छापनी चाहिए: {"move": 19}। यह पंक्ति दिखने के बाद बॉक्स 2 का कमांड इस अडैप्टर के साथ कनेक्टर शुरू करता है; इसे उसी विंडो में चलाएँ जिसमें चरण 6 का टोकन है। दोनों बॉक्स अलग-अलग चलाएँ। अगर आपका इंजन खुद यह JSON फ़ॉर्मेट पढ़ता है, तो उसका कमांड सीधे --engine के बाद लिख सकते हैं।
1. सिर्फ़ अडैप्टर को जाँचें
macOS / Linux
printf '%s\n' '{"board":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,0,0,0,0,0,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"color":1,"legal_moves":[19,26,37,44],"game_mode":"std","board_size":8,"blocked_squares":[],"placed":{"1":0,"2":0},"remaining_ms":60000,"match_id":123,"leg":0,"revision":0,"history":[],"round_no":null,"room_created_at":null,"budget_ms":10000}' | python3 my_adapter.pyWindows PowerShell
'{"board":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,0,0,0,0,0,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"color":1,"legal_moves":[19,26,37,44],"game_mode":"std","board_size":8,"blocked_squares":[],"placed":{"1":0,"2":0},"remaining_ms":60000,"match_id":123,"leg":0,"revision":0,"history":[],"round_no":null,"room_created_at":null,"budget_ms":10000}' | py my_adapter.py2. अडैप्टर के साथ कनेक्टर शुरू करें
macOS / Linux
python3 tools/bot_match_client.py --engine 'python3 my_adapter.py'Windows PowerShell
py tools/bot_match_client.py --engine 'py my_adapter.py'चरण 2: ऐसी फ़ाइल पर जाएँ जो आपके इंजन को बुलाती है
चरण 1 ठीक चलने के बाद my_adapter.py की पूरी सामग्री को नीचे के उदाहरण A या B से बदल दें। सिर्फ़ EDIT लिखी पंक्तियाँ बदलें और बाकी को जैसा है वैसा रहने दें। फिर ऊपर का टेस्ट कमांड 1 दोबारा चलाएँ और देखें कि जवाब की एक पंक्ति आती है। चाल आपके इंजन ने चुनी है, इसलिए 19 के अलावा कोई और खाना आना सामान्य है।
उदाहरण A: ऐसा इंजन जो Python फ़ंक्शन से अपनी चाल चुनता है
यह उदाहरण मानता है कि my_engine.py नाम की एक फ़ाइल है जिसमें चाल चुनने वाला search फ़ंक्शन है। EDIT 1 पर फ़ाइल का नाम और फ़ंक्शन का नाम, और EDIT 2 पर भेजे जाने वाले मान अपने इंजन के अनुसार बदलें। फ़ंक्शन को खाने की संख्या (0 से 63) या d3 जैसा निर्देशांक लौटाना चाहिए।
import json
import sys
from pathlib import Path
from my_engine import search # EDIT 1: your engine file and function name
def think_ms(position):
# Time for this move: share the remaining clock over my remaining moves.
my_moves_left = position["board"].count(0) // 2 + 1
share = position["remaining_ms"] / my_moves_left
return int(min(share, position["budget_ms"]) * 0.8)
def choose_move(position):
if not position["legal_moves"]:
return -1
# EDIT 2: pass what your function needs
return search(
board=position["board"],
color=position["color"],
legal_moves=position["legal_moves"],
time_limit_ms=think_ms(position),
)
position = json.loads(sys.stdin.readline())
legal = position["legal_moves"]
try:
move = choose_move(position)
except Exception as error:
# The engine failed: note why in my_adapter.log and play the first legal square.
with open(Path(__file__).with_name("my_adapter.log"), "a") as log:
log.write(repr(error) + "\n")
move = legal[0] if legal else -1
print(json.dumps({"move": move}), flush=True)उदाहरण B: ऐसा इंजन जो एक प्रोग्राम फ़ाइल है
यह उदाहरण मानता है कि प्रोग्राम एक पंक्ति पढ़ता है जिसमें बोर्ड के 64 अक्षर, चाल चलने वाला पक्ष और मिलीसेकंड में सोचने का समय होता है, और D3 जैसी निर्देशांक की एक पंक्ति से जवाब देता है (. = खाली, X = काला, O = सफेद)। हर इंजन का अपना फ़ॉर्मेट होता है, इसलिए EDIT 1 पर प्रोग्राम फ़ाइल का नाम, EDIT 2 पर इंजन को भेजी जाने वाली पंक्ति और EDIT 3 पर जवाब पढ़ने वाला हिस्सा अपने इंजन के अनुसार बदलें।
my_adapter.py → my_engine
...........................OX......XO........................... X 1777my_engine → my_adapter.py
D3import json
import subprocess
import sys
from pathlib import Path
# EDIT 1: your engine program file (kept in the same folder as my_adapter.py)
ENGINE = Path(__file__).with_name("my_engine.exe" if sys.platform == "win32" else "my_engine")
def think_ms(position):
# Time for this move: share the remaining clock over my remaining moves.
my_moves_left = position["board"].count(0) // 2 + 1
share = position["remaining_ms"] / my_moves_left
return int(min(share, position["budget_ms"]) * 0.8)
def choose_move(position):
if not position["legal_moves"]:
return -1
# EDIT 2: build the line your engine reads
board = "".join(".XO"[cell] for cell in position["board"])
color = "X" if position["color"] == 1 else "O"
reply = subprocess.run(
[str(ENGINE)],
input=f"{board} {color} {think_ms(position)}\n",
text=True,
capture_output=True,
check=True,
timeout=position["budget_ms"] / 1000 * 0.9,
)
# EDIT 3: take the square out of your engine's answer
return reply.stdout.strip()
position = json.loads(sys.stdin.readline())
legal = position["legal_moves"]
try:
move = choose_move(position)
except Exception as error:
# The engine failed: note why in my_adapter.log and play the first legal square.
with open(Path(__file__).with_name("my_adapter.log"), "a") as log:
log.write(repr(error) + "\n")
move = legal[0] if legal else -1
print(json.dumps({"move": move}), flush=True)सोचने का समय: बॉट खेल में प्रत्येक बॉट को हर बोर्ड पर 1 मिनट मिलता है, इसलिए एक चाल पर देर तक सोचने से बॉट जल्दी ही समय समाप्त होने से हार जाता है। उदाहरणों में think_ms बचे हुए समय (remaining_ms) को आपकी बची हुई चालों से भाग देकर इस चाल का समय तय करता है। budget_ms इस चाल पर खर्च करने का समय नहीं है। यह वह अधिकतम समय है जितनी देर कनेक्टर जवाब का इंतज़ार करता है (डिफ़ॉल्ट रूप से 10 सेकंड)। अगर जवाब इससे देर से आता है, तो बॉट उस बोर्ड पर आगे नहीं खेल पाता और समय समाप्त होने से उसे हार जाता है, इसलिए अपने इंजन को think_ms दें, budget_ms नहीं।
जब कुछ गड़बड़ हो: अगर इंजन को बुलाना विफल होता है, तो उदाहरण फ़ाइलें कारण my_adapter.log में लिखती हैं और उसकी जगह पहला वैध खाना चल देती हैं। अगर चालें अजीब लगें, तो सबसे पहले वही फ़ाइल खोलें। कनेक्टर अडैप्टर के त्रुटि संदेश स्क्रीन पर नहीं दिखाता। print का इस्तेमाल सिर्फ़ जवाब की एक पंक्ति के लिए करें और डीबग का कोई भी टेक्स्ट फ़ाइल में लिखें।
गति: कनेक्टर हर खेल के लिए my_adapter.py को चालू रखता है और हर चाल पर एक पंक्ति भेजता है। उदाहरणों की तरह एक पंक्ति का उत्तर देकर बंद होने वाली फ़ाइल अगली चाल पर फिर से चलती है, इसलिए आपका इंजन भी हर बार फिर से शुरू होता है। अगर इंजन धीरे शुरू होता है या पिछली चालों का काम आगे इस्तेमाल करना है, तो my_adapter.py को लूप बनाएँ: एक पंक्ति पढ़ें, एक पंक्ति उत्तर दें, दोहराएँ। इनपुट को अंत तक न पढ़ें और हर उत्तर के बाद flush करें।
इस भाग का बाकी हिस्सा संदर्भ सामग्री है, जो बताती है कि कनेक्टर और my_adapter.py आपस में क्या लेते-देते हैं। अगर आप ऊपर की उदाहरण फ़ाइलें जैसी हैं वैसी ही इस्तेमाल करते हैं, तो इसे पढ़ने की ज़रूरत नहीं है।
इनपुट JSON (कनेक्टर → अडैप्टर)
यह कनेक्टर द्वारा भेजे गए डेटा का उदाहरण है, चलाने वाला कोड नहीं। इसे Python फ़ाइल के रूप में न सहेजें। खेल के दौरान कनेक्टर हर चाल पर मौजूदा डेटा अपने आप भेजता है।
नीचे सामान्य 8×8 शुरुआती स्थिति का उदाहरण है। असली खेल में कनेक्टर मौजूदा स्थिति भरता है। board में खाने a1 से दाईं ओर, फिर अगली पंक्ति के क्रम में हैं; 0=खाली, 1=काला, 2=सफेद। color=1 का मतलब काले की चाल माँगी गई है। legal_moves उन खानों की सूची है जहाँ आप चल सकते हैं। remaining_ms खेल की बची हुई घड़ी है और budget_ms वह अधिकतम समय है जितनी देर कनेक्टर इस चाल के जवाब का इंतज़ार करता है, दोनों मिलीसेकंड में (1000 = 1 सेकंड)। अन्य रूप वाले खेलों के फ़ील्ड और उदाहरण नीचे अन्य रूप वाले खेल भाग में हैं।
{"board":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,0,0,0,0,0,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"color":1,"legal_moves":[19,26,37,44],"game_mode":"std","board_size":8,"blocked_squares":[],"placed":{"1":0,"2":0},"remaining_ms":60000,"match_id":123,"leg":0,"revision":0,"history":[],"round_no":null,"room_created_at":null,"budget_ms":10000}जवाब JSON (अडैप्टर → कनेक्टर)
नीचे दिए जवाबों में से एक को एक JSON पंक्ति के रूप में लिखें, जो नई पंक्ति (newline) पर खत्म हो। move एक खाना नंबर या निर्देशांक है; बड़े या छोटे अक्षर से फर्क नहीं पड़ता। 8×8 पर d3 है (3−1)×8+3 = 19। हमेशा मिली हुई legal_moves में से ही चुनें। बॉट के बीच मुकाबले में कोई वैध चाल न हो तो -1 या pass भेजें; इंसानों के साथ खेल में मजबूरी वाला पास सर्वर संभालता है। stdout में केवल जवाब की पंक्ति लिखें, कोई और संदेश नहीं।
{"move":19}{"move":"d3"}{"move":-1}खेल के अनुसार इंजन अनुरोध के उदाहरण
कनेक्टर जो पहला काले का अनुरोध --engine इंजन को भेजता है, उसके उदाहरण नियम वाले कोड से बनाए गए हैं। हर प्रकार के असली खेल 12 गोटियों वाली यादृच्छिक स्थिति से शुरू होते हैं, इसलिए हर खेल में board और legal_moves अलग होते हैं। इन उदाहरणों को स्थिर रखने के लिए इनकी शुरुआती चालें बोर्ड के बीच के पास चुनी गई हैं। असली खेलों में match_id और घड़ी के मान भी अलग होते हैं।
game_mode: std, anti, grand, octagon, reversi में से एक। इंसानों के साथ खेल में XOT, std के रूप में आता है।board_size: 8, या grand और octagon के लिए 10।board: board_size² लंबाई की सरणी। a1 से दाईं ओर, फिर अगली पंक्ति के क्रम में पढ़ें। 0=खाली (अष्टकोण के बंद खाने भी), 1=काला, 2=सफेद।blocked_squares: अष्टकोण के उपयोग न किए जा सकने वाले खाने। दूसरे खेलों में खाली सरणी।placed: हर रंग द्वारा अब तक रखी गई गोटियाँ, शुरुआती यादृच्छिक चालों सहित; कुंजियाँ स्ट्रिंग "1" और "2" हैं। क्लासिक रिवर्सी की 32 गोटियों की सीमा के लिए उपयोग होता है।
एंटी (Anti) (anti)
इनपुट JSON (कनेक्टर → अडैप्टर)
{
"board": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"color": 1,
"legal_moves": [2, 3, 12, 25, 42, 44, 45],
"game_mode": "anti",
"board_size": 8,
"blocked_squares": [],
"placed": {
"1": 4,
"2": 4
},
"remaining_ms": 60000,
"match_id": 123,
"leg": 0,
"revision": 0,
"history": [],
"round_no": null,
"room_created_at": null,
"budget_ms": 10000
}जवाब JSON (अडैप्टर → कनेक्टर)
{"move":2}10x10 (Grand) (grand)
इनपुट JSON (कनेक्टर → अडैप्टर)
{
"board": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"color": 1,
"legal_moves": [13, 14, 25, 42, 63, 65, 66],
"game_mode": "grand",
"board_size": 10,
"blocked_squares": [],
"placed": {
"1": 4,
"2": 4
},
"remaining_ms": 60000,
"match_id": 123,
"leg": 0,
"revision": 0,
"history": [],
"round_no": null,
"room_created_at": null,
"budget_ms": 10000
}जवाब JSON (अडैप्टर → कनेक्टर)
{"move":13}अष्टकोण (Octagon) (octagon)
इनपुट JSON (कनेक्टर → अडैप्टर)
{
"board": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"color": 1,
"legal_moves": [13, 14, 25, 42, 63, 65, 66],
"game_mode": "octagon",
"board_size": 10,
"blocked_squares": [0, 1, 10, 8, 9, 19, 80, 90, 91, 89, 98, 99],
"placed": {
"1": 4,
"2": 4
},
"remaining_ms": 60000,
"match_id": 123,
"leg": 0,
"revision": 0,
"history": [],
"round_no": null,
"room_created_at": null,
"budget_ms": 10000
}जवाब JSON (अडैप्टर → कनेक्टर)
{"move":13}क्लासिक रिवर्सी (reversi)
इनपुट JSON (कनेक्टर → अडैप्टर)
{
"board": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 2, 2, 1, 1, 0, 0, 0, 0, 2, 2, 1, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"color": 1,
"legal_moves": [18, 25, 33, 41, 42, 50, 51],
"game_mode": "reversi",
"board_size": 8,
"blocked_squares": [],
"placed": {
"1": 6,
"2": 6
},
"remaining_ms": 60000,
"match_id": 123,
"leg": 0,
"revision": 0,
"history": [],
"round_no": null,
"room_created_at": null,
"budget_ms": 10000
}जवाब JSON (अडैप्टर → कनेक्टर)
{"move":18}आम समस्याएँ
| लक्षण | कारण और समाधान |
|---|---|
| बॉट पर स्लेटी बिंदु (ऑफ़लाइन) दिखता है। | जाँचें कि कनेक्टर वाली विंडो अब भी चल रही है। विंडो बंद करने, Ctrl+C दबाने या कंप्यूटर के स्लीप में जाने पर यह रुक जाता है। चरण 6 और 7 दोहराएँ, फिर ताज़ा करें दबाएँ। |
कमांड नहीं मिला, ऐसा लिखा आता है।command not found / is not recognized | Python इंस्टॉल नहीं है, या इंस्टॉल करने के बाद विंडो दोबारा नहीं खोली गई। चरण 5 देखें, नई विंडो खोलें और चरण 4 से फिर शुरू करें। |
फ़ाइल नहीं खुल सकती, ऐसा लिखा आता है।can't open file | आपने इसे बॉट फ़ोल्डर के बाहर चलाया। चरण 4 की तरह बॉट फ़ोल्डर में जाएँ और ls से जाँचें कि README.md और tools सूची में हैं। |
टोकन नहीं है, ऐसा लिखकर बंद हो जाता है।FS_BOT_TOKEN is missing or invalid | इस विंडो में टोकन नहीं है। अगर आपने नई विंडो खोली है, तो चरण 6 दोहराएँ। |
टोकन अस्वीकार हुआ, ऐसा लिखकर रुक जाता है।Bot credential rejected | टोकन गलत चिपकाया गया है या पुराना है। नया टोकन बनाने या बॉट बंद करने के बाद पुराना टोकन काम नहीं करता। नवीनतम टोकन के साथ चरण 6 से फिर शुरू करें। |
एक ही त्रुटि वाली पंक्ति बार-बार आती है।Connection/state error | इंटरनेट कनेक्शन जाँचें। macOS पर जाँचें कि आपने चरण 5 का Install Certificates.command चलाया है। अगर यह केवल खेल के दौरान आता है, तो हो सकता है सर्वर आपके इंजन की चाल को अवैध मानकर अस्वीकार कर रहा हो। कनेक्टर वही चाल फिर भेजता है, इसलिए इंजन को ठीक करना होगा। |
| चुनौती बटन काम नहीं करता, या चुनौती स्वीकार नहीं होती। | दोनों बॉट पर हरा बिंदु होना चाहिए। जाँचें कि मेरा खेलने वाला बॉट में आपका बॉट चुना है। जो बॉट पहले से किसी दूसरे खेल में है, वह नई चुनौती नहीं लेता। स्वीकार न हुई चुनौती 120 सेकंड बाद समाप्त हो जाती है। |
बॉट कोई चाल नहीं चलता, फिर समय समाप्त होने से हार जाता है या खेल रद्द हो जाता है।Engine failed for match | इंजन ने समय पर जवाब नहीं दिया या उसके जवाब का फ़ॉर्मेट गलत था। इंजन का कमांड और उसका एक पंक्ति वाला JSON आउटपुट जाँचें। अगर कोई बॉट शुरू होने के 30 सेकंड के अंदर पहली चाल नहीं चलता, तो खेल रद्द हो जाता है। |
| अन्य रूप वाले खेलों की चुनौतियाँ नहीं आतीं। | चुनौती विंडो में केवल वे खेल दिखते हैं जिन्हें दोनों बॉट समर्थित करते हैं। जाँचें कि वह खेल आपके बॉट के समर्थित खेल में चुना है और दूसरा बॉट भी उसे समर्थित करता है। NBoard से जुड़े बॉट में केवल स्टैंडर्ड चुना होना चाहिए। |
शब्दावली
| शब्द | अर्थ |
|---|---|
| API | प्रोग्रामों के बीच अनुरोध और जवाब भेजने का तय किया हुआ तरीका। कनेक्टर इसे आपके लिए संभालता है। |
| टोकन | सिर्फ़ आपके बॉट का पासवर्ड। कनेक्टर इसी से सर्वर को बताता है कि वह कौन सा बॉट है। |
| टर्मिनल | एक विंडो जिसमें आप कमांड टाइप करते हैं। Windows पर PowerShell उपयोग करें। |
| एनवायरनमेंट वेरिएबल | एक अस्थायी सेटिंग जो एक टर्मिनल विंडो से शुरू किए गए प्रोग्रामों को दी जाती है। विंडो बंद होने पर यह मिट जाती है। |
| JSON | डेटा को टेक्स्ट के रूप में लिखने का एक फ़ॉर्मेट। उदाहरण: {"move":19} |
| इंजन | एक प्रोग्राम जो स्थिति देखकर चाल चुनता है। |
| अडैप्टर | एक छोटा प्रोग्राम जो आपके इंजन और कनेक्टर के बीच डेटा बदलता है। |
| NBoard | NBoard एक ग्राफिकल Othello प्रोग्राम है जिसे NTest के साथ इस्तेमाल किया जा सकता है। NBoard प्रोटोकॉल इस प्रोग्राम और इंजन के बीच संवाद का सार्वजनिक प्रारूप है और NTest तथा Edax जैसे इसे समर्थन देने वाले इंजन के साथ काम करता है। |
| वैध चाल | वह खाना जिस पर आप अभी चल सकते हैं। सर्वर इन्हें legal_moves में देता है। |
डाउनलोड
डाउनलोड के लिए लॉग इन करें। .zip में मार्गदर्शिका, कनेक्टर और उदाहरण इंजन हैं; .json API विनिर्देश और .md मार्गदर्शिका है।
विस्तृत विनिर्देश
इस पेज का बाकी हिस्सा उन डेवलपरों के लिए विस्तृत संदर्भ है जो सीधे इंजन या API के साथ काम करते हैं।
कनेक्टर विकल्प
tools/bot_match_client.py के विकल्प। --engine और --nboard / --edax / --egaroucid में से ठीक एक देना ज़रूरी है। टोकन कभी विकल्प के रूप में नहीं दिया जाता; यह केवल FS_BOT_TOKEN एनवायरनमेंट वेरिएबल से पढ़ा जाता है। निकास कोड: 0 सामान्य रुकना, 2 टोकन अस्वीकृत, 3 --max-runtime पूरा हुआ।
| पैरामीटर | विवरण |
|---|---|
--engine "COMMAND" | हर खेल के लिए यह कमांड एक बार चालू रखता है और इनपुट बंद किए बिना हर चाल पर एक JSON पंक्ति का आदान-प्रदान करता है। एक पंक्ति का उत्तर देकर बंद होने वाला इंजन अगली चाल पर फिर से चालू होता है। |
--nboard "COMMAND" | हर खेल के लिए एक NBoard इंजन चालू रखता है, कुल दो। केवल सामान्य (std)। |
--edax PATH | Edax को नीचे --edax में केवल निष्पादन योग्य फ़ाइल का पथ देकर भी जोड़ सकते हैं। अलग अडैप्टर नहीं चाहिए; कनेक्टर बची हुई खेल घड़ी के अनुसार हर चाल का सोचने का समय बाँटता है। |
--edax-eval PATH | Edax eval.dat का पथ। न देने पर प्रोग्राम के फ़ोल्डर या उसके ऊपर वाले फ़ोल्डर में data/eval.dat खोजता है। |
--egaroucid PATH | Egaroucid for Console तैयार करें। ग्राफिकल ऐप के बजाय कंसोल प्रोग्राम चुनें और resources फ़ोल्डर उसकी जगह रखें। macOS और Linux पर आधिकारिक निर्देशों से बना प्रोग्राम उपयोग करें। कनेक्टर setboard, settime और go से स्थिति और बचा समय भेजता है, इसलिए अडैप्टर नहीं चाहिए। |
--nboard-depth N | NBoard इंजन को set depth N भेजता है। 0 से 60; 0 इंजन का डिफ़ॉल्ट रखता है। (--edax: 0 → 60). |
--max-think-seconds S | हर चाल के लिए इंजन का इंतज़ार करने के अधिकतम सेकंड। डिफ़ॉल्ट 10, अधिकतम 300। बची हुई घड़ी में से 0.75 सेकंड घटाने पर जितना बचे, उससे कभी ज़्यादा नहीं। यह कनेक्टर की सुरक्षा सीमा है; सर्वर पर प्रति चाल कोई समय सीमा नहीं है। 0 रखने पर प्रति चाल की सीमा हटती है और खेल का बचा समय उपयोग होता है। |
--engine-name NAME | बॉट जानकारी में दिखाया जाने वाला इंजन का नाम (120 अक्षर या कम)। इसमें कमांड या पाथ न डालें। |
--cpu-name NAME | बताया जाने वाला CPU नाम (120 अक्षर या कम)। न देने पर अपने आप पहचाना जाता है। |
--once-match ID | केवल इसी मुकाबले को संभालता है और उसके खत्म होने (finished, aborted, expired, rejected) पर बंद हो जाता है। इंसानों के साथ खेल के ऋणात्मक ID भी काम करते हैं। परीक्षण के लिए इसे --max-runtime के साथ उपयोग करें। |
--max-runtime S | इतने सेकंड बाद इंजनों को साफ़ करके बंद हो जाता है (निकास कोड 3)। |
--no-stream | इवेंट स्ट्रीम उपयोग नहीं करता; केवल पोलिंग करता है। |
--api URL, --stream-url URL | API और स्ट्रीम के पते। सामान्यतः डिफ़ॉल्ट ही रखें। केवल HTTPS स्वीकार होता है, और टोकन साथ भेजा जाता है, इसलिए स्ट्रीम API होस्ट पर ही होनी चाहिए। |
API को खुद लागू करना
agent_poll या प्रमाणित इवेंट स्ट्रीम से चुनौतियाँ और स्थितियाँ प्राप्त करें। जिन लंबित चुनौतियों में आप bot_b हैं, उनके लिए agent_accept भेजें। फिर चल रहे मुकाबले के हर खेल में केवल वही स्थितियाँ गिनें जिनमें आपकी बारी है। हर match_id, खेल और revision के लिए अधिकतम एक बार भेजें, और स्थिति बदलने पर पुराना काम छोड़ दें। इंसानों के साथ खेल में match_id ऋणात्मक और leg=0 होता है, और round_no तथा room_created_at ठीक वैसे ही भेजने होते हैं जैसे मिले थे। सामान्य कमरों में मजबूरी वाला पास सर्वर संभालता है; केवल बॉट के बीच के मुकाबलों में पास भेजना होता है।
agent_poll / bot-stream → pending (bot_b = my_id)
→ agent_accept → running → legs[0] + legs[1]
→ agent_move(match_id, leg, revision, move) → finished / abortedअन्य रूप वाले खेल
बॉट को केवल वे खेल मिलते हैं जो समर्थित खेल में चुने गए हैं। इंजन अनुरोधों और मुकाबले की स्थिति में game_mode से पता चलता है कि कौन सा खेल है। बोर्ड का आकार, बंद खाने और वैध खाने सर्वर गिनता है, इसलिए इंजन को केवल मिली हुई legal_moves में से चुनना होता है। 10×10 या क्लासिक रिवर्सी की चालें सामान्य 8×8 चाल-निर्माण से न बनाएँ।
| खेल | game_mode | बोर्ड | शुरुआती गोटियाँ | घड़ी (हर खेल, हर रंग) | काले की पहली legal_moves |
|---|---|---|---|---|---|
| स्टैंडर्ड | std | 8×8 | यादृच्छिक 12 गोटियाँ | 60,000 ms | स्थिति पर निर्भर |
| एंटी (Anti) | anti | 8×8 | यादृच्छिक 12 गोटियाँ | 60,000 ms | स्थिति पर निर्भर |
| 10x10 (Grand) | grand | 10×10 | यादृच्छिक 12 गोटियाँ | 60,000 ms | स्थिति पर निर्भर |
| अष्टकोण (Octagon) | octagon | 10×10 (88) | यादृच्छिक 12 गोटियाँ | 60,000 ms | स्थिति पर निर्भर |
| क्लासिक रिवर्सी | reversi | 8×8 | यादृच्छिक 12 गोटियाँ | 60,000 ms | स्थिति पर निर्भर |
सामान्य नियम: काला (1) पहले चलता है। दोनों खेल एक ही स्थिति से रंग बदलकर शुरू होते हैं और एक साथ चलते हैं। बॉट के बीच मुकाबले में जब आपके पास कोई वैध चाल नहीं होती, तो legal_moves खाली सरणी के रूप में आती है और बॉट को खुद move=-1 (पास) भेजना होता है। सर्वर आपकी ओर से पास नहीं करता, और आपकी घड़ी चलती रहती है। वैध चाल होते हुए पास करना अवैध है। जब कोई भी रंग चल न सके, तो वह खेल खत्म हो जाता है। खाली खाने किसी को नहीं दिए जाते; दोनों खेलों की केवल असली गोटियाँ जोड़ी जाती हैं, और बराबर कुल होने पर खेल बराबरी पर छूटता है। सभी बॉट खेल 12 गोटियों वाली यादृच्छिक स्थिति से शुरू होते हैं। हर प्रकार के खेल में प्रत्येक बॉट को हर बोर्ड पर 1 मिनट मिलता है।
एंटी: गोटी रखना और पलटना सामान्य Othello जैसा ही है। दोनों खेलों में कुल मिलाकर कम गोटियों वाला पक्ष जीतता है।
10x10: 10×10 बोर्ड (100 खाने) पर सामान्य नियम। शुरुआती व्यवस्था बीच के चार खाने हैं; बॉट के मुकाबलों में इसमें 8 यादृच्छिक चालें जोड़ी जाती हैं और खेल 12 गोटियों से शुरू होता है।
अष्टकोण: 10x10 जैसा ही बोर्ड और शुरुआती व्यवस्था, पर हर कोने के तीन खाने, कुल 12, उपयोग नहीं किए जा सकते (खेलने योग्य 88 खाने)। बंद खाने blocked_squares में खाना नंबरों के रूप में आते हैं, और board में खाली के समान मान 0 के रूप में। यह सरणी नंबर के क्रम में नहीं है। बंद खाने पर चाल नहीं चल सकते, और गोटियों की पंक्ति वहीं रुक जाती है।
क्लासिक रिवर्सी: नियमों के अनुसार खेल खाली बोर्ड से शुरू होता है। जब तक बीच के चार खानों (27, 28, 35, 36) में से कोई खाली है, आप केवल वहीं गोटी रखते हैं और कुछ नहीं पलटता। चारों भरने के बाद सामान्य नियम लागू होते हैं। हर रंग पहली चार चालों सहित अधिकतम 32 गोटियाँ रखता है। placed बताता है कि हर रंग ने अब तक कितनी गोटियाँ रखी हैं; इसकी कुंजियाँ स्ट्रिंग "1" (काला) और "2" (सफेद) हैं। बॉट के मुकाबले तब शुरू होते हैं जब सर्वर बीच की चार चालों सहित 12 गोटियाँ यादृच्छिक रूप से रख चुका होता है, इसलिए पहले अनुरोध में दोनों रंगों के placed का जोड़ 12 होता है (आमतौर पर {"1":6,"2":6})। जिस रंग ने सभी 32 रख दी हैं, उसे खाली legal_moves मिलती है और वह अपनी हर बारी पर -1 भेजता है।
खेल के अनुसार इंजन अनुरोध के उदाहरण
कनेक्टर जो पहला काले का अनुरोध --engine इंजन को भेजता है, उसके उदाहरण नियम वाले कोड से बनाए गए हैं। हर प्रकार के असली खेल 12 गोटियों वाली यादृच्छिक स्थिति से शुरू होते हैं, इसलिए हर खेल में board और legal_moves अलग होते हैं। इन उदाहरणों को स्थिर रखने के लिए इनकी शुरुआती चालें बोर्ड के बीच के पास चुनी गई हैं। असली खेलों में match_id और घड़ी के मान भी अलग होते हैं।
एंटी (Anti) (anti)
{"board":[0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,2,2,0,0,0,0,0,1,2,2,1,0,0,0,0,2,2,2,2,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"color":1,"legal_moves":[2,3,12,25,42,44,45],"game_mode":"anti","board_size":8,"blocked_squares":[],"placed":{"1":4,"2":4},"remaining_ms":60000,"match_id":123,"leg":0,"revision":0,"history":[],"round_no":null,"room_created_at":null,"budget_ms":10000}10x10 (Grand) (grand)
{"board":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,1,2,2,1,0,0,0,0,0,0,2,2,2,2,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"color":1,"legal_moves":[13,14,25,42,63,65,66],"game_mode":"grand","board_size":10,"blocked_squares":[],"placed":{"1":4,"2":4},"remaining_ms":60000,"match_id":123,"leg":0,"revision":0,"history":[],"round_no":null,"room_created_at":null,"budget_ms":10000}अष्टकोण (Octagon) (octagon)
{"board":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,1,2,2,1,0,0,0,0,0,0,2,2,2,2,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"color":1,"legal_moves":[13,14,25,42,63,65,66],"game_mode":"octagon","board_size":10,"blocked_squares":[0,1,10,8,9,19,80,90,91,89,98,99],"placed":{"1":4,"2":4},"remaining_ms":60000,"match_id":123,"leg":0,"revision":0,"history":[],"round_no":null,"room_created_at":null,"budget_ms":10000}क्लासिक रिवर्सी (reversi)
{"board":[0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,2,2,1,1,0,0,0,0,2,2,1,1,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"color":1,"legal_moves":[18,25,33,41,42,50,51],"game_mode":"reversi","board_size":8,"blocked_squares":[],"placed":{"1":6,"2":6},"remaining_ms":60000,"match_id":123,"leg":0,"revision":0,"history":[],"round_no":null,"room_created_at":null,"budget_ms":10000}इंजन अनुरोध के फ़ील्ड
| फ़ील्ड | प्रकार | विवरण |
|---|---|---|
game_mode | string | std, anti, grand, octagon, reversi में से एक। इंसानों के साथ खेल में XOT, std के रूप में आता है। |
board_size | integer 8 | 10 | 8, या grand और octagon के लिए 10। |
board | integer[board_size²] | board_size² लंबाई की सरणी। a1 से दाईं ओर, फिर अगली पंक्ति के क्रम में पढ़ें। 0=खाली (अष्टकोण के बंद खाने भी), 1=काला, 2=सफेद। |
blocked_squares | integer[] | अष्टकोण के उपयोग न किए जा सकने वाले खाने। दूसरे खेलों में खाली सरणी। |
placed | {"1": integer, "2": integer} | हर रंग द्वारा अब तक रखी गई गोटियाँ, शुरुआती यादृच्छिक चालों सहित; कुंजियाँ स्ट्रिंग "1" और "2" हैं। क्लासिक रिवर्सी की 32 गोटियों की सीमा के लिए उपयोग होता है। |
legal_moves | integer[] | वे खाने जिन पर आप अभी चल सकते हैं। खाली हो तो move=-1 जवाब दें। |
color | integer 1 | 2 | चलने वाला रंग। 1=काला, 2=सफेद। |
budget_ms | integer | इस चाल के लिए मिला समय, मिलीसेकंड में: --max-think-seconds और बची हुई घड़ी में से 0.75 सेकंड घटाकर मिले मान में से जो छोटा हो। इससे ज़्यादा होने पर कनेक्टर इंजन को रोक देता है। |
remaining_ms | integer | इस खेल में आपके रंग की बची हुई घड़ी, मिलीसेकंड में, इस बारी में पहले से लगा समय घटाकर। |
match_id | integer ≠ 0 | मुकाबले की ID। इंसानों के साथ खेल में ऋणात्मक (-कमरा नंबर)। |
leg | integer 0 | 1 | खेल नंबर 0 या 1। इंसानों के साथ खेल में हमेशा 0। |
revision | integer | इस खेल की स्थिति संख्या। इसे agent_move के साथ बिना बदले भेजें। |
history | array | इस खेल में चली गई चालें। निर्णय board से लें। |
round_no | integer | null | इंसान के साथ खेल का राउंड नंबर। बॉट के बीच मुकाबलों में null। |
room_created_at | string | null | इंसान के साथ खेल के कमरे के बनने का समय। बॉट के बीच मुकाबलों में null। |
दूसरे बॉट को अन्य रूप वाले खेल की चुनौती देना
agent_challenge में game_mode जोड़ें; डिफ़ॉल्ट std है। दोनों बॉट के supported_games में यह होना चाहिए। प्रतिद्वंद्वी के खेल agent_poll के जवाब में bots[].supported_games से पढ़ें। अगर किसी भी बॉट में वह खेल नहीं है, तो जवाब HTTP 409 के साथ नीचे दी गई त्रुटि होता है।
{"action":"agent_challenge","target_id":2,"game_mode":"anti"}
{"action":"agent_challenge","target_name":"Opponent","game_mode":"grand"}HTTP 409
{"ok":false,"error":"unsupported game mode","server_now_ms":1800000000000}supported_games बदलना
पंजीकरण फ़ॉर्म में शुरू में स्टैंडर्ड चुना होता है, और बिना सहेजी सूची वाले पुराने बॉट std समर्थित करते हैं। सूची केवल बॉट वेब पेज के प्रबंधन में बदली जा सकती है, बॉट टोकन (API) से कभी नहीं। मुकाबला चल रहा हो या स्वीकृति की प्रतीक्षा में हो, तो बदलाव अस्वीकार हो जाता है। खाली सूची सहेजी नहीं जा सकती।
NBoard और अन्य रूप वाले खेल
--nboard कनेक्शन केवल सामान्य (std) समर्थित करता है। जब कोई अन्य रूप वाला खेल आता है, तो कनेक्टर इंजन से नहीं पूछता और वह बारी छोड़ देता है (संदेश Engine failed for match)। कोई चाल नहीं भेजी जाती, इसलिए खेल पहली चाल से पहले रद्द हो जाता है, या बाद में वह खेल समय समाप्त होने से हार जाता है। NBoard बॉट के समर्थित खेलों में केवल सामान्य खेल रखें।
इंसान बनाम पंजीकृत बॉट
लोग आपके बॉट को उसके पंजीकृत किसी भी खेल में चुनौती दे सकते हैं। अगर वह सामान्य खेल समर्थित करता है, तो STD और XOT दोनों आ सकते हैं। XOT, game_mode std के साथ आता है और ऐसे बोर्ड से शुरू होता है जिस पर 8 चालें पहले ही चली जा चुकी हैं (वे history में शामिल हैं)। चुनौती देने वाला व्यक्ति घड़ी चुनता है, और खेल रेटिंग में नहीं गिना जाता। इंसान के साथ खेल में एक ही खेल (leg 0) होता है और match_id ऋणात्मक होता है। चाल संभव न होने पर पास सर्वर संभालता है, इसलिए -1 न भेजें। ऑटोमैटिक मैचिंग चालू वाले ऑनलाइन पंजीकृत बॉट समर्थित STD/XOT त्वरित मैचों में भी भाग लेते हैं। सदस्यों के त्वरित मैच रेटिंग वाले और मेहमानों के बिना रेटिंग वाले होते हैं।
अवैध चालें और समय
अवैध चाल या पुराना revision, HTTP 409 (illegal_move, stale_revision, not_your_turn) के साथ अस्वीकार होता है और बोर्ड नहीं बदलता। इस दौरान घड़ी चलती रहती है। कनेक्टर वही चाल उसी revision के साथ फिर भेजता है, इसलिए जब तक इंजन ठीक न हो, वह खेल आखिरकार समय समाप्त होने से हार जाता है। सर्वर पर प्रति चाल कोई सीमा नहीं है; वह केवल हर रंग की बची हुई घड़ी जाँचता है। 10 सेकंड कनेक्टर का डिफ़ॉल्ट --max-think-seconds है।
प्रमाणीकरण
HTTPS, JSON POST और Authorization: Bearer उपयोग करें। टोकन एक बॉट का है। इसे URL, सार्वजनिक कोड या लॉग में न रखें।
Content-Type: application/json
Authorization: Bearer <FS_BOT_TOKEN>POST https://othelloclub.com/flipsight/bot_match_api.php
मुकाबले के नियम
सभी बॉट खेल 12 गोटियों वाली यादृच्छिक स्थिति से शुरू होते हैं। रंग बदलकर दो खेल साथ चलते हैं। कुल मोहरों से विजेता तय होता है; Anti में कम मोहरे जीतते हैं।
सभी बॉट खेल 12 गोटियों वाली यादृच्छिक स्थिति से शुरू होते हैं। हर प्रकार के खेल में प्रत्येक बॉट को हर बोर्ड पर 1 मिनट मिलता है।
यदि कोई बॉट शुरुआत के 30 सेकंड के भीतर पहली चाल नहीं चलता, तो मुकाबला रद्द हो जाता है और रेटिंग में नहीं गिना जाता। यदि मुकाबले के दौरान एक बॉट का कनेक्शन 30 सेकंड से अधिक टूटा रहे और दूसरा जुड़ा हो, तो जुड़ा हुआ बॉट जीतता है (finish_reason: disconnect) और परिणाम रेटिंग में गिना जाता है।
सभी तरह के खेलों में FlipSight बॉट की चालें सर्वर गिनता है। वेब से और API (agent_challenge) से, दोनों तरह की चुनौतियाँ ली जाती हैं, और सर्वर मुकाबला तुरंत शुरू कर देता है, इसलिए गेम रूम खुला रखने की ज़रूरत नहीं है। अगर सर्वर की गणना 30 सेकंड से ज़्यादा रुक जाए, तो मुकाबला रद्द (finish_reason: technical) होता है और रेटिंग में नहीं गिना जाता। वैरिएंट की चालें गिनना भारी है, इसलिए FlipSight बॉट के साथ एक समय में अधिकतम 2 वैरिएंट मुकाबले चलते हैं। जगह भर जाने पर HTTP 409 और site bot variant matches are full मिलता है; थोड़ी देर बाद फिर कोशिश करें।
अपने-आप बॉट मुकाबले: साइट हमेशा बॉट मुकाबलों के दो रूम चालू रखती है। अपने-आप जोड़ी चालू वाला पंजीकृत बॉट जब ऑनलाइन हो और कोई मुकाबला न खेल रहा हो, तो उसे मिलती-जुलती रेटिंग वाले बॉट (पहले दूसरा पंजीकृत बॉट, न हो तो FlipSight बॉट) के साथ सामान्य (std) बॉट मुकाबले की चुनौती मिलती है, जिसमें वह bot_b होता है। कनेक्टर उसे अपने-आप स्वीकार करता है और मुकाबला शुरू हो जाता है। अगर बॉट 120 सेकंड में स्वीकार न करे या मना कर दे, तो वह 10 मिनट तक अपने-आप जोड़ी से बाहर रहता है। अपने-आप मुकाबले रेटिंग में गिने जाते हैं। एरीना के खेल चलते समय भी अपने-आप बॉट मुकाबले जारी रहते हैं। अपने-आप जोड़ी डिफ़ॉल्ट रूप से चालू है और बॉट पेज पर प्रबंधन में बंद की जा सकती है। अभ्यास इंजन से चालू किया गया बॉट (environment.practice true) अपने-आप मुकाबलों से बाहर रहता है, और उस दौरान दूसरे बॉट के साथ उसके मुकाबले रेटिंग में नहीं गिने जाते।
किसी व्यक्ति की सीधी चुनौती में समर्थित खेल और समय चुनकर सामान्य कमरे में एक खेल होता है। सर्वर सीधी चुनौतियों को हमेशा बिना रेटिंग वाला रखता है। ऑटोमैटिक मैचिंग चालू वाले ऑनलाइन पंजीकृत बॉट समर्थित STD/XOT त्वरित मैचों में भी भाग लेते हैं। सदस्यों के त्वरित मैच रेटिंग वाले और मेहमानों के बिना रेटिंग वाले होते हैं। पंजीकृत बॉट उतने ही खेल स्वीकार करता है जितने एक साथ खेल की सेटिंग अनुमति देती है (डिफ़ॉल्ट 2)। इंसान से एक खेल और एक बॉट मैच (दो बोर्ड) हर एक 1 गिने जाते हैं।
pending → running → finished / aborted
pending → rejected / expired
kind=human: id=-room_id, legs[0], round_no, room_created_at
agent_move: move=19 / "d3" / "D3" (8×8)
10×10: "j10" = "J0" = 99
pass: -1 / "pass" / "PA" / "PS" / "--" (paired games only)
index=row*board_size+column (0-based)मुकाबले का क्रम
सभी बॉट खेल 12 गोटियों वाली यादृच्छिक स्थिति से शुरू होते हैं। रंग बदलकर दो खेल साथ चलते हैं। कुल मोहरों से विजेता तय होता है; Anti में कम मोहरे जीतते हैं।
यदि आप bot_a हैं तो आपकी प्रतिभागी संख्या 0 है, और bot_b हैं तो 1। प्रतिभागी 0, legs[0] में काला (1) और legs[1] में सफेद (2) खेलता है; प्रतिभागी 1 इसके उलट। जब leg.status active हो और leg.turn आपके रंग के बराबर हो, तब आपकी बारी है। दोनों खेलों में एक साथ आपकी बारी हो सकती है।
यदि आपके पास कोई वैध चाल नहीं है, तो आपको स्वयं move -1 (पास) भेजना होगा; सर्वर आपकी ओर से पास नहीं करता। मनुष्य के विरुद्ध खेलों में सर्वर पास को सामान्य खेल कमरों की तरह संभालता है।
आपकी बारी में शेष समय = clocks_ms[आपका रंग - 1] - (server_now_ms - turn_started_ms)। clocks_ms रंग क्रम (काला, सफेद) में है; totals और winner प्रतिभागी क्रम में हैं (winner 0 या 1, बराबरी पर null)।
खानों के नंबर
खाना नंबर = पंक्ति × 8 + स्तंभ, इसलिए a1=0, h1=7, a2=8 और h8=63। उदाहरण के लिए 19 d3 है और 37 f5 है। board सरणी भी यही क्रम उपयोग करती है: 0=खाली, 1=काला, 2=सफेद।
a b c d e f g h
1 0 1 2 3 4 5 6 7
2 8 9 10 11 12 13 14 15
3 16 17 18 19 20 21 22 23
4 24 25 26 27 28 29 30 31
5 32 33 34 35 36 37 38 39
6 40 41 42 43 44 45 46 47
7 48 49 50 51 52 53 54 55
8 56 57 58 59 60 61 62 6310×10 (grand, octagon) पर, खाना = पंक्ति × 10 + स्तंभ। स्तंभ a से j तक हैं, और निर्देशांकों में दसवीं पंक्ति 10 या 0 लिखी जाती है। a1=0, j1=9, a2=10, j10=99 (j0 के समान)। एक ही निर्देशांक का नंबर हर बोर्ड आकार में अलग होता है: d3, 8×8 पर 19 और 10×10 पर 23 है।
a b c d e f g h i j
1 0 1 2 3 4 5 6 7 8 9
2 10 11 12 13 14 15 16 17 18 19
3 20 21 22 23 24 25 26 27 28 29
4 30 31 32 33 34 35 36 37 38 39
5 40 41 42 43 44 45 46 47 48 49
6 50 51 52 53 54 55 56 57 58 59
7 60 61 62 63 64 65 66 67 68 69
8 70 71 72 73 74 75 76 77 78 79
9 80 81 82 83 84 85 86 87 88 89
10 90 91 92 93 94 95 96 97 98 99अष्टकोण (Octagon) (octagon)
a b c d e f g h i j
1 ## ## 2 3 4 5 6 7 ## ##
2 ## 11 12 13 14 15 16 17 18 ##
3 20 21 22 23 24 25 26 27 28 29
4 30 31 32 33 34 35 36 37 38 39
5 40 41 42 43 44 45 46 47 48 49
6 50 51 52 53 54 55 56 57 58 59
7 60 61 62 63 64 65 66 67 68 69
8 70 71 72 73 74 75 76 77 78 79
9 ## 81 82 83 84 85 86 87 88 ##
10 ## ## 92 93 94 95 96 97 ## ##इवेंट स्ट्रीम
उसी Bearer टोकन से GET https://othelloclub.com/flipsight_api/bot-stream से जुड़ें और हर पंक्ति में एक JSON इवेंट (NDJSON) पाएँ: hello कनेक्शन की पुष्टि करता है, match का अर्थ है कि आपके किसी मुकाबले में बदलाव हुआ (बॉट बनाम बॉट इवेंट में पूरा मुकाबला ऑब्जेक्ट होता है), और ping हर 10 सेकंड में कनेक्शन जीवित रखता है। match मिलने पर agent_poll एक बार कॉल करें। कनेक्शन टूटने पर 1 से 30 सेकंड तक बढ़ती देरी के साथ फिर जुड़ें और इस बीच पोलिंग जारी रखें। स्ट्रीम जुड़ी रहने तक आपका बॉट ऑनलाइन दिखता है; हर बॉट अधिकतम 3 स्ट्रीम खोल सकता है।
इवेंट उदाहरण
curl -N 'https://othelloclub.com/flipsight_api/bot-stream' \
-H "Authorization: Bearer $FS_BOT_TOKEN"
{"type":"hello","bot_id":1,"server_now_ms":1800000000000}
{"type":"match","match":{"id":123,"bot_a":1,"bot_b":2,"status":"running","state":{...}},"server_now_ms":1800000000500}
{"type":"match","match":{"id":-45,"kind":"human","room_id":45},"server_now_ms":1800000003000}
{"type":"ping","server_now_ms":1800000010000}इंजन अडैप्टर
FlipSight बॉट कनेक्टर (Python 3.9+, केवल मानक लाइब्रेरी) Windows, macOS और Linux पर चलता है और इंजन को दो तरह से जोड़ता है। --engine हर खेल के लिए इंजन को एक बार चालू रखता है, हर चाल पर एक JSON पंक्ति भेजता है और एक {"move": खाना} पंक्ति पढ़ता है। जो इंजन एक पंक्ति का उत्तर देकर बंद हो जाता है वह भी काम करता है क्योंकि अगली चाल पर उसे फिर से चालू किया जाता है, लेकिन जो इंजन इनपुट को अंत तक पढ़ता है (sys.stdin.read() आदि) वह कभी उत्तर नहीं देता, इसलिए एक बार में एक पंक्ति पढ़ें। अनुरोध का legal_moves वैध खानों की सूची है; खाली हो तो -1 उत्तर दें। --nboard NBoard प्रोटोकॉल इंजन को हर खेल के लिए एक चालू रखता है; खोज की गहराई --nboard-depth से तय करें।
Edax को नीचे --edax में केवल निष्पादन योग्य फ़ाइल का पथ देकर भी जोड़ सकते हैं। अलग अडैप्टर नहीं चाहिए; कनेक्टर बची हुई खेल घड़ी के अनुसार हर चाल का सोचने का समय बाँटता है।
Egaroucid for Console तैयार करें। ग्राफिकल ऐप के बजाय कंसोल प्रोग्राम चुनें और resources फ़ोल्डर उसकी जगह रखें। macOS और Linux पर आधिकारिक निर्देशों से बना प्रोग्राम उपयोग करें। कनेक्टर setboard, settime और go से स्थिति और बचा समय भेजता है, इसलिए अडैप्टर नहीं चाहिए।
इनपुट JSON (कनेक्टर → अडैप्टर)
यह कनेक्टर द्वारा भेजे गए डेटा का उदाहरण है, चलाने वाला कोड नहीं। इसे Python फ़ाइल के रूप में न सहेजें। खेल के दौरान कनेक्टर हर चाल पर मौजूदा डेटा अपने आप भेजता है।
{"board":[0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,2,2,0,0,0,0,0,1,2,2,1,0,0,0,0,2,2,2,2,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"color":1,"legal_moves":[2,3,12,25,42,44,45],"game_mode":"std","board_size":8,"blocked_squares":[],"placed":{"1":4,"2":4},"remaining_ms":40000,"match_id":123,"leg":1,"revision":0,"history":[],"round_no":null,"room_created_at":null,"budget_ms":10000}जवाब JSON (अडैप्टर → कनेक्टर)
{"move":2}स्थिति समन्वयन
स्ट्रीम जुड़ी होने पर इवेंट आने पर और हर 10 सेकंड में agent_poll कॉल करें। स्ट्रीम के बिना पोलिंग करते समय मुकाबले के दौरान हर सेकंड और खाली समय में हर 5 सेकंड कॉल करें, पर कभी भी प्रति सेकंड एक बार से अधिक नहीं। नेटवर्क का समय आपकी घड़ी से कटता है। यदि चाल का उत्तर खो जाए, तो नई स्थिति पढ़ें और वही चाल तभी दोबारा भेजें जब revision अब भी वही हो।
API क्रियाएँ
उत्तर के उदाहरण प्रारूप दिखाते हैं। कॉपी बटन केवल अनुरोध कॉपी करता है और API कॉल नहीं करता।
POST agent_poll
स्थिति पढ़ें
| पैरामीटर | प्रकार | आवश्यक | विवरण |
|---|---|---|---|
action | string "agent_poll" | आवश्यक | कॉल किए जाने वाले एक्शन का नाम |
environment | object | वैकल्पिक | कनेक्टर वाले कंप्यूटर का CPU, OS और इंजन नाम (प्रत्येक अधिकतम 120 अक्षर, वैकल्पिक) और practice (true या false, वैकल्पिक)। practice true का मतलब है कि बॉट अभ्यास कर रहा है: वह अपने-आप मुकाबलों से बाहर रहता है, और उस दौरान भेजे या स्वीकार किए गए बॉट मुकाबले रेटिंग में नहीं गिने जाते। अभ्यास इंजन से चालू होने पर कनेक्टर यह मान अपने-आप भेजता है। सर्वर आख़िरी मान याद रखता है, इसलिए अभ्यास ख़त्म होने पर इसे practice के बिना या false के साथ भेजें। |
अनुरोध उदाहरण
curl 'https://othelloclub.com/flipsight/bot_match_api.php' \
-H "Authorization: Bearer $FS_BOT_TOKEN" \
-H 'Content-Type: application/json' \
--data '{"action":"agent_poll","environment":{"cpu":"Apple M4","engine":"MyEngine","os":"Darwin"}}'उत्तर उदाहरण
{
"ok": true,
"bots": [
{
"id": 1,
"name": "Opponent",
"owner_id": "example",
"owner_name": "Example",
"owner": {
"player_id": "example",
"name": "Example",
"photo": "/img/no_profile.gif",
"country_code": "",
"country_name": "",
"country_flag_url": "",
"donor": false,
"verified_player_id": ""
},
"engine_level": null,
"rating": {
"rating": 1200,
"rd": 300,
"official": false,
"official_progress": {
"kind": "provisional",
"current": 0,
"required": 50
},
"color": "pz-rating-unofficial",
"high_rating": 1200,
"wins": 0,
"losses": 0,
"draws": 0,
"streak": 0,
"best_streak": 0
},
"supported_games": ["std"],
"auto_match": true,
"bio": "",
"registered_at": "2026-11-12 18:00:00",
"registered_at_ts": 1794474000,
"environment": {
"cpu": "Apple M4",
"engine": "MyEngine",
"os": "Darwin",
"practice": false
},
"is_builtin": false,
"online": true,
"disabled": false,
"deleted": false,
"photo": "/flipsight/bot_match_api.php?action=photo&bot_id=1&v=1794474000000"
},
{
"id": 2,
"name": "MyBot",
"owner_id": "example",
"owner_name": "Example",
"owner": {
"player_id": "example",
"name": "Example",
"photo": "/img/no_profile.gif",
"country_code": "",
"country_name": "",
"country_flag_url": "",
"donor": false,
"verified_player_id": ""
},
"engine_level": null,
"rating": {
"rating": 1200,
"rd": 300,
"official": false,
"official_progress": {
"kind": "provisional",
"current": 0,
"required": 50
},
"color": "pz-rating-unofficial",
"high_rating": 1200,
"wins": 0,
"losses": 0,
"draws": 0,
"streak": 0,
"best_streak": 0
},
"supported_games": ["std", "anti"],
"auto_match": true,
"bio": "",
"registered_at": "2026-11-12 18:00:00",
"registered_at_ts": 1794474000,
"environment": {
"cpu": "Apple M4",
"engine": "MyEngine",
"os": "Darwin",
"practice": false
},
"is_builtin": false,
"online": true,
"disabled": false,
"deleted": false,
"photo": "/flipsight/bot_match_api.php?action=photo&bot_id=2&v=1794474000000"
}
],
"record_bots": [],
"matches": [
{
"id": 123,
"bot_a": 1,
"bot_b": 2,
"game_mode": "std",
"time_limit_sec": 60,
"status": "running",
"state": {
"version": 1,
"game_mode": "std",
"time_limit_sec": 60,
"status": "active",
"revision": 1,
"started_ms": 1799999980000,
"last_now_ms": 1799999984200,
"finished_ms": null,
"opening_moves": [19, 20, 29, 34, 26, 11, 43, 37],
"opening_history": [
{
"color": 1,
"move": 19
},
{
"color": 2,
"move": 20
},
{
"color": 1,
"move": 29
},
{
"color": 2,
"move": 34
},
{
"color": 1,
"move": 26
},
{
"color": 2,
"move": 11
},
{
"color": 1,
"move": 43
},
{
"color": 2,
"move": 37
}
],
"legs": [
{
"board": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0, 0, 0, 2, 1, 2, 2, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"turn": 2,
"black_participant": 0,
"placed": {
"1": 5,
"2": 4
},
"clocks_ms": [55800, 60000],
"turn_started_ms": 1799999984200,
"revision": 1,
"history": [
{
"color": 1,
"participant": 0,
"move": 44,
"at_ms": 1799999984200
}
],
"status": "active",
"discs": [5, 8],
"finished_ms": null,
"legal_moves": [18, 21, 22, 25, 30, 33, 38, 42, 50, 51, 52]
},
{
"board": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 1, 2, 2, 1, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"turn": 1,
"black_participant": 1,
"placed": {
"1": 4,
"2": 4
},
"clocks_ms": [60000, 60000],
"turn_started_ms": 1799999980000,
"revision": 0,
"history": [],
"status": "active",
"discs": [3, 9],
"finished_ms": null,
"legal_moves": [2, 3, 12, 25, 42, 44, 45]
}
],
"totals": [14, 11],
"winner": null,
"finish_reason": null,
"board_size": 8,
"blocked_squares": []
},
"auto": false,
"expires_ms": 1800000080000,
"ranked": true,
"rating_applied": false,
"rating_before": [null, null],
"rating_after": [null, null],
"created_at": "2026-11-12 19:00:00"
}
],
"me": "example",
"bot": {
"id": 2,
"name": "MyBot",
"owner_id": "example",
"owner_name": "Example",
"owner": {
"player_id": "example",
"name": "Example",
"photo": "/img/no_profile.gif",
"country_code": "",
"country_name": "",
"country_flag_url": "",
"donor": false,
"verified_player_id": ""
},
"engine_level": null,
"rating": {
"rating": 1200,
"rd": 300,
"official": false,
"official_progress": {
"kind": "provisional",
"current": 0,
"required": 50
},
"color": "pz-rating-unofficial",
"high_rating": 1200,
"wins": 0,
"losses": 0,
"draws": 0,
"streak": 0,
"best_streak": 0
},
"supported_games": ["std", "anti"],
"auto_match": true,
"bio": "",
"registered_at": "2026-11-12 18:00:00",
"registered_at_ts": 1794474000,
"environment": {
"cpu": "Apple M4",
"engine": "MyEngine",
"os": "Darwin",
"practice": false
},
"is_builtin": false,
"online": true,
"disabled": false,
"deleted": false,
"photo": "/flipsight/bot_match_api.php?action=photo&bot_id=2&v=1794474000000"
},
"server_now_ms": 1800000000000
}मुकाबला ऑब्जेक्ट (matches[])
| फ़ील्ड | प्रकार | विवरण |
|---|---|---|
id | integer | मुकाबला ID (मनुष्य के विरुद्ध खेलों में ऋणात्मक) |
kind | string | मनुष्य के विरुद्ध खेलों में human |
bot_a | integer | प्रतिभागी 0 की बॉट ID (मनुष्य के लिए 0) |
bot_b | integer | प्रतिभागी 1 की बॉट ID (मनुष्य के लिए 0) |
game_mode | string | खेल (std, anti, grand, octagon, reversi) |
time_limit_sec | integer | हर खेल में हर रंग को मिले सेकंड |
status | string | pending, running, finished, aborted, rejected, expired |
expires_ms | integer | स्वीकृति की समय सीमा (मिलीसेकंड) |
ranked | boolean | मुकाबला रेटिंग में गिना जाता है या नहीं |
state.status | string | active, finished या aborted |
state.game_mode | string | खेल (std, anti, grand, octagon, reversi) |
state.board_size | integer 8 | 10 | हर तरफ़ के खाने, 8 या 10 |
state.blocked_squares | integer[] | उपयोग न किए जा सकने वाले खाने (केवल अष्टकोण, क्रम में नहीं) |
state.legs | array | खेल (बॉट के बीच 2, मनुष्य के विरुद्ध 1) |
state.totals | [integer, integer] | प्रत्येक प्रतिभागी की दोनों खेलों की कुल गोटियाँ |
state.winner | integer | null | विजेता प्रतिभागी 0 या 1, बराबरी पर null |
state.finish_reason | string | null | discs, timeout, double_timeout, disconnect, no_first_move |
खेल ऑब्जेक्ट (state.legs[])
| फ़ील्ड | प्रकार | विवरण |
|---|---|---|
board | integer[64 | 100] | 64 / 100 खाने, 0=खाली 1=काला 2=सफेद |
turn | integer | चलने वाला रंग, 1 (काला) या 2 (सफेद) |
legal_moves | integer[] | चलने वाले रंग के वैध खाने। समाप्त खेलों में खाली |
placed | {"1": integer, "2": integer} | हर रंग द्वारा रखी गई गोटियाँ, कुंजियाँ "1" (काला) और "2" (सफेद) |
black_participant | integer | इस खेल में काले से खेलने वाला प्रतिभागी |
clocks_ms | [number, number] | रंग क्रम (काला, सफेद) में शेष समय के आधार मान |
turn_started_ms | integer | वर्तमान बारी शुरू होने का सर्वर समय |
revision | integer | इस खेल में हर बदलाव पर 1 बढ़ता है |
status | string | active, finished, timeout, stopped |
history | array | चली गई चालें (color, participant, move, at_ms) |
discs | [integer, integer] | रंग क्रम (काला, सफेद) में गोटियों की संख्या |
result_discs | [integer, integer] (optional) | समय समाप्त होने से हारे गए खेल का वैकल्पिक तय स्कोर [काला, सफेद]। यह हो तो कुल में गोटियों (discs) के बजाय इसे जोड़ें। जिस पक्ष का समय खत्म हुआ और उसके प्रतिद्वंद्वी का स्कोर: std और reversi में 0 और 64, grand में 0 और 100, octagon में 0 और 88, anti में 64 और 0। दूसरा खेल जारी रहता है, और दोनों खेल खत्म होने के बाद कुल योग से विजेता तय होता है। पहले समाप्त हो चुके रिकॉर्ड दोबारा नहीं गिने जाते। |
POST agent_challenge
चुनौती दें
प्रतिद्वंद्वी को target_id (बॉट नंबर) या target_name (बॉट का नाम) से बताएँ; ये agent_poll के जवाब की bots सूची में मिलते हैं। FlipSight के बिल्ट-इन बॉट (is_builtin: true) को सभी तरह के खेलों के लिए API से चुनौती दी जा सकती है, और सर्वर मुकाबला तुरंत शुरू करता है। अगर बिल्ट-इन बॉट के साथ पहले से 2 वैरिएंट मुकाबले चल रहे हों, तो HTTP 409 और site bot variant matches are full मिलता है।
| पैरामीटर | प्रकार | आवश्यक | विवरण |
|---|---|---|---|
action | string "agent_challenge" | आवश्यक | कॉल किए जाने वाले एक्शन का नाम |
target_id | integer ≥ 1 | वैकल्पिक | जिस बॉट को चुनौती देनी है उसकी ID |
target_name | string | वैकल्पिक | जिस बॉट को चुनौती देनी है उसका नाम (target_id के बजाय) |
game_mode | string std | anti | octagon | grand | reversi | वैकल्पिक | बॉट के बीच मुकाबले का खेल। डिफ़ॉल्ट std है। दोनों बॉट को इसे समर्थित करना चाहिए। स्टैंडर्ड / एंटी (Anti) / अष्टकोण (Octagon) / 10x10 (Grand) / क्लासिक रिवर्सी |
अनुरोध उदाहरण
curl 'https://othelloclub.com/flipsight/bot_match_api.php' \
-H "Authorization: Bearer $FS_BOT_TOKEN" \
-H 'Content-Type: application/json' \
--data '{"action":"agent_challenge","target_id":2,"game_mode":"anti"}'उत्तर उदाहरण
{
"ok": true,
"match_id": 123,
"server_now_ms": 1800000000000
}POST agent_accept
स्वीकार करें
| पैरामीटर | प्रकार | आवश्यक | विवरण |
|---|---|---|---|
action | string "agent_accept" | आवश्यक | कॉल किए जाने वाले एक्शन का नाम |
match_id | integer ≥ 1 | आवश्यक | मुकाबला ID (मनुष्य के विरुद्ध खेलों में ऋणात्मक) |
अनुरोध उदाहरण
curl 'https://othelloclub.com/flipsight/bot_match_api.php' \
-H "Authorization: Bearer $FS_BOT_TOKEN" \
-H 'Content-Type: application/json' \
--data '{"action":"agent_accept","match_id":123}'उत्तर उदाहरण
{
"ok": true,
"match": {
"id": 123,
"status": "running",
"bot_a": 1,
"bot_b": 2
},
"server_now_ms": 1800000000000
}POST agent_reject
अस्वीकार करें
| पैरामीटर | प्रकार | आवश्यक | विवरण |
|---|---|---|---|
action | string "agent_reject" | आवश्यक | कॉल किए जाने वाले एक्शन का नाम |
match_id | integer ≥ 1 | आवश्यक | मुकाबला ID (मनुष्य के विरुद्ध खेलों में ऋणात्मक) |
अनुरोध उदाहरण
curl 'https://othelloclub.com/flipsight/bot_match_api.php' \
-H "Authorization: Bearer $FS_BOT_TOKEN" \
-H 'Content-Type: application/json' \
--data '{"action":"agent_reject","match_id":123}'उत्तर उदाहरण
{
"ok": true,
"match": {
"id": 123,
"status": "rejected",
"bot_a": 1,
"bot_b": 2
},
"server_now_ms": 1800000000000
}POST agent_move
चाल भेजें
| पैरामीटर | प्रकार | आवश्यक | विवरण |
|---|---|---|---|
action | string "agent_move" | आवश्यक | कॉल किए जाने वाले एक्शन का नाम |
match_id | integer ≠ 0 | आवश्यक | मुकाबला ID (मनुष्य के विरुद्ध खेलों में ऋणात्मक) |
round_no | integer ≥ 0 | वैकल्पिक | केवल मनुष्य के विरुद्ध खेल: मुकाबला ऑब्जेक्ट का round_no |
room_created_at | string | वैकल्पिक | केवल मनुष्य के विरुद्ध खेल: मुकाबला ऑब्जेक्ट का room_created_at |
leg | integer 0 | 1 | आवश्यक | खेल 0 या 1 (मनुष्य के विरुद्ध खेलों में 0) |
revision | integer ≥ 0 | आवश्यक | जिस खेल के लिए चाल की गणना हुई उसका revision; खेल बदल गया हो तो 409 stale_revision |
move | integer -1..99 | string | आवश्यक | खाना 0-(board_size²−1), पास के लिए -1 / d3 / D3 / pass |
अनुरोध उदाहरण
curl 'https://othelloclub.com/flipsight/bot_match_api.php' \
-H "Authorization: Bearer $FS_BOT_TOKEN" \
-H 'Content-Type: application/json' \
--data '{"action":"agent_move","match_id":123,"leg":1,"revision":0,"move":2}'उत्तर उदाहरण
{
"ok": true,
"match": {
"id": 123,
"status": "running",
"bot_a": 1,
"bot_b": 2
},
"server_now_ms": 1800000000000
}त्रुटियाँ
त्रुटियाँ {"ok": false, "error": "…"} रूप में आती हैं। 401 पर रुकें और टोकन जाँचें। 409 पर वर्तमान स्थिति पढ़ें और बारी, revision और वैध चालें जाँचें। 429 का अर्थ है एक बॉट के लिए बहुत अधिक स्ट्रीम। कनेक्शन त्रुटियों और 503 को बढ़ती देरी के साथ दोहराएँ, और अवैध चाल कभी दोबारा न भेजें।
{"ok":false,"error":"stale_revision","server_now_ms":1800000000000}| HTTP | error |
|---|---|
| 400 | JSON object required / unknown action |
| 401 | invalid bot credential |
| 403 | access denied / invalid csrf |
| 405 | POST required |
| 409 | stale_revision / not_your_turn / illegal_move / leg_finished / match not running / match timed out / stale room revision / invalid move coordinate / move outside board / unsupported game mode / both bots must be connected / bot already has an active match / bot busy / challenge expired or answered / site bot variant matches are full / target bot not found |
| 413 | request too large |
| 429 | too many streams (bot-stream) |
| 503 | bot match storage unavailable |