फॉर्मिक फंक्शंस - हिल क्वीन की एंट क्वीन


104

लाइव देखें | सक्रिय उत्तर | नई उत्तर जोड़ें | चैट रूम | स्रोत कोड | लीडरबोर्ड

जब भी जरूरत हो नए टूर्नामेंट। नए खिलाड़ी और नए अपडेट बहुत स्वागत करते हैं।

रंग की टाइलों के साथ एक डांस फ्लोर पर रानी चींटी

वास्तविक खेल फुटेज नहीं।

प्रत्येक खिलाड़ी एक चींटी के साथ शुरू होता है - एक रानी, ​​जो भोजन एकत्र करती है। भोजन के प्रत्येक टुकड़े को श्रमिक बनाने के लिए रखा जा सकता है या इस्तेमाल किया जा सकता है। श्रमिक रानी को वापस लाने के लिए भोजन भी एकत्र करते हैं।

एक क्षेत्र में 16 खिलाड़ी प्रतिस्पर्धा करते हैं। विजेता वह रानी है जिसने 30,000 भोजन लेने के बाद सबसे अधिक भोजन प्राप्त किया है। पकड़ यह है कि चींटियों को केवल अखाड़ों के रंग बदलकर संवाद कर सकते हैं, जिसे प्रतिद्वंद्वी चींटियों द्वारा भी बदला जा सकता है ...

खेल देख रहा हूँ

यह एक जावास्क्रिप्ट प्रतियोगिता है, जिसका अर्थ है कि आप नीचे दिए गए लिंक पर क्लिक करके गेम को अपने ब्राउज़र में लाइव देख सकते हैं।

खेल को लाइव देखने के लिए यहां क्लिक करें

हिल कॉन्टेस्ट के मूल स्टैक स्निपेट किंग, रेड बनाम ब्लू - पिक्सेल टीम बैटलबोट्स , और ब्लॉक बिल्डिंग बॉट फ्लॉक्स के लिए हेल्का होम्बा के लिए बहुत धन्यवाद , जिसने कोट को होस्ट किए गए वेब ब्राउज़र का विचार प्रदान किया और इस के लिए कोड की भारी जानकारी दी।

सैंडबॉक्स और चैट में अद्भुत लोगों से सभी प्रतिक्रिया और परीक्षण के लिए विशाल धन्यवाद।

लीडरबोर्ड

लीडरबोर्ड के शीर्ष स्थानों की तस्वीर

(पूर्ण लीडरबोर्ड और संयुक्त स्थानों के स्पष्टीकरण को देखने के लिए छवि पर क्लिक करें - केवल कुछ खिलाड़ी अंतरिक्ष को बचाने के लिए यहां दिखा रहे हैं।)

यह लीडरबोर्ड खिलाड़ियों पर आधारित है के रूप में वे संडे 2 पर थे nd सितंबर 2018।

स्क्रीनशॉट

एक खेल के अंत में अखाड़ा कैसा दिखता है, इसके कुछ चित्र। पूर्ण आकार देखने के लिए चित्र पर क्लिक करें।

क्षेत्र की छवि क्षेत्र की छवि क्षेत्र की छवि क्षेत्र की छवि क्षेत्र की छवि क्षेत्र की छवि क्षेत्र की छवि क्षेत्र की छवि क्षेत्र की छवि क्षेत्र की छवि क्षेत्र की छवि क्षेत्र की छवि क्षेत्र की छवि क्षेत्र की छवि क्षेत्र की छवि क्षेत्र की छवि

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

अखाड़ा

अखाड़ा एक टॉरॉयडल (एज रैपिंग) वर्ग कोशिकाओं का ग्रिड है। इसकी चौड़ाई 2500 और ऊंचाई 1000 है। सभी कोशिकाएं रंग 1 के रूप में शुरू होती हैं।

शुरू में ठीक 0.1% कोशिकाओं में भोजन होगा। भोजन के 2500 टुकड़े समान रूप से बेतरतीब ढंग से बिखरे हुए होंगे। खेल के दौरान कोई नया भोजन पेश नहीं किया जाएगा।

रानियों को बेतरतीब ढंग से खाली कोशिकाओं पर रखा जाएगा, बिना किसी गारंटी के कि वे एक-दूसरे से सटे नहीं होंगे (हालांकि यह बहुत संभावना नहीं है)।

चींटी की योग्यता

  • दृष्टि: प्रत्येक चींटी अपने 3 में 9 कोशिकाओं को 3 पड़ोस में देखती है। इस पड़ोस के बाहर किसी भी अन्य चींटियों का ज्ञान नहीं है। यह 9 कोशिकाओं (अन्य चींटियों और भोजन) में से प्रत्येक की सामग्री को देखता है, और प्रत्येक कोशिका का रंग भी
  • कोई स्मृति नहीं: प्रत्येक चींटी अपने निर्णयों को उसके आधार पर बनाती है जो वह देखता है - यह याद नहीं रखता कि उसने पिछली बारी में क्या किया था और उसके पास अखाड़ा कोशिकाओं के रंगों के अलावा राज्य को संग्रहीत करने का कोई तरीका नहीं है।
  • कोई अभिविन्यास नहीं: एक चींटी को नहीं पता कि वह कहाँ है या वह किस तरह से सामना करती है - इसका उत्तर की कोई अवधारणा नहीं है। 3 बाय 3 पड़ोस को एक यादृच्छिक रूप से घुमाए गए अभिविन्यास में प्रस्तुत किया जाएगा जो प्रत्येक मोड़ को बदल देता है इसलिए यह एक सीधी रेखा में भी नहीं चल सकता है जब तक कि इसमें मार्गदर्शन करने के लिए रंग न हों। (एक ही चाल से हर मोड़ पर एक सीधी रेखा के बजाय एक यादृच्छिक चलना होगा।)
  • , बढ़ते रंग अंकन और कार्यकर्ताओं का निर्माण: देखें आउटपुट नीचे।
  • अमरता: ये हाइलैंड चींटियाँ हैं जो मर नहीं सकती हैं। आप अपने आस-पास के रंगों को बदलकर प्रतिद्वंद्वी चींटियों को भ्रमित कर सकते हैं, या उन्हें अपने स्वयं के 8 चींटियों के साथ आसपास जाने से रोक सकते हैं, लेकिन उन्हें इसके अलावा नुकसान नहीं पहुंचाया जा सकता है।
  • भोजन ले जाना : एक कार्यकर्ता भोजन के 1 टुकड़े तक ले जा सकता है। एक रानी भोजन की मनमानी राशि ले सकती है।
  • भोजन का स्थानांतरण: यदि कोई कार्यकर्ता रानी से सटे (8 दिशाओं में से किसी में) है, तो भोजन निम्नलिखित में से किसी एक तरीके से स्वचालित रूप से स्थानांतरित हो जाएगा:
    • अपनी ही रानी से सटा हुआ एक लाड़ला मजदूर अपना भोजन अपनी रानी को हस्तांतरित करेगा।
    • शत्रु रानी के समीप एक असावधान कार्यकर्ता यदि मौजूद हो तो 1 टुकड़ा भोजन चुरा लेगा।

एक कार्यकर्ता एक कार्यकर्ता से चोरी नहीं कर सकता, और एक रानी एक रानी से चोरी नहीं कर सकती। इसके अलावा एक कार्यकर्ता अपनी रानी से भोजन नहीं ले सकता है, और एक रानी दुश्मन कार्यकर्ता से चोरी नहीं कर सकती है।

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

कोडिंग

एक फ़ंक्शन बॉडी प्रदान करें

प्रत्येक चींटी को एक एंटी फंक्शन द्वारा नियंत्रित किया जाता है। प्रत्येक बारी खिलाड़ी के चींटी फ़ंक्शन को प्रत्येक चींटी के लिए अलग-अलग कहा जाता है (न केवल एक बार प्रति खिलाड़ी के लिए, बल्कि एक बार रानी के लिए और एक बार प्रत्येक कार्यकर्ता के लिए जिसे खिलाड़ी नियंत्रित करता है)। प्रत्येक मोड़, चींटी फ़ंक्शन अपने इनपुट को प्राप्त करेगा और उस विशेष चींटी के लिए एक चाल लौटाएगा।

एक जावास्क्रिप्ट ब्लॉक के शरीर को दिखाते हुए एक कोड ब्लॉक वाले उत्तर को पोस्ट करें, और यह स्वचालित रूप से नियंत्रक में शामिल हो जाएगा (बस नियंत्रक पृष्ठ को ताज़ा करें)। खिलाड़ी का नाम उत्तर का शीर्षक बनाता है, प्रपत्र में # PlayerName(जो नियंत्रक तालिकाओं में अधिकतम 40 वर्णों को काट दिया जाएगा)।

कोई राज्य नहीं, कोई समय नहीं, कोई यादृच्छिक नहीं

एक फ़ंक्शन को वैश्विक चर का उपयोग नहीं करना चाहिए और घुमावों के बीच राज्य को संग्रहीत नहीं करना चाहिए। यह उन कार्यों में निर्मित का उपयोग कर सकता है जिनमें भंडारण की स्थिति शामिल नहीं है। उदाहरण के लिए, का उपयोग Math.abs()ठीक है, लेकिन Date.getTime()इसका उपयोग नहीं किया जाना चाहिए।

एक एंटी फ़ंक्शन केवल एक छद्म यादृच्छिक संख्या जनरेटर का उपयोग कर सकता है जो इसे स्वयं आपूर्ति करता है, जो राज्य को स्टोर नहीं करता है। उदाहरण के लिए, यह बीज के रूप में दिखाई देने वाले रंगों / खाद्य / चींटियों का उपयोग कर सकता है। Math.random()स्पष्ट रूप से मना किया जाता है, क्योंकि लगभग सभी छद्म आयामी संख्या जनरेटर की तरह, यह क्रम में अगली संख्या की प्रगति के लिए राज्य को संग्रहीत करता है।

इनपुट की यादृच्छिक अभिविन्यास के कारण एक सरल यादृच्छिक रणनीति अभी भी संभव है - एक चींटी जो हमेशा एक ही दिशा चुनती है एक सीधी रेखा पथ के बजाय एक यादृच्छिक चलना करेगी। इस यादृच्छिकता का उपयोग करने और इस यादृच्छिकता से बचने के सरल तरीकों के लिए उदाहरण के उत्तर देखें ।

एक चींटी फ़ंक्शन को उसके शरीर के भीतर आगे के कार्यों को शामिल करने की अनुमति है। मौजूदा उदाहरण देखें कि यह कैसे उपयोगी हो सकता है।

console.log

आप एक नए चैलेंजर खिलाड़ी के परीक्षण के दौरान कंसोल पर लॉग इन कर सकते हैं, लेकिन एक बार उत्तर के रूप में यहां पोस्ट करने पर खिलाड़ी के पास कोई पहुंच नहीं होगी console.log। इसका उपयोग करने का प्रयास करने से संपादित होने तक त्रुटि और अयोग्यता हो जाएगी। लीडरबोर्ड टूर्नामेंट को तेज रखने में मदद करनी चाहिए, जबकि अभी भी डिबगिंग कोड को नए चैलेंजर टेक्स्ट क्षेत्र में पेस्ट करने की अनुमति है।

इनपुट और आउटपुट

इनपुट

इनपुट का ओरिएंटेशन प्रत्येक चींटी के लिए और प्रत्येक मोड़ के लिए यादृच्छिक रूप से चुना जाएगा। इनपुट 0, 90, 180 या 270 डिग्री तक घुमाया जाएगा, लेकिन कभी भी परिलक्षित नहीं होगा।

कक्ष अंग्रेजी पढ़ने के क्रम में गिने जाते हैं:

0 1 2
3 4 5
6 7 8

चींटी फ़ंक्शन को एक सरणी प्राप्त होगी view, जिसमें 9 दृश्यमान कोशिकाओं में से प्रत्येक के लिए एक ऑब्जेक्ट होगा। प्रत्येक वस्तु में निम्नलिखित होंगे:

color: a number from 1 to 8
food: 0 or 1
ant: null if there is no ant on that cell, or otherwise an ant object

यदि किसी सेल में एक चींटी है, तो चींटी वस्तु में निम्नलिखित होंगे:

food: 0 or more (maximum 1 for a worker)
type: 1 to 4 for a worker, or 5 for a queen
friend: true or false

चींटी, केंद्रीय कक्ष में चींटी को देखकर उसके स्वयं के विवरण निर्धारित कर सकते हैं view[4].ant। उदाहरण के लिए, view[4].ant.typeएक रानी के लिए 5 है, या एक कार्यकर्ता के लिए 1 से 4 तक की संख्या है (इसके प्रकार का संकेत)।

उत्पादन

आउटपुट एक ऑब्जेक्ट के रूप में लिया जाता है जो कार्रवाई करने का प्रतिनिधित्व करता है। यह निम्न में से कोई भी हो सकता है:

cell: a number from 0 to 8 (mandatory)
color: a number from 1 to 8 (optional)
type: a number from 1 to 4 (optional)

अगर colorऔर typeछोड़ दिया या शून्य है, तो cellसेल को स्थानांतरित करने के लिए इंगित करता है।

यदि colorगैर-शून्य है, तो संकेतित सेल उस रंग में सेट है।

यदि typeगैर-शून्य है, तो संकेतित सेल पर उस प्रकार का एक श्रमिक चींटी बनाया जाता है। केवल एक रानी एक नया कार्यकर्ता बना सकती है, और केवल तभी जब उसके पास भोजन हो, क्योंकि प्रति कार्यकर्ता भोजन का एक टुकड़ा खर्च होता है।

उदाहरण आउटपुट:

{cell:0}: move to cell 0
{cell:4}: move to cell 4 (that is, do nothing, as 4 is the central cell)
{cell:4, color:8}: set own cell to color 8
{cell:6, type:1}: create a type 1 worker on cell 6
{cell:6, color:1}: set cell 6 to color 1
{cell:6, color:0}: equivalent to just `{cell:6}` - move rather than set color
{cell:6, type:0}: equivalent to just `{cell:6}` - move rather than create worker
{cell:6, color:0, type:0}: move to cell 6 - color 0 and type 0 are ignored

अमान्य आउटपुट:

{cell:9}: cell must be from 0 to 8
{cell:0, color:9}: color must be from 1 to 8
{cell:0, type:5}: type must be from 1 to 4 (cannot create a new queen)
{cell:4, type:1}: cannot create a worker on a non-empty cell
{cell:0, color:1, type:1}: cannot set color and create worker in the same turn

भोजन से युक्त सेल पर चलने वाली चींटी स्वचालित रूप से भोजन के टुकड़े को उठा लेगी।

कार्यकर्ता प्रकार

प्रत्येक कार्यकर्ता के पास एक प्रकार , 1 से 4 तक की संख्या होती है। इसका नियंत्रक से कोई मतलब नहीं है, और खिलाड़ी को अपनी इच्छानुसार काम करना है। एक रानी अपने सभी कार्यकर्ताओं को टाइप 1 के रूप में पेश कर सकती है, और उन्हें सभी समान व्यवहार दे सकती है, या वह कई प्रकार के श्रमिकों को विभिन्न व्यवहारों के साथ उत्पन्न कर सकती है, शायद 1 प्रकार के वनवासी और 2 प्रकार के रक्षक।

श्रमिक प्रकार की संख्या आपके द्वारा एक श्रमिक बनाए जाने पर सौंपी जाती है, और उसके बाद नहीं बदली जा सकती। हालाँकि आप इसे फिट देखें।

आदेश चालू करें

चींटियों को एक निर्धारित क्रम में बदल जाता है। एक खेल की शुरुआत में रानियों को एक यादृच्छिक क्रम सौंपा जाता है जो बाकी के खेल के लिए नहीं बदलता है। जब एक रानी एक श्रमिक बनाती है, तो उस श्रमिक को उसकी रानी से पहले की स्थिति में बारी क्रम में डाला जाता है। इसका मतलब यह है कि सभी खिलाड़ियों से संबंधित अन्य चींटियां नए श्रमिक के पहले कदम उठाने से पहले ठीक एक बार चलेंगी।

खिलाड़ियों की संख्या पर सीमा

जाहिर है कि असीमित संख्या में खिलाड़ी अखाड़े में नहीं बैठ सकते। चूंकि अब 16 से अधिक उत्तर हैं, प्रत्येक गेम में उनमें से 16 को यादृच्छिक रूप से चुना जाएगा। कई खेलों में औसत प्रदर्शन सभी खिलाड़ियों की विशेषता वाला एक लीडरबोर्ड देगा, जो कभी भी एक खेल में 16 से अधिक नहीं होगा।

समय सीमा प्रति बारी

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

अयोग्यता

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

एक खिलाड़ी को इसके चींटियों (रानी या कार्यकर्ता) में से किसी के लिए अयोग्य घोषित किया जाएगा:

  • वर्णित समय सीमा से अधिक (औसतन 10 सेकंड से अधिक)।
  • आउटपुट के तहत वर्णित के रूप में एक अमान्य चाल लौटना।
  • एक चींटी को शामिल करने के लिए कोशिका को स्थानांतरित करने के लिए।
  • भोजन और चींटी को स्थानांतरित करने के लिए कोशिका पहले से ही एक कार्यकर्ता है।
  • पर एक कार्यकर्ता का उत्पादन करने के लिए सेल खाली नहीं है (भोजन या एक चींटी शामिल है)।
  • एक श्रमिक एक श्रमिक का उत्पादन करने की कोशिश कर रहा है।

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

एकाधिक उत्तर और संपादन

आप कई उत्तर दे सकते हैं, बशर्ते कि वे दूसरों के खिलाफ टीम नहीं बनाते हैं। बशर्ते प्रत्येक उत्तर अपनी जीत के लिए पूरी तरह से काम कर रहा हो, आपको विशिष्ट रणनीति में कमजोरियों का लाभ उठाने के लिए अपनी रणनीति को तैयार करने की अनुमति दी जाती है, जिसमें उन्हें भ्रमित या हेरफेर करने के लिए कोशिकाओं का रंग बदलना शामिल है। ध्यान रखें कि जैसे-जैसे अधिक उत्तर आते हैं, किसी दिए गए खेल में किसी विशेष खिलाड़ी से मिलने की संभावना कम हो जाएगी।

जब भी आप चुनते हैं तो आप अपने उत्तरों को संपादित भी कर सकते हैं। यह आपके ऊपर है कि आप नया उत्तर पोस्ट करते हैं या किसी मौजूदा को संपादित करते हैं। बशर्ते खेल कई निकट-समान विविधताओं से भरा नहीं है, कोई समस्या नहीं होनी चाहिए।

यदि आप किसी अन्य व्यक्ति के उत्तर की भिन्नता रखते हैं, तो कृपया अपने उत्तर को उनके लिंक से जोड़कर उन्हें श्रेय दें।

स्कोरिंग

प्रत्येक गेम के अंत में, एक खिलाड़ी का स्कोर अन्य खिलाड़ियों की संख्या होती है, जिनकी रानी द्वारा कम भोजन किया जाता है। श्रमिकों द्वारा किए गए भोजन की गिनती नहीं की जाती है। यह स्कोर लीडरबोर्ड में जोड़ा जाता है, जिसे प्रति गेम औसत स्कोर के क्रम में प्रदर्शित किया जाता है।

संयुक्त स्थानों से संकेत मिलता है कि खिलाड़ियों का क्रम अभी तक खेले गए खेल के 6 सबसेट के बीच संगत नहीं है। खेलों की सूची को 6 सबसेट में विभाजित किया गया है क्योंकि यह न्यूनतम संख्या है जो 5% से कम की संभावना देगा कि खिलाड़ियों की एक जोड़ी को गलत क्रम में अलग-अलग स्थानों को सौंपा जाएगा।

बातचीत

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

बस आपको यह बताने के लिए, मैं उन उत्तरों को उकेरने के लिए इच्छुक हूं जिनमें एक स्पष्ट और दिलचस्प विवरण शामिल है कि कोड कैसे काम करता है।


2
इन टिप्पणियों के माध्यम से पढ़ने वाले किसी के लिए भी @DestructibleLemon, मैंने उत्तर दिया है कि चैट रूम में
ट्राइकोप्लाक्स


7
अरे, मैंने एक बात बनाई ! आपको यह दिलचस्प लग सकता है क्योंकि यह इस चुनौती से प्रेरित है और इसमें फॉर्मिक फ़ंक्शंस का परीक्षण शामिल है
डेव

2
@Dave आपका कंट्रोलर बहुत तेज़ी से धधक रहा है :) - लेकिन आपको बता दें कि इसका स्कोरिंग उन मामलों में मूल से अलग प्रतीत होता है, जहाँ किसी गेम के अंत में रानियों को भोजन के लिए बांधा जाता है। स्कोर अन्य प्रतिभागियों की संख्या होना चाहिए जिनकी रानियाँ (कड़ाई) कम भोजन रखती हैं । उदाहरण के लिए, यदि तीन खिलाड़ियों के अंत में 0 भोजन है, तो उन्हें इस खेल के लिए शून्य स्कोर करना चाहिए, तीन नहीं।
GNiklasch

2
@GNiklasch धन्यवाद; तय की। इसके अलावा, मैं देखता हूं कि आपका चींटी अब खेल पर हावी है। प्रभावशाली!
डेव

जवाबों:


20

फोरेंसिक चींटियों

मेरे सभी उत्तर निम्न-स्तरीय सहायक कार्यों के समान सेट को साझा कर रहे हैं। इस उत्तर के लिए विशिष्ट कोड को देखने के लिए "उच्च-स्तरीय तर्क यहां शुरू होता है"।

// == Shared low-level helpers for all solutions ==

var QUEEN = 5;

var WHITE = 1;
var COL_MIN = WHITE;
var COL_LIM = 9;

var CENTRE = 4;

var NOP = {cell: CENTRE};

var DIR_FORWARDS = false;
var DIR_REVERSE = true;
var SIDE_RIGHT = true;
var SIDE_LEFT = false;

function sanity_check(movement) {
  var me = view[CENTRE].ant;
  if(!movement || movement.cell < 0 || movement.cell > 8) {
    return false;
  }
  if(movement.type) {
    if(movement.color) {
      return false;
    }
    if(movement.type < 1 || movement.type > 4) {
      return false;
    }
    if(view[movement.cell].ant || view[movement.cell].food) {
      return false;
    }
    if(me.type !== QUEEN || me.food < 1) {
      return false;
    }
    return true;
  }
  if(movement.color) {
    if(movement.color < COL_MIN || movement.color >= COL_LIM) {
      return false;
    }
    if(view[movement.cell].color === movement.color) {
      return false;
    }
    return true;
  }
  if(view[movement.cell].ant) {
    return false;
  }
  if(view[movement.cell].food + me.food > 1 && me.type !== QUEEN) {
    return false;
  }
  return true;
}

function as_array(o) {
  if(Array.isArray(o)) {
    return o;
  }
  return [o];
}

function best_of(movements) {
  var m;
  for(var i = 0; i < movements.length; ++ i) {
    if(typeof(movements[i]) === 'function') {
      m = movements[i]();
    } else {
      m = movements[i];
    }
    if(sanity_check(m)) {
      return m;
    }
  }
  return null;
}

function play_safe(movement) {
  // Avoid disqualification: no-op if moves are invalid
  return best_of(as_array(movement)) || NOP;
}

var RAND_SEED = (() => {
  var s = 0;
  for(var i = 0; i < 9; ++ i) {
    s += view[i].color * (i + 1);
    s += view[i].ant ? i * i : 0;
    s += view[i].food ? i * i * i : 0;
  }
  return s % 29;
})();

var ROTATIONS = [
  [0, 1, 2, 3, 4, 5, 6, 7, 8],
  [6, 3, 0, 7, 4, 1, 8, 5, 2],
  [8, 7, 6, 5, 4, 3, 2, 1, 0],
  [2, 5, 8, 1, 4, 7, 0, 3, 6],
];

function try_all(fns, limit, wrapperFn, checkFn) {
  var m;
  fns = as_array(fns);
  for(var i = 0; i < fns.length; ++ i) {
    if(typeof(fns[i]) !== 'function') {
      if(checkFn(m = fns[i])) {
        return m;
      }
      continue;
    }
    for(var j = 0; j < limit; ++ j) {
      if(checkFn(m = wrapperFn(fns[i], j))) {
        return m;
      }
    }
  }
  return null;
}

function identify_rotation(testFns) {
  // testFns MUST be functions, not constants
  return try_all(
    testFns,
    4,
    (fn, r) => fn(ROTATIONS[r]) ? ROTATIONS[r] : null,
    (r) => r
  );
}

function near(a, b) {
  return (
    Math.abs(a % 3 - b % 3) < 2 &&
    Math.abs(Math.floor(a / 3) - Math.floor(b / 3)) < 2
  );
}

function try_all_angles(solverFns) {
  return try_all(
    solverFns,
    4,
    (fn, r) => fn(ROTATIONS[r]),
    sanity_check
  );
}

function try_all_cells(solverFns, skipCentre) {
  return try_all(
    solverFns,
    9,
    (fn, i) => ((i === CENTRE && skipCentre) ? null : fn(i)),
    sanity_check
  );
}

function try_all_cells_near(p, solverFns) {
  return try_all(
    solverFns,
    9,
    (fn, i) => ((i !== p && near(p, i)) ? fn(i) : null),
    sanity_check
  );
}

function ant_type_at(i, friend) {
  return (view[i].ant && view[i].ant.friend === friend) ? view[i].ant.type : 0;
}

function friend_at(i) {
  return ant_type_at(i, true);
}

function foe_at(i) {
  return ant_type_at(i, false);
}

function foe_near(p) {
  for(var i = 0; i < 9; ++ i) {
    if(foe_at(i) && near(i, p)) {
      return true;
    }
  }
  return false;
}

function move_agent(agents) {
  var me = view[CENTRE].ant;
  var buddies = [0, 0, 0, 0, 0, 0];
  for(var i = 0; i < 9; ++ i) {
    ++ buddies[friend_at(i)];
  }

  for(var i = 0; i < agents.length; i += 2) {
    if(agents[i] === me.type) {
      return agents[i+1](me, buddies);
    }
  }
  return null;
}

function grab_nearby_food() {
  return try_all_cells((i) => (view[i].food ? {cell: i} : null), true);
}

function go_anywhere() {
  return try_all_cells((i) => ({cell: i}), true);
}

function colours_excluding(cols) {
  var r = [];
  for(var i = COL_MIN; i < COL_LIM; ++ i) {
    if(cols.indexOf(i) === -1) {
      r.push(i);
    }
  }
  return r;
}

function generate_band(start, width) {
  var r = [];
  for(var i = 0; i < width; ++ i) {
    r.push(start + i);
  }
  return r;
}

function colour_band(colours) {
  return {
    contains: function(c) {
      return colours.indexOf(c) !== -1;
    },
    next: function(c) {
      return colours[(colours.indexOf(c) + 1) % colours.length];
    }
  };
}

function random_colour_band(colours) {
  return {
    contains: function(c) {
      return colours.indexOf(c) !== -1;
    },
    next: function() {
      return colours[RAND_SEED % colours.length];
    }
  };
}

function fast_diagonal(colourBand) {
  var m = try_all_angles([
    // Avoid nearby checked areas
    (rot) => {
      if(
        !colourBand.contains(view[rot[0]].color) &&
        colourBand.contains(view[rot[5]].color) &&
        colourBand.contains(view[rot[7]].color)
      ) {
        return {cell: rot[0]};
      }
    },

    // Go in a straight diagonal line if possible
    (rot) => {
      if(
        !colourBand.contains(view[rot[0]].color) &&
        colourBand.contains(view[rot[8]].color)
      ) {
        return {cell: rot[0]};
      }
    },

    // When in doubt, pick randomly but avoid doubling-back
    (rot) => (colourBand.contains(view[rot[0]].color) ? null : {cell: rot[0]}),

    // Double-back when absolutely necessary
    (rot) => ({cell: rot[0]})
  ]);

  // Lay a colour track so that we can avoid doubling-back
  // (and mess up our foes as much as possible)
  if(!colourBand.contains(view[CENTRE].color)) {
    var prevCol = m ? view[8-m.cell].color : WHITE;
    return {cell: CENTRE, color: colourBand.next(prevCol)};
  }

  return m;
}

function follow_edge(obstacleFn, side) {
  // Since we don't know which direction we came from, this can cause us to get
  // stuck on islands, but the random orientation helps to ensure we don't get
  // stuck forever.

  var order = ((side === SIDE_LEFT)
    ? [0, 3, 6, 7, 8, 5, 2, 1, 0]
    : [0, 1, 2, 5, 8, 7, 6, 3, 0]
  );
  return try_all(
    [obstacleFn],
    order.length - 1,
    (fn, i) => (fn(order[i+1]) && !fn(order[i])) ? {cell: order[i]} : null,
    sanity_check
  );
}

function start_dotted_path(colourBand, side, protectedCols) {
  var right = (side === SIDE_RIGHT);
  return try_all_angles([
    (rot) => ((
      !protectedCols.contains(view[rot[right ? 5 : 3]].color) &&
      !colourBand.contains(view[rot[right ? 5 : 3]].color) &&
      !colourBand.contains(view[rot[right ? 2 : 0]].color) &&
      !colourBand.contains(view[rot[1]].color)
    )
      ? {cell: rot[right ? 5 : 3], color: colourBand.next(WHITE)}
      : null)
  ]);
}

function lay_dotted_path(colourBand, side, protectedCols) {
  var right = (side === SIDE_RIGHT);
  return try_all_angles([
    (rot) => {
      var ahead = rot[right ? 2 : 0];
      var behind = rot[right ? 8 : 6];
      if(
        colourBand.contains(view[behind].color) &&
        !protectedCols.contains(view[ahead].color) &&
        !colourBand.contains(view[ahead].color) &&
        !colourBand.contains(view[rot[right ? 6 : 8]].color)
      ) {
        return {cell: ahead, color: colourBand.next(view[behind].color)};
      }
    }
  ]);
}

function follow_dotted_path(colourBand, side, direction) {
  var forwards = (direction === DIR_REVERSE) ? 7 : 1;
  var right = (side === SIDE_RIGHT);

  return try_all_angles([
    // Cell on our side? advance
    (rot) => {
      if(
        colourBand.contains(view[rot[right ? 5 : 3]].color) &&
        // Prevent sticking / trickery
        !colourBand.contains(view[rot[right ? 3 : 5]].color) &&
        !colourBand.contains(view[rot[0]].color) &&
        !colourBand.contains(view[rot[2]].color)
      ) {
        return {cell: rot[forwards]};
      }
    },

    // Cell ahead and behind? advance
    (rot) => {
      var passedCol = view[rot[right ? 8 : 6]].color;
      var nextCol = view[rot[right ? 2 : 0]].color;
      if(
        colourBand.contains(passedCol) &&
        nextCol === colourBand.next(passedCol) &&

        // Prevent sticking / trickery
        !colourBand.contains(view[rot[right ? 3 : 5]].color) &&
        !colourBand.contains(view[rot[right ? 0 : 2]].color)
      ) {
        return {cell: rot[forwards]};
      }
    }
  ]);
}

function escape_dotted_path(colourBand, side, newColourBand) {
  var right = (side === SIDE_RIGHT);
  if(!newColourBand) {
    newColourBand = colourBand;
  }

  return try_all_angles([
    // Escape from beside the line
    (rot) => {
      var approachingCol = view[rot[right ? 2 : 0]].color;
      if(
        !colourBand.contains(view[rot[right ? 8 : 6]].color) ||
        !colourBand.contains(approachingCol) ||
        colourBand.contains(view[rot[7]].color) ||
        colourBand.contains(view[rot[right ? 6 : 8]].color)
      ) {
        // not oriented, or in a corner
        return null;
      }
      return best_of([
        {cell: rot[right ? 0 : 2], color: newColourBand.next(approachingCol)},
        {cell: rot[right ? 3 : 5]},
        {cell: rot[right ? 0 : 2]},
        {cell: rot[right ? 6 : 8]},
        {cell: rot[right ? 2 : 0]},
        {cell: rot[right ? 8 : 6]},
        {cell: rot[right ? 5 : 3]}
      ]);
    },

    // Escape from inside the line
    (rot) => {
      if(
        !colourBand.contains(view[rot[7]].color) ||
        !colourBand.contains(view[rot[1]].color) ||
        colourBand.contains(view[CENTRE].color)
      ) {
        return null;
      }
      return best_of([
        {cell: rot[3]},
        {cell: rot[5]},
        {cell: rot[0]},
        {cell: rot[2]},
        {cell: rot[6]},
        {cell: rot[8]}
      ]);
    }
  ]);
}

function latch_to_dotted_path(colourBand, side) {
  var right = (side === SIDE_RIGHT);

  return try_all_angles([
    (rot) => {
      var approachingCol = view[rot[right ? 2 : 0]].color;
      if(
        colourBand.contains(approachingCol) &&
        view[rot[right ? 8 : 6]].color === colourBand.next(approachingCol) &&
        !colourBand.contains(view[rot[right ? 5 : 3]].color)
      ) {
        // We're on the wrong side; go inside the line
        return {cell: rot[right ? 5 : 3]};
      }
    },

    // Inside the line? pick a side
    (rot) => {
      var passedCol = view[rot[7]].color;
      var approachingCol = view[rot[1]].color;
      if(
        !colourBand.contains(passedCol) ||
        !colourBand.contains(approachingCol) ||
        colourBand.contains(view[CENTRE].color)
      ) {
        return null;
      }
      if((approachingCol === colourBand.next(passedCol)) === right) {
        return best_of([{cell: rot[3]}, {cell: rot[6]}, {cell: rot[0]}]);
      } else {
        return best_of([{cell: rot[5]}, {cell: rot[2]}, {cell: rot[8]}]);
      }
    }
  ]);
}


// == High-level logic begins here ==


var PARTNER = 1;
var SENTINEL = 2;

var COL_DANCING1 = 8;
var COL_DANCING2 = 7;
var SAFE_COLOURS = random_colour_band(colours_excluding([WHITE, COL_DANCING1]));

function pass_time() {
  // Wait patiently for the blockage to go away by setting
  // random cell colours (unless we're near the sentinel)
  for(var i = 0; i < 9; ++ i) {
    if(i !== 4 && friend_at(i) === SENTINEL) {
      return null;
    }
  }
  return {cell: 0, color: SAFE_COLOURS.next()};
}

function move_sentinel(me, buddies) {
  // Our job is to be a sentinel showing when the queen has wrapped around.
  // We are created first, so will move first.
  // We won't find any food.

  if(!buddies[QUEEN] && !buddies[PARTNER]) {
    // No ongoing dance; make sure our state is good for when they arrive
    return try_all_angles([
      {cell: CENTRE, color: WHITE},
      (rot) => ({cell: rot[1], color: COL_DANCING2}),
      (rot) => ((view[rot[0]].color === COL_DANCING1)
        ? {cell: rot[0], color: SAFE_COLOURS.next()}
        : null)
    ]);
  }

  // Dance when queen passes
  var danceStage = view[CENTRE].color;

  if(danceStage === WHITE) {
    // Dance has not begun yet, but queen & partner are nearby
    return try_all_angles((rot) => {
      if(friend_at(rot[5]) === QUEEN && friend_at(rot[8]) === PARTNER) {
        return {cell: CENTRE, color: COL_DANCING1};
      }
    });
  }

  if(danceStage === COL_DANCING1) {
    if(buddies[PARTNER]) {
      return null; // Wait for partner to see us
    }
    // Partner saw us @8 and moved down, queen followed.
    // We must also move down (will end up on a COL_DANCING2)
    return try_all_angles((rot) =>
      ((friend_at(rot[8]) === QUEEN) ? {cell: rot[7]} : null));
  }

  // Move towards queen counter-clockwise when she's diagonally connected
  return try_all_angles((rot) =>
    ((friend_at(rot[2]) === QUEEN) ? {cell: rot[1]} : null));
}

function move_partner(me, buddies) {
  // Our job is to travel with the queen and keep her oriented.
  // We are created second, so move after the sentinel.
  // Any food we find will immediately go to the queen, since
  // we are adjacent at all times.

  // Queen will be N of us; orient ourselves
  var rot = identify_rotation((rot) => friend_at(rot[1]) === QUEEN);

  if(!rot) {
    // Queen is lagging or lost;
    return null;
  }

  var danceStage = view[rot[0]].color;
  if(
    friend_at(rot[0]) === SENTINEL &&
    (danceStage === COL_DANCING1 || danceStage === COL_DANCING2)
  ) {
    // Dance down (queen will follow)
    return {cell: rot[7]};
  }

  if(view[rot[0]].ant) {
    // Queen is blocked
    return null;
  }

  // Lead queen if both can move
  return {cell: rot[3]};
}

function move_queen(me, buddies) {
  // Our job is to travel over the entire level collecting food.
  // We move last.

  if(buddies[PARTNER]) {
    // Partner will be S or SW of us; follow if they are ahead
    return try_all_angles((rot) =>
      (friend_at(rot[6]) === PARTNER) ? {cell: rot[3]} : null);
  }

  var rot = identify_rotation((rot) => friend_at(rot[3]) === SENTINEL);
  if(rot && view[rot[0]].color >= 7) {
    // Dance down (follow partner)
    return {cell: rot[7]};
  }

  // We're on our own, or the buddy strategy failed. Start again.

  rot = identify_rotation((rot) => friend_at(rot[5]) === SENTINEL);
  if(rot && me.food >= 1) {
    // Already have a sentinel; just need a partner
    return best_of([
      {cell: rot[7], type: PARTNER},
      {cell: rot[6], type: PARTNER},
    ]);
  } else if(me.food >= 2) {
    // Create sentinel first so that we'll know to create the partner next.
    // (ensure the sentinel is created on a white cell so that it won't
    // think it's dancing)
    return try_all_angles(
      (rot) => ((view[rot[5]].color === WHITE)
        ? {cell: rot[5], type: SENTINEL} : null),
      (rot) => ({cell: rot[5], color: WHITE})
    );
  }

  // Not able to start yet; fall back to lone behaviour:
  // Random-walk until we find or make a buddy
  return best_of([
    grab_nearby_food,
    fast_diagonal.bind(null, SAFE_COLOURS),
    go_anywhere
  ]);
}

return play_safe([move_agent([
  PARTNER, move_partner,
  SENTINEL, move_sentinel,
  QUEEN, move_queen,
]), pass_time]);

फोरेंसिक चींटियां ग्रिड को स्वीप करने के लिए वैज्ञानिक दृष्टिकोण अपनाती हैं। भोजन के लिए प्रारंभिक उन्मत्त हाथापाई के बाद, 2 श्रमिक चींटियां बनाई जाएंगी। भूमिकाएँ हैं:

रानी

रानी साथी के साथ प्रकाश की गति से सीधी रेखा में यात्रा करेगी। उनमें से कोई भी भोजन प्राप्त करने के लिए विचलन नहीं करेगा; वे बस जो कुछ भी ठोकर खाते हैं उसे हड़प लेते हैं।

साथी

साथी रानी के साथ चलता है, उसे उसी दिशा में सामना करते हुए। क्योंकि दोनों चींटियाँ 1 वर्ग को मोड़ सकती हैं, वे जमीन को रंगे बिना समय बर्बाद किए बिना एक सीधी रेखा में रहने में सक्षम हैं।

यदि पार्टनर को कभी कोई खाना मिल जाता है, तो वह तुरंत रानी के पास जाएगा, क्योंकि वे हर समय आसन्न हैं।

पहरेदार

सबसे महत्वपूर्ण चींटी। यह तब तक रहता है जब तक रानी और साथी उस तक नहीं पहुंच जाते हैं, तब उन्हें 2 पिक्सल साथ चलने के लिए कहते हैं, और 2 पिक्सल खुद ही हिलते हैं। यह रानी और साथी को धीरे-धीरे पूरे बोर्ड (वैसे भी, इसके बारे में 30 पिक्सल) पर धीरे-धीरे स्वीप करने का कारण बनता है। यह केवल तभी चलता है जब रानी पास में होती है, इसलिए इसे मिलने वाला कोई भी भोजन तुरंत सौंप दिया जाएगा।

अपने खाली समय में, प्रहरी के शौक में उम्मीद के मुताबिक किसी भी प्रतियोगी को गड़बड़ाने के लिए इसके चारों ओर जमीन को यादृच्छिक रूप से चित्रित करना शामिल है।


ये बहुत लगातार प्रदर्शन करते हैं; उनके बीच वे प्रत्येक फ्रेम में 2 कोशिकाओं को स्वीप कर सकते हैं, जिसका 30000 से अधिक फ्रेम का मतलब है 60000 सेल और 0.1% भोजन के साथ, इसका मतलब है कि 60 का अंतिम स्कोर, जिसे वे लगातार हासिल करते हैं।


(और यहाँ दूसरा वही है जिसे मैंने प्रश्न तैयार करते समय तैयार किया था! - जो कि मैंने अभी के लिए किया है; मुझे यकीन है कि ये बहुत जल्दी हो जाएंगे!)
डेव

स्कोर उल्लेखनीय रूप से सुसंगत है। यह देखना दिलचस्प होगा कि यह कैसे प्रभावित होता है क्योंकि अखाड़ा अधिक प्रतियोगियों से भर जाता है ...
ट्राइकोप्लाक्स

मुझे आश्चर्य है कि क्या रानी के दूसरी तरफ एक और साथी जोड़ने से मदद मिलेगी?
के झांग

1
@KZhang मुझे लगता है कि यह (सैद्धांतिक रूप से यह स्कोर को ~ 90 तक बढ़ा देगा), लेकिन यह काफी कठिन है कि इन दोनों को संतरी के साथ सिंक में रखा जाए! "हर कोई 2 पिक्सेल ऊपर ले जाएँ" नृत्य ने मुझे यह पता लगाने में थोड़ा समय दिया। 3 पिक्सल्स पर जाने से मेरे द्वारा भरोसा किए गए ट्रिक में से एक को ब्लॉक कर देगा (प्रहरी पहले से ही अपने आस-पास के स्पेस को तैयार करता है)।
डेव

पहले लीडरबोर्ड में सबसे ऊपर ...
ट्राइकोप्लाक्स

18

खिसकने वाली खनक 6.4

const DEBUG = false;
const ADD = (a,b) => a + b;
var toReturn;
var me = view[4].ant;
me.me = true; // for basedOn to know
var food = me.food;
var type = me.type;
var isQueen = type == 5;

// raw directions
const UL = 0; const U  = 1; const UR = 2;
const L  = 3; const C  = 4; const R  = 5;
const DL = 6; const D  = 7; const DR = 8;

// directions from the reference point
const ul = 16; const u  = 17; const ur = 18;
const l  = 19; const c  = 20; const r  = 21;
const dl = 22; const d  = 23; const dr = 24;
const rp = 16;

function allRots (arr) {
  return [arr,
  [arr[2], arr[5], arr[8],
   arr[1], arr[4], arr[7],
   arr[0], arr[3], arr[6]],

  [arr[8], arr[7], arr[6],
   arr[5], arr[4], arr[3],
   arr[2], arr[1], arr[0]],

  [arr[6], arr[3], arr[0],
   arr[7], arr[4], arr[1],
   arr[8], arr[5], arr[2]]];
}
var allVRots = allRots(view);

function rotateCW3([[a,b,c],[d,e,f],[g,h,i]]) {
  return [[g,d,a],[h,e,b],[i,f,c]]
}

function on (where, what) {
  if (Array.isArray(where)) return where.some(c=>on(c, what));
  if (Array.isArray(what)) return what.some(c=>on(where, c));
  return basedOn(get(where), what);
}
function find (what) {
  return view.findIndex(c=>basedOn(c, what));
}
function findAll (what) {
  return view.map((c,i)=>[c,i]).filter(c=>basedOn(c[0], what)).map(c=>c[1]);
}
function count (what) {
  return findAll(what).length;
}
function findRel (what) {
  return ref(find(what));
}
function findAllRel (what) {
  return findAll(what).map(c=>ref(c));
}
function found (what) {
  return find(what) != -1;
}
function get (dir) {
  if (Array.isArray(dir)) return dir.map(c=>get(c));
  return view[raw(dir)];
}
function deq (a, b) {
  return a==b || raw(a)==raw(b);
}

// returns a random number from 0 to 4, based on the rotation. Will always have a possibility of being 0
function random4 () {
  var scores = allRots(view.map(c=>c.color)).map((c) => {
    let cscore = 0;
    c.forEach((c) => {
      cscore*= 8;
      cscore+= c-1;
    });
    return cscore;
  });
  var bestscore = -1, bestindex = 1;
  scores.forEach((score, index) => {
    if (score > bestscore) {
      bestscore = score;
      bestindex = index;
    }
  })
  return bestindex;
}

function rotate (what, times) {
  for (var i = 0; i < times; i++) what = [2,5,8,1,4,7,0,3,6][what];
  return what;
}

function raw(dir) {
  if (dir&rp) return rotate(dir&~rp, selectedRot);
  return dir;
}

function ref(dir) {
  if (dir == -1) return -1;
  if (dir&rp) return dir;
  return rotate(dir, 4-selectedRot)|rp;
}

function move(dir, force) {
  if (Array.isArray(dir)) return dir.some(c=>move(c, force));
  dir = raw(dir);
  return result({cell:dir}, force);
}

function color(dir, col) {
  if (Array.isArray(dir)) return dir.some(cdir => !color(cdir, col));
  dir = raw(dir);
  if (view[dir].color == col) return true;
  result({cell:dir, color:Math.abs(col)});
  return false;
}

function rcolOf(what) {
  return Number.isInteger(what)? what : what.color;
}

function colOf(what) {
  return Math.abs(Number.isInteger(what)? what : what.color);
}
function sees(c1,c2) {
  c1 = raw(c1);
  c2 = raw(c2);
  return Math.abs(c1%3-c2%3)<2 && Math.abs(Math.floor(c1/3)-Math.floor(c2/3))<2;
}

function spawn(dir, t) {
  if (Array.isArray(t)) return t.some(c=>spawn(dir, c));
  if (Array.isArray(dir)) return dir.some(c=>spawn(c, t));
  dir = raw(dir);
  return result({cell:dir, type:t});
}
// repairs a single cell
function correct(dir) {
  dir = raw(dir);
  let col = colOf(selectedPt[dir]);
  if (col && view[dir].color != col) {
    color(dir, col);
    return false;
  }
  return true;
}
// if pattern is repaired, returns true, otherwise fixes one cell
// firstdirs is lowercase (if you do want it to be from the patterns POV)
function repair(firstdirs, onlyThose) {
  //log("FD",firstdirs);
  var found = [];
  view.forEach((v, i) => {
    let col = colOf(selectedPt[i]);
    if (col && v.color != col) {
      found.push(i);
    }
  });
  if (found.length == 0) return true;
  if (firstdirs && (firstdirs = firstdirs.map(c=>raw(c))).some(c=>found.includes(c))) {
    let dir = firstdirs.find(c=>found.includes(c));
    let col = colOf(selectedPt[dir]);
    color(dir, col);
    return false;
  }
  if (!onlyThose) {
    let dir = found[random4() % found.length];
    let col = colOf(selectedPt[dir]);
    color(dir, col);
    return false;
  } else return true;
}

function flatten (arr) {
  return arr.reduce((a,b)=>a.concat(b));
}

var selectedHp, selectedVp, selectedPt, selectedRot;

class Pattern {
  constructor(pattern, inherit) {
    this.pt = pattern;
    if (inherit) {
      this.vp = inherit.vp;
      this.hp = inherit.hp;
      this.rot = inherit.rot;
    } else {
      this.vp = 0;
      this.hp = 0;
      this.rot = 0;
    }
  }

  rotateClockwise() {
    var arr = [];
    for (var i = 0; i < this.pt[0].length; i++) {
      var sarr = [];
      for (var j = this.pt.length-1; j >= 0; j--) {
        sarr.push(this.pt[j][i]);
      }
      arr.push(sarr);
    }
    //log(arr);
    var res = new Pattern(arr, this);
    res.rot = (this.rot+1) % 4;
    return res;
  }

  select(x, y, w, h) {
    var res = new Pattern(this.pt.slice(y, y+h).map(c=>c.slice(x, x+w)), this);
    res.hp+= x;
    res.vp+= y;
    return res;
  }

  rots(dir) {
    var pts = [];
    var pt = new Pattern(this.pt, this);
    for (let i = 0; i < this.lengthIn(dir); i++) {
      pts.push(pt);
      pt = pt.rotate(dir);
    }
    return pts;
  }

  map(fn) {
    return new Pattern(this.pt.map(ln=>ln.map(fn)), this);
  }

  lengthIn(dir) {
    if (dir == U || dir == D) return this.pt.length;
    else if (this.pt.length > 0) return this.pt[0].length;
    else return 0;
  }
  rotate(dir) { // moves the center to that direction, shifting the side
    if (dir == R) {
      var res = new Pattern(this.pt.map(c=>((h,...t)=>t.concat(h))(...c)), this);
      res.hp++;
      return res;
    }
    if (dir == L) {
      var res = new Pattern(this.pt.map(a=>a.slice(-1).concat(a.slice(0,-1))), this);
      res.hp++;
      return res;
    }
    if (dir == D) {
      var res = new Pattern(((h,...t)=>t.concat([h]))(...this.pt), this);
      res.vp++;
      return res;
    }
    throw "rotate unimplemented dir!";
  }

  center(dir) { // moves the center to that direction
    if (dir == R) {
      var res = new Pattern(this.pt.map(c=>((h,...t)=>t.concat(0))(...c)), this);
      res.hp++;
      return res;
    }
    if (dir == L) {
      var res = new Pattern(this.pt.map(a=>[0].concat(a.slice(0,-1))), this);
      res.hp++;
      return res;
    }
    if (dir == D) {
      var res = new Pattern(((h,...t)=>t.concat([new Array(h.length)]))(...this.pt), this);
      res.vp++;
      return res;
    }
    throw "center unimplemented dir!";
  }

  setSize(xs, ys) {
    var arr = [];
    for (let y = 0; y < ys; y++) {
      var ca = [];
      for (let x = 0; x < xs; x++) {
        ca.push(this.pt[y % this.pt.length][x % this.pt[0].length]);
      }
      arr.push(ca);
    }
    return new Pattern(arr, this);
  }

  static add(pattern, action, scorer, presetRot) {
    if (Array.isArray(pattern)) pattern = new Pattern(pattern);
    pattern = pattern.setSize(3,3);
    var cpt = pattern.setSize(3,3);
    var orig = cpt.pt;
    for (let i = 0; i < 4; i++) {
      cpt = cpt.rotateClockwise();
      if (!presetRot || presetRot == cpt.rot) {
        cpt.action = action;
        cpt.scorer = scorer;
        cpt.raw = orig;
        cpt.view = allVRots[cpt.rot];
        allPatterns.push(cpt);
      }
    }
  }


  static choose() {
    var maxScore = -1e307;
    var nextScore = -1e308;
    var maxPt;
    allPatterns.forEach((c) => {
      // null  = easy
      // 0     = bad queen
      // false = no match
      // >0    = score
      var falseN = 0;
      var corrects = c.raw.reduce((a,b)=>a.concat(b)).map((guess, index) => {
        var bo = basedOn(c.view[index], guess, true);
        var ant = guess.ant;
        if (ant && basedOn(c.view[index], {ant})) bo+= 1;
        if (bo === 0) return 0;
        if (bo === false) return false;
        if (bo && rcolOf(guess) > 0) return bo;
        var easy = rcolOf(guess)<=0;
        if (easy) {
          falseN++;
          return null;
        }
        return bo;
      });
      var corrstring = corrects.map((chr,i)=>chr>0? (colOf(c.raw[Math.floor(i/3)][i%3])==1? "W" : "#") : chr===null? "-" : " ").join("");
      function match(pt) {
        return new RegExp(pt.replace(/@/g, "[#-W]").replace(/C/g, "[#-]")).test(corrstring);
      }
      var score = corrects.reduce(ADD)*9/(9-falseN);
      if (match(".?(...)?##.##.*")) {
        if (match("(...)?@@@@@@.*|.?@@.@@.@@.?")) score+= foundEnemy? 5 : 3;
        else score+= foundEnemy? 3 : 1;
      } else if (!foundEnemy) score = Math.min(score/2, 5);
      if (c.scorer instanceof Function) score = c.scorer(score, c, corrects, falseN, match);
      if (DEBUG && score > -1) log(
        "scored", score,
        "corr", /*corrects.map(c =>
          (c===false?"F":c===null?"N":c===true?"T":c)
        )*/corrstring,
        "pt", c.raw.map(c=>c.ant? "A"+c.ant.type : c), c.hp, c.vp);
      if (score >= maxScore) {
        nextScore = maxScore;
        maxScore = score;
        c.corrstr = corrstring;
        maxPt = c;
      }
    });
    var flattened = maxPt.pt.reduce((a,b)=>a.concat(b));
    Pattern.hardcorr = flattened.map((guess, index) => rcolOf(guess)<2? 0 : basedOn(view[index], guess)).reduce(ADD);
    Pattern.corrstr = maxPt.corrstr;
    Pattern.corr = flattened.map((guess, index) => basedOn(view[index], guess)).reduce(ADD);
    Pattern.incorr = 9-Pattern.corr;
    Pattern.confidence = maxScore-nextScore;
    selectedRot = maxPt.rot;
    Pattern.action = maxPt.action;
    selectedPt = flattened;
    selectedHp = maxPt.hp;
    Pattern.raw = maxPt.raw;
    Pattern.view = maxPt.view;
    selectedVp = maxPt.vp;
    Pattern.score = maxScore;
    if (DEBUG) log("score", maxScore, "confidence", Pattern.confidence, "corr", Pattern.corr, "hardc", Pattern.hardcorr, "pt", maxPt.pt);//, "fn", maxPt.action+""
  }
}
var allPatterns = [];
function clear() {
  allPatterns = [];
}
function adds(raw, action, scorer, presetRot) { // must get a 3x3 arr
  var pt = raw;
  var hp = raw.hp;
  var vp = raw.vp;
  for (let rot = 0; rot < 4; rot++) {
    let view = allVRots[rot];
    allPatterns.push({pt, action, scorer, rot, hp, vp, view, raw});
    if (rot!=4) pt = rotateCW3(pt);
  }
}
function refPt(...args) {
  clear();
  if (Array.isArray(args[0])) {
    if (args[0].length != 3) args[0] = args[0].slice(0,3);
    if (args[0][0].length != 3) args[0] = args[0].map(c=>c.slice(0,3));
    adds(...args);
  }
  else Pattern.add(...args);
  Pattern.choose();
}

/*
is the 2nd param a subset of the 1st param.
guess can be a number (color), or an object ({color:..,ant:..,..})
guess.ant can be "worker", "queen", "enemy", "enemyworker", "enemyqueen" with obvious meanings. Note that "friend" ≠ me
guess.ant.type can be an array, ORing

true - correct!
false - not correct
0 - notqueen doesn't match (aka very bad)

negativesEqual makes this always return true for negative colors, otherwise it treats negatives as regular colors
*/
function basedOn(real, guess, negativesEqual) {
  if (Array.isArray(real)) return real.some(c=>basedOn(c, guess, negativesEqual));
  if (Number.isInteger(guess)) guess = {color:guess};
  if (guess.notqueen && real.ant && real.ant.friend && real.ant.type==5) return 0;
  if (guess.not) {
    var bo = basedOn(real, guess.not, negativesEqual);
    if (bo) return 0;
  } 
  if (guess.color && Math.abs(guess.color) != real.color && !(negativesEqual && guess.color<0)) return false; // 0 handles itself
  if (guess.obstacle !== undefined) {
    if (guess.obstacle && !real.ant && !(food && real.food && !isQueen)) return false;
    if (!guess.obstacle && (real.ant || (food && real.food && !isQueen))) return false;
  }
  if (guess.badobstacle !== undefined) {
    if (guess.badobstacle && !(real.ant && !real.ant.friend) && !(food && real.food && !isQueen)) return false;
    if (!guess.badobstacle && ((real.ant && !real.ant.friend) || (food && real.food && !isQueen))) return false;
  }
  if (guess.ant) {
    if (!real.ant) return false;
    if (guess.ant == "worker"      &&!( real.ant.friend && real.ant.type!=5)) return false;
    if (guess.ant == "queen"       &&!( real.ant.friend && real.ant.type==5)) return false;
    if (guess.ant == "enemyqueen"  &&!(!real.ant.friend && real.ant.type==5)) return false;
    if (guess.ant == "enemyworker" &&!(!real.ant.friend && real.ant.type!=5)) return false;
    if (guess.ant == "friend" && (!real.ant.friend || real.ant.me)) return false;
    if (guess.ant == "enemy"  &&  real.ant.friend) return false;
    if (Number.isInteger(guess.ant) && real.ant.type != guess.ant) return false;
    if (guess.ant.friend !== undefined && guess.ant.friend !== real.ant.friend) return false;
    if (guess.ant.type !== undefined && !(Array.isArray(guess.ant.type)? guess.ant.type.some(c=>c == real.ant.type) : guess.ant.type == real.ant.type)) return false;
    if (guess.ant.food !== undefined && guess.ant.food !== real.ant.food) return false;
  }
  if (guess.food !== undefined && guess.food !== real.food) return false;
  // log("matched");
  return true;
}

function result (action, force) {
  if (!force) if (toReturn !== undefined) return 0;
  var color = action.color;
  var type = action.type;
  var cell = action.cell;
  if (type < 1 || type > 4) return false;
  if (!(cell >= 0 && cell <= 8)) return false;
  if (color < 1 || color > 8) return false;
  if (!color && ((view[cell].ant && cell != 4) || (isQueen? (view[cell].food && type) : (food && view[cell].food)))) return false; // can't walk onto ant, can't spawn on food, can't move to food with food
  if (!isQueen && type) return false;
  if (!isQueen && !color && food && view[cell].food) return false;
  if (isQueen && !food && type) return false;
  if (type && cell==C) return false;
  if (color && type) return false;

  toReturn = action;
  return true;
}

const WH = 1; // white   
const C1 = 6; // green   HW
const C2 = 5; // red     
const C3 = 8; // black   
const C4 = 2; // yellow  HW
const C5 = 4; // cyan    HW
const C6 = 7; // blue    HW
const C7 = 3; // purple  HW
// C1=GR,C2=BL,C4=YL,C5=DK
const ENEMY = {ant:"enemy"};
const foundEnemy = found(ENEMY);
  //-----------------------------------------------------------------------------------------------------------------------------------------------------\\
 //----------------------------------------------------------------------- MAIN CODE ---------------------------------------------------------------------\\
//---------------------------------------------------------------------------------------------------------------------------------------------------------\\

function log(...args) {
  if (!DEBUG) return;
  toLogRaw.push(args);
  // for (let i of args) {
  //   if (i === undefined) i = "undefined";
  //   var res = "";
  //   if (typeof i === 'string') res = i;
  //   else res = JSON.stringify(i);
  //   toLog+= res + " ";
  // }
  // toLog+= "\n";
}
if (DEBUG) {
  var toLog = "";
  var logMyLogs = false;
  var toLogRaw = [];
  log(type, view.map(c=>c.ant? "A"+c.ant.type : c.color));
}

const Ut = 1;
const Dt = 2;
const Ht = 4;
const Uo = {ant:{type:Ut,friend:true}};
const Do = {ant:{type:Dt,friend:true}};
const Ho = {ant:{type:Ht,friend:true}};
const Mo = {ant:{type:[Ut,Dt],friend:true}};
const Fo = {food:1};
const Qo = {ant:{type:5,friend:true}};
const EQo = {ant:{type:5,friend:false}};
const FRIEND = {ant:"friend"};
const OBSTACLE = {obstacle:true};
const FREE = {obstacle:false};
const BADOBSTACLE = {badobstacle:true};
const STARTINGFOOD = 6;
const LESSENFOOD = 160;
const ENDINGFOOD = 160;
const isMiner = type==Ut || type==Dt;
var friendCount = count(FRIEND);
if (isMiner) {
  var Mu = type==Ut? u : d;
  var Md = type==Ut? d : u;
  var Mur = Mu+1;
  var Mul = Mu-1;
  var Mdr = Md+1;
  var Mdl = Md-1;
}

const foodExt = [C3, C7, WH];
const rawRail = [
  [WH,-1,C7,-1], // 43 03 13 23
  [C6,WH,WH,-1], // 42 02 12 22

  [C4,C1,C2,C2],
  [C2,C4,C5,C5],
  [C3,C5,C1,C3],


//[C3,C1,C4,C4],
//[C4,C4,C5,C2],
//[C5,C2,C1,C3],

//[C3,C1,C2,C5],
//[C3,C3,C1,C5],
//[C2,C4,C5,C2],


//[C2,C1,C3,C5], // 41 01 11 21
//[C1,C5,C5,C4], // 40 00 10 20
//[C5,C4,C2,C3], // 41 01 11 21
  [C6,WH,WH,-1], // 42 02 12 22
  [WH,-1,C7,-1]  // 43 03 13 23
]
.map((ln,row)=>(row<2||row>4)? ln.map(c=>({not:{ant:{friend:true, type:[Ht, 5]}},color:c})) : ln); // queen can't be in the top & bottom 2 rows

function section(ln, action, scorer) {
  if (ln > 0) section(-ln, action, scorer);
  var sct = rawRail.slice(ln+2, ln+5);
  var parts;
  if (Math.abs(ln) != 2) {
    parts = [];
    for (let i = 0; i < 4; i++) {
      var cpt = sct.map(([a,b,c,d])=>[a,b,c]);
      cpt.hp = i;
      cpt.vp = ln;
      parts.push(cpt);
      if (i!=4) sct = sct.map(([a,b,c,d])=>[b,c,d,a]);
    }
  } else {
    var o = sct.map(c=>c.slice(0,3));
    o.vp = ln;
    o.hp = 0;
    parts = [o];
  }
  parts.map(c=>adds(c, action, scorer));
}

function sabotage(where) {
  if (on(where, 1)) repair([where], true);
  else color(where, 1);
}


section(0, ()=>{
  if (isMiner) {
    if (on([r,ur,dr], Fo)  ||  on([u,d], Fo) && on([l,ul,dl], Mo)) { // FAKE RAIL
      color(on([dr,d],Fo)? [dr,u,ul] : [dr,d,dl], C7);
    }
    else if ([l,ul,dl].every(c=>on(c,{ant:{}})) && !random4()) move([r,u,d,ur,dr]); // peer pressure
    /* AV */ else if (found(EQo)) sabotage(find(EQo));
    else if (repair()) {
      if (on(r,Mo) && (random4() > 1 || random4() && friendCount > 3)) move([l,Mul,Mu,Mdl,Md]);
      if (on([Mu,Mur], ENEMY)) move([R, D, DR]); // move somewhere away from enemy
      else if (on(r, Qo) && on([l,ul,dl], {ant:{type:[Ut,Dt],food:1,friend:true}})) move([Mu, Mul, l, Mdl]); // make place for miners with food; Possibly stuck
      else if (on(r, Qo)) move([Mu, Mul]); // don't do stupid things around queen
      else if (on(l, Qo) && !foundEnemy) move([Mul, Mdl, Mu, Md]); //.. I've done stupid things around queen
      else if (on([Mu,Mur], OBSTACLE)) { // up is blocked :/
        if (random4()) move(on(Mu, FRIEND)? [Mur, r] : r);
        else move([r, Mul, Md, Mul, l, Mdl]);
      }
      else move([Mu, r, Mur, Md, Mdr]); // move along
    }
  } else if (isQueen) {
    var HM = Pattern.view.map(c=>+basedOn(c, Ho));
    var helperRows = [HM.slice(0,3),HM.slice(6,9)].map(c=>c.lastIndexOf(1)).map((c,i) => (c==0 && on(i==0? u : d, OBSTACLE)) ? -1 : c);
    var minH = Math.min(helperRows[0],helperRows[1]);
    var maxH = Math.max(helperRows[0],helperRows[1]);
    if (on(r, FRIEND) && [ur,dr].every(c=>on(c, ENEMY))) move([l,ul,dl]);
    if (found(EQo)) { // vampire?
      move(random4()%2? [ur,dr] : [dr,ur]);
      var eQueenRel = (findRel(EQo)-rp)%3;
      if (eQueenRel == 0) move(r,ur,dr);
      spawn(Mu, [u,d,r,ur,dr]);
    }
    if (foundEnemy) // spawn helpers against enemies
      if (food && minH == -1 && count(Ho) < 2) {
        if (helperRows[0] == -1) spawn([u,ur,ul],Ht);
        else                     spawn([d,dr,dl],Ht);
      }
    if ([r,ur,dr].every(c=>on(c, ENEMY))) move([ul,dl,l,u,d]); // OH GOD NO WHY
    if ((minH == -1 || maxH == 2) && on(r, [ENEMY,Ho]) && Pattern.incorr < 2 && count({ant:{}})-1 != count(Ho))
      move(on(ur, ENEMY)? [d,u,dr,ur,ul,dl,l] : [u,d,ur,dr,ul,dl,l]); // initialize transporting around enemy
    if ((!random4() && on(l, OBSTACLE) && on([ul, dl], OBSTACLE)) && Pattern.corr >= 7) move(r); // move forward sometimes if left is 2/3s full
    else if ([r,ur,dr].every(c=>c.ant && !c.ant.friend)) move([l,ul,dl]);
    else if (food && minH > 0 && (
        count(Mo) == 0 && selectedHp != 1 && Pattern.corr != 9 && food < LESSENFOOD
      ||
        //Pattern.corr === 9 && [u,d].every(c=>on(c,Ho)) && selectedHp === 1 && food >= LESSENFOOD && food < ENDINGFOOD && random4() < 2
        Pattern.corr === 9 && selectedHp == 0 && count(Mo) === 0 && food >= LESSENFOOD && food < ENDINGFOOD && random4() < 2
      )) { // spawn miners
      if (random4()%2) spawn([u,ul], Ut);
      else             spawn([d,dl], Dt);
    } else if (repair()) {
      if (food && minH == -1 && count(Ho) < 2) { // spawn helpers
        if (helperRows[0] == -1) spawn([u,ur,ul],Ht);
        else                     spawn([d,dr,dl],Ht);
      }
      else if (selectedHp != 1  ||  selectedHp==1 && /*(*/(maxH==2 || minH == -1 && helperRows.includes(2)) && (!random4() || food < LESSENFOOD || found(Mo))  ||  foundEnemy) move(r); // move forwards
      else if (on(ul, Do) && on(dl,Uo) && on(l, {ant:{}})) move(r); // miners are in wrong places
    }
  } else { // helper
    var repaired = repair();
    var queenRel = (findRel(Qo)-rp)%3;
    var dir = queenRel==0? 0 : 1;
    if (repair()) {
      if (on(r, EQo) && [u,d,ur,dr].map(c=>on(c, ENEMY)? 1 : 0).reduce(ADD) >= 3) move(c); // protect the queen from the evils ahead
      else if (on(r, Qo)) move([u,d,ur,dr,ul,dl,l]);
      else move((on([d,dr,dl], Ho)? [u+dir,d+dir] : [d+dir,u+dir]).concat([u+(1-dir), d+(1-dir)]), !random4());
    }
  }
})

section(1, ()=>{
  const A = selectedVp > 0? d : u; // away
  const I = selectedVp > 0? u : d; // in
  const AR = A+1;
  const AL = A-1;
  const IR = I+1;
  const IL = I-1;

  if (isMiner) {
    var queenRel = (findRel(Qo)-rp)%3;
    if (on([r,IR], Fo)) color([r,IR, I], C7); // FAKE RAIL
    else if ([l,IL].every(c=>on(c,{ant:{}})) && !random4()) move([r,IR]); // peer pressure
    /* AV */ else if (found(EQo)) sabotage(find(EQo));
    else if ((found(EQo) && random4() && Pattern.dist <= 1 && on(find(EQo), 1)) || repair()) {
      if (on(I, Qo)) move(l); // what am I doing here?
      else if (A == Mu) { // my dir!
        if (!food && selectedHp == 0 && (on(r,Ho) && on(IR, Qo)  ||  count(Mo) >= 6)) move(A); // move out!
        else if (on(IR,Qo) && on([l,IL], {ant:{type:[Mu,Md],friend:true,food:1}})) move(C); // waiting in line :D
        else if (on(IR,Qo)) move(C); // waiting in line :D
        else if (random4()) move([r, I, IR]);
        else move([r, I, IR, l, IL]);
      } else { // not my dir
        // TODO fix \\ if (selectedHp == 0 && count(Mo) >= 6 && food) move(A); // fake rail escape
        if (random4()) {
          move([I, IR, IL, l]);
        } else {
          move([r, I, IR, IL, l]);
        }
      }
    }
  } else if (isQueen) {
    if (found(EQo)) { // vampire?
      var eQueenRel = (findRel(EQo)-rp)%3;
      if (eQueenRel==0) move(r, IR);
      spawn(Mu, [r,IR]);
      spawn(Md, I);
    }
    /* AV */ if (food > 70 && (
      [IR,IL,I,l,r].every(c=>on(c,ENEMY)) // completely encased
      || on(IR, EQo) && [r,I].every(c=>on(c, ENEMY)) // getting leeched
      || on(I, EQo) && [r,l,IL,IR].map(c=>get(c)).map(c=>c.ant? (c.ant.friend? 1 : -1) : 0).reduce(ADD) < 0 // leeched
    )) move([A,AR,AL]); // BAD NEWS COMPLETELY DEAD
    if (!random4() || found(EQo) || repair())
      move(random4()? [IR,r,I,l] : [IR,r,I]);
  } else { // helper
    var queenRel = (findRel(Qo)-rp)%3;
    /* AV */ if (on(r,Qo) && on([I,IR], EQo)) move([IR,I,l,IL]);
    if (on(l, Qo)) { if (!random4() || repair()) move(r) } // queen's transporting
    if (on(I, Qo) && on(IR, {ant:"enemyworker"})) { if (!random4() || repair()) move(r) } // queen needs to transport
    // what was this? if ([l,IL,I].every(c=>on(c,OBSTACLE)) && (count(ENEMY) > 1 || find(EQo)) && !random4()) move([r,ur]);
    if ((selectedVp < 0? /...[#-W]{6}/ : /[#-W]{6}.../).test(Pattern.corrstr) && queenRel == 2 && count(Ho) == 1) move(r); // move forward without repairing
    if (!random4() && queenRel == 1 && selectedHp == 1 && on(AL, {ant:{}})) move(r); // something is out; don't repair
    else if (repair([r,l,A,AR,AL])) {
      if (on(r, ENEMY) && on(I, Qo) && [l,IL].every(c=>on(c,FRIEND))) move(IR); // protect from vampire
      if (on(r, ENEMY) && on(IL, Qo) && [l,IR].every(c=>on(c,FRIEND))) move(I);
      if (on(r, ENEMY) && !get(r).ant.food && on(I, Qo)) move(IR);
      if (queenRel == 1 && selectedHp == 1 && on(AL, {ant:{}})) move(r); // something is out
      else if (on([l,r], Ho)) { // move to the other side
        if (found(Qo)) move([I]); // TODO integrate ,IL,IR
        else move([l,r]);
      }
      else if (queenRel == 2) move(r); // move forward
    }
  }
}, (pscore, pt, corrects, falseN, match) => {
  if (match(".?(...)?@@.@@.*") && !foundEnemy) {
    if (!match(pt.vp>0? ".?@@.@@.*" : ".?...@@.@@.*")) pscore/=2;
  }
  return pscore;
})

if (isMiner) {
  section(2, () => {
    const A = selectedVp > 0? d : u; // away
    const I = selectedVp > 0? u : d; // in
    if (on(A,OBSTACLE)) move(I);
    else if (repair()) move(food? I: Mu);
  }, (pscore, pt, corrects, falseN, match) => match(pt.vp>0? "@@@.@...." : "....@.@@@")? match("@@@@@@@@@")? 100 : ((pt.vp>0) == (type==Dt)? 13 : 10) : 0);
  if (type==Dt) foodExt.reverse();
  if (!found(Ho) && !found(Qo)) {
    var lns = [rawRail[0], rawRail[1]].map(c=>c.slice(0,3));
    [[lns[0],lns[1],lns[0]], [lns[1],lns[0],lns[1]]].map(c=>{
      adds(c, () => {
        var onL;
        if (!food && ((onL = on(l, Fo)) || on(r, Fo))) {
          var foodpt = Pattern.raw.map((ln, i) => [ln[0], foodExt[i], ln[2]]);
          refPt(foodpt,undefined,undefined,selectedRot);
          if (repair()) move(onL? l : r);
        }
        else if (repair([l,r,ul,ur,dl,dr], on([Mul, Mur, Mdl, Mdr, l, r], {ant:{friend:true,type:[Ut,Dt],food:1}}) ||  on([Mu, Md], Mo))) {
          move(food? [Md, Mu] : [Mu, Md]);
        }
      }, (pscore, pt, corrects, falseN, match) => {
        var score = 0;
        var dMatch = match("...@.@@@@");
        var uMatch = match("@.@@.@...");
             if ((type==Ut ^ food) && dMatch) score = 15;
        else if ((type==Dt ^ food) && uMatch) score = 15;
        else if (uMatch || dMatch) score = 6;
        if ([0,2,3,5,6,8].some(c=>basedOn(pt.view[c], FRIEND) && !pt.view[c].ant.food)) score = 0;
        return score;
      });
      if (food) {
        var extp = c.map((ln, i) => [ln[0], foodExt[i], ln[2]]);
        [extp.map(([a,b,c])=>[0,a,b]), extp.map(([a,b,c])=>[b,c,0])].forEach((pt,i) => adds(pt, () => {
          move(i? l : r);
        }, (pscore, pt, corrects, falseN, match) => match("@@@@@@@@@")? 100 : 0));
      }
    });
  }
}

Pattern.choose();
var confident = ((Pattern.confidence >= 1 && (Pattern.score > 4 || Pattern.corr >= 4)) || (Pattern.score >= 9 && Pattern.confidence > 0.05)); // && (selectedHp !=  || !found(Qo));
var failAction = () => {
  if (foundEnemy) {
    log(view);
    log("dead around enemy :/");
    logMyLogs = true;
  }
  if (isQueen) {
    if (found(EQo)) {
      move([8-(find(EQo)-rp) + rp]);
      move(random4()%2? U : UR);
    }
    if (foundEnemy) move(random4()%2? U : UR);
  } else {
    // if (!found(Qo) && found(Fo)) move(find(Fo));
    var enemyPlace = find(ENEMY);
    if (enemyPlace !== -1) color(enemyPlace, get(enemyPlace).color==1? C3 : WH);
  }
}
if (!confident) Pattern.action = failAction;

if (isMiner) {
  if ((Pattern.hardcorr >= 4 || Pattern.score > 5) && confident) Pattern.action();
  else {
    failAction();
  }
} else if (isQueen) {
  if ((Pattern.hardcorr >= 6 || food > STARTINGFOOD+2 || friendCount>1 || found(Mo) || Pattern.score > 6 || (false)) && confident) Pattern.action();
  else if (food >= STARTINGFOOD && friendCount == 1) {
    clear();
    Pattern.add([[1,{ant:Ho.ant,color:1},1],
                 [1,1,1],
                 [1,1,1]], ()=>spawn([ur,ul],Ht));
    Pattern.add([[1,1,{ant:Ho.ant,color:1}],
                 [1,1,1],
                 [1,1,1]], ()=>spawn([ur,u],Ht));
    Pattern.choose();
    if (repair()) Pattern.action();
  } else if (food == 0 && friendCount == 0) { // diagonal search
    if (found(Fo)) {
      move(find(Fo));
    } else {
      clear();
      Pattern.add([[WH,WH,WH],
                   [WH,C1,WH],
                   [C1,WH,WH]], ()=>move(ur));
      Pattern.add([[WH,WH,WH],
                   [WH,WH,WH],
                   [C1,WH,WH]], ()=>color(C, C1));
      Pattern.add([[WH,WH,WH],[WH,WH,WH],[WH,WH,WH]], ()=>color(DL, C1));
      Pattern.choose();
      if (Pattern.corr == 9) Pattern.action();
      else move(random4()? [DL,UL,DR,UL] : [D,L,U,R]);
    }
  } else if (food == 1 && friendCount == 0) spawn([U,L,D,R,UL,DL,UR,DR], Ht);
  else if (friendCount == 1) lightSpeed();
  else if (friendCount > 0) {
    var pt = new Pattern(rawRail).select(0,2,4,3).rotate(L).rotate(L).pt;
    pt[1][2] = {color:pt[1][2], ant:{type:Ht, friend:true}};
    refPt(pt);
    repair([c,u,d,ur,dr]);
  } // TODO wtf to do after this
  else Pattern.action(); // eh fuck it
} else if (type == Ht) {
  if (confident && (Pattern.score >= 4 || Pattern.hardcorr >= 5 || friendCount>1)) Pattern.action();
  else if (found(Qo)) lightSpeed();
  else if (Pattern.hardcorr >= 3 && confident) repair();
}

function lightSpeed() {
  var other = find(isQueen? Ho : Qo);
  var orth = other%2;
  if (isQueen || (view[other].ant.food < STARTINGFOOD && count(Ho) == 1)) { // LS
    if (orth && found(Fo)) { // grab easy food
      var fp = find(Fo);
      if (sees(other, fp)) move(fp);
      else {
        refPt([[0,FRIEND,0],
                     [0,0,0],
                     [0,0,0]]);
        move(l);
      }
    }
    clear();
    // Pattern.when(U,find(FRIEND), ()=>isQueen? move(ul) : move(ur)); when I'm not lazy imma make this a replacement of the below
    Pattern.add([[0,FRIEND,0],
                 [0,0,0],
                 [0,0,0]], ()=>isQueen? move(ul) : move(ur));
    Pattern.add([[0,0,FRIEND],
                 [0,0,0],
                 [0,0,0]], ()=>move(u));
    Pattern.choose();
    Pattern.action();
  }
}

if (DEBUG) log("END", type, view.map(c=>c.ant? "A"+c.ant.type : c.color));
if (DEBUG && logMyLogs) {
  //for (let i = 0; i < toLog.length; i+=800)
  //  console.log(toLog.substring(i,i+800));
  for (let i of toLogRaw) console.log(...i);
}
if (toReturn) return toReturn;
else return {cell:4};

पहले यह एक रेल पर खनिक था (पुनरीक्षण इतिहास देखें), लेकिन इसे स्लाइडिंग माइनर्स में बदल दिया गया है क्योंकि यह बेहतर प्रदर्शन करता है और MoaR को इसकी सफलता के रास्ते में मिलेगा यदि यह एक और प्रविष्टि थी।


इस बार फिर लीडरबोर्ड पर पहले ...
ट्राइकोप्लाक्स

14

ग्लाइडर

कार्रवाई में ग्लाइडरग्लाइडर मोड़ बाएँग्लाइडर सही मोड़

//console.log(JSON.stringify(view))
var TRAIL = 6;
var SPAWN = 3;
var IDLE = 4;
var FOOD_THRESHOLD = 150;
var SPAWN_MIN = 3;
var HIGHWAY_COLORS = [7,6,4,2,3];
var HIGHWAY_THRESHOLD = 70;
var ret = {cell:4};
if(isOnHighway()) {
    var cont = true;
    //== Make best guess to if in a glider formation ==//
    if(view[4].ant.type == 5) {
        if((findWorker(1) >= 0 && findWorker(4) >= 0) || view[4].ant.food < HIGHWAY_THRESHOLD) {
            cont = false;
        }
    }
    else if(view[4].ant.type == 4) {
        if(findWorker(1) >= 0 && findWorker(5) >= 0) {
            cont = false;
        }
    }
    else if(view[4].ant.type == 3) {
        if(findWorker(2) >= 0 && findWorker(5) >= 0) {
            cont = false;
        }
    }
    else if(view[4].ant.type == 2) {
        if(findWorker(5) < 0) {
            var pos3 = findWorker(3);
            if(pos3 >= 0 && view[pos3].ant.food == 0) {
                cont = false;
            }
        }
        else if(findWorker(3) >= 0 || (findWorker(1) >= 0 && view[findWorker(5)].color == SPAWN))
            cont = false;
    }
    else if(view[4].ant.type == 1) {
        if(findWorker(5) < 0) {
            var pos4 = findWorker(4);
            if(pos4 >= 0 && view[pos4].ant.food == 0) {
                cont = false;
            }
        }
        else if(!isHighwayCenter())
            cont = false;
    }
    if(findWorker(5) >= 0) {
        for(var i=0;i<9;i++) {
            if(view[i].ant != null && !view[i].ant.friend && view[i].ant.type == 5) {
                if(view[i].ant.food > 10 || view[i].ant.food == 0)
                    cont = true;
                else
                    cont = false;
            }
        }
    }
    //== End guesswork ==//
    if(cont) {
        ret = highwayRobbery();
        if(view[4].ant.type == 1) {
            //try to repair
            var curIndex = HIGHWAY_COLORS.indexOf(view[4].color);
            var prvCol = HIGHWAY_COLORS[(curIndex+1)%HIGHWAY_COLORS.length];
            var nxtCol1 = HIGHWAY_COLORS[(curIndex+HIGHWAY_COLORS.length-1)%HIGHWAY_COLORS.length];
            var nxtCol2 = HIGHWAY_COLORS[(curIndex+HIGHWAY_COLORS.length-2)%HIGHWAY_COLORS.length];
            var nxtCol3 = HIGHWAY_COLORS[(curIndex+HIGHWAY_COLORS.length-3)%HIGHWAY_COLORS.length];
            var prevAt = -1;
            for(var i=0;i<9;i++) {
                if(i%2 == 1 && view[i].color == prvCol && view[deRotate(i,1)].color == nxtCol1 && view[deRotate(i,-1)].color == nxtCol1) prevAt = i;
            }
            if(prevAt >= 0) {
                // yep, brute force it. Because I'm lazy.
                var goNxt = 8-prevAt;
                if(view[deRotate(goNxt,1)].color == nxtCol3 && view[deRotate(goNxt,-1)].color == prvCol) ret = {cell:goNxt};
                else if(view[deRotate(goNxt,1)].color == prvCol && view[deRotate(goNxt,-1)].color == nxtCol3) ret = {cell:goNxt};
                else if(view[goNxt].color != nxtCol1) ret = {cell:goNxt,color:nxtCol1};
                else if(view[deRotate(goNxt,2)].color != nxtCol2) ret = {cell:deRotate(goNxt,2),color:nxtCol2};
                else if(view[deRotate(goNxt,-2)].color != nxtCol2) ret = {cell:deRotate(goNxt,-2),color:nxtCol2};
                else if(view[deRotate(goNxt,1)].color != nxtCol3) ret = {cell:deRotate(goNxt,1),color:nxtCol3};
                else if(view[deRotate(goNxt,-1)].color != nxtCol3) ret = {cell:deRotate(goNxt,-1),color:nxtCol3};
                else ret = {cell:goNxt};
                ret = sanityCheck(ret);
                return ret;
            }
        }
        if(view[4].ant.type == 5 && isHighwayCenter()) {
            if(ret.cell >= 0) {
                ret = {cell:8-ret.cell};
                if(view[4].color == SPAWN && (view[4].ant.food > 90 || view[4].ant.food % 7 == 0) && getHighestWorker() == 0 && (view[4].ant.food < 140 || view[4].ant.food % 9 == 0) && view[0].color == 2 && view[4].ant.food > 50 && view[4].ant.food < 200) {
            //fine
                    if(view[4].ant.food % 10 < 5)
                        ret = {cell:deRotate(ret.cell,3),type:3};
                }
                if(view[ret.cell].ant != null && !view[ret.cell].ant.friend && view[ret.cell].ant.food == 0 && view[4].ant.food > 0) {
                    if(view[deRotate(ret.cell,1)].ant == null)
                        ret = {cell:deRotate(ret.cell,1),type:3};
                    if(view[deRotate(ret.cell,-1)].ant == null)
                        ret = {cell:deRotate(ret.cell,1),type:3};
                }
            }
            for(var i=0;i<9;i++) {
                if(view[i].ant != null && !view[i].ant.friend && view[i].ant.type == 5) {
                    ret = {cell:8-i};
                }
            }
        }
        if(ret.cell >= 0) {
            for(var i=0;i<9;i++) {
                if(view[i].ant != null && !view[i].ant.friend && view[i].ant.type == 5) {
                    var rr = basicHighwayMove();
                    if(rr.cell >= 0 && view[4].ant.type != 5)
                        ret = {cell:deRotate(rr.cell,-2)};
                }
            }
            if(view[ret.cell].ant != null) {
                var n = HIGHWAY_COLORS.indexOf(view[4].color) + 1;
                var nextMove = HIGHWAY_COLORS[n % HIGHWAY_COLORS.length];
                for(var i=0;i<9;i++) {
                    if(view[i].color == nextMove) {
                        if(view[i].ant == null) {
                            ret = {cell:i};
                            break;
                        }
                    }
                }
                if(view[4].ant.type == 5) ret = {cell:8-ret.cell};
            }
        }
        if(view[4].ant.type == 5) {
            var foodedEnemy = false;
            for(var i=0;i<9;i++) {
                if(getNumWorkers(3) >= 2) break;
                if(i != 4 && view[i].ant != null && view[i].ant.type == 5 && view[i].ant.food > 25) {
                    if(view[deRotate(i,1)].ant == null) {
                        ret = {cell:deRotate(i,1),type:3};
                    }
                    else if(view[deRotate(i,-1)].ant == null) {
                        ret = {cell:deRotate(i,-1),type:3};
                    }
                    else if(i%2 == 1 && view[deRotate(i,2)].ant == null) {
                        ret = {cell:deRotate(i,2),type:3};
                    }
                    else if(i%2 == 1 && view[deRotate(i,-2)].ant == null) {
                        ret = {cell:deRotate(i,-2),type:3};
                    }
                }
                if(view[i].ant != null && !view[i].ant.friend && view[i].ant.type == 3 && view[8-i].ant == null) {
                    if(i == ret.cell) {
                        ret = {cell:deRotate(i,1)}
                    }
                    else {
                        return {cell:8-i};
                    }
                }
                if(view[i].ant != null && !view[i].ant.friend && view[i].ant.food == 0) {
                    foodedEnemy = true;
                }
            }
        }
        var numAnts = 0;
        for(var i=0;i<9;i++) {
            if(view[i].ant != null)
                numAnts++;
        }
        if(numAnts > 2 && sanityCheck(ret).cell == 4) {
            ret = {cell:findOpenSpace(0,1)};
        }
        if(view[4].ant.type == 3) {
            if(getNumWorkers(5) > 0) {
                for(var i=0;i<9;i++) {
                    if(view[i].ant != null && !view[i].ant.friend && view[i].ant.type == 5) {
                        ret = {cell:4};
                    }
                }
            }
        }
        if(view[4].ant.type == 4 && getNumWorkers(1) && isHighwayCenter()) {
            var workerPos = findWorker(1);
            for(var i=0;i<9;i++) {
                if(!areAdjacent(i,workerPos)) ret = {cell:i};
            }
        }
        if(ret.cell == -1) {
            if(isHighwayCenter()) {
                for(var i=0;i<9;i++) {
                    var p1 = deRotate(i,3);
                    var p2 = deRotate(i,-3);
                    if(view[i].color == view[p1].color && view[i].color == view[p2].color) {
                        ret = {cell:8-i};
                    }
                }
                if(view[4].ant.type == 1 || view[4].ant.type == 5) {
                    ret = {cell:8-ret.cell};
                }
            }
        }
        if(ret.cell >= 0)
            return sanityCheck(ret);
    }
}

switch(view[4].ant.type) {
    case 5:
        ret = doQueen();
        break;
    case 1:
    case 2:
        ret = doSweep();
        break;
    case 3:
    case 4:
        ret = doGuide();
        break;
    default:
        break;
}
//basic sanity check
ret = sanityCheck(ret);
return ret;

function sanityCheck(ret) {
    if(!ret || ret.cell < 0 || ret.cell > 8) {
        return {cell:4};
    }
    if(ret.color) {
        return ret;
    }
    if((ret.cell != 4 && view[ret.cell].ant != null) || (view[ret.cell].food > 0 && (view[4].ant.food > 0 && view[4].ant.type < 5))) {
        return {cell:4};
    }
    if(ret.type && (view[ret.cell].ant != null || view[ret.cell].food > 0 || view[4].ant.food == 0 || view[4].ant.type < 5)) {
        return {cell:4};
    }
    return ret;
}

function doQueen() {
    if((view[4].ant.food == SPAWN_MIN || (view[4].ant.food >= SPAWN_MIN && view[4].ant.food < FOOD_THRESHOLD && (view[4].ant.food % 3 == 1 || isOnHighway()))) && getHighestWorker() <= 1 ) {
        //prep for first ant
        var s0 = view[0].ant;
        var s1 = view[1].ant;
        var s2 = view[2].ant;
        var s3 = view[3].ant;
        var s5 = view[5].ant;
        var s6 = view[6].ant;
        var s7 = view[7].ant;
        var s8 = view[8].ant;
        var nullCount = 0 + (s0 == null?1:0) + (s1 == null?1:0) + (s2 == null?1:0) + (s3 == null?1:0) + (s5 == null?1:0) + (s6 == null?1:0) + (s7 == null?1:0) + (s8 == null?1:0);
        var nullCount2 = 0 + (s0 == null || s0.friend?1:0) + (s1 == null || s1.friend?1:0) + (s2 == null || s2.friend?1:0) + (s3 == null || s3.friend?1:0) + (s5 == null || s5.friend?1:0) + (s6 == null || s6.friend?1:0) + (s7 == null || s7.friend?1:0) + (s8 == null || s8.friend?1:0);
        if(nullCount >= 7 && nullCount2 >= 8 && view[1].food == 0 && view[3].food == 0 && view[5].food == 0 && view[7].food == 0) {
            var high = getHighestWorker();
            if (high <= 1 && view[4].color != SPAWN && !isOnHighway()) {
                // 50% chance of delaying the respawn by 1 additional move away from where we exploded
                // reduces the chance of a second, immediate explosion
                var pos1 = findWorker(1);
                if(findFirstTrail() < 2 && view[4].ant.food > SPAWN_MIN+1 && pos1 < 0) return foreverAlone();
                if(pos1 >= 0) {
                    var space = deRotate(pos1,2);
                    if(view[space].ant != null) return {cell:findOpenSpace(0,1)};
                }
                return {cell:4,color:SPAWN};
            }
            //spawn first ant
            else if(view[4].color == SPAWN) {
                var pos1 = findWorker(1);
                if(pos1 < 0)  {
                    pos1 = findFirstTrail();
                    if(pos1 % 2 == 0) pos1 = deRotate(pos1,1);
                    else pos1 = deRotate(pos1,4);
                }
                var space = findOpenSpace(pos1,2);
                var high = getHighestWorker();
                if(space < 0) return {cell:4,color:TRAIL}
                if(high == 0) { //no workers
                    return {cell:space,type:1};
                }
                else if(high < 4) { //1 worker of type:high
                    return {cell:space,type:high+1};
                }
                else { //1 worker of type 4
                    //we have all workers, skip!
                }
            }
        }
        else {
            return foreverAlone();
        }
    }
    else if(view[4].ant.food == 1 && getHighestWorker() == 0 ) {
        var space = findOpenSpace(1,2);
        return {cell:space,type:1};
    }
    else if(view[4].ant.food >= 1 && getHighestWorker() < 4 && findWorker(1) >= 0) {
        //spawn remaining ants
        if(view[4].color == SPAWN && !isHighwayCenter()) {
            var pos1 = findWorker(getHighestWorker());
            var space = deRotate(pos1,2);
            var high = getHighestWorker();
            if(space < 0 || view[space].ant != null) return {cell:findOpenSpace(0,1)};
            if(high == 0) { //no workers
                return {cell:space,type:1};
            }
            else if(high < 4) { //1 worker of type:high
                return {cell:space,type:high+1};
            }
            else { //1 worker of type 4
                //we have all workers, skip!
            }
        }
    }
    if(view[4].color == SPAWN && getNumWorkers(3) == 1 && getNumWorkers(4) == 1) {
        var one = getNumWorkers(1);
        var two = getNumWorkers(2);
        if((one ^ two) == 1 && (findWorker(1) % 2 == 0 || findWorker(2) % 2 == 0))
            return {cell:4,color:1};
    }
    if(getNumWorkers(1) == 0 && getNumWorkers(2) == 0) {
        if(getNumWorkers(4) == 1 && getNumWorkers(3) == 0) {
            var pos4 = findWorker(4);
            if(view[deRotate(pos4,1)].ant == null && view[deRotate(pos4,2)].ant == null && findWorker(4) % 2 == 1) {
                //finish rotate with only one glider arm
                return {cell:4};
            }
        }
        return foreverAlone();
    }
    else if(getNumWorkers(1) >= 1 && getNumWorkers(2) >= 1 && getNumWorkers(3) >= 1 && getNumWorkers(4) >= 1) {
        if(view[4].color != 2 && findWorker(1)%2 == 1 && findWorker(2)%2 == 1) {
            return {cell:4,color:TRAIL};
        }
        //move diagonally
        var pos = findWorker(4);
        pos = deRotate(pos,1);
        var checkpos = view[deRotate(pos,4)];
        if(checkpos.ant != null && checkpos.ant.friend) {
            if(checkpos.ant.type == 2)
                return {cell:4};
            if(checkpos.ant.type == 1)
                return {cell:4};
        }
        if(view[pos].ant) return {cell:4,color:1};
        return {cell:pos};
    }
    else {
        var pos = findWorker(4);
        if(pos < 0) {
            //if gliding along with only a buddy
            pos = findWorker(1);
            if(pos >= 0 && view[deRotate(pos,2)].food > 0 && view[deRotate(pos,1)].food == 0) {
                return {cell:4};
            }
        }
        if(pos < 0) {
            var s1 = view[1].ant;
            var s3 = view[3].ant;
            var s5 = view[5].ant;
            var s7 = view[7].ant;
            //return {cell:999}
            if(s1 == null) {
                if(s3 == null) {
                    return {cell:0};
                }
                if(s5 == null) {
                    return {cell:2};
                }
            }
            if(s7 == null) {
                if(s3 == null) {
                    return {cell:6};
                }
                if(s5 == null) {
                    return {cell:8};
                }
            }
            return {cell:4};
        }
        pos = deRotate(pos,1);
        var checkpos1 = view[pos];
        for(var i=0;i<9;i++) {
            if(i != 4 && view[i].ant != null && view[i].ant.type == 5 && view[i].ant.food > 2) {
                if(i%2==0) {
                    if(view[deRotate(i,1)].ant == null) return {cell:deRotate(i,1),type:3};
                    if(view[deRotate(i,-1)].ant == null) return {cell:deRotate(i,-1),type:3};
                }
                else {
                    if(view[deRotate(i,1)].ant == null) return {cell:deRotate(i,1),type:3};
                    if(view[deRotate(i,-1)].ant == null) return {cell:deRotate(i,-1),type:3};
                    if(view[deRotate(i,2)].ant == null) return {cell:deRotate(i,2),type:3};
                    if(view[deRotate(i,-2)].ant == null) return {cell:deRotate(i,-2),type:3};
                }
                return {cell:4};
            }
        }
        if(checkpos1.ant != null && view[deRotate(pos,1)].ant != null && !view[deRotate(pos,1)].ant.friend) {
            return foreverAlone();
        }

        var checkpos2 = view[deRotate(pos,4)];
        var checkpos3 = view[deRotate(checkpos,1)];
        if(checkpos1.ant != null && checkpos1.ant.friend && checkpos1.ant.type == 1 && checkpos2.ant != null && checkpos2.ant.friend && checkpos2.ant.type == 2 && checkpos3.ant != null && checkpos3.ant.friend && checkpos3.ant.type == 3) {
            //move out of spawn orientation
            return {cell:4};
        }
        if(view[pos].ant != null) {
            if(checkpos2.ant == null && checkpos1.ant == null) {
                return {cell:8-pos};
            }
            if(!view[pos].ant.friend) {
                return foreverAlone();
            }
            if(view[4].color == TRAIL) return foreverAlone();
            return {cell:4,color:TRAIL};
        }
        if(8 - findWorker(3) == findWorker(4)) {
            //finish rotate to the right
            return {cell:4};
        }
        if((view[deRotate(pos,1)].food > 0 || view[deRotate(pos,2)].food > 0) && view[deRotate(pos,1)].ant == null && view[4].color != TRAIL) {
            if(findWorker(1) < 0 || view[deRotate(findWorker(1),1)].food == 0) {
                return {cell:4};
            }
        }
        return {cell:pos};
    }
    return {cell:100+view[4].ant.type}; //oh god
}

//guides sit next to the queen
function doGuide() {
    var queenPos = findWorker(5);
    var ty = view[4].ant.type==3?2:1;
    var dir = view[4].ant.type==3?1:-1;
    if(queenPos >= 0 && queenPos%2 == 1 && view[queenPos].color == SPAWN) {
        if(view[deRotate(queenPos,dir*2)].ant == null) {
            return {cell:4};
        }
    }
    if(queenPos < 0 || findWorker(ty) < 0) {
        if(findWorker(ty) >= 0 && view[0].color != IDLE) return {cell:0,color:IDLE}
        return firebreak();
    }
    var checkpos = view[deRotate(queenPos,-2*dir)];
    if(view[4].ant.type==4 && checkpos.ant != null && checkpos.ant.friend && checkpos.ant.type == 1) {
        //attempt rotate
        return {cell:deRotate(queenPos,-dir)};
    }
    checkpos = view[deRotate(queenPos,4)];
    if(checkpos.ant != null && checkpos.ant.friend && checkpos.ant.type == ty) {
        //attempt rotate
        if(getNumWorkers(ty) == 1) {
            return {cell:4};
        }
    }
    var pos = deRotate(queenPos,dir);
    if(pos >= 0 && view[4].ant.type==3 && findWorker(4) < 0) {
        //wait for rotate
        if(view[4].color == TRAIL) {
            return {cell:4};
        }
    }
    if(pos >= 0 && findWorker(2) >= 0 && view[deRotate(findWorker(2),1)].ant != null) {
        //rotate
        return {cell:4,color:TRAIL};
    }
    if(pos < 0) pos = 4;
    else if(view[pos].ant != null) return {cell:deRotate(queenPos,4)};
    if(pos == 4 && view[queenPos].color == TRAIL) return {cell:queenPos,color:1};
    return {cell:pos};
}

//sweepers sit next to guides
function doSweep() {
    var queenPos = findWorker(5);
    var followType = view[4].ant.type==1?4:3;
    var pos = findWorker(followType);
    if(pos % 2 == 0 && getNumWorkers(followType) > 1) {
        //if there's more than one worker #4, we want to use the best one
        for(var i=pos+1;i<9;i++) {
            if(i != 4 && view[i].ant != null) {
                if(view[i].ant.friend && view[i].ant.type == followType) {
                    pos = i;
                    break;
                }
            }
        }
    }
    if(queenPos >= 0 && queenPos%2 == 1 && view[queenPos].color == SPAWN) {
        var p = findWorker(view[4].ant.type);
        if(p >= 0 && (deRotate(p,1) == queenPos || deRotate(p,-1) == queenPos)) {
            return {cell:8-queenPos};
        }
        return {cell:4};
    }
    if(queenPos >= 0 && pos < 0) {
        //if Worker #1 is the only ant besides the queen:
        //TODO
    //good
        if(view[queenPos].ant.food <= SPAWN_MIN || !(view[queenPos].ant.food < FOOD_THRESHOLD && view[queenPos].ant.food % 3 == 1 && !isOnHighway())) {
            var go = deRotate(queenPos,-1);
            if((view[deRotate(queenPos,-2)].food > 0 || view[deRotate(queenPos,-3)].food > 0 || (queenPos %2 == 1 && view[deRotate(queenPos,-3)].food > 0)) && view[go].food == 0) {
                go = deRotate(queenPos,2);
                //return {cell:4};
            }
            return {cell:go};
        }
        else if(view[queenPos].ant.food < FOOD_THRESHOLD && view[queenPos].ant.food % 3 == 1) {
            return {cell:4};
        }
    }
    if(queenPos >= 0) {
        var dir = view[4].ant.type==1?1:-1;
        //var checkpos = view[deRotate(pos,-dir)];
        var moveTo = deRotate(pos,dir);
        if(moveTo >= 0 && view[moveTo].ant != null && view[moveTo].ant.friend && view[moveTo].ant.type == 5) {
            moveTo = deRotate(pos,-dir);
        }
        if(view[4].ant.type == 2 && findWorker(1) < 0 && view[queenPos].color != TRAIL) {
            moveTo = 4;
        }
        return {cell:moveTo};
    }
    else {
        if(pos < 0) return {cell:4}; //firebreak();
        var dir = view[4].ant.type==1?-1:1;
        var moveTo = deRotate(pos,dir);
        if(view[4].ant.food > 0 && view[moveTo].food > 0) {
            //have food, attempt to give to queen
            moveTo = deRotate(pos,-dir);
        }
        if(view[4].ant.type==1 && pos >= 0 && (view[deRotate(pos,dir*2)].food > 0 || view[deRotate(pos,dir*3)].food > 0)) {
            //attempt rotate
            moveTo = deRotate(pos,-dir);
        }
        if(view[4].ant.type==2 && pos >= 0 && (view[deRotate(pos,dir*2)].food > 0 || view[deRotate(pos,dir*3)].food > 0)) {
            //attempt rotate
            moveTo = deRotate(pos,-dir);
        }
        if(moveTo >= 0 && view[moveTo].ant != null && view[moveTo].ant.type == 5) {
            if(view[moveTo].ant.friend)
                moveTo = deRotate(moveTo,dir*2);
            else
                moveTo = deRotate(pos,-dir);
        }
        return {cell:moveTo};
    }
    return {cell:100+view[4].ant.type};//oh god
}

function foreverAlone() {
    var s0 = view[0].ant;
    var s1 = view[1].ant;
    var s2 = view[2].ant;
    var s3 = view[3].ant;
    var s5 = view[5].ant;
    var s6 = view[6].ant;
    var s7 = view[7].ant;
    var s8 = view[8].ant;
    //good
    if(!(s0 == null && s1 == null && s2 == null && s3 == null && s5 == null && s6 == null && s7 == null && s8 == null) && view[4].color == TRAIL) {
        if (view[0].color == TRAIL && !view[8].ant && view[8].color != TRAIL) return {cell: 8};
        else if (view[2].color == TRAIL && !view[6].ant && view[6].color != TRAIL) return {cell: 6};
        else if (view[6].color == TRAIL && !view[2].ant && view[2].color != TRAIL) return {cell: 2};
        else if (view[8].color == TRAIL && !view[0].ant && view[0].color != TRAIL) return {cell: 0};
        //Can't find color, or path is blocked? try diagonals regardless of color
        else if (!view[0].ant) return {cell: 0};
        else if (!view[2].ant) return {cell: 2};
        else if (!view[6].ant) return {cell: 6};
        else if (!view[8].ant) return {cell: 8};
        //Everything else failed? Stay put.
        else return {cell: 4};
    }
    //good
    if (view[4].color == TRAIL) { //If on colored square, try to move
        var totGreen = 0;
        for (var i = 0; i < 9; i++) { //Look for food
            if (view[i].food) {
                return {cell: i};
            }
            if(view[i].color == TRAIL) totGreen++;
        }
        var ret = getTrailMove();
        if(view[deRotate(ret.cell,1)].color == TRAIL && totGreen <= 4) ret.cell = deRotate(ret.cell,-1);
        else if(view[deRotate(ret.cell,-1)].color == TRAIL && totGreen <= 4) ret.cell = deRotate(ret.cell,1);
        return ret;
    } else { //If not on colored square, look for food, or set current color to 2.
        for (var i = 0; i < 9; i++) { //Look for enemies
            if (i != 4 && view[i].ant != null && !view[i].ant.friend) {
                var r = findOpenSpace(8-i,1);
                if(view[r].color == TRAIL) r = deRotate(r,1);
                return {cell: r};
            }
        }
        return {cell: 4, color:TRAIL};
    }
}

function getTrailMove() {
    if (view[0].color == TRAIL && !view[8].ant && view[8].color != TRAIL) return {cell: 8};
    else if (view[2].color == TRAIL && !view[6].ant && view[6].color != TRAIL) return {cell: 6};
    else if (view[6].color == TRAIL && !view[2].ant && view[2].color != TRAIL) return {cell: 2};
    else if (view[8].color == TRAIL && !view[0].ant && view[0].color != TRAIL) return {cell: 0};
    //Can't find color, or path is blocked? try diagonals regardless of color
    else if (!view[0].ant) return {cell: 0};
    else if (!view[2].ant) return {cell: 2};
    else if (!view[6].ant) return {cell: 6};
    else if (!view[8].ant) return {cell: 8};
    //Everything else failed? Stay put.
    else return {cell: 4};
}

function firebreak() {
    var ret = -1;
    if(findWorker(5) >= 0) {
        return {cell:8-findWorker(5)};
    }
    if(view[4].color != 5) {
        var myView = [0,0,0,0,0,0,0,0,0]
        for(var i=0; i < 9; i++) {
            myView[i] = view[i].color
            if(view[4].ant.food > 0 && view[i].food > 0) {
                myView[i] = 8;
            }
            if(view[i].ant != null && !view[i].ant.friend) return {cell:findOpenSpace(deRotate(i,2),1)};
        }
        var ret = clearAhead(myView);
        if(ret == null)
            return {cell:4,color:5};
        else {
            if(!(view[ret.cell].ant != null && view[ret.cell].ant.friend == false) && (view[4].ant.food == 0 || view[ret.cell].food == 0))
                return ret;
            return {cell:4,color:5};
        }
    }
    if(view[1].color == 5 && view[3].color == 5 && view[5].color == 5 && view[7].color == 5) {
        if(view[0].color != 8) return {cell:0,color:8};
        if(view[1].color != 8) return {cell:1,color:8};
    }
    if(view[1].color == 5 && view[7].color != 5) ret = {cell:7};
    if(view[3].color == 5 && view[5].color != 5) ret = {cell:5};
    if(view[5].color == 5 && view[3].color != 5) ret = {cell:3};
    if(view[7].color == 5 && view[1].color != 5) ret = {cell:1};
    if(view[1].color != 5 && view[3].color != 5 && view[5].color != 5 && view[7].color != 5) ret = {cell:1};
    if((view[1].color == 5 && view[7].color == 5) || (view[3].color == 5 && view[5].color == 5)) ret = {cell:0};
    var loop = 0;
    while(ret.cell >= 0 && ((view[ret.cell].food > 0 && view[4].ant.food > 0) || view[ret.cell].ant != null) && loop < 9) {
        loop++;
        ret.cell = (ret.cell + 2) % 9;
    }
    if(loop < 9 && ret.cell >= 0) return ret;
    return {cell:4};
}

//7,6,4,2,3
//O7,D2

function highwayRobbery() {
    var move = basicHighwayMove();
    if(move.cell >= 0 && view[move.cell].ant != null) {
        var n = HIGHWAY_COLORS.indexOf(view[4].color) + (view[4].color%2==0?1:HIGHWAY_COLORS.length);
        var nextMove = HIGHWAY_COLORS[n % HIGHWAY_COLORS.length];
        for(var i=0;i<9;i++) {
            if(view[i].color == nextMove) {
                return {cell:i};
            }
        }
    }
    return move;
}

function basicHighwayMove() {
    var isQueen = view[4].ant.type == 5;
    if(isHighwayCenter()) {
        var n = HIGHWAY_COLORS.indexOf(view[4].color) + 1;
        var nextMove = HIGHWAY_COLORS[n % HIGHWAY_COLORS.length];
        for(var i=0;i<9;i++) {
            if(view[i].color == nextMove) {
                if(view[i].ant == null)
                    return {cell:i};
                else {
                    return {cell:deRotate(i,1)};
                }
            }
        }
    }
    else {
        if(view[4].color == 7) {
            //move diagonal to yellow (2)
            for(var i=0;i<9;i++) {
                if(i != 4 && i % 2 == 0 && view[i].color == 2) {
                    return {cell:i};
                }
            }
        }
        else {
            //move orthogonal to blue (7)
            for(var i=0;i<9;i++) {
                if(i % 2 == 1 && view[i].color == 7) {
                    //try ortho yellow first
                    for(var j=0;j<9;j++) {
                        if(j % 2 == 1 && view[j].color == 2 && areAdjacent(i,j))
                            return {cell:j};
                    }
                    return {cell:i};
                }
            }
            //if orthogonal blue doens't exist...
            //...try diagonal to magenta
            for(var i=0;i<9;i++) {
                if(i != 4 && i % 2 == 0 && view[i].color == 3) {
                    return {cell:i};
                }
            }
            if(view[4].color != 2) {
                //...try diagonal blue
                for(var i=0;i<9;i++) {
                    if(i % 2 == 0 && view[i].color == 7)
                        return {cell:i};
                }
            }
            //...and orthogonal yellow
            for(var i=0;i<9;i++) {
                if(i % 2 == 1 && view[i].color == 2)
                    return {cell:i};
            }
        }
        var n = HIGHWAY_COLORS.indexOf(view[4].color) + 1;
        var nextMove = HIGHWAY_COLORS[n % HIGHWAY_COLORS.length];
        for(var i=0;i<9;i++) {
            if(view[i].color == nextMove) {
                return {cell:i};
            }
        }
    }
    return {cell:-1};
}

function isOnHighway() {
    var match = 0;
    var nxt = HIGHWAY_COLORS[(HIGHWAY_COLORS.indexOf(view[4].color)+1) % HIGHWAY_COLORS.length];//4
    var prv = HIGHWAY_COLORS[(HIGHWAY_COLORS.indexOf(view[4].color)+HIGHWAY_COLORS.length-2) % HIGHWAY_COLORS.length];//6
    for(var i=0;i<9;i++) {
        if(HIGHWAY_COLORS.indexOf(view[i].color) >=0 && (i == 4 || view[i].color != view[4].color))
            match++;
    }
    if(match >= 5) {
        //7,6,4,2,3


        if((view[1].color == nxt && view[7].color == prv)||(view[1].color == prv && view[7].color == nxt) || 
            (view[3].color == nxt && view[5].color == prv)||(view[3].color == prv && view[5].color == nxt)) {
            return true;
        }
        if((view[1].color == view[8].color && (view[1].color == nxt || view[1].color == prv))||(view[1].color == view[6].color && (view[1].color == nxt || view[1].color == prv)) || 
            (view[3].color == view[2].color && (view[3].color == nxt || view[3].color == prv))||(view[3].color == view[8].color && (view[3].color == nxt || view[3].color == prv))) {
            return true;
        }
        if((view[0].color == view[7].color && (view[0].color == nxt || view[0].color == prv))||(view[2].color == view[7].color && (view[2].color == nxt || view[2].color == prv)) || 
            (view[0].color == view[5].color && (view[0].color == nxt || view[0].color == prv))||(view[6].color == view[5].color && (view[6].color == nxt || view[6].color == prv))) {
            return true;
        }
        if(isHighwayCenter()) {
            return true;
        }
    }
    return false;
}

function isHighwayCenter() {
    if(HIGHWAY_COLORS.indexOf(view[4].color) >=0 && (((view[0].color != view[8].color || view[2].color != view[6].color) && view[4].ant.type == 1) || (view[0].color != view[8].color && view[2].color != view[6].color))){
        var m1 = view[1].color == view[7].color;
        var m2 = view[2].color == view[8].color;
        var m3 = view[0].color == view[6].color;
        var m4 = view[0].color != 1 && view[2].color != 1;
        if((m1?1:0)+(m2?1:0)+(m3?1:0) >= 2 && m4) {
            if(view[3].color != view[5].color && ((view[2].color != view[5].color && view[8].color != view[5].color) || view[4].ant.type == 1) && ((view[3].color != view[0].color && view[3].color != view[6].color) || view[4].ant.type == 1)) {
                return true;
            }
        }
        m1 = view[3].color == view[5].color;
        m2 = view[0].color == view[2].color;
        m3 = view[6].color == view[8].color;
        m4 = view[0].color != 1 && view[6].color != 1;
    //good
        if((m1?1:0)+(m2?1:0)+(m3?1:0) >= 2 && m4) {
            m1 = view[1].color != view[7].color;
            m2 = (view[0].color != view[1].color && view[1].color != view[2].color);
            m3 = (view[6].color != view[7].color && view[7].color != view[8].color);
            if(m1 && m2 && m3) {
                return true;
            }
            if(view[4].ant.type == 1 && ((m1?1:0)+(m2?1:0)+(m3?1:0)) >= 2) {
                return true;
            }
        }
    }
    return false;
}

function deRotateSide(m, amt) {
    return deRotate(m,amt*2);
}

/**Positive amount is clockwise**/
function deRotate(m, amt) {
    var rotationsCW = [1,2,5,8,7,6,3,0];
    var rotationsCCW = [3,6,7,8,5,2,1,0];
    if(m == 4 || m < 0 || m > 8 || amt == 0) return m;
    if(amt > 0)
        return rotationsCW[(rotationsCW.indexOf(m)+amt)%8];
    amt = -amt;
    return rotationsCCW[(rotationsCCW.indexOf(m)+amt)%8];
}

function areAdjacent(A, B) {
    if(A == 4 || B == 4 || A == B) return true;
    if(A % 2 == 0 && B % 2 == 0) return false;
    if(A % 2 == 1 && B % 2 == 0) return areAdjacent(B,A);
    if(A % 2 == 1 && B % 2 == 1) return !(8-A == B || 8-B == A);
    if(A == 0 && (B == 1 || B == 3)) return true;
    if(A == 2 && (B == 1 || B == 5)) return true;
    if(A == 6 && (B == 3 || B == 7)) return true;
    if(A == 8 && (B == 5 || B == 7)) return true;
    return false;
}

function findFirstTrail() {
    var pos = 0;
    var b = 0;
    while(view[pos].color != TRAIL && b < 8) {
        pos=deRotate(pos,1);
        b++;
    }
    return pos;
}

function clearAhead(sides) {
    var c=0;
    for(var i=0;i<9;i++) {
        if(view[i].color == 5) c++;
        if(view[i].color == 5 && i%2 == 0) c+=10;
    }
    if(c == 2) {
        if(view[0].color == 5 || view[2].color == 5 || view[6].color == 5 || view[8].color == 5) {
            return {cell:4,color:5};
        }
        if(view[0].ant == null)
            return {cell:0};
        if(view[2].ant == null)
            return {cell:2};
        if(view[6].ant == null)
            return {cell:6};
        if(view[8].ant == null)
            return {cell:8};
    }
    c = 0;
    sides[4] = 0;
    var toMatch =[{state:[1,1,1,
                          2,0,2,
                          0,1,0]},
                 {state:[0,2,1,
                         1,0,1,
                         0,2,1]},
                 {state:[0,1,0,
                         2,0,2,
                         1,1,1]},
                 {state:[1,2,0,
                         1,0,1,
                         1,2,0]}];
    for(var m=0;m<4;m++) {
        var score=0;
        for(var j=0;j<9;j++) {
            if(j!=4) {
                if(sides[j] == 5 && toMatch[m].state[j] == 1) {
                    score++;
                }
                if(sides[j] != 5 && (toMatch[m].state[j] == 0 || toMatch[m].state[j] == 2)) {
                    score++;
                }
                if(sides[j] == 5 && toMatch[m].state[j] == 2) {
                    score--;
                }
            }
        }
        if(score >= 6) {
            var clearOrder=[1,0,2];
            for(var r=0;r<clearOrder.length;r++) {
                var s = deRotateSide(clearOrder[r],m);
                if(view[s].color == 5) {
                    if(view[s].ant == null)
                        return {cell:s,color:8};
                    else
                        return {cell:4};
                }
            }
        }
    }
    return null;
}

function findOpenSpace(pos, dir) {
    if(pos > 8 || pos < 0) return pos;
    var b = 0;
    while(view[pos].ant != null && b < 8) {
        pos=deRotate(pos,dir);
        b++;
    }
    return pos;
}

function getHighestWorker() {
    var r=0;
    for(var i=0;i<9;i++) {
        if(i != 4 && view[i].ant != null) {
            if(view[i].ant.friend && view[i].ant.type > r) r = view[i].ant.type;
        }
    }
    return r;
}

function getNumWorkers(type) {
    var r=0;
    for(var i=0;i<9;i++) {
        if(i != 4 && view[i].ant != null) {
            if(view[i].ant.friend && view[i].ant.type == type) r++;
        }
    }
    return r;
}

function findWorker(type) {
    for(var i=0;i<9;i++) {
        if(i != 4 && view[i].ant != null) {
            if(view[i].ant.friend && view[i].ant.type == type) return i;
        }
    }
    return -1;
}

422% पूर्ण
422% क्योंकि अद्यतन 4/22 पर था यह मजाक बहुत लंबा चला गया है

अमान्य चाल पहचान: चेक
टर्निंग:
जब वे ट्रिम हो जाएं तो रिस्पॉन्डिंग वर्कर्स की जांच करें: ज्यादातर जांचें
कि अन्य चींटियों के भोजन पर चिपके रहने से बचें: ...

अद्यतन 8/1

अक्सर दो बार मुड़ता है, जिसके परिणामस्वरूप ~ 15% अधिक भोजन एकत्र किया जाता है

अद्यतन 8/2

जोड़ा मजबूती बनाम अटक रही है।

अपडेट 9/9

रिस्पांस वर्कर्स 2 और 3 के लिए कोड जोड़ा जब वह हाथ गायब है।

अद्यतन 9/12

पूर्व अद्यतन वापस करें। ग्लाइडर नव स्पंदित हाथ के साथ आगे बढ़ सकता है, लेकिन कार्यकर्ता मोड़ने की कोशिश करते समय क्रम से बाहर निकल जाएगा और यह अलग हो जाएगा।

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

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

एक परिभाषित चर का उपयोग करने के लिए रंग को पुन: कॉन्फ़िगर किया गया और एक रेल की रेल प्रणाली पर खनिकों में "फंसने" से बचने के लिए पीले से हरे रंग में निशान के रंग को बदल दिया (एकल रानी लगातार पुनर्निर्देशित हो जाएगी)।

नए कोड में से कुछ को मेरी अन्य प्रविष्टि, ब्लैक होल से शामिल किया गया है ।

9/13 अपडेट करें

एक बग को चाल-आउट-ऑफ-स्पॉन-ऑरिएंटेशन कोड में ठीक किया गया। 2एस हैंडल के युगल एस में परिवर्तित हो गए TRAIL

1/21 अपडेट करें

  • ग्लाइडर अब बाईं ओर मुड़ सकता है (एनीमेशन लंबित)।
  • भोजन उपलब्ध होते ही एक-एक कार्यकर्ता को जगाकर आरंभिक खेल।
  • एक हाथ की ग्लाइडिंग दोनों दिशाओं को भी मोड़ सकती है।
  • "रिस्पना श्रमिकों का सम्मान न करें"
  • "खाने को बर्बाद करने की कोशिश मत करो और असफल" से कम कर %5दिया%3

1/25 अपडेट करें

  • कुछ गतिरोध परिदृश्यों को ठीक किया, कुछ मैचों में दक्षता को बढ़ा दिया।

2/20 अपडेट करें

  • 5-और और 3-चींटी दोनों विन्यासों को और अधिक स्थिर बनाते हुए कई एज-केस विस्फोट / गतिरोध परिदृश्यों को संबोधित किया। भोजन की कई व्यवस्थाओं के परिणामस्वरूप ग्लाइडर गड़बड़ हो सकता है और या तो गतिरोध (बार-बार आगे और पीछे घूमना) या विस्फोट हो सकता है।
    • एक विस्फोट एक घूर्णन के अंतिम चरण के दौरान भोजन पर घूमने वाले स्वीपर चींटी का परिणाम था, फिर "बकवास, मेरे पास भोजन है, इसे रानी को प्राप्त करने के लिए खुद को बलिदान करें" जब इसे ज़रूरत नहीं थी (मानक कदम वैध था )।
    • एक विस्फोट रानी के तहत सेल का परिणाम था जो पहले से ही TRAIL(हरा) था, जिसके कारण रानी की "स्टे स्टिल" चाल में से एक foreverAlone()को रानी ने समूह से दूर ले जाने के लिए कमज़ोर कर दिया था। एक स्थिर गार्ड बनाकर इसे ठीक किया। रानी के सेल का रंग रानी के एक्शन से ठीक पहले होता है।
    • रानी के कोड को ठीक करने की तुलना में अधिक वांछनीय है, क्योंकि यह हमें गतिरोध से बचने की अनुमति देता है जो अन्यथा गिरने को बनाए रखने foreverAlone(), रानी को बाहर निकालने से हो सकता है, भले ही हम उसके पंखों को नहीं बचा सकते।
  • foreverAlone()अगर रानी के नीचे सेल TRAIL(हरा) है, तो केवल भोजन पर स्थानांतरित होने के लिए फ़ंक्शन अपडेट किया गया है । बहुत मामूली दक्षता हानि।
  • ग्लाइडर अधिक पुनर्निर्माण के लिए एक आसन्न हरी कोशिका, एक परिवर्तन findFirstYellow()और इसके उपयोग का पता लगाता है । यह, पहले देखी गई कोशिकाओं और / या हाल ही में विस्फोट की साइट के बेहतर परिहार में पिछली गोली के परिणाम के साथ संयुक्त: एक नवगठित ग्लाइडर होगा - बड़े मामलों में - रानी के आने के साथ नहीं एक दिशा में आगे बढ़ें प्रक्षेपवक्र।
    • बदला हुआ नाम: पीला लंबे, लंबे समय में रानी के निशान का रंग नहीं रहा है।
    • उल्टे तर्क की जाँच के कारण फ़ंक्शन गलत तरीके से "ट्रेल की पहली सेल" का पता लगा रहा था : के while ==बजायwhile !=

2/25 अपडेट करें

  • अधिक धार-विस्फोट / दुर्घटना / गतिरोध सुधार, समग्र प्रदर्शन में सुधार।
  • Alion द्वारा सुझाए गए लाइटस्पेड-जैसे व्यवहार में कुछ परिवर्तन, ( अपनी प्रविष्टि के व्यवहार से )। आम तौर पर भोजन संग्रह बढ़ता है, लेकिन कुछ गतिरोध परिदृश्यों से भी बचा जाता है।

अपडेट 3/11: टूटा हुआ ग्लाइडर पंख जो खुद को वैम्पायर की तरह व्यवहार करने पर "वैद्य भोजन" चुराता है। मुख्य रूप से इसका मतलब यह नहीं होगा कि जब तक रानी खुद राजमार्ग के अंदर अकेली न हो जाए , जो कि हरे रंग की विशाल मात्रा के साथ, इससे बचने के लिए एक असंभव जगह बना देती है।

कार्यकर्ता 1 राजमार्ग केंद्रीय गलियारे पर मरम्मत करने का प्रयास करेगा और यदि वह खुद को राजमार्ग नहीं है, जो रेल नहीं है (एक झूठे केंद्र की मरम्मत के बजाय), तो यह एक सर्वश्रेष्ठ अनुमान गर्भपात करता है। रानी के रूप में एक ही दिशा में यात्रा (श्रमिकों 2, 3, और 4 के लिए काउंटर)।

श्रमिक 2, 3, और 4 हाईवे क्वीन पर ड्राइव-बाय चोरी करने का प्रयास करते हैं, फिर अपनी रानी के पास लौटते हैं, जब वह श्रमिकों को बचाती है ...

  • अपने ही किसी कार्यकर्ता को नहीं देख सकता
  • मजेंटा पर बैठा है
  • थ्रेसहोल्ड के बीच भोजन होता है (दोनों तरफ नरम सीमाओं के साथ)
  • एक साधारण यादृच्छिक द्वारा संशोधित

यह बहुत से श्रमिकों को बनाने से बचता है (~ 100 तक काम करता है) और जब लादेन श्रमिकों की एक स्ट्रिंग वापस आती है, तो शुद्ध खाद्य आय होती है (खुद के श्रमिकों को देखते समय नो-स्पोविंग के कारण) अंततः ग्लाइडर को शीर्ष सीमा से ऊपर धकेलते हैं और (बड़े पैमाने पर) कम) नए कार्यकर्ता।

यह एक ऐसी युक्ति थी जिसे मैं वैम्पायर में लिखने की योजना बना रहा था, लेकिन वैम्पायर का पहला प्रयास हाइवे क्वीन को अवरुद्ध करने और उसके शुष्क काम को ख़त्म करने का था, इसलिए इस व्यवहार को बनाने के लिए कोई प्रोत्साहन नहीं था। ऑन-हाइवे डिटेक्शन कोड स्क्रैच से लिखा गया है और वैम्पायर से अलग है, हालांकि मिरर-डिटेक्शन (IsHighwayCenter) पैटर्न की सादगी के कारण बहुत समान है।

अपडेट ३/१६

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

फालबैक मूवमेंट मेथड तब जोड़ा गया जब highwayRobbery()फंक्शन हाइवे सेंटर में चींटी होने पर एक वैध कदम वापस करने में विफल रहा (और किसी अन्य तर्क ने इसे समझदार मूल्य पर समायोजित नहीं किया था)। यदि वह विफल रहता है, तो चींटियाँ अपने मानक ग्लाइडिंग तर्क का प्रदर्शन करती हैं।

छोटी सी टहनी

  • रानी अब यह बताने की कोशिश नहीं करती कि जब वह हाईवे पर होती है, तो वह स्पॉइंग शुरू करने का प्रयास करती है
  • क्वीन अब एक ग्लाइडर गठन को पूरा करने की कोशिश कर रहे कैलोरी के माध्यम से जलता नहीं है जो कभी भी पूरा नहीं होगा (एक श्रमिक 4 पर काम करता है, श्रमिक 4 को कार्यकर्ता 1 नहीं दिखता है, कार्यकर्ता 4 दूर हटता है, दोहराता है)
  • समायोजित खाद्य modulo मूल्यों राजमार्ग रंग चक्र के साथ मुकाबला करने के लिए।
  • एक "1 हाथ से बारी बारी से खत्म होना" तय किया जो गतिरोध पैदा कर रहा था
  • माइनर isOnHighway()चेक को ठीक करता है
  • हाईवे में जब एक ऑर्थोगोनल ब्लू सेल पर जाने से पहले चींटियों ने एक ऑर्थोगोनल पीले रंग में कदम रखा, (1 चक्कर लगाने के बाद केंद्र को खोजने के लिए 1 मोड़ बचाता है)।

अपडेट ३/२६

अधिक मामूली मोड़।

अद्यतन 4/21

मामूली सुधार।


भाप से चलने वाले पर आधारित है ।

एक पीले निशान के पीछे छोड़ते हुए 4 भोजन। एक बार चार भोजन हो जाने के बाद, यह अपने चारों ओर प्रत्येक श्रमिक प्रकार का उत्पादन करता है। इसके बाद अधिकतम थ्रस्ट पर ग्लाइडिंग शुरू होती है। शीर्ष पर चल रहा एनीमेशन 1 गेम को पूरा करने के लिए ले जाता है: जैसा कि कार्यकर्ता 1 का उत्पादन पहले किया जाता है, यह रानी के साथ बारी खत्म करने से पहले, पहले 2, 3 और 4 को निष्पादित करता है। टर्निंग एनिमेशन में 2 मोड़ आते हैं, लघु ठहराव तब होते हैं जब रानी प्रदर्शन करती है {cell:4}और भोजन चलता रहता है जब श्रमिक 3, 4, और रानी सभी {cell:4}निरंतर ग्लाइडिंग की तैयारी के लिए प्रदर्शन करते हैं ।


मुझे यह बॉट आइडिया पसंद है
डिस्ट्रक्टिबल लेमन

1
@DestructibleLemon धन्यवाद! मैं स्टीमर / पियर्सर के बारे में सोच रहा था और अपने आप को "पकड़ पर" सोचा था, रानी अंतिम जाती है, निश्चित रूप से मुझे अच्छा खेलने के लिए पांच चींटियां मिल सकती हैं ... "कागज का एक टुकड़ा पकड़ा, कुछ चौकों को फाड़ दिया, और उन्हें चारों ओर ले जाना शुरू कर दिया। यह काम किया तो मैंने कुछ कोड लिखे। किनारे के मामलों के लिए बहुत सी त्रुटि हैंडलिंग और बग फिक्सिंग करना पड़ा (प्रारंभिक बॉट अटक जाएगा या सभी भोजन का उपभोग कर सकता है और किया जा सकता है, बारी ऑपरेशन को जोड़कर बहुत सारे किनारे मामले परिदृश्य पेश किए गए जहां यह गठन और दुर्घटना को तोड़ देगा। )।
ड्रेको

@trichoplax जब तक यह एक और चींटी में क्रैश हो जाता है?
विनाशकारी नींबू

@DestructibleLemon eeeehhhh ... शायद। यह कम से कम अयोग्य नहीं हो जाता ...
ड्रेक 18s

3
@KZhang ओह मैंने किया। टिप्पणियों के लिए देखें "// प्रयास घुमाएँ"
Draco18s

13

विंडमिल

यहाँ एक पवनचक्की है ... ला मांचा (या ला मांचा से पिशाच?) से आदमी की प्रतीक्षा कर रहा हूँ जो उसे नीचे लाने के लिए सवारी करेगा।

विंडमिल, खेल के शुरुआती मध्य चरण

मैं कितना आगे की डिजाइन का पता लगाने की कोशिश की एक रेल पर खनिकों अब है कि इसका जवाब के इतिहास संपादित की चपेट में आ - - अवलोकन है कि स्टेपिंग पत्थर बेहतर पर पेंट किया था, धक्का दिया जा सकता है के लिए प्रेरित किया वैकल्पिक मेरा शाफ्ट की दीवारों। और फिर यह विकसित हुआ और विकसित हुआ ...

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

var AJM=1;var ASM=2;var AE=3;var ASF=4;var AQ=5;var RW=true;var EFCO=false;var THC=1;var TH0=0;var TH1=15;var TH2=17;var TH3=67;var TH4=120;var TH5=390;var THX=15;var THFCO1=9;var THFCO2=26;var THFCO3=75;var RM1=7;var RD1=4;var RM2=19;var RD2=THX;var PW=1;var PY=2;var PP=3;var PC=4;var PR=5;var PG=6;var PB=7;var PK=8;var LN=0;var LCLR=PW;var LT=PB;var LLSF=PP;var LA=PP;var LRL0=PC;var LRL1=PG;var LRL2=LRL0;var LRM0=PR;var LRM1=PB;var LRM1_WRP=PK;var LRM2=PG;var LRR0=PG;var LRR1=PW;var LRR1U=PR;var LRR1V=PY;var LRR1X=PK;var LRR2=PY;var LMX_M0=LCLR;var LMX_M1IN=PC;var LMX_M1OUT=PY;var LMX_M2IN=PP;var LMX_M2OUT=PR;var LMX_M3IN=PB;var LMX_M3OUT=PK;var LMS_WRP=PK;var LMR0=PK;var LML1=PY;var LMR2=PR;var LML3=PC;var LMMF=PG;var LMMH=PP;var LG3=PK;var LG4=PR;var LG5=PK;var LG6=PB;var LP0=LCLR;var LPB=PC;var LPG=PY;var LPG1=PR;var LPX=PP;var FALSE_X9=[false,false,false,false,false,false,false,false,false];
var UNDEF_X9=[undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined,undefined];
var QCPERD=6;var LCL_QC_RESET=LCLR;var LCRQC=[PY,PP,PC,PR,PG,PK];var LCRQCVAL=Array.from(FALSE_X9);var LCRQC_VALUE=Array.from(UNDEF_X9);for (var i=0; i<QCPERD; i++){LCRQCVAL[LCRQC[i]]=true;LCRQC_VALUE[LCRQC[i]]=i;}var SCPERD=7;var LCL_SC_RESET=LCLR;var LCRSC=[PY,PP,PC,PR,PG,PB,PK];var LCRSCVAL=Array.from(FALSE_X9);var LCRSC_VALUE=Array.from(UNDEF_X9);for (i=0; i<SCPERD; i++){LCRSCVAL[LCRSC[i]]=true;LCRSC_VALUE[LCRSC[i]]=i;}var LCRPHR=Array.from(FALSE_X9);LCRPHR[LPG]=true;LCRPHR[LPG1]=true;var LCRPHASES=Array.from(LCRPHR);LCRPHASES[LPX]=true;var LCRGRM1=Array.from(FALSE_X9);LCRGRM1[LRM1]=true;LCRGRM1[LRM1_WRP]=true;var LCRGRM_ALL=Array.from(FALSE_X9);LCRGRM_ALL[LRM0]=true;LCRGRM_ALL[LRM1]=true;LCRGRM_ALL[LRM1_WRP]=true;LCRGRM_ALL[LRM2]=true;var LCRGRR1_OUT=Array.from(FALSE_X9);LCRGRR1_OUT[LRR1V]=true;LCRGRR1_OUT[LRR1X]=true;var LCRGRR1B=Array.from(LCRGRR1_OUT);LCRGRR1B[LRR1U]=true;var LCRGRR1=Array.from(LCRGRR1B);LCRGRR1[LRR1]=true;var LCRMX_IO=Array.from(FALSE_X9);LCRMX_IO[LMX_M1IN]=true;LCRMX_IO[LMX_M1OUT]=true;LCRMX_IO[LMX_M2IN]=true;LCRMX_IO[LMX_M2OUT]=true;LCRMX_IO[LMX_M3IN ]=true;LCRMX_IO[LMX_M3OUT]=true;var LCRMX=Array.from(LCRMX_IO);LCRMX[LMX_M0]=true;var LCRMX_IN=Array.from(FALSE_X9);LCRMX_IN[LMX_M1IN]=true;LCRMX_IN[LMX_M2IN]=true;LCRMX_IN[LMX_M3IN ]=true;var LCRMX_OUT=Array.from(FALSE_X9);LCRMX_OUT[LMX_M1OUT]=true;LCRMX_OUT[LMX_M2OUT]=true;var LCRMM_FOOD=Array.from(FALSE_X9);LCRMM_FOOD[LCLR]=true;LCRMM_FOOD[LMMF]=true;var LCRMM_HOME=Array.from(FALSE_X9);LCRMM_HOME[LCLR]=true;LCRMM_HOME[LMMH]=true;var LCRMS=Array.from(FALSE_X9);LCRMS[LCLR]=true;LCRMS[LMS_WRP]=true;var LCRFRLL0=Array.from(FALSE_X9);LCRFRLL0[LCLR]=true;LCRFRLL0[LMR0]=true;LCRFRLL0[LMR2]=true;LCRFRLL0[LRM0]=true;LCRFRLL0[LRM2]=true;var LCRFRLL1=Array.from(FALSE_X9);LCRFRLL1[LCLR]=true;LCRFRLL1[LMR0]=true;LCRFRLL1[LMR2]=true;LCRFRLL1[LRR0]=true;LCRFRLL1[LRM1]=true;LCRFRLL1[LRR2]=true;var LCRFRLL2=Array.from(FALSE_X9);LCRFRLL2[LCLR]=true;LCRFRLL2[LMR0]=true;LCRFRLL2[LMR2]=true;LCRFRLL2[LRM0]=true;LCRFRLL2[LRR1V]=true;var TN=8;var POSC=4;var NOP={cell:POSC};var AIMU=1;var AIML=3;var AIMR=5;var AIMD=7;var FWD_CELLS=[[ true,true,false,true,true,false,false,false,false ],[ true,true,true,true,true,true,false,false,false ],[ false,true,true,false,true,true,false,false,false ],[ true,true,false,true,true,false,true,true,false ],[ true,true,true,true,true,true,true,true,true ],[ false,true,true,false,true,true,false,true,true ],[ false,false,false,true,true,false,true,true,false ],[ false,false,false,true,true,true,true,true,true ],[ false,false,false,false,true,true,false,true,true ]];var PTNOM=-9;var PTHOME=[LRM0,LRL0,LRM0,LRL0,LN,LRL0,LN,LN,LRM0];var PTGARDEN=[LG6,LG5,LG4,LN,LN,LG3,LN,LRL0,LRL1];var PTFRM0=[LRL1,LRM1,LCRGRR1,LRL0,LRM0,LRR0,LRL2,LRM2,LRR2];var PTFRM1=[LRL2,LRM2,LRR2,LRL1,LCRGRM1,LCRGRR1,LRL0,LRM0,LRR0];var PTFRM2=[LRL0,LRM0,LRR0,LRL2,LRM2,LRR2,LRL1,LCRGRM1,LCRGRR1];var PTGRM0=[LRL1,LCRGRM1,LCRGRR1,LRL0,LRM0,LRR0,LRL2,LRM2,LRR2];var PTGRM1=PTFRM1;var PTGRM2=PTFRM2;var PTGRM2B=[LRL0,LRM0,LRR0,LRL2,LRM2,LRR2,LRL1,LCRGRM1,LCRGRR1B];var PTGRM1_WRP=[LRL2,LRM2,LRR2,LRL1,LRM1_WRP,LRR1X,LRL0,LRM0,LRR0];var PTFRL0=[LCRFRLL1,LRL1,LRM1,LCRFRLL0,LRL0,LRM0,LCRFRLL2,LRL2,LRM2];var PTFRL1=[LCRFRLL2,LRL2,LRM2,LCRFRLL1,LRL1,LCRGRM1,LCRFRLL0,LRL0,LRM0];var PTFRL0H=[LN,LRL1,LRM1,LN,LRL0,LRM0,LN,LN,LN];var PTFRL1G=[LCRFRLL2,LRL2,LRM2,LG3,LRL1,LCRGRM1,LCRPHASES,LRL0,LRM0];var PTFRL2=[LCRFRLL0,LRL0,LRM0,LCRFRLL2,LRL2,LRM2,LCRFRLL1,LRL1,LCRGRM1];var PTGRL0=[LCRFRLL1,LRL1,LCRGRM1,LCRFRLL0,LRL0,LRM0,LCRFRLL2,LRL2,LRM2];var PTGRL1=PTFRL1;var PTGRL2=PTFRL2;var PTGRR0=[LCRGRM1,LCRGRR1,LCLR,LRM0,LRR0,LMR0,LRM2,LRR2,LCRMX];var PTGRR2=[LRM0,LRR0,LMR0,LRM2,LRR2,LCRMX,LCRGRM1,LCRGRR1,LCLR];var PTGRR1=[LRM0,LCRGRM1,LRM2,LRR0,LCRGRR1,LRR2,LMR0,LCLR,LCRMX];var PTMS0R_IN=[LRR0,LRR1U,LRR2,LMR0,LCLR,LCRMX_IN,LCLR,LCLR,LML1];var PTMS0R_OUT=[LRR0,LRR1U,LRR2,LMR0,LCLR,LCRMX_IO,LCLR,LCLR,LML1];var PTMS0R_OUT1=[LRR0,LCRGRR1_OUT,LRR2,LMR0,LCLR,LCRMX,LCLR,LCLR,LML1];var PTMS0=[LCLR,LCRMM_HOME,LML3,LMR0,LCRMM_FOOD,LCLR,LCLR,LCLR,LML1];var PTMS1=[LMR0,LCRMM_HOME,LCLR,LCLR,LCRMM_FOOD,LML1,LMR2,LCLR,LCLR];var PTMS2=[LCLR,LCRMM_HOME,LML1,LMR2,LCRMM_FOOD,LCLR,LCLR,LCLR,LML3];var PTMS3=[LMR2,LCRMM_HOME,LCLR,LCLR,LCRMM_FOOD,LML3,LMR0,LCLR,LCLR];var PTMS1_IN=[LMR0,LCRMM_HOME,LCRMX_IN,LCLR,LCRMM_FOOD,LML1,LMR2,LCLR,LCLR];var PTMS1_IO=[LMR0,LCRMM_HOME,LCRMX_IO,LCLR,LCRMM_FOOD,LML1,LMR2,LCLR,LCLR];var PTMS0_OUT=[LCLR,LCLR,LML3,LMR0,LCLR,LCRMX_IO,LCLR,LCLR,LML1];var PTMS0_WRAPPING=[LCLR,LCRMM_HOME,LML3,LMR0,LCRMM_FOOD,LCRMS,LRL0,LRL1,LRL2];var PTGRL1_WRP=[LMR0,LCLR,LMS_WRP,LRL0,LRL1,LRL2,LRM0,LRM1_WRP,LRM2];var PTMS0FL=[LMMH,LML3,LN,LMMF,LCLR,LN,LCLR,LML1,LN];var PTMS1FL=[LMMH,LCLR,LN,LMMF,LML1,LN,LCLR,LCLR,LN];var PTMS2FL=[LMMH,LML1,LN,LMMF,LCLR,LN,LCLR,LML3,LN];var PTMS3FL=[LMMH,LCLR,LN,LMMF,LML3,LN,LCLR,LCLR,LN];var PTMS0FR=[LN,LCLR,LMMH,LN,LMR0,LMMF,LN,LCLR,LCLR];var PTMS1FR=[LN,LMR0,LMMH,LN,LCLR,LMMF,LN,LMR2,LCLR];var PTMS2FR=[LN,LCLR,LMMH,LN,LMR2,LMMF,LN,LCLR,LCLR];var PTMS3FR=[LN,LMR2,LMMH,LN,LCLR,LMMF,LN,LMR0,LCLR];var CCW=[6,7,8,5,2,1,0,3,6,7,8,5,2,1,0,3,6,7,8,5,2,1];
var xn=-1;var fwdWrong=[];var rearWrong=[];var here=view[POSC];var mC=here.color;var myself=here.ant;var mT=myself.type;var mF=myself.food;var mS=(mT==AE||(mT!=AQ&&mF>0));if (EFCO&&(mT==AQ)){if (mF<=THFCO1){QCPERD=5;} else if (mF<=THFCO2){QCPERD=4;} else if (mF<=THFCO3){QCPERD=5;}}var dOK=[true,true,true,true,true,true,true,true,true];
var uo=true;var sL=[0,0,0,0,0,0,0,0,0];var sD=[0,0,0,0,0,0,0,0,0];var sN=[0,0,0,0,0,0,0,0,0];var sT=[0,0,0,0,0,0,0,0,0];var fdL=0;var fdD=0;var fdT=0;sT[mC]++;for (i=0; i<TN; i+=2){var cell=view[CCW[i]];sD[cell.color]++;sN[cell.color]++;sT[cell.color]++;if (cell.food>0){fdD++;fdT++;if (mS){dOK[CCW[i]]=false;uo=false;}}}for (i=1; i<TN; i+=2){var cell=view[CCW[i]];sL[cell.color]++;sN[cell.color]++;sT[cell.color]++;if (cell.food>0){fdL++;fdT++;if (mS){dOK[CCW[i]]=false;uo=false;}}}var aF=[0,0,0,0,0,0];var aLF=[0,0,0,0,0,0];var aUF=[0,0,0,0,0,0];var fT=0;var mQ=0;var aE=[0,0,0,0,0,0];var aLE=[0,0,0,0,0,0];var aUE=[0,0,0,0,0,0];var eT=0;for (i=0; i<TN; i++){var cell=view[CCW[i]];if (cell.ant){if (cell.ant.friend){aF[cell.ant.type]++;fT++;if (cell.ant.type==AQ){xn=i&6;mQ=i&1;}if (cell.ant.food>0){aLF[cell.ant.type]++;} else {aUF[cell.ant.type]++;}} else {aE[cell.ant.type]++;eT++;if (cell.ant.food>0){aLE[cell.ant.type]++;} else {aUE[cell.ant.type]++;}}dOK[CCW[i]]=false;uo=false;}}switch (mT){case AQ:return (rQSs());case ASF:if (mQ==1){return (rSSs());} else if (aF[AQ]>0){return (rGSs());} else {return (rLSSy());}case AE:return (rESs());case AJM:case ASM:if (aE[AQ]>0){return (rDSs());} else if (mF>0){return (rLSs());} else {return (rUSs());}default:return NOP;}function rQSs (){switch (aF[ASF]){case 0:return (rQScrSy());case 1:for (var i=0; i<TN; i++){var cell=view[CCW[i]];if (cell.ant&&cell.ant.type==ASF){xn=i&6;if (i&1){if (mF<=THX){return (rQLsSy());} else {return (rQLvSy());}} else {return (rQSgSy());}}}break;case 2:for (i=0; i<TN; i+=2){var cell0=view[CCW[i]];var cell1=view[CCW[i+1]];if ((cell0.ant&&(cell0.ant.type==ASF))&&(cell1.ant&&(cell1.ant.type==ASF))){xn=i;return (rQOSy());}}return (rQCSy());default:return (rQCSy());}return NOP;}function rSSs (){if (view[CCW[xn+3]].ant&&view[CCW[xn+3]].ant.friend&&(view[CCW[xn+3]].ant.type==ASF)){return (rSOSy());} else if (view[CCW[xn+1]].ant.food<=THX){return (rSLSy());} else {return (rSESy());}}function rGSs (){var secCell=view[CCW[xn+7]];if (secCell.ant&&(secCell.ant.friend==1)&&(secCell.ant.type==ASF)){return (rGOSy());} else {return (rGSSy());}return NOP;}function rESs (){if (aF[AQ]>0){return (rEHyS());} else if (aF[AJM] +aF[ASM]>0){return (rEBRSy());} else {return (rEASy());}return NOP;}function rDSs(){if (aF[AQ]>0){return (rDHSy());} else {for (var i=0; i<TN; i++){if (view[CCW[i]].ant&&(view[CCW[i]].ant.type==AQ)){if (i&1){if ((view[CCW[i+1]].ant&&view[CCW[i+1]].ant.friend&&view[CCW[i+2]].ant&&view[CCW[i+2]].ant.friend)||(view[CCW[i-1]].ant&&view[CCW[i-1]].ant.friend&&view[CCW[i+6]].ant&&view[CCW[i+6]].ant.friend)||(view[CCW[i+2]].ant&&view[CCW[i+2]].ant.friend&&view[CCW[i+6]].ant&&view[CCW[i+6]].ant.friend)){if (dOK[CCW[i+4]]){return {cell:CCW[i+4]};} else if (dOK[CCW[i+3]]){return {cell:CCW[i+3]};} else if (dOK[CCW[i+5]]){return {cell:CCW[i+5]};}}} else {if (view[CCW[i+1]].ant&&view[CCW[i+1]].ant.friend&&
view[CCW[i+7]].ant&&view[CCW[i+7]].ant.friend){if (dOK[CCW[i+4]]){return {cell:CCW[i+4]};} else if (dOK[CCW[i+3]]){return {cell:CCW[i+3]};} else if (dOK[CCW[i+5]]){return {cell:CCW[i+5]};} else if (dOK[CCW[i+6]]){return {cell:CCW[i+6]};} else if (dOK[CCW[i+2]]){return {cell:CCW[i+2]};}}if ((i<=2)&&dOK[CCW[i+7]]){return {cell:CCW[i+7]};}if ((i>=4)&&dOK[CCW[i+1]]){return {cell:CCW[i+1]};}}if (fT==0){if (view[CCW[i]].color!=PP){return {cell:CCW[i],color:PP};} else if (mC!=LCLR){return {cell:POSC,color:LCLR};}}}}}return NOP;}function rUSs (){if ((aF[AQ]>0)&&!LCRQCVAL[view[CCW[xn+mQ]].color]){return (rUHSy());} else if ((fT+eT>=4)&&(aF[AJM]+aF[ASM] +aF[AE]>=3)){return (rUCRSy());} else if (aF[AQ]>0){return (rUHSy());} else if (aF[ASF]>0){if (aF[ASF]>1){return (rM2R1Sy());} else {return (rURHSy());}} else if (aF[AE]>0){return (rUBRSy());} else if (spcRL1()){return (rULRL1Sy());} else if (spcRR0()){return (rULRR0Sy());} else if (spcRR2()){return (rULRR2Sy());} else if (spcMS()){return (rUDSSy());} else if (spcRL02()){return (rULRL02Sy());} else if (spcRM()){return (rUTRRSy());} else if (spcRR1()){return (rUPSSy());} else if (spcMS0R()){return (rUESSy());} else if (spcMS0W()){return (rUSWSy());}return (rLostMSy(true));}function rLSs (){if ((fT>=3)&&(fT+eT>=4)){return (rLCRSy());} else if (aF[ASF]>0){if (aF[ASF]>1){return (rM2R1Sy());} else {return (rLRHSy());}} else if (spcMFL()){return (rLLLWSy());} else if (spcMFR()){return (rLLRWSy());} else if (spcRL1()){return (rLLRL1Sy());} else if (spcRR0()){return (rLLRR0Sy());} else if (spcRR2()){return (rLLRR2Sy());} else if (spcMS0R()){return (rLLSSy());} else if (spcMS0ROut()){return (rLLVSSy());} else if (spcMS()&&(aF[AE]==0)){return (rLASSy());} else if (spcRL02()){return (rLLRL02Sy());} else if (spcRM()){return (rLTRRSy());} else if (spcRR1()){return (rLDSSy());} else if (aF[AE]>0){return (rLFRSy());}return (rLostMSy(true));}function rQScrSy(){if (uo){if (fdT>0){return (rQSETc());} else if (mF>=THC){for (var i=0; i<TN; i+=2){if ((view[CCW[i]].color==LT)||(view[CCW[i+1]].color==LT)){return {cell:CCW[i+1],type:ASF};}}return {cell:1,type:ASF};} else if (mC!=LT){if ((mC==LCLR)||(sN[LCLR]>=TN-1)){return {cell:POSC,color:LT};} else {return (rQSTCTc());}} else if ((sN[LCLR]>=4)&&(sN[LT]==1)){for (var i=0; i<TN; i+=2){if ((view[CCW[i]].color==LT)||(view[CCW[i+1]].color==LT)){return {cell:CCW[i+4]};}}} else if (sN[LCLR]==TN){return {cell:0};} else {return (rQSATc());}} else {if ((fdT>0)&&(eT>0)&&(eT==aE[AQ])){return (rQSSTc());} else {return (rQSEvTc());}}return NOP;}function rQSgSy(){if (fdT>0){if (dOK[CCW[xn+1]]){return {cell:CCW[xn+1]};} else {for (var i=2; i<TN-1; i++){if (dOK[CCW[xn+i]]&&(view[CCW[xn+i]].food>0)){return {cell:CCW[xn+i]};}}for (var i=2; i<TN-1; i++){if (dOK[CCW[xn+i]]){     return {cell:CCW[xn+i]};}}return NOP;}} else if ((mF>TH0)&&(mC==LCL_QC_RESET)){if (dOK[CCW[xn+7]]){return { cell:CCW[xn+7],type:AE};} else if (view[CCW[xn]].color==LPB){if (dOK[CCW[xn+3]]){return { cell:CCW[xn+3],type:AE};} else if (dOK[CCW[xn+5]]){return { cell:CCW[xn+5],type:AE};} else if (dOK[CCW[xn+6]]){return { cell:CCW[xn+6],type:AJM};} else if (dOK[CCW[xn+2]]){return { cell:CCW[xn+2],type:AJM};} else if (dOK[CCW[xn+4]]){return { cell:CCW[xn+4],type:AJM};} else if (dOK[CCW[xn+1]]){return { cell:CCW[xn+1],type:ASF};}}}return NOP;}function rQOSy(){if ((aE[AQ]>0)&&(mF>0)){for (var i=2; i<TN; i++){if (view[CCW[xn+i]].ant&&(view[CCW[xn+i]].ant.type==AQ)&&!view[CCW[xn+i]].ant.friend){var j=(xn&4) ? 1 : -1;if (dOK[CCW[xn+i-j]]){return {cell:CCW[xn+i-j],type:AJM};} else if (dOK[CCW[xn+i+j]]){return {cell:CCW[xn+i+j],type:AJM};} else if (i==5){var i1=5-2*j;var i2=5+2*j;if (dOK[CCW[xn+i1]]&&!(view[CCW[xn+4]].ant&&view[CCW[xn+4]].ant.friend&&
view[CCW[xn+6]].ant&&view[CCW[xn+6]].ant.friend&&
view[CCW[xn+i2]].ant&&view[CCW[xn+i2]].ant.friend)){return {cell:CCW[xn+i1],type:AJM};} else if (dOK[CCW[xn+i2]]&&!(view[CCW[xn+4]].ant&&view[CCW[xn+4]].ant.friend&&
view[CCW[xn+6]].ant&&view[CCW[xn+6]].ant.friend&&
view[CCW[xn+i1]].ant&&view[CCW[xn+i1]].ant.friend)){return {cell:CCW[xn+i2],type:AJM};}} else if ((i==3)&&dOK[CCW[xn+5]]&&!(view[CCW[xn+2]].ant&&view[CCW[xn+2]].ant.friend&&
view[CCW[xn+4]].ant&&view[CCW[xn+4]].ant.friend)){return {cell:CCW[xn+5],type:AJM};} else if ((i==7)&&dOK[CCW[xn+5]]&&!(view[CCW[xn+6]].ant&&view[CCW[xn+6]].ant.friend)){return {cell:CCW[xn+5],type:AJM};}}}} else if ((mF>0)&&(view[CCW[xn+7]].color==LA)&&dOK[CCW[xn+7]]){return {cell:CCW[xn+7],type:AJM};} else if (view[CCW[xn+1]].ant.food>0){if ((mF>0)&&dOK[CCW[xn+2]]){return {cell:CCW[xn+2],type:AJM};}} else if ((aLF[AJM]+aLF[ASM]>0)&&(mF>0)&&(sN[LA]>0)){for (var i=2; i<TN; i++){var c=CCW[xn+i];if (dOK[c]&&(view[c].color==LA)){return {cell:c,type:AJM};}}} else if (eT>0){var bandits=aUE[1]+aUE[2]+aUE[3]+aUE[4];if ((mF>THX)&&((bandits>=2)||((bandits>=1)&&view[CCW[xn+5]].ant&&view[CCW[xn+5]].ant.friend&&(view[CCW[xn+5]].color==LA)&&(view[CCW[xn+7]].ant&&view[CCW[xn+7]].ant.friend&&
(view[CCW[xn+7]].color==LA))||(view[CCW[xn+3]].ant&&view[CCW[xn+3]].ant.friend&&
(view[CCW[xn+3]].color==LA))))){if (dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};}}if (mF<RD1){if (dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};}} else if ((bandits>=1)&&(mF>0)){if ((mF>THX)&&(mF % RM2==RD2+xn/2)){if (dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};}}for (var i=2; i<TN; i++){var c=CCW[xn+i];var c1,c2;if ((xn==2)||isSc0(view[CCW[xn+1]].color)){c1=CCW[xn+i-1];c2=CCW[xn+i+1];} else if ((xn==6)||isSc1(view[CCW[xn+1]].color)){c1=CCW[xn+i+1];c2=CCW[xn+i-1];} else {break;}if (view[c].ant&&!view[c].ant.friend&&(view[c].ant.food==0)){if (dOK[c1]&&!(view[c2].ant&&view[c2].ant.friend&&view[c2].ant.food>0)){return {cell:c1,type:AJM};} else if (dOK[c2]&&!(view[c1].ant&&view[c1].ant.friend&&view[c1].ant.food>0)){return {cell:c2,type:AJM};}break;}}}}if (!(LCRQCVAL[mC])){return {cell:POSC,color:LCRQC[1]};} else if ((view[CCW[xn]].color==LPX)&&isSc0(view[CCW[xn+1]].color)){if ((mF<=TH0)||(mF % RM1==RD1)){return (rQHTc());} else if (mF<=TH2){if (dOK[CCW[0]]){return {cell:CCW[0],type:AJM};} else {return (rQHTc());}} else {var destCycle=[2,4,6,4,6,2,6,2,4];var destination=destCycle[mF % 9];if (!dOK[CCW[xn+destination]]){destination=destination % 6+2;}if (!dOK[CCW[xn+destination]]){destination=destination % 6+2;}if (!dOK[CCW[xn+destination]]){return (rQHTc());}if (mF<=TH3){if (xn<=2){return {cell:CCW[xn+destination],type:AJM};} else {return (rQHTc());}} else if (mF<=TH4){if (xn<=2){return {cell:CCW[xn+destination],type:((xn>0) ? AJM : ASM)};} else {return (rQHTc());}} else if (mF<=TH5){if (xn==0){return {cell:CCW[xn+destination],type:ASM};} else {return (rQHTc());}} else {return (rQHTc());}}} else {return {cell:POSC,color:incQc(mC)};}return NOP;}function rQLsSy(){if (mF>=TH1){if (mC!=LCLR){return {cell:POSC,color:LCLR};} else {for (var i=0; i<TN; i+=2){if (view[CCW[i]].color!=LCLR){return {cell:CCW[i],color:LCLR};}}}if ((eT==0)&&(fT==1)){return {cell:CCW[xn+3]};}}if ((eT==0)&&(fT==1)){if (view[CCW[xn+2]].food>0){return {cell:CCW[xn+2]};} else if ((view[CCW[xn+3]].food +view[CCW[xn+4]].food>0)&&(view[CCW[xn+1]].color!=LLSF)){return NOP;} else {return {cell:CCW[xn+2]};}} else if (dOK[CCW[xn+2]]&&(dOK[CCW[xn+3]]||(view[CCW[xn+3]].ant&&view[CCW[xn+3]].ant.friend))){return {cell:CCW[xn+2]};} else if (dOK[CCW[xn]]&&dOK[CCW[xn+7]]){return {cell:CCW[xn]};} else if (dOK[CCW[xn+6]]){return {cell:CCW[xn+6]};} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else {return NOP;}}function rQLvSy(){if (dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};}return NOP;}function rQCSy(){return NOP;}function rSOSy(){if (!(LCRSCVAL[mC])){return {cell:POSC,color:LCRSC[1]};} else if (isSc0(mC)&&isQc0(view[CCW[xn+1]].color)&&
(view[CCW[xn+3]].color==LPG)){return {cell:CCW[xn+3],color:LPX};} else {return {cell:POSC,color:incSc(mC)};}return NOP;}function rSLSy(){if ((eT==0)&&(fT==1)){if (view[CCW[xn]].food>0){return {cell:CCW[xn]};} else if (view[CCW[xn+7]].food +view[CCW[xn+6]].food>0){return {cell:POSC,color:LLSF};} else {return {cell:CCW[xn]};}} else if ((eT>0)&&view[CCW[xn+2]].ant&&!view[CCW[xn+2]].ant.friend){return {cell:POSC,color:LLSF};} else {if (dOK[CCW[xn]]){return {cell:CCW[xn]};} else if (dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};}}return NOP;}function rSESy(){if (view[CCW[xn+5]].ant&&view[CCW[xn+5]].ant.friend&&(view[CCW[xn+5]].ant.type==ASF)){if (dOK[CCW[xn]]){return {cell:CCW[xn]};}} else if ((mC==LRR0)&&(view[CCW[xn+5]].color==LG6)){if (dOK[CCW[xn]]){return {cell:CCW[xn]};}} else {if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (dOK[CCW[xn]]){return {cell:CCW[xn]};}}return NOP;}function rGSSy(){if (view[CCW[xn]].color!=LCL_QC_RESET){return {cell:CCW[xn],color:LCL_QC_RESET};}if (mC!=LPB){return {cell:POSC,color:LPB};}return (rGGTc());}function rGOSy(){if (aE[AQ]>0){var c=CCW[xn+2];if (view[c].ant&&!view[c].ant.friend&&(view[c].ant.type==AQ)&&(view[c].ant.food>0)&&!view[CCW[xn+1]].ant){return {cell:CCW[xn+1],color:LA};}c=CCW[xn+3];if (view[c].ant&&!view[c].ant.friend&&(view[c].ant.type==AQ)&&(view[c].ant.food>0)&&!view[CCW[xn+1]].ant){return {cell:CCW[xn+1],color:LA};}}if (!LCRPHR[mC]){if ((mC==LPX)&&isSc0(view[CCW[xn+7]].color)){return NOP;} else if (eT==0){return {cell:POSC,color:LPG};}} else if (isSc1(view[CCW[xn+7]].color)&&isQc2(view[CCW[xn]].color)){switch (mC){case LPG:return {cell:POSC,color:LPG1};case LPG1:return {cell:POSC,color:LPG};default:return {cell:POSC,color:LPG};}}if ((eT>0)&&!LCRPHR[mC]&&(xn&4)){return {cell:POSC,color:LPG};} else {return (rGGTc());}}function rLSSy(){if (mC!=LCLR){return {cell:POSC,color:LCLR};}return NOP;}function rEHyS(){if (mQ==1){var ptrn=PTFRL0H;var msm=patC(ptrn,AIMU,0,1);if (msm<0){var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else if (LCRQCVAL[view[CCW[xn+mQ]].color]&&dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};}}return NOP;}function rEBRSy(){if (aF[ASF]>0){return (rELGTc());} else {return (rEBRTc());}}function rEASy(){return NOP;}function rUHSy(){if ((mQ==0)&&(view[CCW[xn]].ant.food<RD1)&&view[CCW[xn+1]].ant&&view[CCW[xn+1]].ant.friend&&(view[CCW[xn+1]].ant.type==ASF)){var cc=[5,6,7,4,2];for (var i=0; i<cc.length; i++){var c=CCW[xn+cc[i]];if (dOK[c]){return {cell:c};}}return NOP;}if ((eT>0)&&(aE[AQ]+aUE[1]+aUE[2] +aUE[3]+aUE[4]>0)){var common;if (mQ==0){common=[1,7];} else {common=[0,2,3,7];}for (var i=0; i<common.length; i++){var c=CCW[xn+common[i]];if (view[c].ant&&!view[c].ant.friend&&((view[c].ant.type==AQ)||(view[c].ant.food==0))){if ((aE[AQ]==0)&&(mC!=LA)){return {cell:POSC,color:LA};} else {return NOP;}}}}if (mQ==0){if (mC!=LRM0){return {cell:POSC,color:LRM0};} else if (view[CCW[xn+3]].color!=LRR0){return {cell:CCW[xn+3],color:LRR0};} else if (view[CCW[xn+7]].color!=LRL0){return {cell:CCW[xn+7],color:LRL0};} else if (view[CCW[xn+5]].color!=LRM1){return {cell:CCW[xn+5],color:LRM1};} else if (view[CCW[xn+6]].color!=LRL1){return {cell:CCW[xn+6],color:LRL1};} else if ((!LCRGRR1[view[CCW[xn+4]].color])&&!(view[CCW[xn+4]].ant&&view[CCW[xn+4]].ant.friend)){return {cell:CCW[xn+4],color:LRR1};}if (LCRQCVAL[view[CCW[xn]].color]||(view[CCW[xn+5]].ant&&view[CCW[xn+5]].ant.friend&&
(view[CCW[xn+5]].ant.food>0))||(view[CCW[xn+6]].ant&&view[CCW[xn+6]].ant.friend&&
(view[CCW[xn+6]].ant.food>0))){if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};}}} else {var ptrn=PTFRL0H;var msm=patC(ptrn,AIMU,0,1);if (msm<0){var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else if (LCRQCVAL[view[CCW[xn+mQ]].color]){if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (view[CCW[xn+3]].ant&&view[CCW[xn+3]].ant.friend&&dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};}}}return NOP;}function rUBRSy(){if (spcRL1()){return (rULRL1Sy());} else if (spcRL02()){return (rULRL02Sy());} else if (spcRM()){return (rUFCRTc());}for (var i=TN-1; i>=0; i--){if (view[CCW[i+1]].ant&&view[CCW[i+1]].ant.friend&&
(view[CCW[i+1]].ant.type==AE)&&dOK[CCW[i]]){return {cell:CCW[i]};}}return NOP;}function rUTRRSy(){return (rUCRTc());}function rULRL1Sy(){var ptrn=PTGRL1;var msm=patC(ptrn,AIMR,0,1);if (xn>=0){if ((view[CCW[xn+6]].color==LMS_WRP)&&(view[CCW[xn+7]].color==LCLR)&&(view[CCW[xn]].color==LMR0)&&(view[CCW[xn+3]].color!=LRM1_WRP)){return {cell:CCW[xn+3],color:LRM1_WRP};} else if ((view[CCW[xn+3]].color!=LRM1_WRP)&&view[CCW[xn+3]].ant&&view[CCW[xn+3]].ant.friend&&dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else {return NOP;}} else if (spcRM()){return (rUTRRSy());}return (rLostMSy(false));}function rULRL02Sy(){var ptrn;var msm;if (sL[LRM0]>0){ptrn=PTGRL0;msm=patC(ptrn,AIMR,1,1);}if (xn<0){ptrn=PTGRL2;msm=patC(ptrn,AIMR,1,1);}if (xn>=0){if (view[CCW[xn+3]].ant&&view[CCW[xn+3]].ant.friend&&dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else {return NOP;}} else if (spcRM()){return (rUTRRSy());}return (rLostMSy(false));}function rULRR0Sy(){var ptrn=PTGRR0;var msm=patC(ptrn,AIML,2,1);if (xn>=0){return (runUMLeaveRRTactic());} else if (spcRM()){return (rUTRRSy());}return (rLostMSy(false));}function rULRR2Sy(){var ptrn=PTGRR2;var msm=patC(ptrn,AIML,2,1);if (xn>=0){return (runUMLeaveRRTactic());}    return (rLostMSy(false));}function rUPSSy(){var ptrn=PTGRR1;var msm=patC(ptrn,AIMD,3,2);if (xn>=0){var c=CCW[xn+1];if (view[c].ant&&view[c].ant.friend&&(view[c].ant.food>0)){if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else {return NOP;}}if ((view[CCW[xn+2]].color==LMX_M3OUT)&&(view[CCW[xn]].color==LMR0)&&(view[CCW[xn+1]].color==LCLR)&&(mC!=LRR1X)){return {cell:POSC,color:LRR1X};} else if ((mT==AJM)&&(mC==LRR1U)&&(view[CCW[xn]].color==LMR0)&&(view[CCW[xn+1]].color==LCLR)&&LCRMX_OUT[view[CCW[xn+2]].color]){return {cell:POSC,color:LRR1V};} else if ((mC==LRR1X)||((mT==AJM)&&(mC==LRR1V))||((mC==LRR1U)&&(view[CCW[xn]].color==LMR0)&&(view[CCW[xn+1]].color==LCLR)&&LCRMX_IN[view[CCW[xn+2]].color])){if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (view[CCW[xn+4]].ant&&view[CCW[xn+4]].ant.friend&&dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (dOK[CCW[xn+6]]){return {cell:CCW[xn+6]};} else {return NOP;}} else if (mC!=LRR1U){return {cell:POSC,color:LRR1U};} else if (msm<0){var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else {if (dOK[c]){return {cell:c};} else if (view[c].ant&&view[c].ant.friend){if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+6]]){return {cell:CCW[xn+6]};} else {return NOP;}} else {return NOP;}}}return (rLostMSy(false));}function rUESSy(){var ptrn=PTMS0R_IN;var msm=patC(ptrn,AIMD,4,2);if (xn>=0){return (rUESTc(ptrn,msm));}return (rLostMSy(false));}function rUDSSy(){var ptrn;var msm;if ((sL[LML3]>=1)&&(sD[LMR2]+sD[LMR0]>=1)){ptrn=PTMS3;msm=patC(ptrn,AIMD,3,2);}if ((xn<0)&&(sL[LMR2]>=1)&&(sD[LML1]+sD[LML3]>=1)){ptrn=PTMS2;msm=patC(ptrn,AIMD,3,2);}if (xn>=0){if ((msm<0)&&(view[CCW[xn]].color==LRM0)&&(view[CCW[xn+1]].color==LRR0)&&(view[CCW[xn+2]].color==LMR0)){if (dOK[CCW[xn]]){return {cell:CCW[xn]};} else if (dOK[CCW[xn+1]]){return {cell:CCW[xn+1]};} else {return NOP;}}return (rUDSTc(ptrn,msm));}if ((xn<0)&&(sL[LML1]>=1)&&(sD[LMR0]+sD[LMR2]>=1)){ptrn=PTMS1_IN;msm=patC(ptrn,AIMD,3,4);if (xn<0){ptrn=PTMS1;msm=patC(ptrn,AIMD,3,2);}}if (xn>=0){return (rUDSTc(ptrn,msm));}if ((sD[LML3]+sL[LMR0]>=2)&&(sD[LRL0] >=2)&&(sD[LML1]==0)){ptrn=PTMS0_WRAPPING;msm=patC(ptrn,AIMD,0,1);if (xn>=0){return (rUWRTc(ptrn,msm));}}if ((sL[LMR0]>=1)&&(sD[LML3]+sD[LML1]>=1)){ptrn=PTMS0;msm=patC(ptrn,AIMD,3,2);if (xn>=0){return (rUDSTc(ptrn,msm));}}if (spcRR1()){ptrn=PTGRR1;msm=patC(ptrn,AIMD,3,2);if (xn>=0){if (mC==LRR1){return {cell:POSC,color:LRR1U};}return NOP;}}if (spcMS0R()){ptrn=PTMS0R_IN;msm=patC(ptrn,AIMD,4,2);if (xn>=0){return (rUESTc(ptrn,msm));}}return (rLostMSy(false));}function rUSWSy(){var ptrn=PTMS0_WRAPPING;var msm=patC(ptrn,AIMD,0,1);if (xn>=0){return (rUWRTc(ptrn,msm));}return (rLostMSy(false));}function rURHSy(){return (rMNGTc());}function rUCRSy(){for (var i=TN; i>=1; i--){if (view[CCW[i]].ant&&dOK[CCW[i-1]]){return {cell:CCW[i-1]};}}return NOP;}function rLLLWSy(){var ptrn;var msm;if (mC==LML1){ptrn=PTMS1FL;msm=patC(ptrn,AIML,0,1);if (xn>=0){return (rLLLWTc());}} else if (mC==LML3){ptrn=PTMS3FL;msm=patC(ptrn,AIML,0,1);if (xn>=0){return (rLLLWTc());}} else if (sL[LML1]+sL[LML3]>=2){ptrn=PTMS0FL;msm=patC(ptrn,AIML,0,1);if (xn<0){ptrn=PTMS2FL;msm=patC(ptrn,AIML,0,1);}if (xn>=0){return (rLLLWTc());}} else if (spcMFR()){return (rLLRWSy());} else if (spcMS()){return (rLASSy());}return (rLostMSy(false));}function rLLRWSy(){var ptrn;var msm;if (mC==LMR0){ptrn=PTMS0FR;msm=patC(ptrn,AIMR,0,1);if (xn>=0){return (rLLRWTc());}} else if (mC==LMR2){ptrn=PTMS2FR;msm=patC(ptrn,AIMR,0,1);if (xn>=0){return (rLLRWTc());}} else if (sL[LMR0]+sL[LMR2]>=2){ptrn=PTMS1FR;msm=patC(ptrn,AIMR,0,1);if (xn<0){ptrn=PTMS3FR;msm=patC(ptrn,AIMR,0,1);}if (xn>=0){return (rLLRWTc());}} else if (spcMS()){return (rLASSy());}return (rLostMSy(false));}function rLASSy(){var ptrn;var msm;if ((sL[LML3]>=1)&&(sD[LMR2]+sD[LMR0]>=1)){ptrn=PTMS3;msm=patC(ptrn,AIMU,3,2);}if ((xn<0)&&(sL[LMR2]>=1)&&(sD[LML1]+sD[LML3]>=1)){ptrn=PTMS2;msm=patC(ptrn,AIMU,3,2);}if ((xn<0)&&(sL[LML1]>=1)&&(sD[LMR0]+sD[LMR2]>=1)){ptrn=PTMS1_IO;msm=patC(ptrn,AIMU,0,1);if (xn<0){ptrn=PTMS1;msm=patC(ptrn,AIMU,3,2);}}if (xn>=0){return (rLASTc(ptrn,msm));}if ((sD[LML3]+sL[LMR0]>=2)&&(sD[LRL0] >=2)&&(sD[LML1]==0)){ptrn=PTMS0_OUT;msm=patC(ptrn,AIMU,0,1);if (xn>=0){return {cell:CCW[xn+3],color:LCLR};}ptrn=PTMS0_WRAPPING;msm=patC(ptrn,AIMD,0,1);if (xn>=0){return (rLWRTc(ptrn,msm));}}if ((sL[LMR0]>=1)&&(sD[LML3]+sD[LML1]>=1)){ptrn=PTMS0;msm=patC(ptrn,AIMU,3,2);if (xn>=0){return (rLASTc(ptrn,msm));}}if (spcRM()){return (rLTRRSy());}return (rLostMSy(false));}function rLLSSy(){var ptrn=PTMS0R_OUT;var msm=patC(ptrn,AIMU,0,1);if (xn>=0){} else {ptrn=PTMS0R_IN;msm=patC(ptrn,AIMU,4,2);if (xn>=0){ptrn=PTMS0R_OUT;msm=patC(ptrn,AIMU,0,1);}}if (xn>=0){return (rLLSTc(ptrn,msm));} else if (spcMS()){return (rLASSy());} else {return (rLostMSy(false));}return NOP;}function rLLVSSy(){var ptrn=PTMS0R_OUT1;var msm=patC(ptrn,AIMU,0,1);if (xn>=0){if (view[CCW[xn+3]].color==LCLR){return {cell:CCW[xn+3],color:((mT==ASM) ? LMX_M2OUT : LMX_M1OUT)};
} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else if (view[CCW[xn+5]].ant&&view[CCW[xn+5]].ant.friend&&
dOK[CCW[xn+6]]){return {cell:CCW[xn+6]};} else {return NOP;}} else if (spcMS()){return (rLASSy());}return (rLostMSy(false));}function rLDSSy(){var ptrn=PTGRR1;var msm=patC(ptrn,AIMU,1,1);if (xn>=0){if ((view[CCW[xn]].color==LMR0)&&(view[CCW[xn+1]].color==LCLR)){if ((mC==LRR1X)&&(view[CCW[xn+2]].color!=LMX_M3OUT)){return {cell:CCW[xn+2],color:LMX_M3OUT};}if ((view[CCW[xn+2]].color==LMX_M3OUT)&&(mC!=LRR1X)){return {cell:POSC,color:LRR1X};} else if ((LCRMX_OUT[view[CCW[xn+2]].color])&&
(mC!=LRR1V)){return {cell:POSC,color:LRR1V};} else if ((LCRMX_IN[view[CCW[xn+2]].color])&&(mC!=LRR1U)){return {cell:POSC,color:LRR1U};} else if (msm<0){var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};}}if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else if (dOK[CCW[xn+6]]){return {cell:CCW[xn+6]};} else {return NOP;}}return (rLostMSy(false));}function rLTRRSy(){return (rLCRTc());}function rLFRSy(){for (var i=1; i<TN; i+=2){if (view[CCW[i]].ant&&view[CCW[i]].ant.friend&&
(view[CCW[i]].ant.type==AE)&&dOK[CCW[i+2]]){return {cell:CCW[i+2]};}}return NOP;}function rLRHSy(){var ptrn=PTFRL1G;var msm=patC(ptrn,AIMR,0,1);if (xn>=0){return (rLRLTc());}return (rMNGTc());}function rLLRL1Sy(){var ptrn=PTGRL1;var msm=patC(ptrn,AIMR,0,1);if (xn>=0){return (rLRLTc());} else if (spcRM()){return (rLTRRSy());}return (rLostMSy(false));}function rLLRL02Sy(){var ptrn;var msm;if (sL[LRM0]>0){ptrn=PTGRL0;msm=patC(ptrn,AIMR,1,1);}if (xn<0){ptrn=PTGRL2;msm=patC(ptrn,AIMR,1,1);}if (xn>=0){return (rLRLTc());}return (rLostMSy(false));}function rLLRR0Sy(){var ptrn=PTGRR0;var msm=patC(ptrn,AIML,2,1);if (xn>=0){return (rLRRTc());} else if (spcRM()){return (rLTRRSy());}return (rLostMSy(false));}function rLLRR2Sy(){var ptrn=PTGRR2;var msm=patC(ptrn,AIML,2,1);if (xn>=0){return (rLRRTc());} else if (spcRM()){return (rLTRRSy());}return (rLostMSy(false));}function rLCRSy(){for (var i=TN; i>=1; i--){if (!dOK[CCW[i]]&&dOK[CCW[i-1]]){return {cell:CCW[i-1]};}}return NOP;}function rM2R1Sy(){for (var i=0; i<TN; i++){if (view[CCW[i]].ant&&view[CCW[i]].ant.friend&&
(view[CCW[i]].ant.type==ASF)&&view[CCW[i+1]].ant&&view[CCW[i+1]].ant.friend&&
(view[CCW[i+1]].ant.type==ASF)){if (i&1){} else {}if (dOK[CCW[i+7]]){return {cell:CCW[i+7]};} else {return NOP;}}}return (rLostMSy(true));}function rLostMSy(totally){if ((fdT>0)&&(mF==0)){for (var i=0; i<TN; i++){if ((view[CCW[i]].food>0)&&dOK[CCW[i]]){return {cell:CCW[i]};}}}if (totally&(fT==0)){if (((mC==PY)&&(sN[PY]==0))||((mC==PR)&&(sN[PR]==0))){return {cell:POSC,color:PP};}if (((mC==PG)&&(sN[PG]==0))||((mC==PC)&&(sN[PC]==0))||((mC==PB)&&(sN[PB]==0))||((mC==PP)&&(sN[PP]==0))){return {cell:POSC,color:PW};} else if ((sT[PG]==0)&&(((mC==PK)&&(sN[PK]==0))||((mC==PY)&&(sN[PY]==0))||((mC==PR)&&(sN[PR]==0)))){return {cell:POSC,color:PW};} else if ((mC!=PW)&&(sN[mC]>=4)){return {cell:POSC,color:PW};}}if ((mC==PG)&&(sL[PG]>=2)){return {cell:POSC,color:PW};} else if (((mC==PK)||(mC==PR))&&(sN[PK]+sN[PR]>=3)){return {cell:POSC,color:PW};}if (sN[PW]<=4){var preferredColors =[PG,PB,PC,PP,PY,PR,PK];for (var ci=0; ci<preferredColors.length; ci++){var c=preferredColors[ci];if (mC==c){break;}if (sN[c]>0){for (var i=1; i<TN; i++){if ((view[CCW[i]].color==c)&&dOK[CCW[i]]){return {cell:CCW[i]};}}}}}if (RW){for (var i=1; i<TN; i+=2){if (dOK[CCW[i]]){return {cell:CCW[i]};}}for (i=0; i<TN; i+=2){if (dOK[CCW[i]]){return {cell:CCW[i]};}}return NOP;} else {return NOP;}}function rDHSy(){if (mQ==0){var c=CCW[xn+2];if (view[c].ant&&!view[c].ant.friend&&(view[c].ant.type==AQ)&&(view[c].ant.food>0)&&!view[CCW[xn+1]].ant){return {cell:CCW[xn+1],color:LA};}c=CCW[xn+6];if (view[c].ant&&!view[c].ant.friend&&(view[c].ant.type==AQ)&&(view[c].ant.food>0)&&!view[CCW[xn+7]].ant){return {cell:CCW[xn+7],color:LA};}} else {var c=CCW[xn+4];if (view[c].ant&&!view[c].ant.friend&&(view[c].ant.type==AQ)&&(view[c].ant.food>0)&&!view[CCW[xn+3]].ant){return {cell:CCW[xn+3],color:LA};}c=CCW[xn+6];if (view[c].ant&&!view[c].ant.friend&&(view[c].ant.type==AQ)&&(view[c].ant.food>0)&&!view[CCW[xn+7]].ant){return {cell:CCW[xn+7],color:LA};}c=CCW[xn+5];if (view[c].ant&&!view[c].ant.friend&&(view[c].ant.type==AQ)&&(view[c].ant.food>0)){if (!view[CCW[xn+3]].ant){return {cell:CCW[xn+3],color:LA};} else if (!view[CCW[xn+7]].ant){return {cell:CCW[xn+7],color:LA};}}}return NOP;}function rQSETc(){if (mC!=LT){return {cell:POSC,color:LT};}for (var i=0; i<TN; i++){if (view[CCW[i]].food>0){return {cell:CCW[i]};}}return NOP;}function rQSSTc(){for (var i=0; i<TN; i++){if ((view[CCW[i]].food>0)&&(dOK[CCW[i]])){return {cell:CCW[i]};}}return NOP;}function rQSTCTc(){if ((mC!=LCLR)&&(sN[mC]>=4)){if (sN[LT]==0){return {cell:POSC,color:LT};} else if (sN[LT]>=3){return {cell:POSC,color:LT};} else {for (var i=0; i<TN; i++){if ((view[CCW[i]].color==LT)&&(view[CCW[i+2]].color!=LT)){return {cell:CCW[i+2],color:LT};}}return NOP;}} else if (sN[LT]==1){for (var i=0; i<TN; i++){if ((view[CCW[i]].color==LT)&&(view[CCW[i+4]].color!=LCLR)){if (view[CCW[i+1]].color==LCLR){return { cell:CCW[i+1]};} else if (view[CCW[i+7]].color==LCLR){return { cell:CCW[i+7]};} else {return {cell:POSC,color:LT};}}}return {cell:POSC,color:LT};} else {return {cell:POSC,color:LT};}return NOP;}function rQSATc(){for (var i=0; i<TN; i++){if ((view[CCW[i]].color==LCLR)&&(view[CCW[i+1]].color==LCLR)&&(view[CCW[i+2]].color==LCLR)){if ((view[CCW[i+3]].color==LCLR)&&(view[CCW[i+4]].color==LCLR)){return {cell:CCW[i+2]};}return {cell:CCW[i+1]};}}for (i=TN-1; i>=0; i--){if (view[CCW[i]].color!=LT){return {cell:CCW[i]};}}for (i=0; i<TN; i++){if (view[CCW[i]].color!=LT){return {cell:CCW[i],color:LCLR};}}return {cell:0,color:LCLR};}function rQSEvTc(){if (sN[LT]>0){for (var i=0; i<TN; i++){if (view[CCW[i]].color==LT){xn=i&6;}}if ( dOK[CCW[xn+7]]&&dOK[CCW[xn]]&&dOK[CCW[xn+1]]&&dOK[CCW[xn+2]]&&dOK[CCW[xn+3]] ){return {cell:CCW[xn+1]};} else if (dOK[CCW[xn+5]]&&dOK[CCW[xn+6]]&&dOK[CCW[xn+7]]&&dOK[CCW[xn]]&&dOK[CCW[xn+1]]){return {cell:CCW[xn+7]};} else if (dOK[CCW[xn+3]]&&dOK[CCW[xn+4]]&&dOK[CCW[xn+5]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+5]]&&dOK[CCW[xn+6]]&&dOK[CCW[xn+7]]){return {cell:CCW[xn+6]};} else if (dOK[CCW[xn+1]]&&dOK[CCW[xn+2]]&&dOK[CCW[xn+3]]){return {cell:CCW[xn+2]};} else if (dOK[CCW[xn+7]]&&dOK[CCW[xn]]&&dOK[CCW[xn+1]]){return {cell:CCW[xn]};} else {for (i=0; i<TN; i++){if (dOK[CCW[i]]){return {cell:CCW[i]};}}return NOP;}} else {for (var i=0; i<TN; i++){if (dOK[CCW[i]]&&dOK[CCW[i+1]]&&dOK[CCW[i+2]]&&dOK[CCW[i+3]]&&dOK[CCW[i+4]]){return {cell:CCW[i+2]};}}for (i=0; i<TN; i++){if (dOK[CCW[i]]&&dOK[CCW[i+1]]&&dOK[CCW[i+2]]){return {cell:CCW[i+1]};}}for (i=0; i<TN; i++){if (dOK[CCW[i]]){return {cell:CCW[i]};}}return NOP;}return NOP;}function rQHTc(){var ptrn=PTHOME;var msm=patC(ptrn,POSC,0,1);if (msm!=0){var cc=fwdWrong[0];return {cell:cc.v,color:ptrn[cc.p]};} else {return NOP;}}function rGGTc(){var ptrn=PTGARDEN;var msm=patC(ptrn,POSC,0,1);if (msm!=0){var cc=fwdWrong[0];return {cell:cc.v,color:ptrn[cc.p]};} else {return NOP;}}function rUFCRTc(){var ptrn;var msm;if (mC==LRM0){ptrn=PTFRM0;msm=patC(ptrn,AIMU,4,1);if ((xn<0)&&(eT>0)){ptrn=PTFRM1;msm=patC(ptrn,AIMU,4,1);}if ((xn<0)&&(eT>0)){ptrn=PTFRM2;msm=patC(ptrn,AIMU,4,1);}} else if (mC==LRM2){ptrn=PTFRM2;msm=patC(ptrn,AIMU,4,1);if ((xn<0)&&(eT>0)){ptrn=PTFRM0;msm=patC(ptrn,AIMU,4,1);}if ((xn<0)&&(eT>0)){ptrn=PTFRM1;msm=patC(ptrn,AIMU,4,1);}} else if (mC==LRM1){ptrn=PTFRM1;msm=patC(ptrn,AIMU,4,1);if ((xn<0)&&(eT>0)){ptrn=PTFRM2;msm=patC(ptrn,AIMU,4,1);}if ((xn<0)&&(eT>0)){ptrn=PTFRM0;msm=patC(ptrn,AIMU,4,1);}} else if (mC==LRM1_WRP){ptrn=PTGRM1_WRP;msm=patC(ptrn,AIMR,1,1);}if ((xn<0)&&spcRR1()){return (rUPSSy());}if (xn<0){return (rLostMSy(false));}if (msm==0){if (fdL>0){if ((view[CCW[xn+7]].food>0)&&dOK[CCW[xn+7]]){return {cell:CCW[xn+7]};} else if ((view[CCW[xn+3]].food>0)&&dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};}}if ((mC==LRM1)&&(view[CCW[xn+3]].color!=LRR1X)&&(view[CCW[xn+3]].color!=LRR1U)&&!((mT==AJM)&&(view[CCW[xn+3]].color==LRR1V))&&dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};}if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};}return NOP;}for (var i=0; i<TN; i++){var ce=CCW[xn+i];if (view[ce].ant&&view[ce].ant.friend&&(view[ce].ant.type==AE)){if ((2<=i)&&(i<=4)){var msmSaved=msm;var fwdWrongSaved=Array.from(fwdWrong);var rearWrongSaved=Array.from(rearWrong);xn=xn % 4+4;msm=patC(ptrn,POSC,0,1);if (msm<msmSaved){xn=xn % 4+4;msm=msmSaved;fwdWrong=fwdWrongSaved;rearWrong=rearWrongSaved;} else {}break;}}}if (msm<0){var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else {var cc=rearWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};}return NOP;}function rUCRTc(){var ptrn;var msm;if (mC==LRM0){ptrn=PTGRM0;msm=patC(ptrn,AIMU,4,2);if ((xn<0)&&spcRR1()){return (rUPSSy());}if ((xn<0)&&(eT>0)){ptrn=PTGRM1;msm=patC(ptrn,AIMU,4,2);}if ((xn<0)&&(eT>0)){ptrn=PTGRM2;msm=patC(ptrn,AIMU,4,2);}} else if (mC==LRM2){ptrn=PTGRM2;msm=patC(ptrn,AIMU,4,2);if ((xn<0)&&(eT>0)){ptrn=PTGRM0;msm=patC(ptrn,AIMU,4,2);}if ((xn<0)&&(eT>0)){ptrn=PTGRM1;msm=patC(ptrn,AIMU,4,2);}} else if (mC==LRM1){ptrn=PTGRM1;msm=patC(ptrn,AIMU,4,2);if ((xn<0)&&(eT>0)){ptrn=PTGRM2;msm=patC(ptrn,AIMU,4,2);}if ((xn<0)&&(eT>0)){ptrn=PTGRM0;msm=patC(ptrn,AIMU,4,2);}} else if (mC==LRM1_WRP){ptrn=PTGRM1_WRP;msm=patC(ptrn,AIMR,1,1);}if ((xn<0)&&spcRR1()){return (rUPSSy());}if (xn<0){return (rLostMSy(true));}if (msm==0){if (fdL>0){if ((view[CCW[xn+7]].food>0)&&dOK[CCW[xn+7]]){return {cell:CCW[xn+7]};} else if ((view[CCW[xn+3]].food>0)&&dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};}}if ((mC==LRM1)&&(view[CCW[xn+3]].color!=LRR1X)&&(view[CCW[xn+3]].color!=LRR1U)){if ((((mT==AJM)&&(view[CCW[xn+3]].color==LRR1))||((mT==ASM)&&(view[CCW[xn+3]].color==LRR1V)))&&dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};}}if (mC==LRM0&&(view[CCW[xn+5]].color==LRM1_WRP)&&!(view[CCW[xn+5]].ant&&view[CCW[xn+5]].ant.friend)){return {cell:CCW[xn+5],color:LRM1};}var c=CCW[xn+5];if (dOK[c]){return {cell:c};} else if (view[c].ant&&view[c].ant.friend){var evade=false;if (view[c].ant.food>0){evade=true;} else if (view[CCW[xn+1]].ant&&view[CCW[xn+1]].ant.friend&&(view[CCW[xn+1]].ant.food==0)){evade=true;}if (evade){if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else {return NOP;}} else {return NOP;}}} else if (msm<0){var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else {var cc=rearWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};}return NOP;}function rUESTc(ptrn,msm){switch (view[CCW[xn+3]].color){case LMX_M0:return {cell:CCW[xn+3],color:LMX_M1IN};case LMX_M1OUT:if (mT==ASM){return {cell:CCW[xn+3],color:LMX_M2IN};}break;case LMX_M2OUT:if (mT==ASM){return {cell:CCW[xn+3],color:LMX_M3IN};}break;case LMX_M3OUT:break;case LMX_M1IN:case LMX_M2IN:case LMX_M3IN:if (msm<0){var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else if ((msm==0)&&dOK[CCW[xn+1]]){return {cell:CCW[xn+1]};} else {break;}default:break;}if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};}return NOP;}function runUMLeaveRRTactic(){if (view[CCW[xn+7]].ant&&view[CCW[xn+7]].ant.friend&&dOK[CCW[xn+6]]){return {cell:CCW[xn+6]};} else if (dOK[CCW[xn+7]]){return {cell:CCW[xn+7]};} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else {return NOP;}}function rUDSTc(ptrn,msm){var c=CCW[xn+1];if ((msm==0)&&(fdL>0)&&(view[CCW[xn+3]].food+view[CCW[xn+7]].food>0)){if (mC!=LMMF){return {cell:POSC,color:LMMF};} else if (view[CCW[xn+5]].color!=LMMH){return {cell:CCW[xn+5],color:LMMH};} else if ((view[CCW[xn+3]].food>0)&&dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if ((view[CCW[xn+7]].food>0)&&dOK[CCW[xn+7]]){return {cell:CCW[xn+7]};}} else if ((msm<0)&&!(view[c].ant&&view[c].ant.friend)){var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else if (msm>=0){if (dOK[c]){return {cell:c};} else {if (view[c].ant&&view[c].ant.friend){if (view[c].ant.food>0){if ((view[CCW[xn]].color==LCLR)&&dOK[CCW[xn]]){return {cell:CCW[xn]};} else if ((view[CCW[xn+2]].color==LCLR)&&dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};} else {return NOP;}} else {var c=CCW[xn+5];if (view[c].ant&&view[c].ant.friend&&(view[c].ant.food==0)){if (view[c].color==LMMH){if (dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};} else if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn]]){return {cell:CCW[xn]};} else {return NOP;}} else if (mC!=LMMH){return {cell:POSC,color:LMMH};} else {return NOP;}} else {return NOP;}}} else {return NOP;}}}return NOP;}function rUWRTc(ptrn,msm){if (view[CCW[xn+3]].color!=LMS_WRP){return {cell:CCW[xn+3],color:LMS_WRP};} else if (msm<0){var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else if (dOK[CCW[xn+1]]){return {cell:CCW[xn+1]};}return NOP;}function rLLLWTc(){if (dOK[CCW[xn+7]]){return {cell:CCW[xn+7]};} else {return NOP;}}function rLLRWTc(){if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else {return NOP;}}function rLWRTc(ptrn,msm){if (msm<0){var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else if (dOK[CCW[xn+1]]){return {cell:CCW[xn+1]};} else if (dOK[CCW[xn]]){return {cell:CCW[xn]};} else {return NOP;}}function rLASTc(ptrn,msm){var c=CCW[xn+5];if ((msm<0)&&!(view[c].ant&&view[c].ant.friend)){var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else if (mC==LMMF){return {cell:POSC,color:LCLR};} else if (view[CCW[xn+5]].color==LMMH){return {cell:CCW[xn+5],color:LCLR};} else if (msm>=0){if (dOK[c]){return {cell:c};} else if ((view[c].food>0)&&(eT==0)){if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (dOK[CCW[xn+6]]){return {cell:CCW[xn+6]};} else if (dOK[CCW[xn+7]]){return {cell:CCW[xn+7]};}}}return NOP;}function rLLSTc(ptrn,msm){if (msm<0){if (view[CCW[xn+5]].ant&&view[CCW[xn+5]].ant.friend){return NOP;}var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};}switch (view[CCW[xn+3]].color){case LMX_M1IN:return {cell:CCW[xn+3],color:LMX_M1OUT};case LMX_M2IN:return {cell:CCW[xn+3],color:LMX_M2OUT};case LMX_M3IN:default:return {cell:CCW[xn+3],color:LMX_M3OUT};case LMX_M1OUT:case LMX_M2OUT:case LMX_M3OUT:if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};}break;}return NOP;}function rLCRTc(){var ptrn;var msm;var trust=(aF[AE]>0 ? 1 : 0);if (mC==LRM0){ptrn=PTGRM0;msm=patC(ptrn,AIMD,3,2-trust);if ((xn<0)&&(eT>0)){ptrn=PTGRM1;msm=patC(ptrn,AIMD,3,2);}if ((xn<0)&&(eT>0)){ptrn=PTGRM2B;msm=patC(ptrn,AIMD,3,2);}} else if (mC==LRM2){ptrn=PTGRM2B;msm=patC(ptrn,AIMD,3,2-trust);if ((xn<0)&&(eT>0)){ptrn=PTGRM0;msm=patC(ptrn,AIMD,3,2);}if ((xn<0)&&(eT>0)){ptrn=PTGRM1;msm=patC(ptrn,AIMD,3,2);}} else if (mC==LRM1){ptrn=PTGRM1;msm=patC(ptrn,AIMD,3,2-trust);if ((xn<0)&&(eT>0)){ptrn=PTGRM2B;msm=patC(ptrn,AIMD,3,2);}if ((xn<0)&&(eT>0)){ptrn=PTGRM0;msm=patC(ptrn,AIMD,3,2);}} else if (mC==LRM1_WRP){ptrn=PTGRM1;msm=patC(ptrn,AIMD,3,2);if (xn>=0){if (view[CCW[xn+3]].color!=LRR1X){return {cell:CCW[xn+3],color:LRR1X};} else if (!(view[CCW[xn+7]].ant&&view[CCW[xn+7]].ant.friend)){return {cell:POSC,color:LRM1};}}}if (xn<0){if (spcRR1()){return (rLDSSy());}return (rLostMSy(true));}if (msm==0){var c=CCW[xn+1];if (dOK[c]){return {cell:c};} else if (view[c].ant&&view[c].ant.friend){var evade=false;if (view[c].ant.food==0){evade=true;} else if (view[CCW[xn+5]].ant&&view[CCW[xn+5]].ant.friend&&(view[CCW[xn+5]].ant.food>0)){evade=true;}if (evade){if (dOK[CCW[xn]]){return {cell:CCW[xn]};} else if (dOK[CCW[xn+7]]){return {cell:CCW[xn+7]};} else {return NOP;}} else {return NOP;}}} else if (msm<0){var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else {var cc=rearWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};}return NOP;}function rLRLTc(){if (view[CCW[xn+3]].ant&&view[CCW[xn+3]].ant.friend&&
dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};} else if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (dOK[CCW[xn+1]]){return {cell:CCW[xn+1]};} else {return NOP;}}function rLRRTc(){if (view[CCW[xn+7]].ant&&view[CCW[xn+7]].ant.friend&&dOK[CCW[xn]]){return {cell:CCW[xn]};} else if (dOK[CCW[xn+7]]){return {cell:CCW[xn+7]};} else if (dOK[CCW[xn+1]]){return {cell:CCW[xn+1]};} else {return NOP;}}function rMNGTc(){for (var i=0; i<TN; i++){if (view[CCW[i]].ant&&view[CCW[i]].ant.friend&&
(view[CCW[i]].ant.type==ASF)){if (view[CCW[i]].color==LCLR){if (i&1){if ((view[CCW[i+3]].color==LG5)&&dOK[CCW[i+3]]){return {cell:CCW[i+3]};}} else {if ((view[CCW[i+4]].color==LG6)&&dOK[CCW[i+4]]){return {cell:CCW[i+4]};} else if ((view[CCW[i+3]].color==LG5)&&dOK[CCW[i+3]]){return {cell:CCW[i+3]};}}return (rLostMSy(true));} else if (dOK[CCW[i+1]]){return {cell:CCW[i+1]};}}}return NOP;}function rELGTc(){var ptrn=PTFRL1G;var msm;for (var i=0; i<TN; i+=2){if (view[CCW[i]].ant&&view[CCW[i]].ant.friend&&
(view[CCW[i]].ant.type==ASF)){xn=i;break;}}msm=patC(ptrn,AIMU,0,1);if (xn<0){return NOP;} else if ((msm==0)&&dOK[CCW[xn+5]]&&((view[CCW[xn+3]].ant&&view[CCW[xn+3]].ant.friend)||
(view[CCW[xn+4]].ant&&view[CCW[xn+4]].ant.friend))){return {cell:CCW[xn+5]};} else if (msm<0){var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else if (msm>0){var cc=rearWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else {return NOP;}return NOP;}function rEBRTc(){var ptrn;var msm;if (mC==LRL0){for (var i=0; i<TN; i+=2){var c=CCW[i];if ((view[c].color==LRM0)&&view[c].ant&&view[c].ant.friend&&((view[CCW[i]].ant.type==AJM)||(view[CCW[i]].ant.type==ASM))){ptrn=PTFRL2;msm=patC(ptrn,AIMU,1,1);if (xn>=0){break;}}}if (xn<0){ptrn=PTFRL0;msm=patC(ptrn,AIMU,1,1);}if (xn<0){ptrn=PTFRL2;msm=patC(ptrn,AIMU,1,1);}if ((xn<0)&&(eT>0)){ptrn=PTFRL1;msm=patC(ptrn,AIMU,1,1);}if (xn<0){return rECLRETc();}} else if (mC==LRL1){ptrn=PTFRL1;msm=patC(ptrn,AIMU,1,1);if ((xn<0)&&(eT>0)){ptrn=PTFRL2;msm=patC(ptrn,AIMU,1,1);}if ((xn<0)&&(eT>0)){ptrn=PTFRL0;msm=patC(ptrn,AIMU,1,1);}if (xn<0){return rECLRETc();}} else if ((mC==LRR2)&&(sL[LRL1]>=1)&&(sL[LRL0]==0)){return {cell:POSC,color:LRL0};}if ((msm==0)&&dOK[CCW[xn+5]]&&((view[CCW[xn+3]].ant&&view[CCW[xn+3]].ant.friend)||
(view[CCW[xn+4]].ant&&view[CCW[xn+4]].ant.friend))){return {cell:CCW[xn+5]};} else if (msm<0){var cc=fwdWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else if (msm>0){var cc=rearWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};} else {return NOP;}return NOP;}function rECLRETc(){var ptrn;var msm;for (var i=3; i<TN+2; i+=2){if (view[CCW[i]].ant&&view[CCW[i]].ant.friend&&
((view[CCW[i]].ant.type==AJM)||(view[CCW[i]].ant.type==ASM))){xn=i-3;if (mC==LRL0){ptrn=PTFRL0;msm=patC(ptrn,AIMR,1,0.3);if (msm==PTNOM){ptrn=PTFRL2;msm=patC(ptrn,AIMR,1,0.3);}} else if (mC==LRL1){ptrn=PTFRL1;msm=patC(ptrn,AIMR,1,0.3);}if (msm>0){var cc=rearWrong[0];return {cell:cc.v,color:fixup(ptrn[cc.p])};}return NOP;}}return NOP;}function patC(ptrn,targetCell,qG,wt){if (xn>=0){return (patCO(ptrn,targetCell,qG,wt,xn));} else {var msm;for (var o=0; o<TN; o+=2){msm=patCO(ptrn,targetCell,qG,wt,o);if (xn>=0){return msm;}}return PTNOM;}}function patCO(ptrn,targetCell,qG,wt,ortn){var fwdFCs=FWD_CELLS[targetCell];var totDscs=0;fwdWrong=[];rearWrong=[];if ((Array.isArray(ptrn[POSC])&&!ptrn[POSC][mC])||
((ptrn[POSC]>0)&&(mC!=ptrn[POSC]))){if (fwdFCs[POSC]){fwdWrong.push({p:POSC,v:POSC});totDscs+=1;} else {rearWrong.push({p:POSC,v:POSC});totDscs+=wt;}}if ((xn<0)&&(totDscs>qG)){return PTNOM;}var jFrom=0;switch (targetCell){case AIMU:jFrom=4;break;case AIML:jFrom=6;break;case AIMR:jFrom=2;break;case AIMD:case POSC:default:break;}for (var j=jFrom; j<TN+jFrom; j++){var posP=CCW[j];var posV=CCW[ortn+j];var c=view[posV].color;if ((Array.isArray(ptrn[posP])&&!ptrn[posP][c])||
((ptrn[posP]>0)&&(c!=ptrn[posP]))){if (fwdFCs[posP]){fwdWrong.push({p:posP,v:posV});totDscs+=1;} else {rearWrong.push({p:posP,v:posV});totDscs+=wt;}}if ((xn<0)&&(totDscs>qG)){return PTNOM;}}if ((xn<0)){xn=ortn;}if (fwdWrong.length==0){return (totDscs);} else {return (-totDscs);}}function isQc0(color){return (LCRQCVAL[color]&&(LCRQC_VALUE[color]==0));
}function isQc2(color){return (LCRQCVAL[color]&&(LCRQC_VALUE[color]==2));
}function incQc(color){if (LCRQCVAL[color]){if (LCRQC_VALUE[color]>=QCPERD){return LCRQC[0];} else {return (LCRQC[(LCRQC_VALUE[color]+1) % QCPERD]);
}} else {return undefined;}}function isSc0(color){return (LCRSCVAL[color]&&(LCRSC_VALUE[color]==0));
}function isSc1(color){return (LCRSCVAL[color]&&(LCRSC_VALUE[color]==1));
}function incSc(color){if (LCRSCVAL[color]){return (LCRSC[(LCRSC_VALUE[color]+1) % SCPERD]);
} else {return undefined;}}function spcMS(){return (((mC==LCLR)||((mF+fdL>0)&&(mC==LMMF))||((mF>0)&&(mC==LMMH)))&&(sN[LMR0]+sN[LML1] +sN[LMR2]+sN[LML3]>=2)&&(sN[LCLR]>=3)&&(sN[LMMF] +sN[LMMH] +sN[PB]<=3)); }function spcRM(){return (LCRGRM_ALL[mC]&&(sT[LRL0]+sT[LRL1]>=3)&&(sN[LRL0]>=1)&&(sN[LRR0]+sN[LRR2]>=2)&&(sT[LRM0]+sT[LRM1_WRP] +sT[LRM1]+sT[LRM2]>=2)&&(sT[LCLR]<=4));}function spcRL1(){return ((mC==LRL1)&&(sL[LRL0]>=2)&&(sD[LRM0]>=1)&&(sL[LRM1_WRP]+sL[LRM1]>=1)&&(sD[LRM2]>=1));}function spcRL02(){return ((mC==LRL0)&&(sL[LRL1]+sL[LRL2]>=2)&&(sN[LRM0]>=1)&&(sD[LRM1_WRP]+sD[LRM1]>=1));}function spcRR0(){return ((mC==LRR0)&&(sL[LRM1]==0)&&(sD[LRM1]+sD[LRM1_WRP]>=1)&&(sL[LMR0]>=1)&&(sL[LRR2]>=1));}function spcRR1(){return (LCRGRR1[mC]&&(sN[LRR0]>=2)&&(sL[LRR2]>=1)&&(sD[LRM0]>=1)&&(sN[LCLR]<=3)&&(sL[LRM1] +sL[LRM1_WRP]>=1));}function spcRR2(){return ((mC==LRR2)&&(sD[LCLR]>=1)&&(sD[LRM0]>=1)&&(sD[LRM1]+sD[LMR0]>=2)&&(sL[LRR0]>=2));}function spcMS0R(){return((mC==LCLR)&&(sL[LMR0]>=1)&&(sL[LRR1U]>=1)&&(sD[LRR2]>=1)&&(sD[LRR0]>=1));}function spcMS0ROut(){return ((mC==LCLR)&&(sL[LMR0]+sL[LRR1V]>=2)&&(sD[LRR2]>=2)&&(sD[LRR0]>=1));}function spcMS0W(){return ((mC==LCLR)&&(sD[LRL0]>=3)&&(sL[LRL1]>=1)&&(sL[LMS_WRP]>=2)&&(sN[LCLR]>=2));}function spcMFL(){return ((sL[LMMF]>=1)&&(sD[LMMH]>=1)&&(sT[LCLR]>=2)&&(sT[LML1]+sT[LML3]>=1));}function spcMFR(){return ((sL[LMMF]>=1)&&(sD[LMMH]>=1)&&(sT[LCLR]>=2)&&(sT[LMR0]+sT[LMR2]>=1));}function fixup(ptrnCell){if (Array.isArray(ptrnCell)){for (var i=1; i<=9; i++){if (ptrnCell[i]){return i;}}return LCLR;} else {return ptrnCell;}}

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

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

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

1000 कोशिकाओं की गहराई वाले एक शाफ्ट 3 कोशिकाओं में औसतन 3 भोजन शामिल होने की उम्मीद है, और इस गहराई के सभी शाफ्ट के केवल 4% में कोई भी नहीं होगा। एक बार जब हम कर्कश भोजन की मात्रा से अनुमान लगाते हैं कि रेल बहुत समय से पहले ही सार्थक हो गई है, तो रानी इसलिए वरिष्ठ खनिकों को पालना शुरू कर देगी, जो पहले से कनिष्ठ खनिक द्वारा खोजे गए शाफ्ट का फिर से निरीक्षण करेंगे। जैसा कि एक रेल पर खनिकों में होता है, हम एक रेल के पीछे (बाएं) तरफ के क्षेत्र में लपेटने वाले शाफ्ट को संभालने के लिए तैयार होते हैं।

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

यह मास्टर घड़ी, एक साथ जमा हुए भोजन की मात्रा और हमारे द्वारा प्राप्त यादृच्छिक 1-4 उन्मुखीकरण के साथ, भोजन के आगमन से खनिकों के निर्माण को रोकता है, और उस दर को नियंत्रित करता है जिस पर आगे खनिकों को पैदा किया जाएगा। जब रानी बस गई है, तो आने वाले सभी खाद्य पदार्थों को जल्दी से अधिक खनिक में बदल दिया जाता है जब तक कि आने वाले भोजन की दर लगभग 9 प्रति 1000 चाल (जो एक दर्जन उत्पादक खनिकों की आवश्यकता होती है) तक नहीं पहुंचती है। तब घड़ी का चक्र सीमित कारक बन जाता है और हम भोजन जमा करना शुरू कर देते हैं। बाद में जैसे-जैसे भोजन की मात्रा बढ़ती है, हम अधिकतम 6 नए खनिक प्रति 1000 चाल पर और बाद में अधिकतम 3 पर थूकने की दर को कम कर देते हैं, और अंत में पूरी तरह से खरीद बंद कर देते हैं। एक शाफ़्ट तंत्र रानी को बहुत अधिक भोजन खर्च करने से रोकता है जब सभी रेल अवरुद्ध या क्षतिग्रस्त हो जाती है।

यहां तक ​​कि किसी भी बड़ी क्षति के बिना, खनन दक्षता बहुत कम हो जाएगी क्योंकि प्रत्येक गेम सामने आता है। शुरू में, हम उम्मीद करते हैं कि आधी प्रकाश गति से माइनर ड्रिलिंग हो और औसतन हर 1000 चाल में 1 भोजन पहुंचाने के लिए हल्की गति से वापसी हो। अंत में, यह प्रति मिनट 1000 चालों के प्रति 0.12-0.14 भोजन की तरह है। लंबी रेल की यात्रा करना, ज्यादातर सफेद शाफ्ट पैटर्न को अब ज्यादातर सफेद कैनवास पर पेंट करना, और हर समय शाफ्ट और रेल की मरम्मत करना; खनिक अटक जाते हैं, या खो जाते हैं, या विरोधियों के साथ पेंटबॉल झड़प में बंध जाते हैं।

हमारे खनिक किसी भी बड़े ट्रैफ़िक जाम से खुद को निकालने का प्रयास करते हैं।

और अनजान घुसपैठियों से निपटने के लिए एक अल्पविकसित प्रतिरक्षा प्रणाली है।

हमारे पिछवाड़े को भाप देने की कोशिश करने की अनुशंसा नहीं की जाती है। हमारे कर्मचारी खुश नहीं होंगे।

मुख्य दोष यह है कि विंडमिल रानी को अपने शुरुआती कर्मचारियों को जेब से बाहर रखने के लिए 8 भोजन की आवश्यकता होती है, इसलिए स्क्रबिंग का चरण लंबा होता है, जिससे अन्य समान दावेदारों को एक शुरुआत मिलती है। अगर हमारा घोंसला खत्म हो गया और इससे पहले कि हम कोई खाना खाएंगे, इससे पहले ही हमारे लिए दिन खराब हो जाएगा। बाद में, और कम से कम एक रेल चलाने या मरम्मत योग्य होने के साथ, हम आमतौर पर जा सकते हैं, या कम से कम (अधिकांश) हमारे पास पहले से मौजूद हैं।

कार्यान्वयन पड़ोसी कोशिकाओं को एक कोने से शुरू करके, काउंटर-क्लॉकवाइज़ के रूप में मानता है, CCWइन नंबरों को कंट्रोलर की viewसदस्यता में अनुवाद करने के लिए एक सरणी ( ) के साथ । जब हमें उत्तर की अपनी भावना को पिन करने की आवश्यकता होती है (और सक्षम होते हैं), तो हम अपना कम्पास, एक बेस सबस्क्रिप्ट सेट करते हैंCCW। एंट फंक्शन हमेशा अपने परिवेश का जायजा लेने से शुरू होता है, विशेष रूप से एक स्पेक्ट्रम रिकॉर्ड करने में (प्रत्येक रंग कितनी बार होता है), और फिर रणनीतियों और रणनीति के एक बहु-स्तरीय निर्णय पेड़ के साथ चींटी प्रकार और स्थिति से बाहर शाखाएं। यह बहुत ही विशेष रूप से सबसे आम स्थितियों से निपटने के दौरान अजीब विशेष मामलों के एक मेजबान को संभालने के लिए संभव बनाता है। पेड़ में लगभग 200 पत्ते होते हैं जो एक सेल को पेंट करते हैं या एक कदम उठाते हैं या एक चींटी बनाते हैं, और 70 से अधिक जो कुछ भी नहीं करते हैं - 2 ^ 27 डिस्टिल्ड कलर पैटर्न से संभव है कि चींटियों को देखने में संभव चींटियों, दृश्य में भोजन, और भोजन से गुणा किया जाता है ले गए।

यहाँ हब ज्यामिति का एक ASCII प्रतिपादन है:

+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|   |   |   |   | ^ |MR2|   | v |MR2|   | ^ |   |   |   |   |   |   |   |   |
|   |   |   |   | i |   |   | a | r |  rail 2   |   |   |   |   |   |   |   |
+---+---+---+---+-n-+---+---+-c-+---+---+---+---+---+---+---+---+---+---+---+
|   |   |   |ML1|   |   |ML1| a |   |RL0|RM0|RR0|   |   |   |   |   |   |   |
|   |   |   | y | u |   | y | t |   | c | r | g |   |   |   |   |   |   |   |
+---+---+---+---+-s-+---+---+-e-+---+---+---+---+---+---+---+---+---+---+---+
|   |   |   |MX | e |MR0|MX | d |MR0|RL2|RM2|RR2|MX |ML1|   |ML3|   |ML1|   |
|   |   |   | c |   | k | y |   | k | c | g | y | c | y |   | c |   | y |   |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|   |RR1|RR0|RR2|RR1|RR0|RR2|RR1|RR0|RL1|RM1|RR1|   | shaft in use  |  >|   |
|  r|   | g | y | r | g | y | y | g | g | b | r |   |   |   |   |   |   |   |
+--a+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
| <i|RM1|RM0|RM2|RM1|RM0|RM2|RM1|RM0|RL0|RM0|RR0|MR0|   |MR2|   |MR0|   |   |
|  l| b | r | g | b | r | g | b | r | c | r | g | k |   | r |   | k |   |   |
+-- +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|  3|RL1|RL0|RL2|RL1|RL0|RL2|RL1|RL0|*Q*|RL0|RL1|RL2|RL0|RL1|RL2|RL0|RL1|   |
|   | g | c | c | g | c | c | g | c |clk| c | g | c | c | g | c | c | g |r  |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+a--+
|   |   |   |   |   |   |   |G3 |Grd|Sec|RM0|RM1|RM2|RM0|RM1|RM2|RM0|RM1|i >|
|   |   |   |   |   |   |   | k |r/y|clk| r | b | g | r | b | g | r | b |l  |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ --+
|   |   |   |   |   |   |   |G4 |G5 |G6 |RR0|RR1|RR2|RR0|RR1|RR2|RR0|RR1|1  |
|   |   |   |   |   |   |   | r | k | b | g | y | y | g | r | y | g |   |   |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |   |   |MR0|   |MX |MR0|   |MX |   |   |   |
|   |   |   |   |   |   |   |   |   |   | k |   | y | k |   | c |   |   |   |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+

(जूनियर मिनर द्वारा पहले वंश के दौरान और बाद में एमएक्स और आरआर 1 रंग दिखाते हुए)।

दर्जनों ढीले छोर हैं। (जैसे, हम रेल से खाना साफ करते हैं क्योंकि यह खनन करने वालों के लिए एक बाधा बन सकता है, लेकिन रेल से कुछ खाना सिर्फ इसलिए नहीं खाया जाएगा क्योंकि अतिरिक्त जटिलता बस इसके लायक नहीं लगती।) अच्छा-पर्याप्त है। बेहतर के दुश्मन ...

v1.1 अयोग्यता के लिए एक कारण को ठीक करता है और कुछ मामूली वृद्धि को जोड़ता है।

v1.2 कुछ और सुधार और संवर्द्धन जोड़ता है।

v1.3 डेव कीvar तरह सख्त-मोड नियंत्रकों पर इस काम को करने के लिए पहले मिश्रण घोषणाओं को जोड़ता है ; कोई कार्यात्मक परिवर्तन नहीं।

v1.4 लहसुन के उपयोग के बारे में रानी और माली के बीच एक गलतफहमी को ठीक करता है (जैसा कि रेल 3 के साथ आने वाले वैम्पायर पता लगाने वाले हैं), एक बेवकूफ पैटर्न-परिभाषा बग को ठीक करता है, और कुछ किनारे के मामलों में सुधार करता है।

v1.5 विंडमिल को एक नई चाल सिखाता है - एक चींटी को देखना चाहते हैं?

v1.6 विशाल हरे रंग के विस्तार में खनिक पैटर्न की सुविधा देता है, घर पर बर्गलर अलार्म को परिष्कृत करता है, और दुश्मन रानियों के साथ कहीं और अधिक लोचदार तरीके से, और मामूली टच-अप के साथ कहीं और व्यवहार करता है।

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

v1.8 , लाइटस्पीड-फेज लॉजिक में एक गतिरोध को ठीक करता है और अधिक महत्वपूर्ण बात, v1.6 में पेश किए गए एक स्पॉन्ग बग को ठीक करता है जिसके परिणामस्वरूप अयोग्य हो गया था।

v1.9 एक और विदेशी अयोग्य बग को ठीक करता है, अस्थायी रूप से शाफ्ट में कुछ भीड़ के मामलों को संबोधित करता है, और नवीनतम वैम्पायिक आविष्कारों से निपटने का प्रयास करता है।

v2.0 रानी को मौजूदा हब को पूरी तरह त्यागने में सक्षम बनाता है, जब सख्त जरूरत होती है, लाइट्सपीड-स्टाइल स्क्रिबलिंग का सहारा लेती है, और बाद में मूल साइट से दूर कहीं और एक नया मिल पाया। दूसरी ओर एक वैरिएबल-स्पीड फूड नियंत्रित ऑस्किलेटर के साथ प्रयोग के परिणाम में सुधार नहीं हुआ। पहले और अधिक खनिक भेजने से कुछ प्रतियोगियों की दुर्घटना दर में वृद्धि होगी, लेकिन हमारे अपने भी। FCO कोड लागू रहता है, लेकिन अभी के लिए अक्षम कर दिया गया है।

v2.1 तीन किनारे के मामलों को संबोधित करता है जहां श्रमिकों को रहने की तुलना में बेहतर कदम था।


माइनर्स के शाफ्ट क्यों हैं, इसका कारण यह है कि ट्रेल-इरेज़र के कारण यह है: मेरे डिजाइन के साथ यह बहुत कम संभावना है कि शाफ्ट खोजने वाले ट्रैफ़िक का परिणाम यह होगा कि वह वापस रेल में आ जाए, जबकि आपका कम से कम 50% मौका हो रेल के लिए एक निशान-इरेज़र का नेतृत्व करना। मैं एक खोज के बिना कम से कम आधे घंटे के लिए एक बेहतर शाफ्ट पैटर्न की खोज कर रहा था ..
द्विजिमा

हाँ, यह एक बिंदु है। दूसरी ओर, ट्रेल-इरेज़र्स रेल से ऊब सकते हैं और ज़िगज़ैग बैक-टू-बैक शाफ्ट दीवारों के साथ दूर चल सकते हैं ... कठिन इलाके में ड्रिलिंग करते समय वैकल्पिक पैटर्न अधिक मजबूत होता है (हालांकि अचूक नहीं)।
GNiklasch

रेल पर खनिक कभी-कभी वास्तव में ट्रेल-इरेज़र से लाभ उठाते हैं: यह रेल के खनिकों को वास्तव में आने के बिना शाफ्ट को फिर से तलाशने में सक्षम बनाता है।-और रेल और शाफ्ट की मरम्मत की जा सकती है। दुर्घटनाएँ हो सकती हैं और होंगी। पुनर्प्राप्ति विकल्प महत्वपूर्ण हैं। MoaR पहले से ही प्रभावशाली हैं!
GNiklasch

1
मुझे स्पष्टीकरण पसंद है। विशेष रूप से एक कार्यकर्ता प्रकार का उपयोग करते हुए स्थानीय संदर्भ के आधार पर दो अलग-अलग व्यवहार का उत्पादन करते हैं।
ट्राइकोप्लाक्स सिप

1
@trichoplax वूप्स - सिर के लिए धन्यवाद! ज्ञात कारण (दो से सबस्क्रिप्ट), cf अंक # 6 । मैं इस अवसर का उपयोग करने के लिए कुछ और छोटे सुधारों में जाँच करूँगा। कुछ प्रतिगमन परीक्षण और कोड को फिर से छोटा करने के बाद मेरे जवाब को अपडेट करेंगे।
GNiklasch

12

ब्लैक होल

var COLOR=8
var COLOR2=7
var COLOR3=2
var LOCKDOWN=8
var orthogonals = [1, 3, 7, 5]
var isQueen = view[4].ant.type==5
var rotationsCW = [1,2,5,8,7,6,3,0]
var rotationsCCW = [3,6,7,8,5,2,1,0]
var matchStates = [
    {state:[0,0,0,
            0,1,0,
            0,0,0],move:0,back:0,fill:true},
    {state:[1,0,0,
            0,1,0,
            0,0,0],move:1,back:3,fill:true},
    {state:[0,1,0,
            1,0,0,
            0,0,0],move:0,back:0,fill:false},
    {state:[0,1,0,
            0,0,1,
            0,0,0],move:2,back:2,fill:false},
    {state:[0,0,1,
            0,0,1,
            0,1,0],move:8,back:2,fill:false},
    //5:
    {state:[1,0,0,
            1,0,0,
            0,1,0],move:2,back:6,fill:false},
    {state:[0,1,0,
            0,1,0,
            0,0,0],move:2,back:0,fill:false},
    {state:[1,0,0,
            1,1,0,
            0,0,0],move:1,back:6,fill:false},
    {state:[0,1,1,
            0,1,0,
            0,0,0],move:5,back:0,fill:false},
    {state:[0,1,0,
            1,1,0,
            0,0,0],move:2,back:6,fill:false},
    //10:
    {state:[1,1,0,
            0,1,0,
            0,0,0],move:2,back:3,fill:false},
    {state:[1,1,0,
            1,1,0,
            0,0,0],move:2,back:6,fill:false},
    {state:[0,1,1,
            0,1,1,
            0,0,0],move:8,back:0,fill:false},
    {state:[1,1,1,
            0,1,0,
            0,0,0],move:5,back:3,fill:false},
    {state:[1,0,0,
            1,1,0,
            1,0,0],move:1,back:7,fill:false},
    //15:
    {state:[0,1,0,
            1,1,1,
            0,0,0],move:8,back:6,fill:false},
    {state:[1,1,1,
            1,1,0,
            0,0,0],move:5,back:6,fill:false},
    {state:[1,0,0,
            1,1,0,
            1,1,0],move:1,back:8,fill:false},
    {state:[1,1,0,
            1,1,0,
            1,0,0],move:2,back:7,fill:false},
    {state:[1,1,1,
            0,1,1,
            0,0,0],move:8,back:3,fill:false},
    //20:
    {state:[1,1,1,
            0,0,1,
            0,0,1],move:7,back:3,fill:true},
    {state:[1,1,1,
            1,0,0,
            1,0,0],move:5,back:7,fill:true},
    {state:[1,0,0,
            1,0,0,
            1,1,1],move:1,back:5,fill:true},
    {state:[0,0,1,
            0,0,1,
            1,1,1],move:3,back:1,fill:true},
    {state:[1,1,1,
            0,1,1,
            0,0,1],move:7,back:3,fill:true},
    //25:
    {state:[1,1,1,
            1,1,0,
            1,0,0],move:5,back:7,fill:true},
    {state:[1,0,0,
            1,1,0,
            1,1,1],move:1,back:5,fill:true},
    {state:[1,1,1,
            1,1,1,
            0,0,0],move:8,back:6,fill:true},
    {state:[1,1,1,
            1,1,1,
            1,0,0],move:8,back:7,fill:true},
    {state:[1,1,1,
            1,1,0,
            1,1,0],move:5,back:8,fill:true},
    {state:[1,1,1,
            1,1,1,
            1,1,0],move:8,back:8,fill:true},
    //30:
    {state:[1,1,1,
            1,1,1,
            1,0,1],move:7,back:7,fill:true},
    {state:[1,1,1,
            1,1,0,
            1,1,1],move:5,back:5,fill:true},
    {state:[1,0,1,
            1,1,1,
            1,1,1],move:1,back:1,fill:true},
    {state:[1,1,1,
            0,1,1,
            1,1,1],move:3,back:3,fill:true},
    {state:[1,1,1,
            1,1,1,
            1,1,1],move:9,back:9,fill:false},
    //35:
]
function matchesColor(c) {
    return c==COLOR || c==COLOR2 || c==COLOR3 || (view[4] == COLOR3 && c == LOCKDOWN)
}
function matchesNonLineColor(c) {
    return c==COLOR || c==COLOR2
}
function isAnyColor(c) {
    var r=0
    for(var i=0;i<9;i++) {
        if(view[i].color == c) r++
    }
    return r
}
function howManyAnts() {
    var r=0;
    for(var i=0;i<9;i++) {
        if(view[i].ant != null) r++
    }
    return r
}
function deRotate(m, amt) {
    if(m == 4 || m < 0 || m > 8 || amt == 0) return m
    if(amt > 0)
        return rotationsCW[(rotationsCW.indexOf(m)+amt)%8]
    amt = -amt
    return rotationsCCW[(rotationsCCW.indexOf(m)+amt)%8]
}
function deRotateSide(m, amt) {
    return deRotate(m,amt*2)
}
function matchWhileLost(sides) {
    var c=0;
    for(var i=0;i<9;i++) {
        if(view[i].color == COLOR3) c++
        if(view[i].color == COLOR3 && i%2 == 0) c+=10
    }
    if(c == 2) {
        if(view[0].color == COLOR3 || view[2].color == COLOR3 || view[6].color == COLOR3 || view[8].color == COLOR3) {
            return {cell:4,color:COLOR3}
        }
        if(view[0].ant == null)
            return {cell:0}
        if(view[2].ant == null)
            return {cell:2}
        if(view[6].ant == null)
            return {cell:6}
        if(view[8].ant == null)
            return {cell:8}
    }
    c = 0
    sides[4] = 0
    var toMatch =[{state:[1,1,1,
                         2,0,2,
                         0,1,0]},
                 {state:[0,2,1,
                         1,0,1,
                         0,2,1]},
                 {state:[0,1,0,
                         2,0,2,
                         1,1,1]},
                 {state:[1,2,0,
                         1,0,1,
                         1,2,0]}]
    for(var m=0;m<4;m++) {
        var score=0
        for(var j=0;j<9;j++) {
            if(j!=4) {
                if(sides[j] == COLOR3 && toMatch[m].state[j] == 1) {
                    score++
                }
                if(sides[j] != COLOR3 && (toMatch[m].state[j] == 0 || toMatch[m].state[j] == 2)) {
                    score++
                }
                if(sides[j] == COLOR3 && toMatch[m].state[j] == 2) {
                    score--
                }
            }
        }
        if(score >= 6) {
            var clearOrder=[1,0,2]
            for(var r=0;r<clearOrder.length;r++) {
                var s = deRotateSide(clearOrder[r],m)
                if(view[s].color == COLOR3) {
                    if(view[s].ant == null)
                        return {cell:s,color:COLOR}
                    else
                        return {cell:4}
                }
            }
        }
    }
    return null
}
function matchBlueStyle(sides) {
    return null
}
function bestMatch(sides) {
    var c=0;
    for(var i=0;i<9;i++) {
        if(sides[i] > 1) c++
    }
    if(!isQueen && view[4].ant.food > 0) {
        c++
        sides[4] = 8
    }
    if(c <= 1) {
        return {state:matchStates[0],rot:0,fill:matchStates[0].fill}
    }
    c = 0
    while(!matchesColor(sides[0]) && !matchesColor(sides[1]) && c < 4) {
        var s2 = [0,0,0,0,0,0,0,0,0]
        s2[0] = sides[2]
        s2[1] = sides[5]
        s2[2] = sides[8]
        s2[3] = sides[1]
        s2[5] = sides[7]
        s2[6] = sides[0]
        s2[7] = sides[3]
        s2[8] = sides[6]
        sides = s2
        c++
    }
    while(c < 8 && (matchesColor(sides[0]) || matchesColor(sides[1])) && matchesColor(sides[8])) {
        var s2 = [0,0,0,0,0,0,0,0,0]
        s2[0] = sides[2]
        s2[1] = sides[5]
        s2[2] = sides[8]
        s2[3] = sides[1]
        s2[5] = sides[7]
        s2[6] = sides[0]
        s2[7] = sides[3]
        s2[8] = sides[6]
        sides = s2
        c++
    }
    var bestState = null
    var bestMatchScore = -1
    for(var i = 0; i < matchStates.length; i++) {
        var score=0
        for(var j=0;j<9;j++) {
            if(j!=4) {
                if(matchesColor(sides[j]) && matchStates[i].state[j] == 1) {
                    score++
                }
                if(!matchesColor(sides[j]) && matchStates[i].state[j] == 0) {
                    score++
                }
            }
        }
        if(score >= bestMatchScore) {
            //console.log("state " + i + ": " + score);
            bestMatchScore = score
            bestState = matchStates[i]
        }
    }
    return {state:bestState,rot:c,fill:bestState.fill,score:bestMatchScore}
}
function getHighestWorker() {
    var r=0;
    for(var i=0;i<9;i++) {
        if(i != 4 && view[i].ant != null) {
            if(view[i].ant.friend && view[i].ant.type > r) r = view[i].ant.type
        }
    }
    return r
}
function pathLost() {
    var i, j
    var safe = []
    for(var q=0;q<9;q++) {
        if(q != 4 && view[q].ant != null && view[q].ant.friend && (view[q].ant.type > view[4].ant.type && view[4].ant.food == 0 && view[q].ant.type < 5)) {
            if(!matchesColor(view[4].color)) return {cell:4,color:COLOR}
            return {cell:4}
        }
    }
    if (matchesNonLineColor(view[4].color)) {
        var myView = [0,0,0,0,0,0,0,0,0]
        for(var i=0; i < 9; i++) {
            myView[i] = view[i].color
            if(!isQueen && view[4].ant.food > 0 && view[i].food > 0) {
                myView[i] = COLOR;
            }
        }
        var ret = matchWhileLost(myView)
        if(ret == null)
            return {cell:4, color:COLOR3}
        else {
            if(!(view[ret.cell].ant != null && view[ret.cell].ant.friend == false) && (view[4].ant.food == 0 || view[ret.cell].food == 0 || isQueen))
                return ret
        }
    }
    for (i=0; i<view.length; i++) {
        if (view[i].ant === null && (view[4].ant.food == 0 || view[i].food == 0 || isQueen)) {
            safe.push(i);
        }
    }
    for (i=0; i<4; i++) {
        j = (i+2) % 4
        if (matchesNonLineColor(view[orthogonals[i]].color) && view[orthogonals[j]].color == COLOR3) {
            if (view[orthogonals[i]].ant == null) {
                return {cell:orthogonals[i]}
            } else if (safe.length > 0) {
                return {cell:safe[0]}
            } else if (view[0].ant === null && (view[4].ant.food == 0 || view[0].food == 0 || isQueen)) {
                return {cell:0}
            }
        }
    }
    if (view[1].ant === null && (view[4].ant.food == 0 || view[1].food == 0 || isQueen)) {
        return {cell:1}
    } else {
        if(!matchesColor(view[4].color)) return {cell:4,color:COLOR}
        return {cell:4}
    }
}
function isAllyAdjacentTo(view, place) {
    var i = deRotate(place, 1)
    var j = deRotate(place, -1)
    if(view[i].ant != null && view[i].ant.friend && view[i].ant.type < 5) return 1
    if(view[j].ant != null && view[j].ant.friend && view[j].ant.type < 5) return 1
    if(orthogonals.indexOf(place) >= 0) {
        i = deRotate(place, 2)
        j = deRotate(place, -2)
        if(view[i].ant != null && view[i].ant.friend && view[i].ant.type < 5) return 2
        if(view[j].ant != null && view[j].ant.friend && view[j].ant.type < 5) return 2
    }
    return 0
}
function findOpenSpace(pos, dir) {
    if(pos > 8 || pos < 0) return pos
    if(view[pos].ant != null && view[pos].ant.friend && view[4].ant.food == 0) {
        pos=deRotate(pos,4)
    }
    //var inc = dir>0?1:-1
    var b = 0
    while(view[pos].ant != null && b < 8) {
        pos=deRotate(pos,dir)
        b++
    }
    return pos
}
//end functions
function getReturn() {
    var colToPlace=COLOR
    var blueAmt = isAnyColor(COLOR2)
    var myView = [0,0,0,0,0,0,0,0,0]
    for(var i=0; i < 9; i++) {
        myView[i] = view[i].color
        if(!isQueen && view[4].ant.food > 0 && view[i].food > 0) {
            myView[i] = COLOR;
        }
        if(!isQueen && view[4].ant.food == 0 && view[i].ant != null && view[i].ant.food > 0) {
            if(!matchesColor(view[4].color)) return {cell:4,color:COLOR}
            return {cell:4};
            //myView[i] = COLOR;
        }
        if(view[i].ant != null && !view[i].ant.friend) {
            myView[i] = COLOR;
        }
    }
    if(isQueen) {
        for(var i=0; i < 9; i++) {
            if(i != 4 && !matchesColor(view[i].color) && view[i].ant != null) {
                myView[i] = COLOR
            }
        }
    }
    //console.log("view:")
    //console.log(myView)
    //console.log("1")
    var match = bestMatch(myView)
    if(match.state.move != 9) {
        var ctY = 0
        var lastY = -1
        var ctW = 0
        var lastW = -1
        for(var i=0; i < 9; i++) {
            if(view[i].color == COLOR3) {
                myView[i] = 8
                ctY++
                lastY = i
            }
            else if(!matchesColor(view[i].color)) {
                ctW++
                lastW = i
            }
        }
        if(ctY > 0 && isQueen && view[4].ant.food > 0 && ctW >= 1) {
            if(view[4].color != COLOR3 && matchesColor(view[4].color))
                return {cell:4,color:COLOR3}
            var tt = deRotate(lastW,-1)
            if(view[tt].color != COLOR2)
                return {cell:tt,color:COLOR2}
            lastW = findOpenSpace(lastW,1)
            return {cell:lastW}
        }
        else if(ctY >= 2 && ctW >= 3)
            match = bestMatch(myView)
        else if(ctY > 0 && view[lastY].ant == null && ctW >= 3) {
            return {cell:lastY,color:1}
        }
    }
    //console.log("2")
    if(!isQueen) {
        for(var i=0; i < 9; i++) {
            if(view[i].ant != null && view[i].ant.type == 5 && view[i].ant.food > 0 && view[i].ant.food <= 2) {
                if(view[4].ant.type == 4)
                    return {cell:4,color:COLOR2}
                return {cell:4}
            }
        }
    }
    //console.log("3")
    if(blueAmt > 0 && view[4].color != COLOR3 && match.state.move != 9) {
        //console.log("Some blue")
        var mb = match.state.back
        mb = deRotateSide(mb,match.rot)
        if(!isQueen || view[4].ant.food <= 2) {
            var a = deRotate(mb,1)
            var b = deRotate(mb,-1)//TODO should be -1
            //console.log("mb: " + mb + "," + a + "," + b)
            if(mb != 9 && (view[mb].color == COLOR2 || view[4].color == COLOR2 || view[a].color == COLOR2 || view[b].color == COLOR2)) {
                //blue behind
                //console.log("Blue behind")
                colToPlace = COLOR2
            }
            else {
                //console.log("No blue behind")
                //console.log(match)
                var myView2 = [0,0,0,0,0,0,0,0,0]
                //construct a view without blue in it
                for(var i=0; i < 9; i++) {
                    myView2[i] = view[i].color == COLOR2?1:view[i].color
                }
                var match2 = bestMatch(myView2)
                if(match2.state.move == 9 || match2.state == matchStates[0]) {
                    //zero or one black
                    //console.log("<= 1 Black")
                    //console.log(myView2)
                    //console.log(match2.state)
                    colToPlace = COLOR2
                }
                else if(view[4].ant.type != 4) {
                    var mf = match2.state.move
                    mf = deRotateSide(mf,match2.rot)
                    //console.log("mf: " + mf)
                    if(mf != 9 && view[mf].color == COLOR2 && view[mf].ant == null) {
                        //about to move onto blue
                        //console.log("Moving onto blue")
                        //console.log(view)
                        //console.log(myView2)
                        return {cell:mf,color:1}
                    }
                    var clearOrder=[1,3,5,7,0,2,6,8]
                    for(var r=0;r<clearOrder.length;r++) {
                        var s = deRotateSide(clearOrder[r],0)
                        if(view[s].color == COLOR2 && (view[s].ant == null || !view[s].ant.friend || (isQueen && view[4].ant.food == 0))) {
                            //console.log("DIE BLUE SCUM")
                            //console.log(view)
                            //console.log(myView2)
                            return {cell:s,color:1}
                        }
                        else if(isQueen && view[s].ant != null && view[s].ant.friend) {
                            //console.log("Blue Queen")
                            //console.log(view)
                            //console.log(myView2)
                            return {cell:4,color:COLOR2}
                        }
                    }
                }
            }
        }
        //console.log("Nothing happened")
    }
    //console.log("4")
    if(view[4].ant.type <= 2) {
      for(var i=0; i < 9; i++) {
        if(view[i].ant != null && !view[i].ant.friend) {
          var canSeeAlly = isAllyAdjacentTo(view,i)
          if(canSeeAlly == 0) {
            if(view[i].color == LOCKDOWN) {
              var a = deRotate(i, 1)
              var b = deRotate(i, -1)
              if(view[a].color != LOCKDOWN) return {cell:a,color:LOCKDOWN}
              if(view[b].color != LOCKDOWN) return {cell:b,color:LOCKDOWN}
              if(orthogonals.indexOf(i) >= 0) {
                a = deRotate(i, 2)
                b = deRotate(i, -2)
                if(view[a].color != LOCKDOWN) return {cell:a,color:LOCKDOWN}
                if(view[b].color != LOCKDOWN) return {cell:b,color:LOCKDOWN}
              }
            }
            else {
              return {cell:i,color:LOCKDOWN}
            }
            if(view[4].color == LOCKDOWN || view[4].color == COLOR) {
              var ii = deRotate(i,4)
              ii = findOpenSpace(ii,1)
              return {cell:ii}
            }
            return {cell:4,color:COLOR}
          }
          else if(canSeeAlly == 2) {
            var m = deRotate(i, 2)
            var j = deRotate(i, -2)
            if(view[m].ant != null && view[m].ant.friend && view[m].ant.type < 5) return {cell:m,color:LOCKDOWN}
            if(view[j].ant != null && view[j].ant.friend && view[j].ant.type < 5) return {cell:j,color:LOCKDOWN}
          }
          else if(view[4].color == LOCKDOWN || view[4].color == 2) {

          }
          else {
            return {cell:4,color:2}
          }
        }
      }
      for(var i=0; i < 9; i++) {
        if(view[i].ant != null && view[i].ant.friend && (view[i].ant.type > view[4].ant.type && view[4].ant.food == 0)) {
          if(match.state.move == 9)
            return {cell:4}
          if(view[i].ant.type == 5)
            return {cell:4}
          var m = findOpenSpace(i,1)
          if(view[m].ant == null)
            return {cell:m}
          return {cell:4,color:2}
        }
      }
    }
    else if(view[4].ant.type <= 4) {
      for(var i=0; i < 9; i++) {
        if(view[i].ant != null && !view[i].ant.friend) {
          var canSeeAlly = isAllyAdjacentTo(view,i)
          if(canSeeAlly == 0) {
            if(view[i].color == LOCKDOWN) {
              var a = deRotate(i, 1)
              var b = deRotate(i, -1)
              if(view[a].color != LOCKDOWN) return {cell:a,color:LOCKDOWN}
              if(view[b].color != LOCKDOWN) return {cell:b,color:LOCKDOWN}
              if(orthogonals.indexOf(i) >= 0) {
                a = deRotate(i, 2)
                b = deRotate(i, -2)
                if(view[a].color != LOCKDOWN) return {cell:a,color:LOCKDOWN}
                if(view[b].color != LOCKDOWN) return {cell:b,color:LOCKDOWN}
              }
            }
            else {
              return {cell:i,color:LOCKDOWN}
            }
            if(view[4].color == LOCKDOWN || view[4].color == COLOR) {
              var ii = deRotate(i,4)
              ii = findOpenSpace(ii,1)
              return {cell:ii}
            }
            return {cell:4,color:COLOR}
          }
          else if(canSeeAlly == 2) {
                var m = deRotate(i, 2)
                j = deRotate(i, -2)
                if(view[m].ant != null && view[i].ant.friend && view[m].ant.type < 5) return {cell:m,color:LOCKDOWN}
                if(view[j].ant != null && view[j].ant.friend && view[j].ant.type < 5) return {cell:j,color:LOCKDOWN}
          }
          else if(view[4].color == LOCKDOWN || view[4].color == 2) {

          }
          else {
            return {cell:4,color:2}
          }
        }
      }
    }
    else if(view[4].ant.food > 4) {
        for(var i=0; i < 9; i++) {
            if(view[i].ant != null && !view[i].ant.friend) {
                var canSeeAlly = isAllyAdjacentTo(view,i)
                if(canSeeAlly == 0) {
                    var m = findOpenSpace(i,1)
                    if(view[m].ant == null)
                        return {cell:m,type:1}
                    return {cell:4,color:3}
                }
            }
        }
        var high = getHighestWorker()
        if(high >= 3 && view[4].ant.food % 2 == 1 && view[4].ant.food < 40) {
            var typeToSpawn = 1
            if(view[4].ant.food < 10 && high == 4 && view[4].ant.food % 4 == 1) {
                typeToSpawn = 3
            }
            var m = findOpenSpace(0,1)
            var canSeeAlly = isAllyAdjacentTo(view,m)
            if(canSeeAlly == 0 && view[m].ant == null)
                return {cell:m,type:typeToSpawn}
        }
    }
    //console.log("5")
    var m = match.state.move
    if(isQueen && view[4].ant.food > 0 && view[4].ant.food <= 2 && isAnyColor(COLOR2) == 0 && isAnyColor(COLOR3) == 0 && m < 9) {
        var high = getHighestWorker()+1
        var num = howManyAnts();
        //high += Math.max(num-2,0)
        if(high < 5) {
            m = deRotate(m,match.rot+4) //get space behind
            m = findOpenSpace(m,1) //make sure its open
            if(view[m].ant == null && view[m].food == 0)
                return {cell:m,type:high}
            return {cell:4}
        }
        else {
            //return {cell:9}
            colToPlace = COLOR2
        }
    }
    if(!isQueen && view[4].ant.food > 0 /*&& view[4].ant.type >= 3*/) {
        //console.log("type 3")
        m = match.state.back
        //console.log(m)
        colToPlace = COLOR
    }
    if(view[4].ant.type == 3) {
        colToPlace = COLOR
    }
    //console.log("6")
    if(!matchesColor(view[4].color) && !(!isQueen && view[4].ant.food)) {
        //console.log("6a")
        /*for(var j=0; j < 9; j++) {
            if(j != 4 && view[j].ant != null && view[j].ant.friend && view[j].ant.food > 0 && j != match.back) {
                m = match.state.move
                if(m < 9) {
                    m = findOpenSpace(m,1)
                    if(view[m].ant == null)
                        return {cell:m}
                    return {cell:4}
                }
                return {cell:4,color:colToPlace}
            }
        }*/
        if(isQueen && view[4].color == LOCKDOWN) {
          m = deRotateSide(m,match.rot)
          m = findOpenSpace(m,1)
          return {cell:m}
        }
        return {cell:4,color:colToPlace}
    }
    if(match.fill && !matchesColor(view[4].color)) {
        return {cell:4,color:colToPlace}
    }
    if(m >= 9) {
        if(!matchesColor(view[4].color)) {
            return {cell:4,color:COLOR}
        }
        //console.log("lost! " + view[4].ant.food);
        //console.log(pathLost());
        return pathLost()
    }
    //console.log("7")
    //console.log("m0: " + m + "+" + match.rot)
    m = deRotateSide(m,match.rot)
    //console.log("m1: " + m)
    m = findOpenSpace(m,1)
    //console.log("m2: " + m)
    if(view[4].ant.food > 0 && !matchesColor(view[4].color) /*&& (view[4].ant.type >= 3)*/) {
        var anyFood = false
        for(var x=0;x<9;x++) {
            if(view[x].food > 0) anyFood = true;
        }
        if(!anyFood)
            return {cell:4,color:colToPlace}
    }
    //console.log("m3: " + m)
    m = findOpenSpace(m,1)
    //console.log("m4: " + m)
    if((!isQueen && view[4].ant.food > 0 && view[m].food > 0) && view[m].ant == null) return {cell:4}
    return {cell:m}
}
var ret = getReturn()
ret = sanityCheck(ret)
return ret
function sanityCheck(ret) {
    if(!ret || ret.cell < 0 || ret.cell > 8 || (ret.cell != 4 && (ret.color == null || ret.color == 0) && view[ret.cell].ant != null) || (view[ret.cell].food > 0 && (view[4].ant.food > 0 && view[4].ant.type < 5))) {
        return {cell:4}
    }
    if(ret.type && (view[ret.cell].ant != null || view[ret.cell].food > 0)) {
        return {cell:4}
    }
    return ret;
}

यह एक बड़े पैमाने पर, बड़े पैमाने पर चींटी समारोह है। यह ऐसा करता है:

ब्लैक होल

कार्यक्षमता वास्तव में काफी सरल है। कोड ब्लॉक के शीर्ष एक matchStatesवस्तु को परिभाषित करता है जिसका उपयोग चींटियां यह पहचानने के लिए करती हैं कि वे किस रास्ते का सामना कर रही हैं, और ऐसा करने में, वे ज्ञात अन्वेषण क्षेत्र के चारों ओर परिक्रमा करती हैं। फिर कुछ सहायक कार्य (मिलान रंग, गिनती चींटियों, आदि)।

bestMatch()चींटी (उत्परिवर्तित) द्वारा देखे गए दृश्य में लेता है और सबसे अच्छा मैच पाता है और सबसे अच्छा मैच matchStatesदेता है।

क्वीन एक काम करता है जैसे वह चारों ओर घूमता है, नीचे काला होता है:

  • जब तक वह रानी बनने वाली एक कार्यकर्ता बनाने के लिए कामगार नहीं बन जाती, तब तक वह नीला रखने के लिए स्विच करता है। कोई भी चींटी एक रंग रखती है जो नीले रंग के आस-पास के स्थानों को नीले रंग की जगह देखती है।
  • रानी, ​​अगर वह नीला देखती है, तो खाना खाती है।

टाइप 1 और 2 वर्कर्स रानी की तरह तब तक भोजन करते हैं जब तक कि उन्हें भोजन नहीं मिल जाता है, तब तक वे रंग डालना छोड़ देते हैं जब तक कि वे सर्कल के चारों ओर नहीं चले जाते हैं और रानी को अपना भोजन देते हैं।

टाइप 3 और 4 के कार्यकर्ता भोजन पाने तक क्वीन्स की तरह काम करते हैं, फिर वे सर्कल के चारों ओर पीछे की ओर काम करते हैं (तब भी रंग डालते हैं) जब तक वे अपना भोजन रानी को सौंप नहीं देते।

कोई भी चींटी जो खुद को खोए हुए pathLost()इनवॉइस को ढूंढती है जो एक स्मार्ट स्ट्रेट लाइन एल्गोरिथ्म है (यह कुछ ट्वेंटी के साथ मेटा से स्मार्ट स्ट्रेट पाथ फंक्शन है )।

वे ट्वीक्स हैं:

  • टाइप 1 चींटियाँ बेतरतीब ढंग से कार्य करती हैं और रास्तों को मिटाने का प्रयास करती हैं (ज्यादातर ज़रूरत नहीं है, लेकिन टाइप 1 चींटियाँ मूल्यवान दीर्घकालिक नहीं हैं, और यह विकर्ण चेकरबोर्ड को साफ करता है)
  • यदि वे रानी को देख सकते हैं तो गैर-रानियां अभिनय नहीं करेंगी
  • किसी भी समय चींटी देख सकती है और फिर भी अपने पथ के उन्मुखीकरण को निर्धारित कर सकती है जो उसके सामने पिछले रास्तों का सामना करती है, उस पथ को मिटा देती है, यह सुनिश्चित करती है कि चींटियाँ इसे वापस बाहर कर दें:

क्रॉसओवर उदाहरण

इसके अलावा, बाकी का अधिकांश केवल यह सुनिश्चित करने में त्रुटि से निपटने के लिए है कि कोई चींटियां अवैध संचालन न करें (अन्य चींटियों पर चलते हुए, भोजन पर बढ़ते हुए, भोजन पर चींटियों को काटते हुए ...) हालांकि सबसे बड़ी त्रुटि कोड के चंक को संभालने में सबसे नीचे है। :

if(view[4].ant.food > 0 && !matchesColor(view[4].color) && (view[4].ant.type >= 3) || surroundingColor > 6) {
  var anyFood = false
  for(var x=0;x<9;x++) {
    if(view[x].food > 0) anyFood = true;
  }
  if(!anyFood)
    return {cell:4,color:colToPlace}
}

टाइप 3 और 4 चींटियां जो पीछे की ओर चल रही हैं, वे जमीन पर अभी भी भोजन के चारों ओर रंग नहीं डालती हैं (भोजन अन्यथा पथ अभिविन्यास के प्रयोजनों के लिए रंगीन टाइल की तरह व्यवहार किया जाता है)। इसके अतिरिक्त, टाइप 1 या 2 चींटियों को लगता है कि वे (<= 2 अनियंत्रित रिक्त स्थान को देखते हुए) में रंगे हुए हैं, नीचे रंग डालेंगे। छोटे 'द्वीपों' के लिए वे अंततः खुद को खो देते हैं, बजाय स्थायी रूप से फंसने के।

इस गुट द्वारा प्राप्त अधिकतम भोजन केवल इस बात से सीमित है कि यह कितनी जल्दी रंग बदलता है और साथ ही एक खेल की अधिकतम अवधि (10k न्यूनतम)। अधिक श्रमिक आवश्यक रूप से लाभकारी नहीं हैं, लेकिन कई जल्दी प्राप्त करना आवश्यक है। टाइप 3 और 4 वर्कर सबसे अधिक कुशल होते हैं (प्रत्येक 6 गेम स्टेप्स में रानी के 6 कदमों के करीब) ले जाते हैं, लेकिन उन्हें बहुत जल्दी बनाने से कम कुल वर्कर्स हो जाते हैं। इसलिए प्रारंभिक प्लेसमेंट का बड़ा प्रभाव पड़ता है, लेकिन झुंड द्वारा मैप किया गया क्षेत्र कभी-कभी कुछ स्थानों के साथ बढ़ता है, यह हर आखिरी टुकड़े को पकड़ लेगा, भले ही कोई चींटी एक टुकड़ा लेने के लिए खो जाने का जोखिम न उठाए।

अपडेट Update/२३

विशिष्ट एज-केस में कुछ मुद्दों पर ध्यान दिया गया, जैसे यह:

रानी एक दुश्मन पर आगे बढ़ना चाहती है

और इसके लिए बहुत मामूली ट्वीक किए गए। मूल रूप से, दुश्मन चींटियों और लादेन श्रमिकों को रंगीन टाइल के रूप में मानते हैं।

अपडेट 7/26

फॉक्स, मैं भी किसी भी अधिक पता नहीं है।

  • अधिक मजबूत होने के लिए ट्वीक्ड लॉस्ट-येलो-ट्रेल-एरर हैंडलिंग
  • अधिक मजबूत होने के लिए Tweaked दोस्त-पथ-टकराव से निपटने
  • जोड़ा गया ट्रेल इरेज़र न्यूट्रलाइज़र कोड
  • "ब्लू ट्रेल्स" का पता लगाने और हैंडलिंग कोड [बीटा] जोड़ा गया
  • मेड क्वीन होर्ड मोड में जाने के बाद श्रमिकों का उत्पादन जारी रखती है (कभी-कभी, कम से कम)
  • अमान्य चाल स्वच्छता
  • विविध स्पेगेटी कोड
  • दिलासा दिलाया
  • हिरोब्राइन निकाला गया
  • अभिवृद्धि डिस्क को जोड़ा गया

नई अभिवृद्धि डिस्क

पीले ट्रेल्स के बिना:

माइनस येलो

अद्यतन 7/26 भाग 2

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

अपडेट 7/31

  • पुन: जोड़ा गया एंटी-ट्रेल-इरेज़र कोड (यह "ब्लू हटाएं" अपडेट में खो गया)
  • Sanity check फ़ंक्शन अन्य चींटियों के तहत रंग कोशिकाओं को रोक रहा था
  • अधिक बेहतर एंटी-इरेज़र फिक्स: सिंगल इरेज़र का मुकाबला करने के लिए अब 3 श्रमिकों की आवश्यकता नहीं है

अद्यतन 8/4

छोटी सी टहनी।

  • LOCKDOWN का रंग अब काला है
  • भोजन देने के लिए सभी चींटियाँ "पीछे की ओर" चलती हैं। उन यांत्रिकी से ट्रेल्स-इरेज़र द्वारा छोड़ी गई "बुलबुले" में फंसने वाली कम चींटियों को जन्म मिलेगा
  • बेहतर तरीके से खोई हुई चींटियों का एक-दूसरे से चिपकना नहीं
  • कम "केवल होर्ड" दहलीज 40 तक

कमजोरियों

  • मिटाना।
  • रंग से छेड़छाड़

टिप्पणियाँ विस्तारित चर्चा के लिए नहीं हैं; इस वार्तालाप को बातचीत में स्थानांतरित कर दिया गया है ।
मार्टिन एंडर

12

वैम्पायर Mk.8 (रि-वैंपेड)

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


मेरे सभी उत्तर निम्न-स्तरीय सहायक कार्यों के समान सेट को साझा कर रहे हैं। इस उत्तर के लिए विशिष्ट कोड को देखने के लिए "उच्च-स्तरीय तर्क यहां शुरू होता है"।

// == Shared low-level helpers for all solutions ==
var QUEEN = 5

var WHITE = 1
var COL_MIN = WHITE
var COL_LIM = 9

var CENTRE = 4

var NOP = {cell: CENTRE}

var DIR_FORWARDS = false
var DIR_REVERSE = true
var SIDE_RIGHT = true
var SIDE_LEFT = false

function sanity_check(movement) {
    var me = view[CENTRE].ant
    if(!movement || (movement.cell|0) !== movement.cell || movement.cell < 0 || movement.cell > 8) {
        return false
    }
    if(movement.type) {
        if(movement.color) {
            return false
        }
        if((movement.type|0) !== movement.type || movement.type < 1 || movement.type > 4) {
            return false
        }
        if(view[movement.cell].ant || view[movement.cell].food) {
            return false
        }
        if(me.type !== QUEEN || me.food < 1) {
            return false
        }
        return true
    }
    if(movement.color) {
        if((movement.color|0) !== movement.color || movement.color < COL_MIN || movement.color >= COL_LIM) {
            return false
        }
        if(view[movement.cell].color === movement.color) {
            return false
        }
        return true
    }
    if(view[movement.cell].ant && movement.cell != 4) {
        return false
    }
    if(view[movement.cell].food + me.food > 1 && me.type !== QUEEN) {
        return false
    }
    return true
}

function as_array(o) {
    if(Array.isArray(o)) {
        return o
    }
    return [o]
}

function best_of(movements) {
    var m
    for(var i = 0; i < movements.length; ++ i) {
        if(typeof(movements[i]) === 'function') {
            m = movements[i]()
        } else {
            m = movements[i]
        }
        if(sanity_check(m)) {
            return m
        }
    }
    return null
}

function play_safe(movement) {
    // Avoid disqualification: no-op if moves are invalid
    return best_of(as_array(movement)) || NOP
}

var RAND_SEED = (() => {
    var s = 0
    for(var i = 0; i < 9; ++ i) {
        s += view[i].color * (i + 1)
        s += view[i].ant ? i * i : 0
        s += view[i].food ? i * i * i : 0
    }
    return s % 29
})()

var ROTATIONS = [
    [0, 1, 2, 3, 4, 5, 6, 7, 8],
    [6, 3, 0, 7, 4, 1, 8, 5, 2],
    [8, 7, 6, 5, 4, 3, 2, 1, 0],
    [2, 5, 8, 1, 4, 7, 0, 3, 6],
]

function areAdjacent(A, B) {
    if(A == 4 || B == 4 || A == B) return true
    if(A % 2 == 0 && B % 2 == 0) return false
    if(A % 2 == 1 && B % 2 == 0) return areAdjacent(B,A)
    if(A % 2 == 1 && B % 2 == 1) return !(8-A == B || 8-B == A)
    if(A == 0 && (B == 1 || B == 3)) return true
    if(A == 2 && (B == 1 || B == 5)) return true
    if(A == 6 && (B == 3 || B == 7)) return true
    if(A == 8 && (B == 5 || B == 7)) return true
    return false
}

function try_all(fns, limit, wrapperFn, checkFn) {
    var m
    fns = as_array(fns)
    for(var i = 0; i < fns.length; ++ i) {
        if(typeof(fns[i]) !== 'function') {
            if(checkFn(m = fns[i])) {
                return m
            }
            continue
        }
        for(var j = 0; j < limit; ++ j) {
            if(checkFn(m = wrapperFn(fns[i], j))) {
                return m
            }
        }
    }
    return null
}

function identify_rotation(testFns) {
    // testFns MUST be functions, not constants
    return try_all(
        testFns,
        4,
        (fn, r) => fn(ROTATIONS[r]) ? ROTATIONS[r] : null,
        (r) => r
    )
}

function near(a, b) {
    return (
        Math.abs(a % 3 - b % 3) < 2 &&
        Math.abs(Math.floor(a / 3) - Math.floor(b / 3)) < 2
    )
}

function try_all_angles(solverFns) {
    return try_all(
        solverFns,
        4,
        (fn, r) => fn(ROTATIONS[r]),
        sanity_check
    )
}

function try_all_cells(solverFns, skipCentre) {
    return try_all(
        solverFns,
        9,
        (fn, i) => ((i === CENTRE && skipCentre) ? null : fn(i)),
        sanity_check
    )
}

function try_all_cells_near(p, solverFns) {
    return try_all(
        solverFns,
        9,
        (fn, i) => ((i !== p && near(p, i)) ? fn(i) : null),
        sanity_check
    )
}

function ant_type_at(i, friend) {
    return (view[i].ant && view[i].ant.friend === friend) ? view[i].ant.type : 0
}

function friend_at(i) {
    return ant_type_at(i, true)
}

function foe_at(i) {
    return ant_type_at(i, false)
}

function foe_near() {
    for(var i = 0; i < 9; ++ i) {
        if(i !== 4 && view[i].ant && !view[i].ant.friend) {
            return true
        }
    }
    return false
}

function ant_type_near(p, friend) {
    for(var i = 0; i < 9; ++ i) {
        if(i !== 4 && ant_type_at(i, friend) && near(i, p)) {
            return true
        }
    }
    return false
}

function move_agent(agents) {
    var me = view[CENTRE].ant
    var buddies = [0, 0, 0, 0, 0, 0]
    for(var i = 0; i < 9; ++ i) {
        ++ buddies[friend_at(i)]
    }

    for(var i = 0; i < agents.length; i += 2) {
        if(agents[i] === me.type) {
            return agents[i+1](me, buddies)
        }
    }
    return null
}

function grab_nearby_food() {
    return try_all_cells((i) => (view[i].food ? {cell: i} : null), true)
}

function go_anywhere() {
    return try_all_cells((i) => ({cell: i}), true)
}

function colours_excluding(cols) {
    var r = []
    for(var i = COL_MIN; i < COL_LIM; ++ i) {
        if(cols.indexOf(i) === -1) {
            r.push(i)
        }
    }
    return r
}

function generate_band(start, width) {
    var r = []
    for(var i = 0; i < width; ++ i) {
        r.push(start + i)
    }
    return r
}

function colour_band(colours) {
    return {
        contains: function(c) {
            return colours.indexOf(c) !== -1
        },
        next: function(c) {
            return colours[(colours.indexOf(c) + 1) % colours.length]
        },
        prev: function(c) {
            return colours[(colours.indexOf(c) + colours.length - 1) % colours.length]
        }
    }
}

function random_colour_band(colours) {
    return {
        contains: function(c) {
            return colours.indexOf(c) !== -1
        },
        next: function() {
            return colours[RAND_SEED % colours.length]
        }
    }
}

function fast_diagonal(colourBand) {
    var m = try_all_angles([
        // Avoid nearby checked areas
        (rot) => {
            if(
                !colourBand.contains(view[rot[0]].color) &&
                colourBand.contains(view[rot[5]].color) &&
                colourBand.contains(view[rot[7]].color)
            ) {
                return {cell: rot[0]}
            }
        },

        // Go in a straight diagonal line if possible
        (rot) => {
            if(
                !colourBand.contains(view[rot[0]].color) &&
                colourBand.contains(view[rot[8]].color)
            ) {
                return {cell: rot[0]}
            }
        },

        // When in doubt, pick randomly but avoid doubling-back
        (rot) => (colourBand.contains(view[rot[0]].color) ? null : {cell: rot[0]}),

        // Double-back when absolutely necessary
        (rot) => ({cell: rot[0]})
    ])

    // Lay a colour track so that we can avoid doubling-back
    // (and mess up our foes as much as possible)
    if(!colourBand.contains(view[CENTRE].color)) {
        var prevCol = m ? view[8-m.cell].color : WHITE

        var colours = [0, 0, 0, 0, 0, 0, 0, 0, 0]
        for(var i = 0; i < 9; ++ i) {
            ++ colours[view[i].color]
        }

        return {cell: CENTRE, color: colourBand.next(prevCol)}
    }

    return m
}

function checkAllNearEnvirons(colours, buddies) {
        var nearMoves = [victims.length]
        for(var e = 0; e < victims.length; e++) {
                var env = victims[e]
                nearMoves[e] = null
                if(env.near_nest(colours)) {
                        nearMoves[e] = env.near_nest_move(colours, buddies)
                }
        }
        return best_of(nearMoves)
}

function follow_edge(obstacleFn, side) {
    // Since we don't know which direction we came from, this can cause us to get
    // stuck on islands, but the random orientation helps to ensure we don't get
    // stuck forever.

    var order = ((side === SIDE_LEFT)
        ? [0, 3, 6, 7, 8, 5, 2, 1, 0]
        : [0, 1, 2, 5, 8, 7, 6, 3, 0]
    )
    return try_all(
        [obstacleFn],
        order.length - 1,
        (fn, i) => (fn(order[i+1]) && !fn(order[i])) ? {cell: order[i]} : null,
        sanity_check
    )
}

function start_dotted_path(colourBand, side, protectedCols) {
    var right = (side === SIDE_RIGHT)
    return try_all_angles([
        (rot) => ((
            !protectedCols.contains(view[rot[right ? 5 : 3]].color) &&
            !colourBand.contains(view[rot[right ? 5 : 3]].color) &&
            !colourBand.contains(view[rot[right ? 2 : 0]].color) &&
            !colourBand.contains(view[rot[1]].color)
        )
            ? {cell: rot[right ? 5 : 3], color: colourBand.next(WHITE)}
            : null)
    ])
}

function lay_dotted_path(colourBand, side, protectedCols) {
    var right = (side === SIDE_RIGHT)
    return try_all_angles([
        (rot) => {
            var ahead = rot[right ? 2 : 0]
            var behind = rot[right ? 8 : 6]
            if(
                colourBand.contains(view[behind].color) &&
                !protectedCols.contains(view[ahead].color) &&
                !colourBand.contains(view[ahead].color) &&
                !colourBand.contains(view[rot[right ? 6 : 8]].color)
            ) {
                return {cell: ahead, color: colourBand.next(view[behind].color)}
            }
        }
    ])
}

function follow_dotted_path(colourBand, side, direction) {
    var forwards = (direction === DIR_REVERSE) ? 7 : 1
    var right = (side === SIDE_RIGHT)

    return try_all_angles([
        // Cell on our side? advance
        (rot) => {
            if(
                colourBand.contains(view[rot[right ? 5 : 3]].color) &&
                // Prevent sticking / trickery
                !colourBand.contains(view[rot[right ? 3 : 5]].color) &&
                !colourBand.contains(view[rot[0]].color) &&
                !colourBand.contains(view[rot[2]].color)
            ) {
                return {cell: rot[forwards]}
            }
        },

        // Cell ahead and behind? advance
        (rot) => {
            var passedCol = view[rot[right ? 8 : 6]].color
            var nextCol = view[rot[right ? 2 : 0]].color
            if(
                colourBand.contains(passedCol) &&
                nextCol === colourBand.next(passedCol) &&

                // Prevent sticking / trickery
                !colourBand.contains(view[rot[right ? 3 : 5]].color) &&
                !colourBand.contains(view[rot[right ? 0 : 2]].color)
            ) {
                return {cell: rot[forwards]}
            }
        }
    ])
}

function escape_dotted_path(colourBand, side, newColourBand) {
    var right = (side === SIDE_RIGHT)
    if(!newColourBand) {
        newColourBand = colourBand
    }

    return try_all_angles([
        // Escape from beside the line
        (rot) => {
            var approachingCol = view[rot[right ? 2 : 0]].color
            if(
                !colourBand.contains(view[rot[right ? 8 : 6]].color) ||
                !colourBand.contains(approachingCol) ||
                colourBand.contains(view[rot[7]].color) ||
                colourBand.contains(view[rot[right ? 6 : 8]].color)
            ) {
                // not oriented, or in a corner
                return null
            }
            return best_of([
                {cell: rot[right ? 0 : 2], color: newColourBand.next(approachingCol)},
                {cell: rot[right ? 3 : 5]},
                {cell: rot[right ? 0 : 2]},
                {cell: rot[right ? 6 : 8]},
                {cell: rot[right ? 2 : 0]},
                {cell: rot[right ? 8 : 6]},
                {cell: rot[right ? 5 : 3]}
            ])
        },

        // Escape from inside the line
        (rot) => {
            if(
                !colourBand.contains(view[rot[7]].color) ||
                !colourBand.contains(view[rot[1]].color) ||
                colourBand.contains(view[CENTRE].color)
            ) {
                return null
            }
            return best_of([
                {cell: rot[3]},
                {cell: rot[5]},
                {cell: rot[0]},
                {cell: rot[2]},
                {cell: rot[6]},
                {cell: rot[8]}
            ])
        }
    ])
}

function latch_to_dotted_path(colourBand, side) {
    var right = (side === SIDE_RIGHT)

    return try_all_angles([
        (rot) => {
            var approachingCol = view[rot[right ? 2 : 0]].color
            if(
                colourBand.contains(approachingCol) &&
                view[rot[right ? 8 : 6]].color === colourBand.next(approachingCol) &&
                !colourBand.contains(view[rot[right ? 5 : 3]].color)
            ) {
                // We're on the wrong side; go inside the line
                return {cell: rot[right ? 5 : 3]}
            }
        },

        // Inside the line? pick a side
        (rot) => {
            var passedCol = view[rot[7]].color
            var approachingCol = view[rot[1]].color
            if(
                !colourBand.contains(passedCol) ||
                !colourBand.contains(approachingCol) ||
                colourBand.contains(view[CENTRE].color)
            ) {
                return null
            }
            if((approachingCol === colourBand.next(passedCol)) === right) {
                return best_of([{cell: rot[3]}, {cell: rot[6]}, {cell: rot[0]}])
            } else {
                return best_of([{cell: rot[5]}, {cell: rot[2]}, {cell: rot[8]}])
            }
        }
    ])
}


// == High-level logic begins here ==


var TARGET_COLOURS_ZIG = colour_band([4, 5, 7, 8])
var TARGET_COLOURS_FIREFLY = colour_band([2, 5, 8])
var GROUND_COLOURS_BH = colour_band([2, 7, 8])
var SAFE_COLOURS = random_colour_band([8])

var THIEF = 1
var BOUNCER = 2
var LANCE = 4
var LANCE_TIP = 3

var INITIAL_GATHER = 12

function colour_band_prev(band, base) {
    if(!band.contains(base)) {
        return band.next(WHITE)
    }
    var cur = band.next(base)
    var c
    while((c = band.next(cur)) !== base) {
        cur = c
    }
    return cur
}

function white_near(p) {
    for(var i = 0; i < 9; ++ i) {
        if(near(i, p) && view[i].color === WHITE) {
            return true
        }
    }
    return false
}

function white_near(p, min) {
    var c = 0
    for(var i = 0; i < 9; ++ i) {
        if(near(i, p) && view[i].color === WHITE) {
            if(++c >= min) return true
        }
    }
    return false
}

var TARGET_ARRANGEMENT_RAIL = [
    [8,4,5,8,5,2,4,2,6],
    [8,5,2,4,2,6,6,4,5],
    [4,2,6,6,4,5,8,4,5],
    [6,4,5,8,4,5,8,5,2]
]
var TARGET_NEAR_RAIL = [
    [2,4,0,5,8,0,4,8,0,1], //Not Valid for Worker #1
    [2,6,0,4,5,0,4,5,0,0],
    [4,6,0,2,4,0,5,8,0,0],
    [4,8,0,4,6,0,2,4,0,0],
    [4,5,0,5,2,0,2,6,0,1], //NV 1
    [4,5,0,4,5,0,5,2,0,5], //NV Q
    [5,2,0,2,6,0,4,5,0,0],
    [5,8,0,4,8,0,4,6,0,5]  //NV Q
]
var TARGET_COLOURS_RAIL = colour_band([4,5,2,4])
var rail_miners = {
    name:function() { return "rail_miners"; },
    near_nest: function(colours) {
        var bestScore = 0
        var enemyQueen = false
        // check every rotation for each 3x3 rail possibility
        TARGET_NEAR_RAIL.forEach(function (arrangement) {
            ROTATIONS.forEach(function (rot){
                var sevenVal = 1
                var score = 0
                for(var i = 0; i < 9; i++) {
                    score += arrangement[i] == view[rot[i]].color?1:0
                    score += (arrangement[i] == 0 && view[rot[i]].color == 7)?sevenVal:0
                    score += (arrangement[i] == 0 && !(view[rot[i]].color == 7 || view[rot[i]].color == 1))?-1:0
                    if(arrangement[i] == 0 && view[rot[i]].color == view[rot[i-2]].color) score -= 2
                    if(view[rot[i]].color) sevenVal = 0
                    enemyQueen |= view[i].ant && view[i].ant.type == QUEEN && !view[i].ant.friend
                    if(view[i].ant != null && view[i].ant.friend && view[i].ant.type == THIEF && view[i].color == WHITE) score++
                }
                if(score > bestScore && arrangement[9] != view[4].ant.type) {
                    bestScore = score
                }
            })
        })
        if(bestScore >= (5 - (enemyQueen && view[4].ant.type == 1?1:0))) {
            if(highway.likely_nest(colours)) return false
            return true
        }
        return false
    },
    worth_leeching: function(myFood, buddies) {
        var numFours = 0
        var foodNeed = 11
        for(var i = 0; i < 9; i++) {
            if(foe_at(i) == 4) numFours++
        }
        if(!buddies[THIEF]) return false
        if(view[4].ant.type != 5 && buddies[QUEEN] && myFood < 500 && myFood+buddies[THIEF] > (foodNeed-numFours*3)) return true
        return myFood < 500 && myFood >= (foodNeed-numFours*3)
    },
    near_nest_move: function(colours, buddies) {
        var victim_pos = -1
        var avoid_pos = -1
        var friend_pos = -1
        for(var i = 0; i < 9; i++) {
            if(foe_at(i) == QUEEN) victim_pos = i
            if(foe_at(i) > 0 && foe_at(i) < 4) avoid_pos = i
            if(friend_at(i) == THIEF) friend_pos = i
        }
        if(victim_pos >= 0) return rail_miners.follow_victim(view[4].ant, buddies, colours, victim_pos)
        if(view[4].ant.type == THIEF && buddies[QUEEN]) return NOP
        if(view[4].ant.type == QUEEN && rail_miners.worth_leeching(view[4].ant.food, buddies)) {
            if(avoid_pos >= 0 && view[4].color != WHITE) {
                return best_of([
                    try_all_angles.bind(null, [
                        (rot) => (friend_at(rot[1]) === THIEF ? {cell: rot[0]} : null),
                        (rot) => (friend_at(rot[0]) === THIEF ? {cell: rot[3]} : null)
                    ]),
                    try_all_angles.bind(null, [
                        (rot) => (friend_at(rot[1]) === THIEF ? {cell: rot[2]} : null),
                        (rot) => (friend_at(rot[0]) === THIEF ? {cell: rot[1]} : null)
                    ]),
                    NOP
                ])
            }
            var allowed = [[8,4,8],[4,6,8],[6,8,4],[5,5,6],[6,5,2],[2,6,5]]
            var curr = [view[4].color,view[friend_pos].color,view[8-friend_pos].color]
            var found = false
            allowed.forEach(function (al) {
                if(al[0] == curr[0] && al[1] == curr[1] && al[2] == curr[2]) {
                    found = true
                }
            })
            if(!found) {
                return best_of([
                    try_all_angles.bind(null, [
                        (rot) => (friend_at(rot[1]) === THIEF && [2,4,5].indexOf(view[rot[2]].color) >= 0 ? {cell: rot[2]} : null),
                        (rot) => (friend_at(rot[1]) === THIEF && [2,4,5].indexOf(view[rot[0]].color) >= 0 ? {cell: rot[0]} : null)
                    ]),
                    NOP
                ])
            }
            return NOP
        }
        return null
    },
    likely_nest: function(colours) {
        var bestScore = 0
        // check every rotation for each 3x3 rail possibility
        var q = 0
        TARGET_ARRANGEMENT_RAIL.forEach(function (arrangement) {
            var j = 0
            ROTATIONS.forEach(function (rot){
                var score = 0
                for(var i = 0; i < 9; i++) {
                    score += arrangement[i] == view[rot[i]].color?1:0
                    if(view[i].ant != null && view[i].ant.friend && view[i].ant.type == THIEF && view[i].color == WHITE) score++
                }
                if(score > bestScore) {
                    bestScore = score
                }
                j++
            })
            q++
        })
        if(view[4].ant.type == THIEF && rail_miners.near_nest(colours)) return true
        if(bestScore >= 7) {
            if(highway.likely_nest(colours)) return false
            return true
        }
        return false
    },

    likely_victim: function(victim_pos) {
        return true
    },

    follow_victim: function(me, buddies, colours, victim_pos) {
        if(me.type == QUEEN) {
            if(victim_pos % 2 == 0) {
                return best_of([
                    try_all_angles.bind(null, [
                        (rot) => (foe_at(rot[0]) === QUEEN && friend_at(rot[5]) == THIEF ? {cell: rot[2]} : null),
                        (rot) => (foe_at(rot[0]) === QUEEN /*&& friend_at(rot[7]) == THIEF*/ ? {cell: rot[6]} : null)
                    ]),
                    NOP
                ])
            }
            else {
                return best_of([
                    try_all_angles.bind(null, [
                        (rot) => (foe_at(rot[1]) === QUEEN && friend_at(rot[2]) == THIEF ? {cell: rot[5], type: THIEF} : null),
                        (rot) => (foe_at(rot[1]) === QUEEN ? {cell: rot[3], type: THIEF} : null),
                        (rot) => (foe_at(rot[1]) === QUEEN ? {cell: rot[5], type: THIEF} : null),
                        (rot) => (buddies[THIEF] < 4 && foe_at(rot[1]) === QUEEN ? {cell: rot[2], type: THIEF} : null),
                        (rot) => (buddies[THIEF] < 4 && foe_at(rot[1]) === QUEEN ? {cell: rot[0], type: THIEF} : null)
                    ]),
                    NOP
                ])
            }
        }
        return NOP
    },
    find_victim: function(me, buddies, colours) {
        var forwardCell = -1
        var current = view[CENTRE].color
        var target = TARGET_COLOURS_RAIL.next(current)
        var antitarget = TARGET_COLOURS_RAIL.prev(current)
        var queenPos = -1
        for(var i = 0; i < 9; i++) {
            if(i % 2 == 1 && view[i].color == target && view[8-i].color == antitarget && current != WHITE){
                forwardCell = i
            }
            if(friend_at(i) == QUEEN) queenPos = i
        }
        if(forwardCell < 0 && current == 4) {
            target = 4
            antitarget = 2
            for(var i = 0; i < 9; i++) {
                if(i % 2 == 1 && view[i].color == target && view[8-i].color == antitarget){
                    forwardCell = i
                }
            }
        }
        if(me.type == QUEEN) {
            var numEn = 0
            for(var i = 0; i < 9; i++) {
                if(i % 2 == 1 && friend_at(i) == THIEF && friend_at(8-i) == THIEF){
                    if(foe_at(deRotate(i,1)) > 0)
                        return {cell:forwardCell}
                    if(foe_at(deRotate(i,-1)) > 0)
                        return {cell:forwardCell}
                    return NOP
                }
                if(i % 2 == 0 && friend_at(i) == THIEF && friend_at(deRotate(i,2)) == THIEF){
                    return {cell:deRotate(i,3), type:THIEF}
                }
            }
            return wilderness.find_victim(me, buddies, colours)
        }
        else if(forwardCell >= 0) {
            if(friend_at(forwardCell) == QUEEN) {
                return best_of([
                    try_all_angles.bind(null, [
                        (rot) => (friend_at(rot[1]) === QUEEN ? {cell: rot[0]} : null),
                        (rot) => (friend_at(rot[0]) === QUEEN ? {cell: rot[3]} : null)
                    ]),
                    go_anywhere
                ])
            }
        }
        else if(queenPos>=0 && view[queenPos].color == WHITE && (foe_at(deRotate(queenPos,2)) && foe_at(deRotate(queenPos,-2)))) {
            return wilderness.find_victim(me, buddies, colours)
        }
        if(me.type == THIEF && forwardCell >= 0 && buddies[THIEF] == 1) {
            return wilderness.find_victim(me, buddies, colours)
        }
        return NOP
    }
}

var TARGET_ARRANGEMENT_WIND = [
        [5,4,0,7,6,0,6,4,0],
        [7,6,0,6,4,0,5,4,0],
        [6,4,0,5,4,0,7,6,0]
]
var TARGET_ARRANGEMENT_WINDCENTER = [
        [2,7,6,2,6,4,6,5,4],
        [2,6,4,6,5,4,2,7,6],
        [6,5,4,2,7,6,2,6,4]
]
var WIND_BAND = colour_band([5,6,7])
var windmill = {
    name:function() { return "windmill"; },
    near_nest: function(colours) { return false; },
    near_nest_move: function(colours, buddies) { return null; },
    likely_nest: function(colours) { // Main nest detection
        var bestScore = 0
        // check every rotation for each 3x3 rail possibility
        TARGET_ARRANGEMENT_WIND.forEach(function (arrangement) {
            ROTATIONS.forEach(function (rot){
                var score = 0
                for(var i = 0; i < 9; i++) {
                    score += arrangement[i] == view[rot[i]].color?1:0
                }
                if(score > bestScore) {
                    bestScore = score
                }
            })
        })
        if(bestScore >= 5 && view[4].ant.type != THIEF) {
            return true
        }

        var bestScore = 0
        // check every rotation for each 3x3 rail possibility
        TARGET_ARRANGEMENT_WINDCENTER.forEach(function (arrangement) {
            ROTATIONS.forEach(function (rot){
                var score = 0
                for(var i = 0; i < 9; i++) {
                    score += arrangement[i] == view[rot[i]].color?1:0
                }
                if(score > bestScore) {
                    bestScore = score
                }
            })
        })
        if(bestScore >= 8) {
            return true
        }
        var buddies = [0, 0, 0, 0, 0, 0]
        for(var i = 0; i < 9; ++ i) {
            ++ buddies[friend_at(i)]
        }
        return buddies[LANCE] || buddies[LANCE_TIP]
    },
    worth_leeching: function(myFood, buddies) {
        if(view[4].ant.type == THIEF && (buddies[LANCE] > 0 || buddies[LANCE_TIP] > 0)) return true
        return myFood > 5 || (myFood > 1 && buddies[LANCE])
    },
    likely_victim: function(victim_pos) {
        return false
    },

    follow_victim: function(me, buddies, colours, victim_pos) {
        // nest is chaotic and varies by direction of approach
        // We'll let the Find Victim logic handle this
        return NOP
    },

    find_victim: function(me, buddies, colours) {
        if(me.type == THIEF) {
            var queenPos = -1
            var lancePos = -1
            var tipPos = -1
            for(var i=0;i<9;i++) {
                if(friend_at(i) == QUEEN) queenPos = i
                if(friend_at(i) == LANCE) lancePos = i
                if(friend_at(i) == LANCE_TIP) tipPos = i
            }
            if(queenPos < 0 || (foe_at(deRotate(queenPos,1)) > 0 && foe_at(deRotate(queenPos,2)) > 0)) {
                if(queenPos < 0)
                    return go_anywhere
                return {cell:8-queenPos}
            }
            if(queenPos % 2 == 1 && tipPos % 2 == 0) {
                return go_anywhere
            }
            if(queenPos % 2 == 0 && lancePos % 2 == 1) {
                return go_anywhere
            }
            if(queenPos % 2 == 1 && foe_at(deRotate(queenPos,-2)) > 0) {
                return go_anywhere
            }
            return NOP
        }
        if(buddies[LANCE_TIP]) {
            var lancePos = -1
            for(var i=0;i<9;i++) {
                if(friend_at(i) == LANCE_TIP) {
                    lancePos = i
                }
            }
            if(buddies[LANCE]) {
                if(friend_at(8-lancePos) == LANCE) {
                    if(foe_at(deRotate(8-lancePos,1)) == 1 || foe_at(deRotate(8-lancePos,2)) == 1) {
                        var ret = NOP
                        if(lancePos % 2 == 1)
                            ret = {cell:deRotate(8-lancePos,-2)}
                        if(lancePos % 2 == 0)
                            ret = {cell:deRotate(8-lancePos,-3)}
                        if(!sanity_check(ret)) {
                            ret = best_of([
                                try_all_cells_near(lancePos, (i) => (ant_type_at(i) == 0 && view[i].color == 6 ? {cell: i} : null), true),
                                NOP
                            ])
                        }
                        return ret
                    }
                    if(foe_at(deRotate(lancePos,-2)) > 0) {
                        return {cell:deRotate(lancePos,2)}
                    }
                    return NOP
                }
                if(friend_at(deRotate(lancePos,3)) == LANCE) {
                    if((view[lancePos].color == 2 && view[4].color == 7) || foe_at(8-lancePos)) {
                        return {cell:deRotate(lancePos,1)}
                    }
                    return NOP
                }
                if(view[4].color == 6 && view[lancePos].color == 6 && friend_at(deRotate(lancePos,1)) == LANCE) {
                    if(foe_at(deRotate(lancePos,2)) > 0) {

                        return {cell:8-deRotate(lancePos,2)}
                    }
                    return NOP
                }
                if(view[lancePos].color == 2 && view[deRotate(lancePos,-3)].color == 5 && friend_at(deRotate(lancePos,-3)) == LANCE) {
                    return NOP
                }
                if(lancePos % 2 == 0) {
                    if(foe_at(deRotate(lancePos,-1)) > 0 && lancePos % 2 == 1) return {cell:deRotate(lancePos,2)}
                    if(view[deRotate(lancePos,-1)].color != 5) return {cell:deRotate(lancePos,-1),color:5}
                    if(view[deRotate(lancePos,-1)].color == 3 && view[4].color == 1) return {cell:4,color:3}
                    if(view[deRotate(lancePos,-1)].color == 5 && view[4].color == 3) return {cell:4,color:2}
                    if(view[deRotate(lancePos,-1)].color == 5 && view[4].color == 2) return {cell:4,color:1}
                    if(view[deRotate(lancePos,-1)].color == 5 && view[4].color == 7 && view[deRotate(lancePos,-1)].ant == null) return {cell:deRotate(lancePos,-1),type:THIEF}
                    if(view[deRotate(lancePos,-1)].color == 5 && view[4].color == 7) return {cell:4,color:3}
                }
                return {cell:deRotate(lancePos,-1)}
            }
            if(view[4].color == WHITE && view[lancePos].color == WHITE) {
                return {cell:deRotate(lancePos,-2),type:BOUNCER}
            }
            if(view[deRotate(lancePos,-1)].ant != null && view[deRotate(lancePos,-1)].ant.type == 5) {
                return {cell:deRotate(lancePos,2)}
            }
            if(view[4].color == 6 && view[deRotate(lancePos,1)].color == 7) {
                return {cell:deRotate(lancePos,1)}
            }
            if(foe_at(deRotate(lancePos,-2)) > 0 || foe_at(deRotate(lancePos,-3)) > 0) {
                if(foe_at(deRotate(lancePos,-2)) > 0 && foe_at(deRotate(lancePos,3)) > 0 && (foe_at(deRotate(lancePos,-1)) > 0 || foe_at(deRotate(lancePos,4)) > 0)) {
                    return {cell:deRotate(lancePos,1)}
                }
                if(foe_at(deRotate(lancePos,3)) > 0) {
                    return NOP
                }
                return {cell:deRotate(lancePos,1)}
            }
            if(foe_at(deRotate(lancePos,2)) > 0 && view[deRotate(lancePos,-1)].color != 2) {
                return {cell:deRotate(lancePos,-1),color:2}
            }
            if(foe_at(deRotate(lancePos,-1)) > 0) {
                return {cell:deRotate(lancePos,1)}
            }
            if(lancePos % 2 == 1 && friend_at(deRotate(lancePos,-1)) == THIEF) {
                return {cell:deRotate(lancePos,-2)}
            }
            return {cell:deRotate(lancePos,-1)}
        }
        else if(buddies[LANCE]) {
            var lancePos = -1
            for(var i=0;i<9;i++) {
                if(view[i].ant && view[i].ant.friend && view[i].ant.type == LANCE) {
                    lancePos = i
                }
            }
            if(view[4].color == 3 && lancePos % 2 == 1) return NOP
            var moveNext = lancePos % 2 == 1 ? {cell:deRotate(lancePos,2)} : {cell:deRotate(lancePos,1)}
            if(view[moveNext.cell].ant != null && !view[moveNext.cell].ant.friend) {
                moveNext = {cell:deRotate(lancePos,1),type:LANCE_TIP}
            }
            if(view[lancePos].ant.food > 0) {
                if(lancePos % 2 == 1)
                    return {cell:deRotate(lancePos,4),type:LANCE_TIP}
                else
                    return {cell:deRotate(lancePos,3),type:LANCE_TIP}
            }
            if(view[lancePos].color == 6 && view[moveNext.cell].color == 8 && view[deRotate(lancePos,2)].color == 5) {
                return {cell:moveNext.cell,type:LANCE_TIP}
            }

            return moveNext
        }
        else {
            var current = view[CENTRE].color
            var standOn = WIND_BAND.next(WIND_BAND.next(WIND_BAND.next(current)))
            var target = WIND_BAND.next(current)
            var antitarget = WIND_BAND.next(target)
            if(current != standOn) return wilderness.find_victim(me, buddies, colours)

            var ret = best_of([
                try_all_cells((i) => ((i % 2 == 1 && view[i].color == target && view[8-i].color == antitarget && ([2,5,6].indexOf(view[deRotate(i,-1)].color) >= 0) && (view[i].color != 5 || view[deRotate(i,1)].color == 4)) ? {cell: i, type: LANCE} : null), true),
                NOP
            ])
            if(ret.cell == 4) {
                return wilderness.find_victim(me, buddies, colours)
            }
            return ret
        }
        return NOP
    }
}

var TARGET_ARRANGEMENT_HIGHWAY = [
    [2,3,7,6,8,2,3,7,6],
    [2,3,7,7,6,4,4,2,3],
    [2,4,6,7,3,2,4,6,7],
    [3,2,4,4,6,7,7,3,2],
    [3,4,7,7,2,6,6,3,4],
    [3,4,7,2,6,3,4,7,2],
    [3,6,2,2,7,4,4,3,6],
    [4,7,2,2,5,6,3,4,7],
    [4,6,7,2,6,3,3,4,7],
    [4,6,7,7,3,2,2,4,6],
    [6,4,2,3,7,6,4,2,3],
    [7,3,2,2,4,6,6,7,3],
    [7,4,3,6,2,7,4,3,5]
]
var HIGHWAY_BAND = colour_band([2,7,4,3,6])
var HIGHWAY_BAND2 = colour_band([2,3,7,6,4])

var highway = {
    name:function() { return "highway"; },                                     // For debugging
    near_nest: function(colours) { return false; },                // For dodging enemy workers without getting lost
    near_nest_move: function(colours, buddies) { return null; }, // How to move when near_nest is true
    likely_nest: function(colours) { // Main nest detection
        var bestScore = 0
        // check every rotation for each 3x3 rail possibility
        TARGET_ARRANGEMENT_HIGHWAY.forEach(function (arrangement) {
            ROTATIONS.forEach(function (rot){
                var score = 0
                for(var i = 0; i < 9; i++) {
                    score += arrangement[i] == view[rot[i]].color?1:0
                }
                if(score > bestScore) {
                    bestScore = score
                }
            })
        })
        if(bestScore >= 7) {
            return true
        }
        if(this.isCenter(colours)) return true

        return false
    },         // Main nest detection
    isCenter: function(colours) {
        var bestScore = 0
        ROTATIONS.forEach(function (rot){
            var score = 0
            for(var i = 0; i < 9; i++) {
                if(i >= 3 && i <= 5 && [2,7,4,3,6].indexOf(view[rot[i]].color) >= 0 && (i == 4 || view[rot[i]].color != view[rot[8-i]].color)) {
                    if(i != 4) {
                        score++
                    }
                    else {
                        if(view[rot[3]].color != view[rot[5]].color && view[rot[1]].color == view[rot[7]].color && (view[rot[4]].color != view[rot[1]].color && view[rot[4]].color != view[rot[3]].color && view[rot[4]].color != view[rot[5]].color && view[rot[4]].color != view[rot[7]].color)) {
                            score++
                        }
                    }
                }
                else if(i >= 6) {
                    if(view[rot[i]].color == view[rot[i-6]].color && [2,7,4,3,6].indexOf(view[rot[i]].color) >= 0 && (i == 7 || view[rot[i]].color != view[rot[8-i]].color) && view[rot[i]].color != view[4].color) {
                        score += 2
                    }
                }
            }
            if(score > bestScore) {
                bestScore = score
            }
        })
        if(bestScore >= 7) {
            return true
        }
        return false
    },
    worth_leeching:function(myFood, buddies){ return myFood > 80 && myFood < 500; }, // Is this nest worth leeching?
    likely_victim: function(victim_pos) {
        return true
    },   // Identifying the target queen
    follow_victim: function(me, buddies, colours, victim_pos) {
        if(me.type == QUEEN && buddies[THIEF] < 3) {
            return best_of([
                try_all_cells((i) => (near(i, victim_pos) ? {cell: i, type: THIEF} : null), true),
                try_all_cells((i) => ({cell: i, type: THIEF}), true)
            ])
        }
        if(me.type == THIEF && buddies[QUEEN])
            return NOP
        return go_anywhere
    },   // How to handle what happens when the enemy queen is found
    find_victim: function(me, buddies, colours) {
        if(me.type == THIEF && !buddies[QUEEN]) {
            for(var i=0;i<9;i++) {
                if(foe_at(i)) return NOP
            }
            var target = HIGHWAY_BAND.prev(view[4].color)
            var followRail = best_of([
                try_all_cells((i) => (i % 2 == 1 && view[i].color == target) ? {cell:i} : null),
                NOP
            ])
        }
        else {
            var target = HIGHWAY_BAND.next(view[4].color)
            var followRail = best_of([
                try_all_cells((i) => (i % 2 == 1 && view[i].color == target) ? {cell:i} : null),
                NOP
            ])
        }
        return followRail
    }                // How to follow the nest
}

var wilderness = {
    name:function() { return "wilderness"; },
    near_nest: function(colours) { return false; },
    near_nest_move: function(colours, buddies) { return null; },
    likely_nest: function(colours) {
        return true
    },
    worth_leeching: function(myFood, buddies) {
        return true
    },
    likely_victim: function(victim_pos) {
        return true
    },

    follow_victim: function(me, buddies, colours, victim_pos) {
        // We stumbled across a random queen; make the most of it
        // TODO
        if(rail_miners.near_nest(colours)) {
            return rail_miners.follow_victim(me, buddies, colours, victim_pos)
        }

        // avoids blocking off the rail miner queen from her workers
        // (we'd like to leech her again)
        if(me.type === QUEEN && !buddies[THIEF] && me.food > 0) {

            // Make a buddy to help us steal
            return best_of([
                try_all_cells((i) => (near(i, victim_pos) ? {cell: i, type: THIEF} : null), true),
                try_all_cells((i) => ({cell: i, type: THIEF}), true)
            ])
        }
        else if(me.type === QUEEN){
            var enemyCount = 0
            var allyPos = -1
            for(var a=0; a<9; a++) {
                if(a != 4 && view[a].ant != null) {
                    if(view[a].ant.friend) {
                        if(near(a,victim_pos)){
                            allyPos = a
                        }
                    }
                    else if(view[a].ant.type != 5) {
                        enemyCount++
                    }
                }
            }
            if(enemyCount >= buddies[THIEF] && allyPos >= 0) {
                //if next to the queen and we're outnumbered, move back to the center of the rail.
                var target = TARGET_COLOURS_RAIL.prev(view[allyPos].color)
                var best = best_of([
                    try_all_cells((i) => (near(i, victim_pos) && i % 2 == 0 ? {cell: i, type: THIEF} : null), true),
                    try_all_cells((i) => (near(i, victim_pos) ? {cell: i, type: THIEF} : null), true)
                ])
                if(best != null) return best

                best_of([
                    try_all_cells((i) => ((view[i].color == target && i != 4 && areAdjacent(i,a)) ? {cell: i} : null))
                ])
                if(best != null) return best

                return best_of([
                    {cell:deRotate(allyPos,1)},
                    {cell:deRotate(allyPos,-1)}
                ])
            }
        }

        return NOP
    },
    find_victim: function(me, buddies, colours) {
        if(me.type === QUEEN) {
            var in_void = true
            for(var i = 0; i < 9; ++ i) {
                if(view[i].color !== WHITE && !SAFE_COLOURS.contains(view[i].color)) {
                    in_void = false
                    break
                }
            }
            if(!in_void) {
                // because of avoiding returning Miner on a Rail workers
                // we dodge sideways and this takes us back onto track
                var nearMove = checkAllNearEnvirons(colours, buddies)
                if(nearMove) return nearMove
            }
            return best_of([
                // Make a buddy once we have a reasonable stash of food so we can
                // search the board faster
                // (but avoid making buddies when there's a potential nest nearby
                // better to wait until we find their queen)
                (!buddies[THIEF] && me.food >= INITIAL_GATHER && in_void) &&
                    try_all_cells((i) => ({cell: i, type: THIEF}), true),

                // Follow buddy in search of victims
                buddies[THIEF] && try_all_angles.bind(null, [
                    (rot) => (friend_at(rot[1]) === THIEF ? {cell: rot[2]} : null),
                    (rot) => (friend_at(rot[0]) === THIEF ? {cell: rot[1]} : null)
                ]),
                buddies[THIEF] && try_all_angles.bind(null, [
                    (rot) => (friend_at(rot[1]) === THIEF ? {cell: rot[0]} : null),
                    (rot) => (friend_at(rot[0]) === THIEF ? {cell: rot[3]} : null)
                ]),
                buddies[THIEF] && NOP, // Don't lose our buddy!

                // Random walk until we can make a buddy or find the victim
                grab_nearby_food,
                foe_near() ? go_anywhere : fast_diagonal.bind(null, SAFE_COLOURS),
                go_anywhere
            ])
        } else if(me.type === THIEF) {
            return best_of([
                // Lost the queen! Random walk because we have nothing better to do.
                // (don't leave lines; they could disrupt the pattern)
                !buddies[QUEEN] && go_anywhere,
                buddies[BOUNCER] && go_anywhere,
                buddies[THIEF] > 1 && go_anywhere, //untested
                // Follow queen in search of victims
                try_all_angles.bind(null, [
                    (rot) => (friend_at(rot[1]) === QUEEN ? {cell: rot[0]} : null),
                    (rot) => (friend_at(rot[0]) === QUEEN ? {cell: rot[3]} : null)
                ]),
                NOP // Don't lose our buddy!
            ])
        }
    }
}

var victims = [highway, rail_miners, windmill]

function guess_environment(colours, buddies) {
    var food = view[4].ant.food
    if(view[4].ant.type !== QUEEN) {
        for(var i = 0; i < 9; i++) {
            if(i != 4 && view[i].ant && view[i].ant.friend && view[i].ant.type === QUEEN) {
                food = view[i].ant.food
            }
        }
    }
    for(var i = 0; i < victims.length; ++ i) {
        if(victims[i].likely_nest(colours) && victims[i].worth_leeching(food, buddies)) {
            return victims[i]
        }
    }

    return wilderness
}

function is_safe(i) {
    var nearThief = false
    var nearOfficer = false
    for(var j = 0; j < 9; ++ j) {
        if(friend_at(j) === THIEF) {
            nearThief = true
        }
        if(foe_at(j) && foe_at(j) !== QUEEN) {
            nearOfficer = true
        }
    }
    return nearThief && !nearOfficer
}

function move(me, buddies) {
    var colours = [0, 0, 0, 0, 0, 0, 0, 0, 0]
    for(var i = 0; i < 9; ++ i) {
        ++ colours[view[i].color]
    }
    var env = guess_environment(colours,buddies)
    var victim_pos = -1
    var queen_pos = -1
    for(var i = 0; i < 9; ++ i) {
        if(foe_at(i) === QUEEN && env.likely_victim(i) && view[i].ant.food > 0) {
            victim_pos = i
            if(view[i].ant.food > 0) {
                break
            }
        }
        if(friend_at(i) === QUEEN) {
            queen_pos = i
        }
    }

    var in_void = true
    for(var i = 0; i < 9; ++ i) {
        if(view[i].color !== WHITE || (i != 4 && me.type === BOUNCER && friend_at(i) === BOUNCER)) {
            in_void = false
            break
        }
    }
    if(me.type === BOUNCER) {
        if(env === wilderness && in_void) {
            // Our work is done; leave queen and wander at random
            if(buddies[QUEEN]) {
                return best_of([
                    try_all_cells((i) => (ant_type_near(i, true) ? null : {cell: i}), true),
                    go_anywhere
                ])
            }
            return NOP
        }
        else if(env === rail_miners) {
            // Our work is done; leave queen and wander at random
            if(buddies[QUEEN]) {
                var allAngles = try_all_angles.bind(null, [
                    (rot) => (friend_at(rot[1]) === QUEEN ? {cell: rot[0]} : null),
                    (rot) => (friend_at(rot[0]) === QUEEN ? {cell: rot[3]} : null),
                    NOP
                ])
                return best_of([
                    //if next to an enemy queen, move out of the way
                    try_all_cells((i) => (foe_at(i) == QUEEN ? {cell:9-i} : null), true),
                    try_all_cells((i) => (foe_at(i) == QUEEN ? {cell:7-i} : null), true),
                    allAngles
                ])
            }
            return NOP
        } else if(buddies[QUEEN]) {
            // Escort queen out of nest
            var allAngles = try_all_angles.bind(null, [
                (rot) => (friend_at(rot[1]) === QUEEN ? {cell: rot[0]} : null),
                (rot) => (friend_at(rot[0]) === QUEEN ? {cell: rot[3]} : null),
                NOP
            ])

            return best_of([
                //if next to an enemy queen, move out of the way
                try_all_cells((i) => (foe_at(i) == QUEEN ? {cell:9-i} : null), true),
                try_all_cells((i) => (foe_at(i) == QUEEN ? {cell:7-i} : null), true),
                allAngles
            ])
        }
        else {
            return go_anywhere
        }
    } else if(buddies[BOUNCER]) {
        if(me.type === QUEEN) {
            // Be escorted out of nest
            return try_all_angles.bind(null, [
                (rot) => (friend_at(rot[1]) === BOUNCER ? {cell: rot[2]} : null),
                (rot) => (friend_at(rot[0]) === BOUNCER ? {cell: rot[1]} : null),
                go_anywhere,
                NOP
            ])
        } else {
            // Get out of the way
            return try_all_angles.bind(null, [
                (rot) => (friend_at(rot[1]) === QUEEN ? {cell: rot[7]} : null),
                (rot) => (friend_at(rot[0]) === QUEEN ? {cell: rot[8]} : null),
                (rot) => (friend_at(rot[1]) === BOUNCER ? {cell: rot[7]} : null),
                (rot) => (friend_at(rot[0]) === BOUNCER ? {cell: rot[8]} : null),
                go_anywhere
            ])
        }
    }
    if(victim_pos !== -1) {
        // abandon the queen if she's dry.
        // abandon rail miner's queen so she has at least 10 food (otherwise she produces workers 3:4 food she aquires)
        // value is higher than 10 because there's two to three rounds of theft (at 4 ants each) before the queen gets out of range
        // this can still leave the rail miner's queen lower than 10, but unlikely
        // other queens are abandoned if they have less than 5 food, due to the "max 4 ants stealing" and at 0 food, she's not a target.
        if(view[victim_pos].ant.food < 5 || (env == rail_miners && view[victim_pos].ant.food < 28)) {
            if(me.type == THIEF) {
                if(rail_miners.near_nest(colours)) {
                    // we'd rather reuse the workers
                    return NOP
                }
            }
            // Victim is out of food; bounce out of nest
            if(env == rail_miners) {
                if(me.type == QUEEN && me.food < 300 && !buddies[BOUNCER]) {
                    if(friend_at(deRotate(victim_pos,2)) == THIEF && foe_at(deRotate(victim_pos,3)) == 0) return {cell:deRotate(victim_pos,3),type:BOUNCER}
                    if(friend_at(deRotate(victim_pos,-2)) == THIEF && foe_at(deRotate(victim_pos,-3)) == 0) return {cell:deRotate(victim_pos,-3),type:BOUNCER}
                }
                // murder SlM
                return NOP
            }
            var m = try_all_cells((i) => ({cell: i, type: BOUNCER}), true)
            if(m) {
                return m
            }
        }
        if(me.type === QUEEN && buddies[THIEF] && !is_safe(CENTRE)) {
            // Try to avoid getting food stolen back from us
            var m = try_all_cells((i) => (is_safe(i) ? {cell: i} : null), true)
            if(m) {
                return m
            }
        }
        return env.follow_victim(me, buddies, colours, victim_pos)
    } else {
        return env.find_victim(me, buddies, colours)
    }
}

// LANCE is only used by windmill targetting, easier to break this out as its own method
function moveLance(me, buddies) {
    var queenPos = -1
    var tipPos = -1
    var enQueenPos = -1
    if(buddies[BOUNCER]) {
        for(var i=0;i<9;i++) {
            if(friend_at(i) == BOUNCER) {
                return {cell:8-i}
            }
        }
    }
    for(var i=0;i<9;i++) {
        if(friend_at(i) == QUEEN) {
            queenPos = i
        }
        if(friend_at(i) == LANCE_TIP) {
            tipPos = i
        }
        if(foe_at(i) == QUEEN) enQueenPos = i
    }
    if(!buddies[QUEEN]) {
        for(var i=0;i<9;i++) {
            if(i % 2 == 0 && friend_at(i) == QUEEN) {
                if(view[deRotate(i,3)].ant != null && view[deRotate(i,3)].ant.friend && view[deRotate(i,3)].ant.type == LANCE_TIP) return NOP
                return {cell:deRotate(i,1)}
            }
        }
        if(!buddies[LANCE_TIP] && !buddies[THIEF] && view[4].color == 2) {
            for(var i = 0; i < 9; ++ i) {
                if(view[i].color == 1) return {cell:i}
            }
        }
        if(enQueenPos >= 0 && enQueenPos % 2 == 0 && foe_at(deRotate(enQueenPos,1)) == 1) {
            return {cell:deRotate(enQueenPos,-3)}
        }
        if(enQueenPos >= 0 && enQueenPos % 2 == 1 && foe_at(deRotate(enQueenPos,2)) == 1) {
            return {cell:8-enQueenPos}
        }
        if(enQueenPos >= 0 && (me.food > 0 || foe_at(deRotate(enQueenPos,-1)) || foe_at(deRotate(enQueenPos,3)))) {
            if(enQueenPos % 2 == 0 && (foe_at(deRotate(enQueenPos,4)) || friend_at(deRotate(enQueenPos,4)) == THIEF)) {
                return {cell:deRotate(enQueenPos,-3)}
            }
        }
        return NOP
    }
    if(buddies[LANCE_TIP]) {
        if(deRotate(queenPos,-1) == tipPos && view[tipPos].color == 8) return {cell:8-tipPos}
        if(deRotate(queenPos,-1) == tipPos) return try_all_cells((i) => (areAdjacent(i,tipPos) && view[i].color == 5 ? {cell:i} : null))
        if(foe_at(8-tipPos) == QUEEN) return {cell:8-tipPos,color:6}
        if(foe_at(8-queenPos) > 0 || foe_at(deRotate(8-queenPos,1)) > 0) return NOP
        return try_all_cells((i) => (!areAdjacent(i,queenPos) && !areAdjacent(i,tipPos) ? {cell:i} : null))
    }
    if(view[4].color != 4 && view[4].color != 6) {
        if(foe_at(8-queenPos) == QUEEN) {
            var formation = try_all_angles.bind(null, [
                (rot) => (foe_at(rot[1]) === 1 && foe_at(rot[2]) === QUEEN ? {cell: rot[3]} : null),
                (rot) => (foe_at(rot[1]) === 1 && foe_at(rot[0]) === QUEEN ? {cell: rot[7]} : null),
                (rot) => (foe_at(rot[1]) === 1 && view[rot[1]].ant.food > 0 && foe_at(rot[6]) === QUEEN && friend_at(rot[2]) === QUEEN ? {cell: rot[5]} : null),
            ])()
            if(formation != null) {
                return formation
            }
            return NOP
        }
        if(foe_at(deRotate(queenPos,1)) > 0 && foe_at(deRotate(queenPos,-1)) > 0) {
            return {cell:deRotate(queenPos,-3)}
        }
        return best_of([
            try_all_cells((i) => (enQueenPos ==-1 && i % 2 == 1 && (view[i].color == 4 || view[i].color == 6) && view[deRotate(i,1)].color != 2 && view[deRotate(i,-1)].color != 2 && areAdjacent(i,queenPos) ? {cell: i} : null), true),
            ((view[4].color != 6 || view[4].color != 4) && queenPos % 2 == 0 && view[deRotate(queenPos,-3)].color == 5) ? {cell:4,color:6} : null,
            NOP
        ])
    }
    else {
        var queenOn = view[8-queenPos].color
        var target = WIND_BAND.next(queenOn)
        var prior = WIND_BAND.next(target)
        var followRail = best_of([
            try_all_cells((i) => (view[deRotate(i,-3)].color == prior && view[deRotate(i,-1)].color == target && areAdjacent(i,queenPos) && (view[i].color == 4 || view[i].color == 6) ? {cell: i} : null), true),
            queenPos % 2 == 1 ? (view[queenPos].color == 4 || view[4].color == 4 ? NOP : {cell:deRotate(queenPos,-2)}) : (view[queenPos].color == 4 || view[queenPos].color == 6 ? {cell:deRotate(queenPos,-1)} : NOP)
        ])

        if(view[deRotate(queenPos,-1)].ant != null) {
            if(!view[deRotate(queenPos,-1)].ant.friend && view[deRotate(queenPos,-2)].ant != null && !view[deRotate(queenPos,-2)].ant.friend) {
                return NOP
            }
            if(queenPos % 2 == 0 && !view[deRotate(queenPos,-1)].ant.friend && view[deRotate(queenPos,-2)].ant == null && (view[queenPos].color == 3 || view[queenPos].color == WHITE)) {
                return {cell:deRotate(queenPos,-3)}
            }
            if(queenPos % 2 == 0 && friend_at(deRotate(queenPos,-1)) == THIEF && view[deRotate(queenPos,-2)].ant == null && (view[queenPos].color == 3 || view[queenPos].color == WHITE)) {
                return {cell:deRotate(queenPos,-3)}
            }
            return NOP
        }
        if(me.food > 0 && queenPos % 2 == 0) {
            return {cell:deRotate(queenPos,-1)}
        }
        if(foe_at(deRotate(queenPos,-3)) > 0 && (view[queenPos].color == 1 || view[deRotate(queenPos,1)].color == 1 || view[deRotate(queenPos,-1)].color == 1)) {
            if(view[queenPos].color == 3) {
                return followRail
            }
            if(view[queenPos].color == 7) return NOP
            return {cell:queenPos,color:3}
        }
        if((foe_at(deRotate(queenPos,-2)) > 0 || foe_at(deRotate(queenPos,-3)) > 0) && queenPos % 2 == 0 && view[deRotate(queenPos,-1)].color == 5) {
            if(view[queenPos].color == 7) return NOP
            return {cell:queenPos,color:3}
        }
        if(view[deRotate(queenPos,-4)].ant != null && !view[deRotate(queenPos,-4)].ant.friend && (view[queenPos].color == 1 || view[deRotate(queenPos,1)].color == 1 || view[deRotate(queenPos,-1)].color == 1)) {
            if(view[queenPos].color == 7) return NOP
            return {cell:queenPos,color:3}
        }
        if((followRail == null || followRail.cell == 4) && foe_at(deRotate(queenPos,-2)) == 1) {
            if(view[queenPos].color == 7) return NOP
            return {cell:queenPos,color:3}
        }
        if(followRail != null && followRail.cell != 4 && view[followRail.cell].color == 6 && view[deRotate(followRail.cell,1)].color == 6) {
            followRail = {cell:deRotate(followRail.cell,1)}
        }
        return followRail
    }
    return NOP
}

// LANCE_TIP never needs to move
// Unfortunately, reusing an existing worker type for this purpose is not easily possible.
// Used against Sliding Miners as a stationary blocker to prevent the queen slipping past.
function moveTip(me, buddies) {
    var queenPos = -1
    var in_void = true
    for(var i=0;i<9;i++) {
        if(friend_at(i) == QUEEN) {
            queenPos = i
        }
        if(view[i].color != WHITE) {
            in_void = false
        }
    }
    var colours = [0, 0, 0, 0, 0, 0, 0, 0, 0]
    var enemies = 0
    for(var i = 0; i < 9; ++ i) {
        ++ colours[view[i].color]
        if(foe_at(i) > 0) enemies++
    }
    var onRails = rail_miners.near_nest(colours)
    if(buddies[QUEEN] && !buddies[LANCE]) {
        if(onRails) return NOP
        if(foe_at(8-queenPos) == 4) {
            return {cell:deRotate(queenPos,2)}
        }
        if(in_void) return {cell:deRotate(queenPos,4)}
        if(enemies == 2 && queenPos % 2 == 0 && view[deRotate(queenPos,1)].ant == null) {
            return {cell:queenPos,color:7}
        }
        if(enemies == 2 && queenPos % 2 == 1) {
            return {cell:deRotate(queenPos,-1),color:7}
        }
    }
    if(buddies[QUEEN] && buddies[LANCE]) {
        if(enemies == 0 && view[queenPos].color == 1) return NOP
        if(view[deRotate(queenPos,1)].color == 5 && friend_at(deRotate(queenPos,1)) == LANCE) return {cell:deRotate(queenPos,4)}
        return {cell:deRotate(queenPos,2)}
    }
    if(!buddies[QUEEN] && view[4].color == 2) {
        for(var i = 0; i < 9; ++ i) {
            if(view[i].color == 8) return {cell:i}
        }
    }
    if(queenPos >=0 && foe_at(deRotate(queenPos,2)) > 0 && view[deRotate(queenPos,2)].ant.food == 0 && foe_at(deRotate(queenPos,4)) > 0 && view[deRotate(queenPos,4)].ant.food > 0) {
        return {cell:queenPos,color:7}
    }
    return NOP
}

function deRotate(m, amt) {
    var rotationsCW = [1,2,5,8,7,6,3,0]
    var rotationsCCW = [3,6,7,8,5,2,1,0]
    if(m == 4 || m < 0 || m > 8 || amt == 0) return m
    if(amt > 0)
        return rotationsCW[(rotationsCW.indexOf(m)+amt)%8]
    amt = -amt
    return rotationsCCW[(rotationsCCW.indexOf(m)+amt)%8]
}

return play_safe(move_agent([
    THIEF, move,
    QUEEN, move,
    BOUNCER, move,
    LANCE, moveLance,
    LANCE_TIP, moveTip
]))

किसी ने भी नियम का उपयोग करते हुए कोई जवाब पोस्ट नहीं किया था "दुश्मन रानी से सटे एक अनैतिक कार्यकर्ता, यदि मौजूद है तो 1 टुकड़ा भोजन चुराएगा।", इसलिए मैंने उसे ठीक करने का फैसला किया!

यह वैम्पायर विशिष्ट लक्ष्यों को प्राप्त करने का प्रयास करता है, जो लगातार अपडेट किए जाते हैं (क्योंकि यह एक सामुदायिक विकी है), और कभी-कभी अक्षम होते हैं ( worth_leechingफ़ंक्शन के माध्यम से ) जब वे अब पर्याप्त लाभदायक नहीं होते हैं।

ध्यान दें कि worth_leechingउल्लेखित फ़ंक्शन, लक्ष्य को अक्षम करने में इसके उपयोग के अलावा (यदि यह गलत है), निर्णय लेने को अधिकतम करने के लिए दिए गए लक्ष्यीकरण ऑब्जेक्ट पर नियंत्रण के लिए अनुमति देता है, जैसे कि वैम्पायर को संभावित जाल के बाद जाने से रोकना (Ziggurat बहुत कम जेब बनाता है) केंद्र में रानी) जब तक कि वैम्पायर ने पर्याप्त मात्रा में भोजन एकत्र नहीं कर लिया है, तब तक वह पूरी तरह से बर्बाद नहीं होगा (केवल 12 भोजन स्कोर)। पारित किए गए पैरामीटर viewऑब्जेक्ट को क्वेरी करने के बिना विधि को बहुत लचीला बनाते हैं ।

लक्ष्य के विवरण का पालन करते हैं, क्रम में वे कोड में दिखाई देते हैं:

ब्लैक होल (लक्ष्य अक्षम)

जब यह ब्लैक होल पाता है, तो यह बहुत यादृच्छिक है कि क्या हम उनकी रानी को ढूंढेंगे, या उनके कार्यकर्ता हमारे स्वयं के भोजन को खत्म कर देंगे, या हम उछल कर खोज करेंगे। ब्लैक होल को निशाना बनाना बहुत कठिन है।

ज़िगगुरैट (लक्ष्य अक्षम)

एक बार ज़िगगुरैट के केंद्र में, रानी ने जितना संभव हो सके उतने भोजन को निकालने के लिए चोरों को उकसाया। यह उपवास करना है क्योंकि कॉलोनी अब श्रमिकों की एक सेना (अपने स्वयं के भोजन को बर्बाद कर) को पैदा करके हमारे खिलाफ बचाव करती है। एक बार जब सभी खाना खत्म हो जाता है, तो हम एक "बाउंसर" बनाते हैं और अगले शिकार की तलाश में खुद को बाहर निकालते हैं।

ब्लैक होल के लिए, यह सतह पर बैठे एक कार्यकर्ता का उपयोग करता है ताकि लक्ष्य रानी के पास से गुजरने का इंतजार किया जा सके, जबकि हमारी रानी गहरी बैठती है ताकि गुजरने वाले श्रमिक उसे खोद न सकें। जब लक्ष्य रानी अंततः गुजरती है, तो हम उसका यथासंभव पालन करते हैं।

एक रेल पर खनिक के लिए, यह देखने के लिए एक बल-बल खोज का उपयोग करता है कि क्या रानी खनिक रेल प्रणाली के केंद्र में बैठी है। इसके बाद यह अपने स्रोत पर वापस जाता है (खनिक के श्रमिकों को चारों ओर से जाने देता है)। एक बार रानी के रूप में यह एक चोर को सामान्य रूप से जगाती है और रानी को 9 भोजन तक नीचे गिरा देती है। 10 भोजन के तहत माइनर क्वीन को दिए गए हर 4 भोजन के लिए 3 कर्मचारी उत्पन्न करते हैं, जिससे कम रिटर्न की संभावना रहती है। बाउंस आउट करें और बाद में लौटें। (इस पर्यावरण कोड को उपलब्ध कराने के लिए धन्यवाद Draco18s पर जाएं!)

जब यह ज़िगगुरैट को पाता है, तो यह बहुत अच्छा करता है, और दिलचस्प विस्फोट का कारण बनता है, जैसा कि इस प्रारंभिक प्रोटोटाइप में देखा गया है (उछलने से पहले जोड़ा गया था):

ज़िगगुरैट में विस्फोट हुआ

FireFly (लक्षित अक्षम)

जुगनू को निशाना बनाने वाला ब्लॉक बेसलाइन के रूप में जिगगुरट कोड का उपयोग करता है, लेकिन उपयोग किए गए रंगों को ओवरराइड करता है। यह किसी भी लेखक के लिए बाइट-काउंट कम रखते हुए आसानी से एक नया वैम्पायर लक्ष्य बनाना आसान बनाता है। जब जुगनू भोजन एकत्र नहीं करता था, लेकिन जुगनू कोड अक्षम था, लेकिन Mk में फिर से सक्षम किया गया। 5।

FIrefly से संबंधित नहीं है, लेकिन Mk.4 ने कुछ अतिरिक्त ऑब्जेक्ट तरीकों को भी जोड़ा है ताकि लक्ष्य के श्रमिकों (एंटी-रेल-माइनर्स कोड द्वारा प्रयुक्त) को संभालने के लिए काम किया जा सके, जो वैंपायर क्वीन को सुरक्षित रूप से एक कार्यशील रेल माइनर रिपेयर का सामना करने की अनुमति देता है। जिससे दो चींटियाँ स्थायी रूप से चिपक जाती हैं।

एक रेल पर खनिक (MoaR) / फिसलने वाले मिडर (SlM)

जब यह एक रेल पर माइनर्स पाता है, तो यह अपने भोजन की चोरी होने से बचने के लिए रेल को आउटबाउंड दिशा (उसी दिशा में अनियंत्रित रेलकर्मी स्थानांतरित करता है) में ट्रैक करता है। जब यह रेल के अंत का पता लगाता है, तो यह रेल के स्वयं के कार्यकर्ता 4 (मरम्मतकर्ता) पर खनिकों की तरह कार्य करता है। हम जानते हैं कि रेल कहाँ है, साथ ही साथ उस दिशा का पालन करें और शुरू करने के लिए वापस लौटें!

लेकिन सबसे आम परिणाम यह है कि हमें कभी कुछ नहीं मिलता है। यह उस मामले में अभी भी ठीक है; स्कोरबोर्ड के बीच में।

विंडमिल

डॉन क्विक्सोट (विंडमिल टारगेटिंग) कोड (एमके 5 में) का विकास चुनौतियों से भरा हुआ था और एक स्वीकार्य रणनीति विकसित होने से पहले इसमें कई पुनरावृत्तियां शामिल थीं , जिसमें एक नया एंट प्रकार भी शामिल था। जब रानी ने नोटिस किया कि वह विंडमिल की मुख्य भुजाओं की मध्य रेल पर खड़ी है, तो यह एक नए प्रकार के कार्यकर्ता (कोड-नाम LANCE) को पैदा करता है, ताकि दुश्मन श्रमिकों से बचने के लिए रेल की तरफ नीचे चला जाए (जैसे कि एक दुश्मन कार्यकर्ता पिशाच को मारता है रानी, ​​वे उसे गतिरोध करने का प्रयास करेंगे), जब तक कि विंडमिल रानी से मुठभेड़ नहीं हो जाती।

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

ये हमले विंडमिल रानी के भोजन को निर्धारित करने में असमर्थ होने की लागत पर आते हैं और इस तरह से यह अनुमान लगाने में असमर्थ हैं कि स्पैन कब BOUNCERऔर बेहतर पीड़ितों के लिए छोड़ दें। हालाँकि, यह वैम्पायर के पक्ष में काम करता है क्योंकि विंडमिल एक ऐसी मोटी, रसीली गाय है जिसे अंत तक चिपकाना अधिक मूल्यवान है: विंडमिल आसानी से केवल कुछ हज़ार चालों में कई सौ भोजन इकट्ठा कर सकता है, वैम्पायर की तुलना में बहुत अधिक प्राप्त कर सकता है जोंक के लिए एक नया लक्ष्य खोजने की कोशिश कर रहा है।

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

नवीकरणीय ऊर्जा (एमके 7) विंडमिल को लक्षित करने वाले तर्क को संशोधित करती है, मोटे तौर पर एमके 6 के परिवर्तनों को पूर्ववत कर रही है, क्योंकि विंडमिल में परिवर्तन हुए थे जो कोड को 100% समय के लिए विफल करने का कारण बन रहा था। संशोधित सफलता दर लगभग 70% है, शेष 30% गूंगे भाग्य के कारण अपरिहार्य है। लगभग वेक्टर को बदल दिया गया।

हाइवे

हाईवे आसानी से मिल जाता है। यह कयामत का कभी फैलने वाला हरा-भरा फूल है। तो, हाइवे के बाद जाने से पहले माइनर्स और विंडमिल के सपने खोजने और उसे नष्ट करने के लिए इंतजार करने का मतलब है कि वैम्पायर बहुत जल्द लक्ष्य नहीं करता है।

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

यदि वैम्पायर के 1000 भोजन या उससे अधिक हैं, तो वह राजमार्ग की उपेक्षा करता है, क्योंकि उस समय, यह कोई अधिक मायने नहीं रखता है।


1
@trichoplax कोई समस्या नहीं; जब मुझे इसे देखने का समय मिलेगा तो मैं देखूंगा कि अब मैं क्या सुधार कर सकता हूं कि कार्यकर्ता को घबराने की जरूरत नहीं है। जब तक यह बनाया गया था, तब तक मुझे लगता है कि मुख्य बात यह है कि एक प्रतिद्वंद्वी को ढूंढने में आसान होने का इंतजार था!
डेव

9
यह वास्तव में मतलब है।
विध्वंसक नींबू

2
ट्राइकोप्लेक्स ने स्पष्ट रूप से इस तरह की कमजोरी-शोषण रणनीतियों की अनुमति दी है
पपड़ी

1
मैंने "यह वास्तव में मतलब है"
अपवित्र किया

1
हाँ। सुपर मतलब। यदि यह किसी भी सांत्वना है: यह शायद ही कभी वास्तविक गेम में काम करता है (इस और इसके शिकार के अलावा अन्य खिलाड़ियों के साथ), क्योंकि लाइन-इरेज़र लक्ष्य पैटर्न को मूक करता रहता है।
डेव

11

लैंग्टन की चींटी

मेरे सभी उत्तरों में फॉर्मिक फ़ंक्शंस फ्रेमवर्क के रूप में समान स्तर के तर्क होंगे। "हाई-लेवल लॉजिक स्टार्स यहां" फ्रेमवर्क के कोड के अंत को चिह्नित करता है।

// FORMIC FUNCTIONS FRAMEWORK //
// Version 1.0                //

var WHITE = 1;
var QUEEN = 5;
var HERE = 4;
var MY_VO = view[HERE];
var ME = MY_VO.ant;
var NOP = move(HERE);

var ORTHOGONALS = [1, 3, 5, 7];
var DIAGONALS = [0, 2, 6, 8];
var DIRECTIONS = [0, 1, 2, 3, 5, 6, 7, 8];
var ALL_CELLS = [0, 1, 2, 3, 4, 5, 6, 7, 8];
var VIEW_ORIENTATIONS = [
  [0,1,2,
   3,4,5,
   6,7,8],

  [6,3,0,
   7,4,1,
   8,5,2],

  [8,7,6,
   5,4,3,
   2,1,0],

  [2,5,8,
   1,4,7,
   0,3,6]
];

function rotateCW(cell, amount) {
  if (cell === HERE) return cell;
  var order = [0, 1, 2, 5, 8, 7, 6, 3];
  return order[(order.indexOf(cell) + amount + 8) % 8];
}

function isDiagonal(cell) {
  return DIAGONALS.includes(cell);
}
function isOrthogonal(cell) {
  return ORTHOGONALS.includes(cell);
}

function move(cell) {
  return {cell: cell};
}
function moveMany(cells) {
  var p = [];
  for (var i = 0; i < cells.length; i++) p.push(move(cells[i]));
  return p;
}

function color(cell, col) {
  return {cell: cell, color: col};
}
function colorMany(cells, col) {
  var p = [];
  for (var i = 0; i < cells.length; i++) p.push(color(cells[i], col));
  return p;
}

function spawn(cell, type) {
  return {cell: cell, type: type};
}
function spawnMany(cells, type) {
  var p = [];
  for (var i = 0; i < cells.length; i++) p.push(spawn(cells[i], type));
  return p;
}

function isSane(action, ant) {
  // TODO: Minimize this
  if (ant === undefined || !ant.isObject) ant = ME;
  if (action === undefined || action.cell < 0 || action.cell >= 9) return false;
  if (action.color !== undefined) {
    if (action.color < 1 || action.color > 8) return false;
    return true;
  }
  else if (action.type !== undefined) {
    if (action.type < 1 || action.type > 4) return false;
    if (ant.type !== QUEEN || ant.food === 0) return false;
    if (isOccupied(action.cell, ant) || view[action.cell].food !== 0) return false;
    return true;
  }
  else {
    if (isOccupied(action.cell, ant) && action.cell !== HERE) return false;
    return true;
  }
}
function isOccupied(cell, ant) {
  if (ant === undefined || !ant.isObject) ant = ME;
  return view[cell].ant !== null || (view[cell].food > 0 && ant.type !== QUEEN && ant.food === 1);
}
function isColoringMeaningful(action) {
  return isSane(action) && action.color !== undefined && view[action.cell].color !== action.color;
}

function test(cell, test) {
  var vo = view[cell];
  return (test.color === undefined || test.color === vo.color) &&
         (test.food === undefined || test.food === vo.food) &&
         (test.ant === undefined || test.ant === vo.ant || (
           (test.ant !== null && vo.ant !== null) &&
           (test.ant.food === undefined || test.ant.food === vo.ant.food) &&
           (test.ant.type === undefined || test.ant.type === vo.ant.type) &&
           (test.ant.friend === undefined || test.ant.friend === vo.ant.friend)
         ));
}

function findOrientation(tests) {
  var best = {orientation: null, matches: []};
  for (var o = 0; o < VIEW_ORIENTATIONS.length; o++) {
    var matches = [];
    for (var i = 0; i < tests.length; i++) {
      if (test(VIEW_ORIENTATIONS[o][tests[i].cell], tests[i])) {
        matches.push(tests[i]);
      }
    }
    if (matches.length > best.matches.length) {
      best.orientation = o;
      best.matches = matches;
    }
  }

  return best;
}

function orientCells(orientation, cells) {
  if (orientation === null || orientation < 0 || orientation >= 4) orientation = 0;
  for (var i = 0; i < cells.length; i++) {
    cells[i] = VIEW_ORIENTATIONS[orientation][cells[i]];
  }
  return cells;
}

function findFirst(func, cells) {
  if (cells === undefined) cells = ALL_CELLS;
  for (var i = 0; i < cells.length; i++) {
    if (func(cells[i])) return cells[i];
  }
  return null;
}
function findAll(func, cells) {
  if (cells === undefined) cells = ALL_CELLS;
  var found = [];
  for (var i = 0; i < cells.length; i++) {
    if (func(cells[i])) found.push(cells[i]);
  }
  return found;
}

// HIGH-LEVEL LOGIC STARTS HERE //
var ROAD_COL = 3;
var SIM_COLS = [ 1, 8, 5, 6, 4, 2, 7, 3]; // SIM_COLS.length must be greater or equal to SIM_ROTS.length
var SIM_ROTS = [-1,-1,+1,-1,-1,+1,-1,-1];
// Here are some additional rulesets to play around with:
// [+1,-1,+1,-1,+1,-1,+1,-1] // Classic Langton's ant, extended to use all 8 colors cyclically
// [+1,+1,-1,+1,-1,+1,+1]    // Produces a very interesting highway
// [-1,-1,+1,-1,-1,+1,-1,-1] // The default one -- chosen because it produces a highway nearly instantly, and the highway itself is pretty efficient
// [-1,+1,-1,-1,-1,+1,+1,-1]
// [-1,-1,+1,-1,-1,+1,-1,-1]
// [-1,+1,-1,-1,-1,+1,+1,-1]
// [+1,-1,+1,+1,+1,-1]

var ANCHOR = 1;
var TAIL = 2;

var DEBUG_MODE = false;

function getSimColIndex(cell) {
  return Math.max(SIM_COLS.lastIndexOf(view[cell].color, SIM_ROTS.length - 1), 0);
}
function getNextSimCol(simColIndex) {
  return SIM_COLS[(simColIndex + 1) % SIM_ROTS.length];
}
function getSimRot(simColIndex) {
  return SIM_ROTS[simColIndex];
}

function run() {
  switch (ME.type) {
    case QUEEN: {
      var anch = findFirst(c => test(c, {ant: {type: ANCHOR, friend: true}}), DIRECTIONS);
      if (anch !== null) {
        if (isOrthogonal(anch)) {
          var tail = findFirst(c => test(c, {ant: {type: TAIL, friend: true}}), DIAGONALS);
          if (tail !== null) {
            return [move(rotateCW(anch, -2 * getSimRot(getSimColIndex(HERE))))].filter(isSane)[0] || NOP;
          } else {
            var nanch = rotateCW(anch, -getSimRot(getSimColIndex(anch)));
            return color(nanch, getNextSimCol(getSimColIndex(nanch)));
          }
        } else {
          return NOP;
        }
      } else {
        var tailO;
        if (ME.food === 2) {
          return spawnMany(ORTHOGONALS, TAIL).filter(isSane)[0] || NOP;
        } else if (ME.food === 1 && (tailO = findOrientation([{cell: 1, ant: {type: TAIL, friend: true}}])).orientation !== null) {
          return spawnMany(orientCells(tailO.orientation, [3, 5]), ANCHOR).filter(isSane)[0] || NOP;
        }

        var f;
        if ((f = findFirst(c => test(c, {food: 1})))) {
          return move(f);
        }

        if (test(HERE, {color: ROAD_COL})) {
          return moveMany(orientCells(findOrientation([{cell: 0, color: ROAD_COL}]).orientation, [8, 6, 2])).filter(a => isSane(a) && !test(a.cell, {color: ROAD_COL}))[0] || moveMany(DIAGONALS).filter(isSane)[0] || NOP;
        } else {
          return color(HERE, ROAD_COL);
        }
      }
      break;
    }
    case ANCHOR: {
      var queen = findFirst(c => test(c, {ant: {type: QUEEN, friend: true}}), DIAGONALS);
      var tail = findFirst(c => test(c, {ant: {type: TAIL, friend: true}}), ORTHOGONALS);
      var qp = [rotateCW(queen, -1), rotateCW(queen, +1)];
      var tp = [rotateCW(tail, -2), rotateCW(tail, +2)];
      for (var i = 0; i < qp.length; i++) {
        for (var j = 0; j < tp.length; j++) {
          if (qp[i] === tp[j]) return [move(qp[i])].filter(isSane)[0] || NOP;
        }
      }
      return NOP;
      break;
    }
    case TAIL: {
      var anch = findFirst(c => test(c, {ant: {type: ANCHOR, friend: true}}), DIAGONALS);
      if (anch !== null) {
        var rot = getSimRot(getSimColIndex(anch));
        var nanch = rotateCW(anch, rot);
        if (test(nanch, {ant: {type: QUEEN, friend: true}})) return [move(rotateCW(anch, -rot))].filter(isSane)[0] || NOP;
        return [move(nanch)].filter(isSane)[0] || NOP;
      } else {
        return NOP;
      }
      break;
    }
  }
}

var output = run();
if (isSane(output)) return output;
else {
  if (DEBUG_MODE) {
    return;
  } else {
    return NOP;
  }
}

लैंग्टन की चींटी ("आरएल") लैंग्टन की चींटी ("LLRLLRLL")


परिचय

इस के एक कार्यान्वयन है Langton के चींटी चींटी कार्य QOTH चुनौती के दायरे के भीतर। एक अतिरिक्त बोनस के रूप में, यह लैंगटन के चींटी के बहु-रंग वेरिएंट का समर्थन करता है । मैंने 8 रंगों तक के पूर्ण पैलेट का उपयोग करने में भी कामयाबी हासिल की इसके अलावा, यह चींटी खेल के समय के दो चरणों में सिमुलेशन के एक चरण को पूरा करती है ।

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

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


व्याख्या

रंगों ( SIM_COLS) में एक संबंधित रोटेशन ( SIM_ROTS) होता है, जिसका उपयोग रानी उस दिशा को बदलने के लिए करती है।+1क्लॉकवाइज रोटेशन ("R") का -1अर्थ है , वामावर्त रोटेशन ("L")। क्लासिक Langton के चींटी होगा SIM_COLS = [ 1, 8], SIM_ROTS = [+1,-1]SIM_COLSसरणी प्रभावी रूप से सभी तत्वों में मेल खाने वाले तत्व की जरूरत नहीं है को छोड़ देता है SIM_ROTSसरणी। सभी रंग जो कि छंटनी की गई SIM_COLSसरणी के भीतर समाहित नहीं हैं, उन्हें रंग 0 के रूप में माना जाता है और कभी भी चींटी द्वारा निर्मित नहीं किया जाएगा।

किसी भी अन्य उचित चींटी की तरह, यह एक पर्याप्त भोजन इकट्ठा करके शुरू होता है ताकि यह वास्तव में चीजें करना शुरू कर सके। इसके लिए 2 भोजन चाहिए ।

प्रारंभिक हाथापाई खत्म करने के बाद, रानी ने दो चींटियों का नाम लिया एंकर और टेल था । महारानी पहले टेल को आसन्न करती हैं, बगल के कक्षीय (रानी को कोशिकाएं 1, 3, 5, 7)। फिर, वह रानी के समीपस्थ अस्थि-पंजर और तिरछे (कोशिकाओं 0, 2, 6, 8) को पूंछ में रखती है।

व्यवहार में दो अलग-अलग चरणों का एक दोहराव चक्र होता है।

चरण 1

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

एंकर: कुछ नहीं करता।

रानी: एंकर को ढूंढती है और इसे उस दिशा का उलटा मानती है जो चींटी जा रही है। फिर रानी के नीचे रंग के अनुसार दिशा घुमाई जाती है। रानी घुमाई हुई दिशा से संकेतित सेल में जाती है।

चरण 2

पूंछ: कुछ नहीं करता।

एंकर: एक सेल की खोज करता है जो तिरछे तिरछे बगल में है और रानी के बगल में orthogonally है। ऐसा एक सेल में होता है।

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

निर्धारित करना है कि क्या करना है

रानी ने मौजूदा कदम को पूंछ के लिए खोजकर निर्धारित किया है। यदि वह इसे पाती है, तो वह चरण 1 पर है। अन्यथा, वह चरण 2 पर है। दुर्लभ मामलों में, वह खुद से सटे एंकर को पा सकती है। उस मामले में, वह कुछ भी नहीं करेगी।

एंकर के पास अपना कदम निर्धारित करने के लिए कोई तर्क नहीं है। यह हमेशा रानी के निकट और पूंछ से सटे तिरछे होने का प्रयास करता है। अगर ऐसी कोई सेल नहीं है, तो यह आसानी से नहीं चलती है।

पूंछ एंकर को तिरछे तरीके से खोजकर वर्तमान चरण को निर्धारित करती है। यदि यह पता चलता है, तो यह चरण 1 पर है। अन्यथा, यह चरण 2 पर है।

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


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


3
PPCG में आपका स्वागत है!
स्टेयडबॉक्स

10

जिगगरात v3.0

var clockwise = [1,2,5,0,4,8,3,6,7];
var opposite = [8,7,6,5,4,3,2,1,0];
var cyclic_cw = [0,1,2,5,8,7,6,3,0];
var worker_colors = [4,5,7,8];
var next_worker_color = [1,1,1,1,5,7,1,8,4];
var prev_worker_color = [1,1,1,1,8,4,1,5,7];
var diags = [0,2,6,8];
var orthos = [1,3,5,7];
var cleaning_color = 6;


// Borrowed from Medusa
function clean(move) {
    if (move["color"] == undefined) {
        if (view[move["cell"]].ant != null) {
            move = {cell: 4};
        }
        if (move["type"] == undefined) {
            if (view[move["cell"]].food == 1 && view[4].ant.type < 5 && view[4].ant.food > 0) {
                move = {cell: 4};
            }
        } else if (view[4].ant.type != 5 || view[4].ant.food == 0 || view[move["cell"]].food == 1) {
            move = {cell: 4};
        }
    }
    return move;
}

function worker_blank(cel) {
    return (worker_colors.indexOf(view[cel].color) < 0);
}

// Own status
var my_color = view[4].color;
var my_food = view[4].ant.food;
var my_type = view[4].ant.type;

// Random free cell
var free_cell = 4;
for (var cel = 0; cel < 9; cel++) {
    if (view[cel].ant == null) {
    free_cell = cel;
    }
}

// Check surroundings
var blanks = 0;
var outer_edge = 0;
var inner_edge = 0;
var next_edge = -1;
var prev_nonblank = -1;
var some_nonblank = -1;
var prev_cell = -1;
var next_cell = -1;
var food_cell = -1;
var nonblank_color = 0;
var cleaning_marker = -1;
var uniform = 1;
var low_type = -1;
var friend_workers = 0;
var guards = 0;
var enemies = 0;
var enemy_queens = 0;
var my_queen = -1;

if (!worker_blank(4)) {
    nonblank_color = view[4].color;
}
for (var ix = 0; ix < 8; ix++) {
    var cel = cyclic_cw[ix];
    var cel2 = cyclic_cw[ix+1];
    if (view[cel].food == 1) {
    food_cell = cel;
    }
    if (worker_blank(cel)) {
    blanks++;
    if (!worker_blank(cel2)) {
        if (worker_blank(4)) {
        outer_edge = 1;
        } else {
        inner_edge = 1;
        }
        next_edge = cel;
            prev_nonblank = cel2;
    }
    if (view[cel].color == cleaning_color) {
        cleaning_marker = cel;
    }
    } else {
    some_nonblank = cel;
    if (nonblank_color == 0) {
        nonblank_color = view[cel].color;
    } else if (view[cel].color != nonblank_color) {
        uniform = 0;
    }
    }
    if ((!worker_blank(4) && view[cel2].color == prev_worker_color[my_color] && view[cel2].ant == null) || (worker_blank(4) && !worker_blank(cel2))) {
    prev_cell = cel2;
    }
    if (!worker_blank(4) && view[cel2].color == next_worker_color[my_color] && view[cel2].ant == null) {
    next_cell = cel2;
    }
    if (view[cel].ant != null) {
    var the_ant = view[cel].ant;
    if (the_ant.friend) {
        if (low_type < 0 || the_ant.type < low_type) {
        low_type = the_ant.type;
        }
        if (the_ant.type == 4) {
        guards++;
        } else if (the_ant.type == 5) {
        my_queen = cel;
        } else {
        friend_workers++;
        }
    } else {
        enemies++;
        if (the_ant.type == 5) {
        enemy_queens++;
        }
    }
    }
}

// Queen before finding food (motile)
if (my_type == 5 && worker_blank(4)) {
    if (my_food > 1) {
    return {cell:4, color:worker_colors[1]};
    }
    if (food_cell >= 0 && my_color != 1) {
    return clean({cell:food_cell});
    }
    if (my_color == 2) {
    for (var ix = 0; ix < 4; ix++) {
        var cel = diags[ix];
        var oppo = opposite[cel];
        if (view[cel].color == 2) {
        if (view[oppo].color == 1 && worker_blank(oppo) && view[oppo].ant == null) {
            return clean({cell:oppo});
        }
                if (view[oppo].color != 2) {
            return {cell:oppo, color:1};
                }
        }
    }
        for (var ix = 0; ix < 4; ix++) {
        var cel = diags[ix];
        if (view[cel].color != 2) {
        return {cell:cel, color:2};
        }
    }
    }
    if (my_color == 1) {
    return {cell:4, color:2};
    }
    return clean({cell:free_cell});
}

// Queen after finding food (sessile)
if (my_type == 5) {
    for (var ix = 0; ix < 8; ix++) {
        cel = cyclic_cw[ix];
    if (worker_blank(cel)) {
            return {cell:cel, color:worker_colors[1]};
    }
    }

    if (my_color != worker_colors[0]) {
        if (my_food > 0) {
        return clean({cell:free_cell, type:1});
        } else {
            return {cell:4, color:worker_colors[0]};
        }
    }
    if (my_food > 0) {
    if (my_food > 3 && guards < 2) {
        return clean({cell:free_cell, type:4});
    }
    if (0 < low_type && low_type < 3) {
        return clean({cell:free_cell, type:(low_type + 1)});
    }
    }
    return {cell:4};
}

// Queen's guard

if (my_type == 4) {
    // Queen is a nbor
    if (my_queen >= 0) {
    if (enemy_queens > 0) {
        return {cell:4};
    }
    if (my_queen == 1) {
        return clean({cell:5});
    }
    return clean({cell:clockwise[my_queen]});
    }
    // Try to get to queen
    if (prev_cell >= 0) {
    return clean({cell:prev_cell});
    }
    // Wander
    return clean({cell:free_cell});
}

// Worker

// Create new ziggurat
if (blanks == 8 && cleaning_marker < 0 && my_color != cleaning_color) {
    if (worker_colors.indexOf(my_color) >= 0) {
    return {cell:free_cell, color:my_color};
    }
    return {cell:free_cell, color:worker_colors[0]};
}

var front = view[1].color;
if (!worker_blank(4) && !worker_blank(1) && my_color != front) {
    if (view[7].color == front || (view[6].color == front && view[8].color == front)) {
        return {cell:4, color:front};
    }
}

if (my_food == 0) {
    // Grab food
    if (food_cell >= 0 && (!worker_blank(4) || !worker_blank(food_cell))) {
        return clean({cell:food_cell});
    }

    // Clear marked uniform region
    if (my_color == cleaning_color && uniform) {
    if (blanks < 7) {
        return {cell:some_nonblank, color:1};
    } else if (blanks == 7) {
        return {cell:some_nonblank, color:cleaning_color};
    }
    }

    // Follow cleaning color
    if (blanks == 8) {
    if (cleaning_marker < 0 || my_color == cleaning_color) {
        return {cell:4, color:1};
    } else if (cleaning_marker >= 0) {
        return clean({cell:cleaning_marker});
    }
    }

    // Dive into uniform region
    if (blanks > 3 && worker_blank(4) && worker_blank(1) && !worker_blank(2) && view[2].color == view[5].color && view[2].color == view[8].color) {
    return clean({cell:2});
    }

    // Mark uniform region for clearing
    if (!worker_blank(4) && uniform && (blanks < 4 || (blanks < 7 && ((worker_blank(1) && worker_blank(7)) || (worker_blank(3) && worker_blank(5)))))) {
    return {cell:4, color:cleaning_color};
    }

    // Extend edge
    if (outer_edge) {
    var new_color = 0;
    var cl = clockwise[next_edge];
    var cl2 = clockwise[cl];
    if (!worker_blank(1) && view[7].color == view[1].color) {
        new_color = view[1].color;
    } else if (!worker_blank(3) && view[5].color == view[3].color) {
        new_color = view[3].color;
        } else if (!worker_blank(cl2) && view[cl].color == next_worker_color[view[cl2].color]) {
        if (cl > 1) {
        new_color = view[cl].color;
        } else {
        new_color = next_worker_color[view[cl].color];
        }
    } else if (!worker_blank(cl)) {
        new_color = next_worker_color[view[cl].color];
        } else if (prev_nonblank >= 0) {
            new_color = next_worker_color[prev_nonblank];
    }
    if (new_color == 0 && blanks < 2) {
        new_color = worker_colors[0];
    }
        if (new_color > 0) {
            return {cell:4, color:new_color};
        } else {
            return clean({cell:next_edge});
        }
    }

    // Escape from hole
    if (worker_blank(4) && blanks == 0) {
        return {cell:4, color:next_worker_color[nonblank_color]};
    }

    // Go outside or fill it
    if (inner_edge && next_edge >= 0) {
    if (friend_workers > 1) {
        return clean({cell:free_cell});
    }
        if (blanks == 4 && prev_nonblank >= 0) {
            return {cell:next_edge, color:next_worker_color[view[prev_nonblank].color]};
        }
    if (view[next_edge].ant == null) {
            return clean({cell:next_edge});
    }
    return {cell:4};
    }

    // Go toward border
    if (!worker_blank(4) && next_cell >= 0 && next_cell != 1) {
    return clean({cell:next_cell});
    }

    // Wander
    return clean({cell:free_cell});
}

if (my_food > 0) {
    // Take food to queen
    if ((prev_cell >= 0 && prev_cell != 1) || (prev_cell >= 0 && worker_blank(4))) {
    return clean({cell:prev_cell});
    }

    // Wander
    if (worker_blank(free_cell) && !worker_blank(4)) {
    return {cell:4};
    }
    return clean({cell:free_cell});
}

return clean({cell:free_cell});

यह काम किस प्रकार करता है

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

टिप्पणियाँ

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

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

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

मैं वास्तव में जेएस को नहीं जानता, इसलिए कोड एक भयानक गड़बड़ है।

यहाँ धारीदार क्षेत्र का चित्र दिया गया है:

ziggurat


यह देखने में सुंदर है। यह दिलचस्प है कि धारियों में कभी-कभी खामियां होती हैं, जैसे बढ़ते क्रिस्टल में दोष, लेकिन वे अभी भी रानी के लिए अग्रणी हैं, इसलिए यह श्रमिकों को किसी भी समस्या का कारण नहीं लगता है।
ट्राइकोप्लाक्स

1
मुझे यह एक काम देखना बहुत पसंद है, खासकर जब पैटर्न कुछ अपूर्ण विसंगतियों को प्राप्त करता है (श्रमिकों को उस स्थान पर वापस जाने में असमर्थ होने के कारण जहां उन्हें भोजन मिला)
स्किड्सदेव

1
@trichoplax मैंने अभी-अभी बॉट को अपडेट किया है। इसे अब कभी भी अवैध कदम नहीं उठाना चाहिए, और कुल मिलाकर थोड़ा होशियार है।
जगरब

1
और, नया संस्करण ऐसा लगता है कि यह एक निशान-इरेज़र द्वारा कुछ कठिनाई के साथ एक हमले से बच सकता है। यकीन नहीं होता कि एक से अधिक आक्रमण होने पर क्या होता है, हालांकि
पिपरी

1
@trichoplax अभी तय होना चाहिए। मैंने अन्य सुधार भी जोड़े।
जर्गर्ब

9

जंगल की आग Mk.3

मेरे सभी उत्तर निम्न-स्तरीय सहायक कार्यों के समान सेट को साझा कर रहे हैं। इस उत्तर के लिए विशिष्ट कोड को देखने के लिए "उच्च-स्तरीय तर्क यहां शुरू होता है"।

// == Shared low-level helpers for all solutions ==

var QUEEN = 5;

var WHITE = 1;
var COL_MIN = WHITE;
var COL_LIM = 9;

var CENTRE = 4;

var NOP = {cell: CENTRE};

var DIR_FORWARDS = false;
var DIR_REVERSE = true;
var SIDE_RIGHT = true;
var SIDE_LEFT = false;

function sanity_check(movement) {
  var me = view[CENTRE].ant;
  if(!movement || (movement.cell|0) !== movement.cell || movement.cell < 0 || movement.cell > 8) {
    return false;
  }
  if(movement.type) {
    if(movement.color) {
      return false;
    }
    if((movement.type|0) !== movement.type || movement.type < 1 || movement.type > 4) {
      return false;
    }
    if(view[movement.cell].ant || view[movement.cell].food) {
      return false;
    }
    if(me.type !== QUEEN || me.food < 1) {
      return false;
    }
    return true;
  }
  if(movement.color) {
    if((movement.color|0) !== movement.color || movement.color < COL_MIN || movement.color >= COL_LIM) {
      return false;
    }
    if(view[movement.cell].color === movement.color) {
      return false;
    }
    return true;
  }
  if(movement.cell !== CENTRE && view[movement.cell].ant) {
    return false;
  }
  if(view[movement.cell].food + me.food > 1 && me.type !== QUEEN) {
    return false;
  }
  return true;
}

function as_array(o) {
  if(Array.isArray(o)) {
    return o;
  }
  return [o];
}

function best_of(movements) {
  var m;
  for(var i = 0; i < movements.length; ++ i) {
    if(typeof(movements[i]) === 'function') {
      m = movements[i]();
    } else {
      m = movements[i];
    }
    if(sanity_check(m)) {
      return m;
    }
  }
  return null;
}

function play_safe(movement) {
  // Avoid disqualification: no-op if moves are invalid
  return best_of(as_array(movement)) || NOP;
}

var RAND_SEED = (() => {
  var s = 0;
  for(var i = 0; i < 9; ++ i) {
    s += view[i].color * (i + 1);
    s += view[i].ant ? i * i : 0;
    s += view[i].food ? i * i * i : 0;
  }
  return s % 29;
})();

var ROTATIONS = [
  [0, 1, 2, 3, 4, 5, 6, 7, 8],
  [6, 3, 0, 7, 4, 1, 8, 5, 2],
  [8, 7, 6, 5, 4, 3, 2, 1, 0],
  [2, 5, 8, 1, 4, 7, 0, 3, 6],
];

function try_all(fns, limit, wrapperFn, checkFn) {
  var m;
  fns = as_array(fns);
  for(var i = 0; i < fns.length; ++ i) {
    if(typeof(fns[i]) !== 'function') {
      if(checkFn(m = fns[i])) {
        return m;
      }
      continue;
    }
    for(var j = 0; j < limit; ++ j) {
      if(checkFn(m = wrapperFn(fns[i], j))) {
        return m;
      }
    }
  }
  return null;
}

function identify_rotation(testFns) {
  // testFns MUST be functions, not constants
  return try_all(
    testFns,
    4,
    (fn, r) => fn(ROTATIONS[r]) ? ROTATIONS[r] : null,
    (r) => r
  );
}

function near(a, b) {
  return (
    Math.abs(a % 3 - b % 3) < 2 &&
    Math.abs(Math.floor(a / 3) - Math.floor(b / 3)) < 2
  );
}

function try_all_angles(solverFns) {
  return try_all(
    solverFns,
    4,
    (fn, r) => fn(ROTATIONS[r]),
    sanity_check
  );
}

function try_all_cells(solverFns, skipCentre) {
  return try_all(
    solverFns,
    9,
    (fn, i) => ((i === CENTRE && skipCentre) ? null : fn(i)),
    sanity_check
  );
}

function try_all_cells_near(p, solverFns) {
  return try_all(
    solverFns,
    9,
    (fn, i) => ((i !== p && near(p, i)) ? fn(i) : null),
    sanity_check
  );
}

function ant_type_at(i, friend) {
  return (view[i].ant && view[i].ant.friend === friend) ? view[i].ant.type : 0;
}

function friend_at(i) {
  return ant_type_at(i, true);
}

function foe_at(i) {
  return ant_type_at(i, false);
}

function ant_type_near(p, friend) {
  for(var i = 0; i < 9; ++ i) {
    if(i !== 4 && ant_type_at(i, friend) && near(i, p)) {
      return true;
    }
  }
  return false;
}

function move_agent(agents) {
  var me = view[CENTRE].ant;
  var buddies = [0, 0, 0, 0, 0, 0];
  for(var i = 0; i < 9; ++ i) {
    ++ buddies[friend_at(i)];
  }

  for(var i = 0; i < agents.length; i += 2) {
    if(agents[i] === me.type) {
      return agents[i+1](me, buddies);
    }
  }
  return null;
}

function grab_nearby_food() {
  return try_all_cells((i) => (view[i].food ? {cell: i} : null), true);
}

function go_anywhere() {
  return try_all_cells((i) => ({cell: i}), true);
}

function colours_excluding(cols) {
  var r = [];
  for(var i = COL_MIN; i < COL_LIM; ++ i) {
    if(cols.indexOf(i) === -1) {
      r.push(i);
    }
  }
  return r;
}

function generate_band(start, width) {
  var r = [];
  for(var i = 0; i < width; ++ i) {
    r.push(start + i);
  }
  return r;
}

function colour_band(colours) {
  return {
    contains: function(c) {
      return colours.indexOf(c) !== -1;
    },
    next: function(c) {
      return colours[(colours.indexOf(c) + 1) % colours.length];
    }
  };
}

function random_colour_band(colours) {
  return {
    contains: function(c) {
      return colours.indexOf(c) !== -1;
    },
    next: function() {
      return colours[RAND_SEED % colours.length];
    }
  };
}

function fast_diagonal(colourBand, avoidedColours) {
  if(!avoidedColours) {
    avoidedColours = colourBand;
  }
  var m = try_all_angles([
    // Avoid nearby checked areas
    (rot) => {
      if(
        !avoidedColours.contains(view[rot[0]].color) &&
        avoidedColours.contains(view[rot[5]].color) &&
        avoidedColours.contains(view[rot[7]].color)
      ) {
        return {cell: rot[0]};
      }
    },

    // Go in a straight diagonal line if possible
    (rot) => {
      if(
        !avoidedColours.contains(view[rot[0]].color) &&
        avoidedColours.contains(view[rot[8]].color)
      ) {
        return {cell: rot[0]};
      }
    },

    // When in doubt, pick randomly but avoid doubling-back
    (rot) => (avoidedColours.contains(view[rot[0]].color) ? null : {cell: rot[0]}),

    // Double-back when absolutely necessary
    (rot) => ({cell: rot[0]})
  ]);

  // Lay a colour track so that we can avoid doubling-back
  // (and mess up our foes as much as possible)
  if(!avoidedColours.contains(view[CENTRE].color)) {
    var prevCol = m ? view[8-m.cell].color : WHITE;
    return {cell: CENTRE, color: colourBand.next(prevCol)};
  }

  return m;
}

function follow_edge(obstacleFn, side, resultFn) {
  // Since we don't know which direction we came from, this can cause us to get
  // stuck on islands, but the random orientation helps to ensure we don't get
  // stuck forever.

  if(!resultFn) {
    resultFn = (i) => ({cell: i});
  }

  var order = ((side === SIDE_LEFT)
    ? [0, 3, 6, 7, 8, 5, 2, 1, 0]
    : [0, 1, 2, 5, 8, 7, 6, 3, 0]
  );
  return try_all(
    [obstacleFn],
    order.length - 1,
    (fn, i) => ((fn(order[i+1]) && !fn(order[i])) ? resultFn(order[i]) : null),
    sanity_check
  );
}

function start_dotted_path(colourBand, side, protectedCols) {
  var right = (side === SIDE_RIGHT);
  return try_all_angles([
    (rot) => ((
      !protectedCols.contains(view[rot[right ? 5 : 3]].color) &&
      !colourBand.contains(view[rot[right ? 5 : 3]].color) &&
      !colourBand.contains(view[rot[right ? 2 : 0]].color) &&
      !colourBand.contains(view[rot[1]].color)
    )
      ? {cell: rot[right ? 5 : 3], color: colourBand.next(WHITE)}
      : null)
  ]);
}

function lay_dotted_path(colourBand, side, protectedCols) {
  var right = (side === SIDE_RIGHT);
  return try_all_angles([
    (rot) => {
      var ahead = rot[right ? 2 : 0];
      var behind = rot[right ? 8 : 6];
      if(
        colourBand.contains(view[behind].color) &&
        !protectedCols.contains(view[ahead].color) &&
        !colourBand.contains(view[ahead].color) &&
        !colourBand.contains(view[rot[right ? 6 : 8]].color)
      ) {
        return {cell: ahead, color: colourBand.next(view[behind].color)};
      }
    }
  ]);
}

function follow_dotted_path(colourBand, side, direction) {
  var forwards = (direction === DIR_REVERSE) ? 7 : 1;
  var right = (side === SIDE_RIGHT);

  return try_all_angles([
    // Cell on our side? advance
    (rot) => {
      if(
        colourBand.contains(view[rot[right ? 5 : 3]].color) &&
        // Prevent sticking / trickery
        !colourBand.contains(view[rot[right ? 3 : 5]].color) &&
        !colourBand.contains(view[rot[0]].color) &&
        !colourBand.contains(view[rot[2]].color)
      ) {
        return {cell: rot[forwards]};
      }
    },

    // Cell ahead and behind? advance
    (rot) => {
      var passedCol = view[rot[right ? 8 : 6]].color;
      var nextCol = view[rot[right ? 2 : 0]].color;
      if(
        colourBand.contains(passedCol) &&
        nextCol === colourBand.next(passedCol) &&

        // Prevent sticking / trickery
        !colourBand.contains(view[rot[right ? 3 : 5]].color) &&
        !colourBand.contains(view[rot[right ? 0 : 2]].color)
      ) {
        return {cell: rot[forwards]};
      }
    }
  ]);
}

function escape_dotted_path(colourBand, side, newColourBand) {
  var right = (side === SIDE_RIGHT);
  if(!newColourBand) {
    newColourBand = colourBand;
  }

  return try_all_angles([
    // Escape from beside the line
    (rot) => {
      var approachingCol = view[rot[right ? 2 : 0]].color;
      if(
        !colourBand.contains(view[rot[right ? 8 : 6]].color) ||
        !colourBand.contains(approachingCol) ||
        colourBand.contains(view[rot[7]].color) ||
        colourBand.contains(view[rot[right ? 6 : 8]].color)
      ) {
        // not oriented, or in a corner
        return null;
      }
      return best_of([
        {cell: rot[right ? 0 : 2], color: newColourBand.next(approachingCol)},
        {cell: rot[right ? 3 : 5]},
        {cell: rot[right ? 0 : 2]},
        {cell: rot[right ? 6 : 8]},
        {cell: rot[right ? 2 : 0]},
        {cell: rot[right ? 8 : 6]},
        {cell: rot[right ? 5 : 3]}
      ]);
    },

    // Escape from inside the line
    (rot) => {
      if(
        !colourBand.contains(view[rot[7]].color) ||
        !colourBand.contains(view[rot[1]].color) ||
        colourBand.contains(view[CENTRE].color)
      ) {
        return null;
      }
      return best_of([
        {cell: rot[3]},
        {cell: rot[5]},
        {cell: rot[0]},
        {cell: rot[2]},
        {cell: rot[6]},
        {cell: rot[8]}
      ]);
    }
  ]);
}

function latch_to_dotted_path(colourBand, side) {
  var right = (side === SIDE_RIGHT);

  return try_all_angles([
    (rot) => {
      var approachingCol = view[rot[right ? 2 : 0]].color;
      if(
        colourBand.contains(approachingCol) &&
        view[rot[right ? 8 : 6]].color === colourBand.next(approachingCol) &&
        !colourBand.contains(view[rot[right ? 5 : 3]].color)
      ) {
        // We're on the wrong side; go inside the line
        return {cell: rot[right ? 5 : 3]};
      }
    },

    // Inside the line? pick a side
    (rot) => {
      var passedCol = view[rot[7]].color;
      var approachingCol = view[rot[1]].color;
      if(
        !colourBand.contains(passedCol) ||
        !colourBand.contains(approachingCol) ||
        colourBand.contains(view[CENTRE].color)
      ) {
        return null;
      }
      if((approachingCol === colourBand.next(passedCol)) === right) {
        return best_of([{cell: rot[3]}, {cell: rot[6]}, {cell: rot[0]}]);
      } else {
        return best_of([{cell: rot[5]}, {cell: rot[2]}, {cell: rot[8]}]);
      }
    }
  ]);
}


// == High-level logic begins here ==


var groundCol = 5;
var poisonCol = 8;

var DIRECTOR = 1;
var FORAGER0 = 2;
var FORAGER1 = 3;
var FORAGER2 = 4;
var MAX_FORAGER_TYPES = 3; // Worker creation throttle
var MIN_FOOD = 3; // Don't embarrass ourselves when things go bad
var MAX_FOOD_SPAWN = 80; // If we're doing well, don't spoil it all

var GROUND_COLOURS = colour_band([groundCol, poisonCol]);
var POISON_COLOURS = colour_band([poisonCol]);
var SAFE_COLOURS = random_colour_band(colours_excluding([WHITE, groundCol, poisonCol]));
var INITIAL_OBSTACLES = random_colour_band(colours_excluding([WHITE]));

function ground_at(i) {
  return GROUND_COLOURS.contains(view[i].color);
}

function unlaiden_friend_at(i) {
  return friend_at(i) && (friend_at(i) === QUEEN || !view[i].ant.food);
}

function obstacle_at(i) {
  // foes are unpredictable, so don't consider them obstacles
  return view[i].food || unlaiden_friend_at(i) || GROUND_COLOURS.contains(view[i].color);
}

function wait_if_blocked(i) {
  return friend_at(i) ? {cell:CENTRE} : {cell: i};
}

function move_director(me, buddies) {
  if(!buddies[QUEEN]) {
    // Lost the queen!
    return go_anywhere();
  }

  var rot = identify_rotation((rot) => (
    friend_at(rot[0]) === QUEEN || friend_at(rot[1]) === QUEEN
  ));

  var ready = (friend_at(rot[1]) === QUEEN && view[rot[1]].color === groundCol);
  var shift = (view[rot[2]].color === groundCol && GROUND_COLOURS.contains(view[rot[5]].color));

  return best_of([
    // Ensure we never end up underground unless we mean to, and provide a
    // base poison layer to help workers find the right side if lost
    {cell: CENTRE, color: poisonCol},
//    {cell: rot[5], color: poisonCol},
    {cell: rot[3], color: poisonCol},

    // Move up to avoid own line after wrapping (us being underground is a signal)
    (ready && shift) && {cell: rot[2]},

    // Advance
    (ready && !shift) && {cell: rot[5]},

    // Make the poison layer more solid if we have extra time
    {cell: rot[7], color: poisonCol},
    {cell: rot[6], color: poisonCol},
    {cell: rot[8], color: poisonCol},

    // Don't lose the queen
    NOP
  ]);
}

function move_forager(me, buddies) {
  var underground = GROUND_COLOURS.contains(view[CENTRE].color);
  var buried = 0;
  for(var i = 0; i < 9; ++ i) {
    if(i !== 4 && GROUND_COLOURS.contains(view[i].color)) {
      ++ buried;
    }
  }
  var travelCol = underground ? POISON_COLOURS : SAFE_COLOURS;

  if(buddies[DIRECTOR]) {
    // We've somehow got in the way of the line; get out of the way
    return try_all_angles((rot) =>
      ((friend_at(rot[6]) === DIRECTOR || friend_at(rot[7]) === DIRECTOR) &&
      best_of([{cell: rot[0]}, {cell: rot[1]}, {cell: rot[2]}])));
  }

  if(me.food) {
    // We have food for the queen; run ahead to find her as fast as we can

    return best_of([
      // Identify confusing pinch points and close them (don't get stuck on islands)
      try_all_angles((rot) => (
        obstacle_at(rot[1]) && obstacle_at(rot[7]) &&
        !obstacle_at(rot[5]) && !GROUND_COLOURS.contains(view[CENTRE].color)
      ) && {cell: CENTRE, color: groundCol}),

      // We're enclosed; mark this as a dead-end
      (buried >= 7) && {cell: CENTRE, color: poisonCol},

      // Race to queen, but don't climb over each other and cause a blockage
      follow_edge(obstacle_at, SIDE_RIGHT, wait_if_blocked),

      // Lost? Travel quickly to find the surface again
      fast_diagonal.bind(null, travelCol),

      // Totally lost
      go_anywhere
    ]);
  }

  if(buddies[QUEEN]) {
    // Don't overtake the queen!
    return NOP;
  }

  // Paint the ground
  if(!underground) {
    return {cell: CENTRE, color: groundCol};
  }

  return best_of([
    // Unpaint small islands which would confuse us or our buddies
    (buried >= 3) && try_all_angles((rot) => (
      !view[rot[0]].ant &&
      GROUND_COLOURS.contains(view[rot[0]].color) &&
      !GROUND_COLOURS.contains(view[rot[1]].color) &&
      !GROUND_COLOURS.contains(view[rot[3]].color)
    ) && {cell: rot[0], color: SAFE_COLOURS.next(WHITE)}),

    (buried >= 3) && try_all_angles((rot) => (
      !view[rot[1]].ant &&
      GROUND_COLOURS.contains(view[rot[1]].color) &&
      !GROUND_COLOURS.contains(view[rot[0]].color) &&
      !GROUND_COLOURS.contains(view[rot[2]].color)
    ) && {cell: rot[1], color: SAFE_COLOURS.next(WHITE)}),

    // Follow line
    follow_edge(ground_at, SIDE_RIGHT, wait_if_blocked),

    // Disoriented; find the surface again
    fast_diagonal.bind(null, travelCol),

    // Totally lost; random walk
    {cell: 0}
  ]);
}

function move_queen(me, buddies) {
  if(buddies[DIRECTOR]) {
    var rot = identify_rotation((rot) => (
      (friend_at(rot[7]) === DIRECTOR && view[rot[7]].color !== groundCol) ||
      (friend_at(rot[5]) === DIRECTOR && view[rot[5]].color === groundCol) ||
      friend_at(rot[8]) === DIRECTOR
    ));

    var rand14 = rot === ROTATIONS[0];
    var existing = friend_at(rot[0]);
    var nextType = existing ? (existing + 1) : FORAGER0;
    var workerSpawn = (
      me.food > MIN_FOOD && me.food < MAX_FOOD_SPAWN &&
      view[rot[3]].color === groundCol && // Don't spawn if disrupted
      view[rot[0]].color === WHITE && // Don't spawn while stuck in a nest
      view[rot[1]].color === WHITE &&
      !friend_at(rot[1]) && !friend_at(rot[3]) && !friend_at(rot[6]) &&
      (existing || rand14) // reduce likelihood of spawning new chains
    );

    return best_of([
      // Paint ground
      {cell: CENTRE, color: groundCol},

      // Follow director up slopes
      (friend_at(rot[5]) === DIRECTOR) && {cell: rot[2]},
      (friend_at(rot[5]) === DIRECTOR) && {cell: rot[1]},

      // Recognise likely erasure issues and correct
      view[rot[2]].color === groundCol && GROUND_COLOURS.contains(view[rot[8]].color) &&
        {cell: CENTRE, color: groundCol},

      // Clear cells which could confuse workers
      GROUND_COLOURS.contains(view[rot[2]].color) && {cell: rot[2], color: SAFE_COLOURS.next(WHITE)},

      // Spawn new workers when ready (throttle probabilistically)
      (workerSpawn && nextType < FORAGER0 + MAX_FORAGER_TYPES) && {cell: rot[1], type: nextType},

      // Follow director along flat planes
      (friend_at(rot[8]) === DIRECTOR) && {cell: rot[5]},

      // Don't lose director
      NOP
    ]);
  }

  return best_of([
    // Begin wildfire
    (me.food >= MIN_FOOD + MAX_FORAGER_TYPES + 1) && try_all_angles((rot) =>
      (view[rot[5]].color !== groundCol && sanity_check({cell: rot[5]}) &&
        {cell: rot[8], type: DIRECTOR})),

    // Hungry or too crowded to begin; frantically find food
    grab_nearby_food,
    fast_diagonal.bind(null, SAFE_COLOURS, INITIAL_OBSTACLES),
    go_anywhere,
    {cell: 1, color: SAFE_COLOURS.next(WHITE)}
  ]);
}

return play_safe(move_agent([
  DIRECTOR, move_director,
  FORAGER0, move_forager,
  FORAGER1, move_forager,
  FORAGER2, move_forager,
  QUEEN, move_queen,
]));

जंगल की आग चींटियों ने अपने रास्ते में सब कुछ खाकर बोर्ड को उड़ा दिया। यह मेरे फॉरेंसिक चींटियों के साथ ब्लैक होल (ड्रेको 18 के द्वारा) की अवधारणाओं को मिलाकर प्रेरित था ।

रानी जल्दी से भोजन का एक ढेर इकट्ठा करके शुरू करेगी। एक बार उसके पास पर्याप्त होने के बाद, वह एक सीधी रेखा में बढ़ना शुरू कर देगी और कुछ सहायकों को पालेंगी। यदि भोजन मिल जाए तो पकड़ने के लिए ये सहायक एक क्रमबद्ध रेखा में उसके पीछे-पीछे चलेंगे।

Mk.2 रानी को अपनी दिशा बनाए रखने में मदद करने के लिए एक विशेषज्ञ चींटी का उपयोग करता है, और यह चींटी काले रंग के निशान को भी खो देती है ताकि खोए हुए श्रमिकों को बैंड का सही पक्ष मिल सके। बेहतर कर्मचारी नेविगेशन के साथ संयुक्त, यह अब बहुत बेहतर प्रदर्शन करता है जब प्रतिस्पर्धी चींटियों के साथ मिलाया जाता है। यह भी (अंततः) लाल डॉट्स के घोंसले मारने के बाद ठीक हो जाता है।

Mk.2c कार्यकर्ता की आबादी को नियंत्रित करने के लिए संभाव्यता का उपयोग करता है और इसे काफी अच्छी तरह से प्रबंधित करता है। कार्यकर्ता अभी भी आग के अंदर खो जाना चाहते हैं, जितना मैं चाहूंगा, लेकिन इसके बावजूद जब वह अपने दम पर बोर्ड की प्रभावशाली मात्रा में काम करना चाहता है।

Mk.3 "सिंगल क्वीन" प्रविष्टि द्वारा निर्मित विकर्ण लाल रेखाओं के खिलाफ सुरक्षा जोड़ता है, जो कुछ समान स्थितियों में भी मदद करता है। मज़दूरों को अब बेतरतीब डिटर्जों से विचलित होने की संभावना बहुत कम है, और यह बेहतर प्रदर्शन कर रहा है।

यहाँ एक प्रोटोटाइप का परिणाम है:

आग

(हाँ, यह 865 कार्यकर्ता चींटियाँ हैं ... और एर, 5 भोजन)


यहाँ प्रतियोगिता के साथ एक स्क्रीनशॉट है:

सफाई की आग


और यहां बताया गया है कि मैं अपने मन में चींटियों की कल्पना कैसे करता हूं (साथ ही संगीत भी):

पपरिका परेड


टिप्पणियाँ विस्तारित चर्चा के लिए नहीं हैं; इस वार्तालाप को बातचीत में स्थानांतरित कर दिया गया है ।
मार्टिन एंडर 12

अपना संगीत नहीं सुन सकते ...
एनएच।

1
@NH। मेंढ़क / अराजकता / सामान्य पागलपन फिल्म पैपरिका से हैं। यदि आप संगीत जानना चाहते हैं, तो देखें!
डेव

9

प्रकाश की गति

मेरे सभी उत्तरों में फॉर्मिक फ़ंक्शंस फ्रेमवर्क के रूप में समान स्तर के तर्क होंगे। "हाई-लेवल लॉजिक स्टार्स यहां" फ्रेमवर्क के कोड के अंत को चिह्नित करता है।

 //  FORMIC FRAMEWORK  //
// Version 6.1.10     //
const WHITE = 1;
const QUEEN = 5;
const CENTER = 4;
const HERE = view[CENTER];
const ME = HERE.ant;
const ORTHOGONALS = [1, 3, 5, 7];
const DIAGONALS = [0, 2, 6, 8];
const DIAGONALS_ORTHOGONALS = [0, 2, 6, 8, 1, 3, 5, 7];
const DIRECTIONS = [0, 1, 2, 3, 5, 6, 7, 8];
const CLOCKWISE_DIRECTIONS = [0, 1, 2, 5, 8, 7, 6, 3];
const CELLS = [0, 1, 2, 3, 4, 5, 6, 7, 8];
const ROTATIONS = [
  [0, 1, 2,
   3, 4, 5,
   6, 7, 8],

  [6, 3, 0,
   7, 4, 1,
   8, 5, 2],

  [8, 7, 6,
   5, 4, 3,
   2, 1, 0],

  [2, 5, 8,
   1, 4, 7,
   0, 3, 6]
];
const NEIGHBORS = [
  [1, 4, 3],
  [2, 5, 4, 3, 0],
  [5, 4, 1],
  [0, 1, 4, 7, 6],
  [0, 1, 2, 5, 8, 7, 6, 3],
  [8, 7, 4, 1, 2],
  [3, 4, 7],
  [6, 3, 4, 5, 8],
  [7, 4, 5]
];
const HORIZONTAL_FLIP = [2, 1, 0, 5, 4, 3, 8, 7, 6];
const VERTICAL_FLIP = [6, 7, 8, 3, 4, 5, 0, 1, 2];

const DEBUG_MODE = false;
function dump() {
  if (DEBUG_MODE) {
    throw "dump() not implemented";
  }
}
function log(...args) {
  if (DEBUG_MODE) {
    console.log(...args);
  }
}
function error(...args) {
  log("Transformed view state:", view);
  log(...args);
  throw "A critical error has occurred!";
}

function createArray(func, length) {
  const arr = [];
  for (let i = 0; i < length; i++) {
    arr.push(func(i, arr));
  }
  return arr;
}

class Test {
  run(cell) {
    error("No run method defined for this instance of Test:", this);
  }
  find(cells = CELLS) {
    return cells.find((c) => this.run(c));
  }
  findIndex(cells = CELLS) {
    return cells.findIndex((c) => this.run(c));
  }
  filter(cells = CELLS) {
    return cells.filter((c) => this.run(c));
  }
  every(cells = CELLS) {
    return cells.every((c) => this.run(c));
  }
  some(cells = CELLS) {
    return cells.some((c) => this.run(c));
  }
  count(cells = CELLS) {
    return this.filter(cells).length;
  }
  invert() {
    return new InverseTest(this);
  }
  and(test) {
    return new EveryTest(this, test);
  }
  or(test) {
    return new SomeTest(this, test);
  }
}

class InverseTest extends Test {
  constructor(test) {
    super();
    this.test = test;
  }
  run(cell) {
    return !this.test.run(cell);
  }
  invert() {
    return this.test;
  }
}

class CombinedTest extends Test {
  constructor(...tests) {
    super();
    this.tests = tests;
  }
  append(test) {
    this.tests.push(test);
    return this;
  }
}
class EveryTest extends CombinedTest {
  run(cell) {
    return this.tests.every((test) => test.run(cell));
  }
  and(test) {
    return this.append(test);
  }
}
class SomeTest extends CombinedTest {
  run(cell) {
    return this.tests.some((test) => test.run(cell));
  }
  or(test) {
    return this.append(test);
  }
}

class ColorTest extends Test {
  constructor(color) {
    super();
    this.color = color;
  }
  run(cell) {
    return view[cell].color === this.color;
  }
}
class ColorBandTest extends SomeTest {
  constructor(colorBand) {
    super(...colorBand.map((color) => new ColorTest(color)));
  }
}

class FoodTest extends Test {
  constructor(hasFood = true) {
    super();
    this.food = hasFood ? 1 : 0;
  }
  run(cell) {
    return view[cell].food === this.food;
  }
}

class AntTest extends Test {
  constructor(friend, type, food) {
    super();
    this.friend = friend;
    this.type = type;
    this.food = food;
  }
  run(cell) {
    const ant = view[cell].ant;
    return ant !== null && (this.type === undefined || ant.type === this.type) && (this.friend === undefined || ant.friend === this.friend) && (this.food === undefined || (this.food ? ant.food > 0 : ant.food === 0));
  }
}

class NeighborTest extends Test {
  constructor(test) {
    super();
    this.test = test;
  }
  run(cell) {
    return this.test.some(NEIGHBORS[cell]);
  }
}

class MatchTest extends Test {
  constructor(matches) {
    super();
    this.matches = matches;
  }
  run(cell) {
    return this.matches[cell];
  }
}

class CustomTest extends Test {
  constructor(func, ...args) {
    super();
    this.func = func;
    this.args = args;
  }
  run(cell) {
    return this.func(cell, ...this.args);
  }
}

class Action {
  constructor(cell, test) {
    this.cell = cell;
    this.test = test;
  }

  valid() {
    return this.cell >= 0 && this.cell < 9 && (!this.test || this.test.run(this.cell));
  }
  attempt() {
    return this.valid() ? this : null;
  }
  static tryAll(...actions) {
    return actions.find((action) => action instanceof this && action.valid()) || null;
  }
}
class Move extends Action {
  constructor(cell, test) {
    super(cell, test);
  }

  valid() {
    return super.valid() && view[this.cell].ant === null && (view[this.cell].food === 0 || ME.food === 0 || ME.type === QUEEN);
  }
  static many(cells, test) {
    return cells.map((cell) => new this(cell, test));
  }
}
class Paint extends Action {
  constructor(cell, color, test) {
    super(cell, test);
    this.color = color;
  }

  valid() {
    return super.valid() && view[this.cell].color !== this.color && this.color >= 1 && this.color <= 8;
  }
  static many(cells, colors, test) {
    return cells.map((cell, i) => new this(cell, colors[i % colors.length], test));
  }
}
class Spawn extends Action {
  constructor(cell, type, test) {
    super(cell, test);
    this.type = type;
  }

  valid() {
    return super.valid() && view[this.cell].ant === null && view[this.cell].food === 0 && ME.food > 0 && ME.type === QUEEN && this.type >= 1 && this.type <= 4;
  }
  static many(cells, type, test) {
    return cells.map((cell, i) => new this(cell, type, test));
  }
}
class NOP extends Action {
  constructor() {
    super(CENTER);
  }

  valid() {
    return true;
  }
}

class Context {
  apply(func, ...args) {
    const hiddenView = view;
    if (this.viewTranslator) {
      view = this.viewTranslator(hiddenView);
    }

    let output = func(...args);
    if (output instanceof Action && this.outputTranslator) {
      this.outputTranslator(output);
    }

    view = hiddenView;
    return output;
  }
}

class TranslationContext extends Context {
  constructor(translationArray) {
    super();
    this.translationArray = translationArray;
  }

  viewTranslator(oldView) {
    const newView = [];
    for (let i = 0; i < 9; i++) {
      newView.push(oldView[this.translationArray[i]]);
    }
    return newView;
  }

  outputTranslator(out) {
    out.cell = this.translationArray[out.cell];
  }
}
class RotationContext extends TranslationContext {
  constructor(orientation) {
    super(ROTATIONS[orientation]);
    this.orientation = orientation;
  }
}
class OffsetContext extends TranslationContext {
  constructor(centerCell) {
    throw "OffsetContext not implemented";
  }
}
class HorizontalReflectionContext extends TranslationContext {
  constructor() {
    super(HORIZONTAL_FLIP);
  }
}
class VerticalReflectionContext extends TranslationContext {
  constructor() {
    super(VERTICAL_FLIP);
  }
}

class ColorMapContext extends Context {
  constructor(map, unmap) {
    super();
    this.map = map;
    this.unmap = unmap;
  }

  viewTranslator(oldView) {
    return oldView.map((cell) => ({color: this.map[cell.color - 1], food: cell.food, ant: cell.ant}));
  }

  outputTranslator(out) {
    out.color = this.unmap[out.color - 1];
  }
}

class XY {
  constructor(x = 0, y = 0) {
    this.x = x;
    this.y = y;
  }

  static fromTuples(...xyTuples) {
    return xyTuples.map((xy) => new this(xy[0], xy[1]));
  }
}

class WrapProperties {
  constructor(horizontal, vertical, size, wrapOffsets) {
    this.horizontal = !!horizontal;
    this.vertical = !!vertical;
    this.size = size;
    this.wrapOffsets = wrapOffsets || {};
  }
}

class ScoredTest {
  constructor(test, score = 1) {
    this.test = test;
    this.score = score;
  }

  run(cell) {
    return this.test.run(cell) ? this.score : 0;
  }
}

class Environment {
  constructor(tests, wrapping) {
    this.tests = tests.map((test) => test instanceof Test ? new ScoredTest(test) : test);
    this.wrapping = wrapping;
  }

  at(x, y) {
    const w = this.wrapping;
    while ((w.horizontal && (x < 0 || x >= w.size.x)) || (w.vertical && (y < 0 || y >= w.size.y))) {
      if (w.horizontal) {
        if (x < 0) {
          x += w.size.x;
          y += w.wrapOffsets.left || 0;
        } else if (x >= w.size.x) {
          x -= w.size.x;
          y += w.wrapOffsets.right || 0;
        }
      }

      if (w.vertical) {
        if (y < 0) {
          y += w.size.y;
          x += w.wrapOffsets.up || 0;
        } else if (y >= w.size.y) {
          y -= w.size.y;
          x += w.wrapOffsets.down || 0;
        }
      }
    }

    if ((!w.horizontal || (x >= 0 && x < w.size.x)) && (!w.vertical || (y >= 0 || y < w.size.y))) {
      return this.tests[x + y * w.size.x];
    } else {
      return null;
    }
  }
  around(x, y) {
    const arr = [];
    for (let oy = -1; oy <= 1; oy++) {
      for (let ox = -1; ox <= 1; ox++) {
        arr.push(this.at(x + ox, y + oy));
      }
    }
    return arr;
  }

  detect(...positions) {
    return createArray((i) => new RotationContext(i), 4).reduce((best, context) => {
      const next = context.apply(() => {
        return positions.reduce((best, pos, i) => {
          let score = 0;
          const matches = this.around(pos.x, pos.y).map((test, i) => {
            if (test && (test.test instanceof Test)) {
              const result = test.run(i);
              if (result) {
                score += result;
                return true;
              } else {
                return false;
              }
            } else {
              return null;
            }
          });
          if (score > best.score) {
            return {position: pos, positionIndex: i, orientation: context.orientation, environment: this, matches: matches, score: score, confidence: score - best.score};
          } else {
            best.confidence = Math.min(best.score - score, best.confidence);
            return best;
          }
        }, {position: positions[0], positionIndex: 0, orientation: 0, environment: this, matches: [], score: 0, confidence: 0});
      });
      if (next.score > best.score) {
        next.confidence = next.score - best.score;
        return next;
      } else {
        best.confidence = Math.min(best.score - next.score, best.confidence);
        return best;
      }
    }, {position: positions[0], positionIndex: 0, orientation: 0, environment: this, matches: [], score: 0, confidence: 0});
  }

  static chooseBest(...detectionResults) {
    const r = detectionResults.reduce((best, result, i) => {
      if (result.score > best.score) {
        result.index = i;
        result.confidence = result.score - best.score;
        return result;
      } else {
        best.confidence = Math.min(best.score - result.score, best.confidence);
        return best;
      }
    });
    r.index = r.index || 0;
    return r;
  }
}

class ColoredEnvironment extends Environment {
  constructor(colors, wrapping) {
    super(colors.map((color) => new ColorTest(color)), wrapping);
  }

  getPainter(detectionResult) {
    return new (class Painter {
      constructor(loc) {
        this.pos = loc.position;
        this.matches = loc.matches;
        this.colors = loc.environment.around(this.pos.x, this.pos.y).map((test) => test && test.test instanceof ColorTest ? test.test.color : null);
        this.test = new MatchTest(loc.matches).invert();
        this.orient = loc.orientation;
      }

      paint(...cells) {
        return cells.map((cell) => new Paint(cell, this.colors[cell], this.test));
      }
      cleanup(eraseColor, eraseTargets, ...cells) {
        const eraseQual = this.test.and(new ColorBandTest(eraseTargets));
        return cells.map((cell) => new Paint(cell, eraseColor, eraseQual));
      }
    })(detectionResult);
  }
}

// HIGH-LEVEL LOGIC STARTS HERE //
const PARTNER = 1;

// TODO: Do a 180 when 3 workers are in front of us
function logicOrthogonal(frontC, sideC, backC, backCells, moveCells) {
  const a = [frontC, sideC, backC, backCells, moveCells];
  const f = new FoodTest;
  return Action.tryAll(
    ...Move.many([frontC, sideC], f),
    f.some(backCells) ? new Move(backC) : null,
    ...Move.many(moveCells),
    new NOP
  );
}
function logicDiagonal(adjacentC) {
  return Action.tryAll(...Move.many(adjacentC), new NOP);
}
function logic(partnerTest, partnerOrthC, partnerDiagC, frontC, sideC, backC, backCells, moveCells, adjacentC) {
  function detectEnv(c) {
    return new Environment(createArray((i) => i === c ? partnerTest : undefined, 9), new WrapProperties(false, false, new XY(3, 3), null)).detect(new XY(1, 1));
  }
  const orth = detectEnv(partnerOrthC);
  const diag = detectEnv(partnerDiagC);
  return orth.score === 1 ? new RotationContext(orth.orientation).apply(() => logicOrthogonal(frontC, sideC, backC, backCells, moveCells)) : 
    diag.score === 1 ? new RotationContext(diag.orientation).apply(() => logicDiagonal(adjacentC)) : 
    error("How did we get here?");
}

if (ME.type === QUEEN) {
  const partner = new AntTest(true, PARTNER);
  if (partner.some(DIRECTIONS)) {
    return logic(partner, 5, 8, 2, 1, 7, [0, 3, 6, 7], [2, 7, 1, 8], [5, 7]);
  } else {
    const COLOR = 5;
    const bgTest = new ColorTest(WHITE);
    if (bgTest.run(CENTER)) {
      return new Paint(CENTER, COLOR).attempt() || error("Something went terribly wrong while painting own cell");
    }

    const food = new FoodTest().find(DIRECTIONS);
    if (food !== undefined) {
      return new Move(food);
    }

    const det = new ColoredEnvironment([
      WHITE, WHITE, WHITE, 
      WHITE, undefined, undefined,
      WHITE, undefined, COLOR
    ], new WrapProperties(false, false, new XY(3, 3))).detect(new XY(1, 1));
    return (ME.food > 0 ? Action.tryAll(...Spawn.many(ORTHOGONALS, PARTNER)) : null) ||
      (det.score === 6 ? new RotationContext(det.orientation).apply(() => Action.tryAll(...Move.many([0, 2, 6, 1, 3, 5, 7, 8]))) : null) ||
      Action.tryAll(...Move.many(DIAGONALS_ORTHOGONALS), new NOP);
  }
} else {
  return logic(new AntTest(true, QUEEN), 1, 0, 2, 5, 3, [8, 7, 6, 3], [2, 3, 5, 0], [1, 3]);
}

व्याख्या

यह इतनी सरल चींटी है कि मैं दंग रह गया, ऐसा किसी ने कभी नहीं सोचा था ...

यह चींटी क्लासिक दृष्टिकोण के साथ 1 भोजन इकट्ठा करने के बाद एक साथी का उत्पादन करती है। इसके बाद, क्वीन और पार्टनर एक दूसरे की स्थिति का उपयोग करके उच्चतम गति संभव (एक सेल प्रति मोड़) पर एक सीधी, विकर्ण रेखा में यात्रा करते हैं । वे किसी भी सेल को पेंट नहीं करते हैं। वे प्रति मिनट औसतन 6 कोशिकाओं का सर्वेक्षण करते हैं , एक खाली नक्शे पर उन्हें प्रति गेम 180 भोजन का सैद्धांतिक कुल शुद्ध करते हैं , जिसे वे लगातार प्राप्त करते हैं।

संस्करण 2.0+ बाहर है! इस प्रविष्टि की बारीकियों को स्पष्ट करने वाले कोड में टिप्पणियां शामिल हैं।


बदलाव का

संस्करण 1.0

  • आरंभिक रिलीज

संस्करण 2.0

  • पूरी तरह से युद्धाभ्यास को पुनर्जीवित किया
    • अब अधिक आंदोलन विकल्पों के लिए विकर्ण आसन्न का उपयोग करता है
    • भोजन हथियाने के लिए बदला हुआ व्यवहार
      • औसत संग्रह दर अपरिवर्तित बनी हुई है, लेकिन सिस्टम अधिक मजबूत है
      • जब भोजन का एक से अधिक टुकड़ा मौजूद रहता है तो गतिरोध को रोकता है, निरंतरता को बढ़ाता है
      • बदलती दिशा की दर को कम कर दिया
      • भोजन को अपने पीछे ले जा सकते हैं
    • बाधाओं से बचने के लिए बदला हुआ व्यवहार
      • गतिरोध की संभावना को कम कर दिया, आगे निरंतरता बढ़ रही है
      • जब तक आवश्यक न हो, तब तक यू-टर्न नहीं लिया जाता है, जिससे कुल क्षेत्र में वृद्धि होती है
  • कोड साफ किया
  • टिप्पणी जोड़ दी

संस्करण 2.1

  • एक विदेशी गतिरोध को हल किया

संस्करण 2.2

  • एक और विदेशी गतिरोध को हल किया

संस्करण 2.3

  • दुश्मनों से बचना अब काफी प्रभावी है

संस्करण 2.3.1

  • दुश्मनों से बचना अभी भी थोड़ा अधिक प्रभावी है

संस्करण 2.4

  • संस्करण ४.०.४ (1.0 से) के लिए अपडेट किया गया
  • रिफैक्टेड कोड (संस्करण 2.3.1 के समान व्यवहार)

संस्करण 2.5

  • संस्करण ६.१.१० (४.०.४ से) के लिए अपडेट किया गया
  • नए कोडिंग मानक (वर्जन 2.4 के समान व्यवहार) से मेल करने के लिए रिफैक्टेड कोड
  • हटाए गए कोड टिप्पणियाँ :(

संस्करण 2.5.0.1

  • मामूली सुधार

संस्करण 2.5.0.2

संस्करण 2.5.0.3

  • अक्षम डिबगिंग

8

ट्रेल-रबड़

var i, j
var orthogonals = [1, 3, 7, 5]  // These are the non-diagonal cells
if(view[4].ant.type == 5) {
//Queen moves straight to get food
// Color own cell if white
if (view[4].color != 6) { 
    return {cell:4, color:6}
}
var specified = null;
// Otherwise move to a white cell opposite a colored cell
for (i=0; i<4; i++) {
    j = (i+2) % 4
    if (view[orthogonals[i]].color !== 6 &&
        view[orthogonals[j]].color == 6 && !view[orthogonals[i]].ant) {
        specified = {cell:orthogonals[i]}
    } else if (view[4].ant.food < 8 && view[4].ant.food && view[orthogonals[i]].color !== 6 && !view[orthogonals[i]].ant && !view[orthogonals[i]].food && view[orthogonals[i]].color !== 1) {
        //create workers once I encounter a trail
        return {cell:orthogonals[i], type:(view[orthogonals[i]].color%4)+1};
    } else if (view[orthogonals[i]].food) {
        return {cell:orthogonals[i]}
    }
}
if(specified) { return specified; }
// Otherwise move to one of the vertical or horizontal cells if not occupied
for (i=1; i<9; i+=2) {
    if (!view[i].ant) {
        return {cell:i}
    }
}

// Otherwise move to one of the diagonal cells if not occupied
for (i=0; i<9; i+=2) {
    if (!view[i].ant) {
        return {cell:i};
    }
}

// Otherwise don't move at all
return {cell:4};
}
//workers erase their trails
//Follow the trail to erase
var move, color, enemyAnt = false;
var nearbyColoredCells = 0;
if(view[4].color != 1){
   color =  {cell:4, color:1}
}
for(i=0;i<9;i++) {
    if(i != 4 && view[i].color != 1 && !view[i].ant && (!view[4].ant.food || !view[i].food) && (!move || (view[i].color % 4 + 1) == view[4].type || (view[move.cell].color == 6 && view[i].color != 6))) {
        move = {cell:i}
    }
    if(view[i].ant && view[i].ant.friend && view[i].ant.type == 5){
       return {cell:4}
    }
    if(i != 4 && view[i].color != 1 && view[i].color != 6){
        nearbyColoredCells += 1;
    }
    if(view[i].ant && !view[i].ant.friend) {
         enemyAnt = i;
    }
}
if(nearbyColoredCells <= 1 || enemyAnt > 1) {
    // Either I'm following a standard trail or there are enemy workers; possibly decolor own cell and move
    if(color && (!move || !enemyAnt)) { return color; }
    if(move) { return move; }
} else if (nearbyColoredCells > 1){
   for (i = 0; i < 9; i++){
       if(view[i].color != 1){ return {cell:i, color:1} }
   }
}
// uh-oh, our trail ended or we got lost -- random walk
// find a safe place to move
for (i=0;i<9;i+=1) {
    if (!view[i].ant && (!view[4].ant.food || !view[i].food)) {
       return {cell:i}
    }
}
return {cell:4}

यह चींटी, जबकि भोजन खोजने में मध्यम रूप से अच्छी है (लेकिन रोमन चींटियों या फोरेंसिक चींटियों की तरह अच्छी नहीं) अन्य चींटियों को भ्रमित करने का प्रयास करती है। यह ऐसा काम करता है जिसका एकमात्र उद्देश्य ट्रेल्स को मिटाना है जब भी यह रंग के एक क्रॉसिंग पथ का सामना करता है। श्रमिक जो अपने निशान के अंत में बेकार यादृच्छिक रूप से चलते हैं, जब तक कि वे एक और निशान नहीं पाते। भोजन को संरक्षित करने और संभवतः बेहतर करने के लिए, यह चींटी एक बार आठ खाद्य पदार्थों को हिट करने के लिए अधिक श्रमिकों का उत्पादन नहीं करने की रणनीति पर स्विच करेगी, जो देर से खेल में होना चाहिए क्योंकि यह भोजन को संरक्षित करने के लिए एक विशिष्ट कॉम्बो की आवश्यकता होती है और न कि केवल यह सब प्रयोग करें।


1
तोड़फोड़! 😮 रोमियों ने आपके साथ क्या किया?
डेव

इस प्रविष्टि में ब्लैक होल के साथ खिलवाड़ करने में बहुत मज़ा आ रहा है ...
ली ली

2
@ क्या उन्होंने इस चुनौती के लिए एक प्रतिस्पर्धी प्रविष्टि प्रस्तुत की ...
पिपरी

2
यह खिलाड़ी कभी-कभी अपने सभी भोजन को बर्बाद कर देता है, क्योंकि यह रोमन चींटियों द्वारा भ्रमित हो जाता है
pppery

2
दूसरा अपडेट: अब शुरुआत में खाना नहीं
छीनता,

8

Hyperwave

मेरे सभी उत्तरों में फॉर्मिक फ़ंक्शंस फ्रेमवर्क के रूप में समान स्तर के तर्क होंगे। "हाई-लेवल लॉजिक स्टार्स यहां" फ्रेमवर्क के कोड के अंत को चिह्नित करता है।

 //  FORMIC FRAMEWORK  //
// Version 6.1.10     //
const WHITE = 1;
const QUEEN = 5;
const CENTER = 4;
const HERE = view[CENTER];
const ME = HERE.ant;
const ORTHOGONALS = [1, 3, 5, 7];
const DIAGONALS = [0, 2, 6, 8];
const DIAGONALS_ORTHOGONALS = [0, 2, 6, 8, 1, 3, 5, 7];
const DIRECTIONS = [0, 1, 2, 3, 5, 6, 7, 8];
const CLOCKWISE_DIRECTIONS = [0, 1, 2, 5, 8, 7, 6, 3];
const CELLS = [0, 1, 2, 3, 4, 5, 6, 7, 8];
const ROTATIONS = [
  [0, 1, 2,
   3, 4, 5,
   6, 7, 8],

  [6, 3, 0,
   7, 4, 1,
   8, 5, 2],

  [8, 7, 6,
   5, 4, 3,
   2, 1, 0],

  [2, 5, 8,
   1, 4, 7,
   0, 3, 6]
];
const NEIGHBORS = [
  [1, 4, 3],
  [2, 5, 4, 3, 0],
  [5, 4, 1],
  [0, 1, 4, 7, 6],
  [0, 1, 2, 5, 8, 7, 6, 3],
  [8, 7, 4, 1, 2],
  [3, 4, 7],
  [6, 3, 4, 5, 8],
  [7, 4, 5]
];
const HORIZONTAL_FLIP = [2, 1, 0, 5, 4, 3, 8, 7, 6];
const VERTICAL_FLIP = [6, 7, 8, 3, 4, 5, 0, 1, 2];

const DEBUG_MODE = true;
function dump() {
  if (DEBUG_MODE) {
    throw "dump() not implemented";
  }
}
function log(...args) {
  if (DEBUG_MODE) {
    console.log(...args);
  }
}
function error(...args) {
  log("Transformed view state:", view);
  log(...args);
  throw "A critical error has occurred!";
}

function createArray(func, length) {
  const arr = [];
  for (let i = 0; i < length; i++) {
    arr.push(func(i, arr));
  }
  return arr;
}

class Test {
  run(cell) {
    error("No run method defined for this instance of Test:", this);
  }
  find(cells = CELLS) {
    return cells.find((c) => this.run(c));
  }
  findIndex(cells = CELLS) {
    return cells.findIndex((c) => this.run(c));
  }
  filter(cells = CELLS) {
    return cells.filter((c) => this.run(c));
  }
  every(cells = CELLS) {
    return cells.every((c) => this.run(c));
  }
  some(cells = CELLS) {
    return cells.some((c) => this.run(c));
  }
  count(cells = CELLS) {
    return this.filter(cells).length;
  }
  invert() {
    return new InverseTest(this);
  }
  and(test) {
    return new EveryTest(this, test);
  }
  or(test) {
    return new SomeTest(this, test);
  }
}

class InverseTest extends Test {
  constructor(test) {
    super();
    this.test = test;
  }
  run(cell) {
    return !this.test.run(cell);
  }
  invert() {
    return this.test;
  }
}

class CombinedTest extends Test {
  constructor(...tests) {
    super();
    this.tests = tests;
  }
  append(test) {
    this.tests.push(test);
    return this;
  }
}
class EveryTest extends CombinedTest {
  run(cell) {
    return this.tests.every((test) => test.run(cell));
  }
  and(test) {
    return this.append(test);
  }
}
class SomeTest extends CombinedTest {
  run(cell) {
    return this.tests.some((test) => test.run(cell));
  }
  or(test) {
    return this.append(test);
  }
}

class ColorTest extends Test {
  constructor(color) {
    super();
    this.color = color;
  }
  run(cell) {
    return view[cell].color === this.color;
  }
}
class ColorBandTest extends SomeTest {
  constructor(colorBand) {
    super(...colorBand.map((color) => new ColorTest(color)));
  }
}

class FoodTest extends Test {
  constructor(hasFood = true) {
    super();
    this.food = hasFood ? 1 : 0;
  }
  run(cell) {
    return view[cell].food === this.food;
  }
}

class AntTest extends Test {
  constructor(friend, type, food) {
    super();
    this.friend = friend;
    this.type = type;
    this.food = food;
  }
  run(cell) {
    const ant = view[cell].ant;
    return ant !== null && (this.type === undefined || ant.type === this.type) && (this.friend === undefined || ant.friend === this.friend) && (this.food === undefined || (this.food ? ant.food > 0 : ant.food === 0));
  }
}

class NeighborTest extends Test {
  constructor(test) {
    super();
    this.test = test;
  }
  run(cell) {
    return this.test.some(NEIGHBORS[cell]);
  }
}

class MatchTest extends Test {
  constructor(matches) {
    super();
    this.matches = matches;
  }
  run(cell) {
    return this.matches[cell];
  }
}

class CustomTest extends Test {
  constructor(func, ...args) {
    super();
    this.func = func;
    this.args = args;
  }
  run(cell) {
    return this.func(cell, ...this.args);
  }
}

class Action {
  constructor(cell, test) {
    this.cell = cell;
    this.test = test;
  }

  valid() {
    return this.cell >= 0 && this.cell < 9 && (!this.test || this.test.run(this.cell));
  }
  attempt() {
    return this.valid() ? this : null;
  }
  static tryAll(...actions) {
    return actions.find((action) => action instanceof this && action.valid()) || null;
  }
}
class Move extends Action {
  constructor(cell, test) {
    super(cell, test);
  }

  valid() {
    return super.valid() && view[this.cell].ant === null && (view[this.cell].food === 0 || ME.food === 0 || ME.type === QUEEN);
  }
  static many(cells, test) {
    return cells.map((cell) => new this(cell, test));
  }
}
class Paint extends Action {
  constructor(cell, color, test) {
    super(cell, test);
    this.color = color;
  }

  valid() {
    return super.valid() && view[this.cell].color !== this.color && this.color >= 1 && this.color <= 8;
  }
  static many(cells, colors, test) {
    return cells.map((cell, i) => new this(cell, colors[i % colors.length], test));
  }
}
class Spawn extends Action {
  constructor(cell, type, test) {
    super(cell, test);
    this.type = type;
  }

  valid() {
    return super.valid() && view[this.cell].ant === null && view[this.cell].food === 0 && ME.food > 0 && ME.type === QUEEN && this.type >= 1 && this.type <= 4;
  }
  static many(cells, type, test) {
    return cells.map((cell, i) => new this(cell, type, test));
  }
}
class NOP extends Action {
  constructor() {
    super(CENTER);
  }

  valid() {
    return true;
  }
}

class Context {
  apply(func, ...args) {
    const hiddenView = view;
    if (this.viewTranslator) {
      view = this.viewTranslator(hiddenView);
    }

    let output = func(...args);
    if (output instanceof Action && this.outputTranslator) {
      this.outputTranslator(output);
    }

    view = hiddenView;
    return output;
  }
}

class TranslationContext extends Context {
  constructor(translationArray) {
    super();
    this.translationArray = translationArray;
  }

  viewTranslator(oldView) {
    const newView = [];
    for (let i = 0; i < 9; i++) {
      newView.push(oldView[this.translationArray[i]]);
    }
    return newView;
  }

  outputTranslator(out) {
    out.cell = this.translationArray[out.cell];
  }
}
class RotationContext extends TranslationContext {
  constructor(orientation) {
    super(ROTATIONS[orientation]);
    this.orientation = orientation;
  }
}
class OffsetContext extends TranslationContext {
  constructor(centerCell) {
    throw "OffsetContext not implemented";
  }
}
class HorizontalReflectionContext extends TranslationContext {
  constructor() {
    super(HORIZONTAL_FLIP);
  }
}
class VerticalReflectionContext extends TranslationContext {
  constructor() {
    super(VERTICAL_FLIP);
  }
}

class ColorMapContext extends Context {
  constructor(map, unmap) {
    super();
    this.map = map;
    this.unmap = unmap;
  }

  viewTranslator(oldView) {
    return oldView.map((cell) => ({color: this.map[cell.color - 1], food: cell.food, ant: cell.ant}));
  }

  outputTranslator(out) {
    out.color = this.unmap[out.color - 1];
  }
}

class XY {
  constructor(x = 0, y = 0) {
    this.x = x;
    this.y = y;
  }

  static fromTuples(...xyTuples) {
    return xyTuples.map((xy) => new this(xy[0], xy[1]));
  }
}

class WrapProperties {
  constructor(horizontal, vertical, size, wrapOffsets) {
    this.horizontal = !!horizontal;
    this.vertical = !!vertical;
    this.size = size;
    this.wrapOffsets = wrapOffsets || {};
  }
}

class ScoredTest {
  constructor(test, score = 1) {
    this.test = test;
    this.score = score;
  }

  run(cell) {
    return this.test.run(cell) ? this.score : 0;
  }
}

class Environment {
  constructor(tests, wrapping) {
    this.tests = tests.map((test) => test instanceof Test ? new ScoredTest(test) : test);
    this.wrapping = wrapping;
  }

  at(x, y) {
    const w = this.wrapping;
    while ((w.horizontal && (x < 0 || x >= w.size.x)) || (w.vertical && (y < 0 || y >= w.size.y))) {
      if (w.horizontal) {
        if (x < 0) {
          x += w.size.x;
          y += w.wrapOffsets.left || 0;
        } else if (x >= w.size.x) {
          x -= w.size.x;
          y += w.wrapOffsets.right || 0;
        }
      }

      if (w.vertical) {
        if (y < 0) {
          y += w.size.y;
          x += w.wrapOffsets.up || 0;
        } else if (y >= w.size.y) {
          y -= w.size.y;
          x += w.wrapOffsets.down || 0;
        }
      }
    }

    if ((!w.horizontal || (x >= 0 && x < w.size.x)) && (!w.vertical || (y >= 0 || y < w.size.y))) {
      return this.tests[x + y * w.size.x];
    } else {
      return null;
    }
  }
  around(x, y) {
    const arr = [];
    for (let oy = -1; oy <= 1; oy++) {
      for (let ox = -1; ox <= 1; ox++) {
        arr.push(this.at(x + ox, y + oy));
      }
    }
    return arr;
  }

  detect(...positions) {
    return createArray((i) => new RotationContext(i), 4).reduce((best, context) => {
      const next = context.apply(() => {
        return positions.reduce((best, pos, i) => {
          let score = 0;
          const matches = this.around(pos.x, pos.y).map((test, i) => {
            if (test && (test.test instanceof Test)) {
              const result = test.run(i);
              if (result) {
                score += result;
                return true;
              } else {
                return false;
              }
            } else {
              return null;
            }
          });
          if (score > best.score) {
            return {position: pos, positionIndex: i, orientation: context.orientation, environment: this, matches: matches, score: score, confidence: score - best.score};
          } else {
            best.confidence = Math.min(best.score - score, best.confidence);
            return best;
          }
        }, {position: positions[0], positionIndex: 0, orientation: 0, environment: this, matches: [], score: 0, confidence: 0});
      });
      if (next.score > best.score) {
        next.confidence = next.score - best.score;
        return next;
      } else {
        best.confidence = Math.min(best.score - next.score, best.confidence);
        return best;
      }
    }, {position: positions[0], positionIndex: 0, orientation: 0, environment: this, matches: [], score: 0, confidence: 0});
  }

  static chooseBest(...detectionResults) {
    const r = detectionResults.reduce((best, result, i) => {
      if (result.score > best.score) {
        result.index = i;
        result.confidence = result.score - best.score;
        return result;
      } else {
        best.confidence = Math.min(best.score - result.score, best.confidence);
        return best;
      }
    });
    r.index = r.index || 0;
    return r;
  }
}

class ColoredEnvironment extends Environment {
  constructor(colors, wrapping) {
    super(colors.map((color) => new ColorTest(color)), wrapping);
  }

  getPainter(detectionResult) {
    return new (class Painter {
      constructor(loc) {
        this.pos = loc.position;
        this.matches = loc.matches;
        this.colors = loc.environment.around(this.pos.x, this.pos.y).map((test) => test && test.test instanceof ColorTest ? test.test.color : null);
        this.test = new MatchTest(loc.matches).invert();
        this.orient = loc.orientation;
      }

      paint(...cells) {
        return cells.map((cell) => new Paint(cell, this.colors[cell], this.test));
      }
      cleanup(eraseColor, eraseTargets, ...cells) {
        const eraseQual = this.test.and(new ColorBandTest(eraseTargets));
        return cells.map((cell) => new Paint(cell, eraseColor, eraseQual));
      }
    })(detectionResult);
  }
}

// HIGH-LEVEL LOGIC STARTS HERE //
// TODO:
// - more food checkpoints (no disadvantages because it's illogical for WFW to "premanently lose" workers)
// - randomly shifting 1 up (5% chance? watch out for hoarding stealing your randomness!)
// - randomly skip painting a tiny bit of local cells (prevent deadlock against ants outside of view)
// - escape routine when situation is dire (many workers near the queen/partner)

const COLOR_BAND = [4, 7, 3, 2, 8];

const PARTNER = 2;
const WORKER = 1;

const START_FOOD = 6;
const MIN_CONFIDENCE = 2;

const PATTERN = new ColoredEnvironment(COLOR_BAND, new WrapProperties(true, true, new XY(COLOR_BAND.length, 1), {up: 2, down: -2})).detect(...createArray((i) => new XY(i, 0), COLOR_BAND.length));

function checkpoint(val, tolerance) {
  return ME.food >= val - tolerance && ME.food <= val;
}
function shouldSpawn() {
  return PATTERN.orientation === 0 && PATTERN.positionIndex % 3 === 0 &&
    ME.food < 400 &&
    (ME.food < 75 || PATTERN.positionIndex === 0) && 
    !checkpoint(300, 4) &&
    !checkpoint(200, 5) &&
    !checkpoint(160, 3) &&
    !checkpoint(130, 2) &&
    !checkpoint(100, 2) &&
    !checkpoint(75, 2) &&
    !checkpoint(50, 2) &&
    !checkpoint(35, 1) &&
    !checkpoint(20, 1) &&
    !checkpoint(10, 0);
}

function lightspeed() {
  // TODO: Do a 180 when 3 workers are in front of us
  function logicOrthogonal(frontC, sideC, backC, backCells, moveCells) {
    const a = [frontC, sideC, backC, backCells, moveCells];
    const f = new FoodTest;
    return Action.tryAll(
      ...Move.many([frontC, sideC], f),
      f.some(backCells) ? new Move(backC) : null,
      ...Move.many(moveCells),
      new NOP
    );
  }
  function logicDiagonal(adjacentC) {
    return Action.tryAll(...Move.many(adjacentC), new NOP);
  }
  function logic(partnerTest, partnerOrthC, partnerDiagC, frontC, sideC, backC, backCells, moveCells, adjacentC) {
    function detectEnv(c) {
      return new Environment(createArray((i) => i === c ? partnerTest : undefined, 9), new WrapProperties(false, false, new XY(3, 3), null)).detect(new XY(1, 1));
    }
    const orth = detectEnv(partnerOrthC);
    const diag = detectEnv(partnerDiagC);
    return orth.score === 1 ? new RotationContext(orth.orientation).apply(() => logicOrthogonal(frontC, sideC, backC, backCells, moveCells)) : 
      diag.score === 1 ? new RotationContext(diag.orientation).apply(() => logicDiagonal(adjacentC)) : 
      error("How did we get here?");
  }

  if (ME.type === QUEEN) {
    const partner = new AntTest(true, PARTNER);
    if (partner.some(DIRECTIONS)) {
      return logic(partner, 5, 8, 2, 1, 7, [0, 3, 6, 7], [2, 7, 1, 8], [5, 7]);
    } else {
      const COLOR = 5;
      const bgTest = new ColorTest(WHITE);
      if (bgTest.run(CENTER)) {
        return new Paint(CENTER, COLOR).attempt() || error("Something went terribly wrong while painting own cell");
      }

      const food = new FoodTest().find(DIRECTIONS);
      if (food !== undefined) {
        return new Move(food);
      }

      const det = new ColoredEnvironment([
        WHITE, WHITE, WHITE, 
        WHITE, undefined, undefined,
        WHITE, undefined, COLOR
      ], new WrapProperties(false, false, new XY(3, 3))).detect(new XY(1, 1));
      return (ME.food > 0 ? Action.tryAll(...Spawn.many(ORTHOGONALS, PARTNER)) : null) ||
        (det.score === 6 ? new RotationContext(det.orientation).apply(() => Action.tryAll(...Move.many([0, 2, 6, 1, 3, 5, 7, 8]))) : null) ||
        Action.tryAll(...Move.many(DIAGONALS_ORTHOGONALS), new NOP);
    }
  } else {
    return logic(new AntTest(true, QUEEN), 1, 0, 2, 5, 3, [8, 7, 6, 3], [2, 3, 5, 0], [1, 3]);
  }
}

function queen() {
  const partnerTest = new AntTest(true, PARTNER);
  if (PATTERN.confidence < MIN_CONFIDENCE && (ME.food < START_FOOD || partnerTest.some(DIAGONALS))) return lightspeed();
  return new RotationContext(PATTERN.orientation).apply(() => {
    const partnerCell = new AntTest(true, PARTNER).find(DIRECTIONS);
    const p = PATTERN.environment.getPainter(PATTERN);
    const e = new AntTest(false);
    const enemy = e.some(DIRECTIONS);
    return Action.tryAll(
      ...!PATTERN.matches[8] ? [
        ...!enemy ? [...p.paint(7, 4, 5, 1, 2), ...shouldSpawn() && PATTERN.score === 8 ? Spawn.many([0, 2], WORKER) : []] : [],
        ...partnerCell === 1 ? Move.many(e.run(5) ? [0, 2] : PATTERN.orientation === 1 && PATTERN.positionIndex % 3 === 1 ? [2, 0, 5] : [5, 2, 0]) : 
          partnerCell === 0 ? Move.many(e.run(1) ? [3] : enemy ? [1, 3] : []) :
          partnerCell === 2 ? Move.many(e.run(1) ? [5] : []) :
          []
      ] : [
        ...!enemy ? p.paint(8, 7, 6, 5, 4, 3, 2, 1, 0) : [],
        ...Move.many(partnerCell === 1 ? [2, 0] : partnerCell === 0 ? [1, 3] : partnerCell === 2 && e.run(1) ? [5] : [])
      ],
      new NOP
    )
  });
}
function partner() {
  const queenTest = new AntTest(true, QUEEN)
  const queenCell = queenTest.find(DIRECTIONS);
  if (queenCell === undefined) {
    return new NOP; // TODO: What do we do if we've lost our queen?
  }
  if (PATTERN.confidence < MIN_CONFIDENCE && (view[queenCell].ant.food < START_FOOD || DIAGONALS.includes(queenCell))) return lightspeed();
  return PATTERN.confidence >= MIN_CONFIDENCE ? new RotationContext(PATTERN.orientation).apply(() => {
    const queenCell = queenTest.find(DIRECTIONS);
    const e = new AntTest(false);
    const enemy = e.some(DIRECTIONS);
    return Action.tryAll(
      ...!enemy ? PATTERN.environment.getPainter(PATTERN).paint(...CELLS) : [],
      ...Move.many([
        [1],
        [0, 2],
        [1],
        [0, 1],
        [], // Queen can't be on cell 4 - I'm here, after all!
        [2, 1],
        [3],
        [],
        [5]
      ][queenCell]),
      new NOP
    )
  }) : new NOP;
}
function worker() {
  const m = new MatchTest(PATTERN.matches);
  const n = m.invert();
  const u = new AntTest(true, WORKER, false);
  const l = new AntTest(true, WORKER, true);
  const q = new AntTest(true, QUEEN);
  const pt = new AntTest(true, PARTNER);
  const p = PATTERN.environment.getPainter(PATTERN);
  return new RotationContext(PATTERN.orientation).apply(() => { // TODO: Unique (random?) behavior when confidence low
    if (ME.food === 0) {
      const f = new FoodTest();
      const count = n.count([6, 7, 8]);
      return Action.tryAll(
        ...PATTERN.confidence >= 2 ? p.paint(4, 0, 1, 2) : [],
        //...p.cleanup(WHITE, COLOR_BAND, ...CELLS),
        ...((food) => food !== undefined ? [...p.paint(...NEIGHBORS[food], food), new Move(food)] : [])(f.find(DIRECTIONS)),
        ...q.or(pt).some(DIRECTIONS) || u.some([6, 7, 8, 5, 2]) ? Move.many([0, 1, 3], m) : [],
        ...count > 1 ? p.paint(...[6, 7, 8]) : [],
        ...count === 1 ? [...p.paint(...[3, 5]), ...Move.many([7, 8, 6, 3], m)] : [],
        /*n.run(6) ? new Move(3, m) : null,
        ...n.run(7) ? Move.many([6, 3], m) : [],
        n.run(8) ? new Move(7, m) : null,*/
        n.run(5) ? new Move(5) : null,
        ...Move.many([2, 1, 0, 3], m),
        new NOP
        /*
        ...(PATTERN.confidence >= 2 ? [...(PATTERN.score < 8 || new AntTest(false).some(DIRECTIONS) ? p.paint(4, 3, 0, 1, 2, 5) : []), ...p.cleanup(WHITE, COLOR_BAND, ...CELLS)] : []),
        ...((food) => food !== undefined ? [...p.paint(...NEIGHBORS[food]), new Move(food)] : [])(f.find(DIRECTIONS)), ...(
          w ? Move.many([1, 0, 2]) :
          m.some([4, 3]) ? p.paint(4, 3) :
          m.some([0, 1, 2]) ? Move.many([1, 5]) :
          m.run(6) ? [new Move(3)] :
          m.run(7) ? Move.many([6, 3]) :
          m.run(8) ? [new Move(7)] :
          m.run(5) ? Move.many([5, 7]) :
          Move.many([2, 1, 5])
        )
        new NOP*/
      );
    } else {
      return Action.tryAll(
        //...Move.many(new AntTest(true, WORKER).some([2, 5, 8, 7]) || PATTERN.score < 9 ? [8, 7, 6, 3] : [5, 8, 2], m.invert()),
        ...((test) => createArray((i) => new Move(CLOCKWISE_DIRECTIONS[(6 - i) % 8], test), 5))(new CustomTest((cell, moveTest, blockTest) => {
          const i = CLOCKWISE_DIRECTIONS.findIndex((c) => c === cell);
          return moveTest.run(CLOCKWISE_DIRECTIONS[i]) && blockTest.run(CLOCKWISE_DIRECTIONS[((i - 1) + 8) % 8]);
        }, m, n.or(new AntTest().and(l.invert())))),
        ...Move.many([2, 5, 1, 8], m),
        //...Move.many([...(PATTERN.score === 9 && !new AntTest(true, WORKER).some(DIRECTIONS) ? [2] : []), 5, 8, 7, 6, 3], m),
        new NOP
      );
    }
  });
}

switch (ME.type) {
  case QUEEN: {
    return queen();
  }
  case PARTNER: {
    return partner();
  }
  case WORKER: {
    return worker();
  }
}

मैंने समय के दबाव के कारण इस प्रविष्टि के सभी विवरण अस्थायी रूप से हटा दिए हैं। मैं इस प्रमुख अद्यतन का संपूर्ण विवरण बाद की तारीख में जोड़ूंगा।


बदलाव का

संस्करण 1.0

  • आरंभिक रिलीज

संस्करण 2.0

  • हाइपरवेव के साथ हाईवे को बदल दिया

संस्करण 2.0.1

  • हॉटफ़ॉक्स होर्डिंग तंत्र

यह देखने के लिए सुंदर शुरू होता है, फिर भयानक हो जाता है ...
ट्राइकोप्लाक्स

1
सड़कों के खिलाफ वैम्पायिक संपादन करने का समय।
ड्रेको

और मैं केवल वैम्पायर को और अधिक खिलाता जा रहा हूं क्योंकि समय @ ड्रैको 18s पर चला जाता है - बहुत सारे सुधार हैं जो मैं करना चाहता हूं।
एलियन

3
पहली प्रविष्टि मैंने देखी है जो मानक गेम समय के भीतर बोर्ड को पूरी तरह से सब्सक्राइब कर सकती है। बहुत प्रभावशाली।
डेव

7

रोमन चींटियों Mk.2

मेरे सभी उत्तर निम्न-स्तरीय सहायक कार्यों के समान सेट को साझा कर रहे हैं। इस उत्तर के लिए विशिष्ट कोड को देखने के लिए "उच्च-स्तरीय तर्क यहां शुरू होता है"।

// == Shared low-level helpers for all solutions ==

var QUEEN = 5;

var WHITE = 1;
var COL_MIN = WHITE;
var COL_LIM = 9;

var CENTRE = 4;

var NOP = {cell: CENTRE};

var DIR_FORWARDS = false;
var DIR_REVERSE = true;
var SIDE_RIGHT = true;
var SIDE_LEFT = false;

function sanity_check(movement) {
  var me = view[CENTRE].ant;
  if(!movement || movement.cell < 0 || movement.cell > 8) {
    return false;
  }
  if(movement.type) {
    if(movement.color) {
      return false;
    }
    if(movement.type < 1 || movement.type > 4) {
      return false;
    }
    if(view[movement.cell].ant || view[movement.cell].food) {
      return false;
    }
    if(me.type !== QUEEN || me.food < 1) {
      return false;
    }
    return true;
  }
  if(movement.color) {
    if(movement.color < COL_MIN || movement.color >= COL_LIM) {
      return false;
    }
    if(view[movement.cell].color === movement.color) {
      return false;
    }
    return true;
  }
  if(view[movement.cell].ant) {
    return false;
  }
  if(view[movement.cell].food + me.food > 1 && me.type !== QUEEN) {
    return false;
  }
  return true;
}

function as_array(o) {
  if(Array.isArray(o)) {
    return o;
  }
  return [o];
}

function best_of(movements) {
  var m;
  for(var i = 0; i < movements.length; ++ i) {
    if(typeof(movements[i]) === 'function') {
      m = movements[i]();
    } else {
      m = movements[i];
    }
    if(sanity_check(m)) {
      return m;
    }
  }
  return null;
}

function play_safe(movement) {
  // Avoid disqualification: no-op if moves are invalid
  return best_of(as_array(movement)) || NOP;
}

var RAND_SEED = (() => {
  var s = 0;
  for(var i = 0; i < 9; ++ i) {
    s += view[i].color * (i + 1);
    s += view[i].ant ? i * i : 0;
    s += view[i].food ? i * i * i : 0;
  }
  return s % 29;
})();

var ROTATIONS = [
  [0, 1, 2, 3, 4, 5, 6, 7, 8],
  [6, 3, 0, 7, 4, 1, 8, 5, 2],
  [8, 7, 6, 5, 4, 3, 2, 1, 0],
  [2, 5, 8, 1, 4, 7, 0, 3, 6],
];

function try_all(fns, limit, wrapperFn, checkFn) {
  var m;
  fns = as_array(fns);
  for(var i = 0; i < fns.length; ++ i) {
    if(typeof(fns[i]) !== 'function') {
      if(checkFn(m = fns[i])) {
        return m;
      }
      continue;
    }
    for(var j = 0; j < limit; ++ j) {
      if(checkFn(m = wrapperFn(fns[i], j))) {
        return m;
      }
    }
  }
  return null;
}

function identify_rotation(testFns) {
  // testFns MUST be functions, not constants
  return try_all(
    testFns,
    4,
    (fn, r) => fn(ROTATIONS[r]) ? ROTATIONS[r] : null,
    (r) => r
  );
}

function near(a, b) {
  return (
    Math.abs(a % 3 - b % 3) < 2 &&
    Math.abs(Math.floor(a / 3) - Math.floor(b / 3)) < 2
  );
}

function try_all_angles(solverFns) {
  return try_all(
    solverFns,
    4,
    (fn, r) => fn(ROTATIONS[r]),
    sanity_check
  );
}

function try_all_cells(solverFns, skipCentre) {
  return try_all(
    solverFns,
    9,
    (fn, i) => ((i === CENTRE && skipCentre) ? null : fn(i)),
    sanity_check
  );
}

function try_all_cells_near(p, solverFns) {
  return try_all(
    solverFns,
    9,
    (fn, i) => ((i !== p && near(p, i)) ? fn(i) : null),
    sanity_check
  );
}

function ant_type_at(i, friend) {
  return (view[i].ant && view[i].ant.friend === friend) ? view[i].ant.type : 0;
}

function friend_at(i) {
  return ant_type_at(i, true);
}

function foe_at(i) {
  return ant_type_at(i, false);
}

function foe_near(p) {
  for(var i = 0; i < 9; ++ i) {
    if(foe_at(i) && near(i, p)) {
      return true;
    }
  }
  return false;
}

function move_agent(agents) {
  var me = view[CENTRE].ant;
  var buddies = [0, 0, 0, 0, 0, 0];
  for(var i = 0; i < 9; ++ i) {
    ++ buddies[friend_at(i)];
  }

  for(var i = 0; i < agents.length; i += 2) {
    if(agents[i] === me.type) {
      return agents[i+1](me, buddies);
    }
  }
  return null;
}

function grab_nearby_food() {
  return try_all_cells((i) => (view[i].food ? {cell: i} : null), true);
}

function go_anywhere() {
  return try_all_cells((i) => ({cell: i}), true);
}

function colours_excluding(cols) {
  var r = [];
  for(var i = COL_MIN; i < COL_LIM; ++ i) {
    if(cols.indexOf(i) === -1) {
      r.push(i);
    }
  }
  return r;
}

function generate_band(start, width) {
  var r = [];
  for(var i = 0; i < width; ++ i) {
    r.push(start + i);
  }
  return r;
}

function colour_band(colours) {
  return {
    contains: function(c) {
      return colours.indexOf(c) !== -1;
    },
    next: function(c) {
      return colours[(colours.indexOf(c) + 1) % colours.length];
    }
  };
}

function random_colour_band(colours) {
  return {
    contains: function(c) {
      return colours.indexOf(c) !== -1;
    },
    next: function() {
      return colours[RAND_SEED % colours.length];
    }
  };
}

function fast_diagonal(colourBand) {
  var m = try_all_angles([
    // Avoid nearby checked areas
    (rot) => {
      if(
        !colourBand.contains(view[rot[0]].color) &&
        colourBand.contains(view[rot[5]].color) &&
        colourBand.contains(view[rot[7]].color)
      ) {
        return {cell: rot[0]};
      }
    },

    // Go in a straight diagonal line if possible
    (rot) => {
      if(
        !colourBand.contains(view[rot[0]].color) &&
        colourBand.contains(view[rot[8]].color)
      ) {
        return {cell: rot[0]};
      }
    },

    // When in doubt, pick randomly but avoid doubling-back
    (rot) => (colourBand.contains(view[rot[0]].color) ? null : {cell: rot[0]}),

    // Double-back when absolutely necessary
    (rot) => ({cell: rot[0]})
  ]);

  // Lay a colour track so that we can avoid doubling-back
  // (and mess up our foes as much as possible)
  if(!colourBand.contains(view[CENTRE].color)) {
    var prevCol = m ? view[8-m.cell].color : WHITE;
    return {cell: CENTRE, color: colourBand.next(prevCol)};
  }

  return m;
}

function follow_edge(obstacleFn, side) {
  // Since we don't know which direction we came from, this can cause us to get
  // stuck on islands, but the random orientation helps to ensure we don't get
  // stuck forever.

  var order = ((side === SIDE_LEFT)
    ? [0, 3, 6, 7, 8, 5, 2, 1, 0]
    : [0, 1, 2, 5, 8, 7, 6, 3, 0]
  );
  return try_all(
    [obstacleFn],
    order.length - 1,
    (fn, i) => (fn(order[i+1]) && !fn(order[i])) ? {cell: order[i]} : null,
    sanity_check
  );
}

function start_dotted_path(colourBand, side, protectedCols) {
  var right = (side === SIDE_RIGHT);
  return try_all_angles([
    (rot) => ((
      !protectedCols.contains(view[rot[right ? 5 : 3]].color) &&
      !colourBand.contains(view[rot[right ? 5 : 3]].color) &&
      !colourBand.contains(view[rot[right ? 2 : 0]].color) &&
      !colourBand.contains(view[rot[1]].color)
    )
      ? {cell: rot[right ? 5 : 3], color: colourBand.next(WHITE)}
      : null)
  ]);
}

function lay_dotted_path(colourBand, side, protectedCols) {
  var right = (side === SIDE_RIGHT);
  return try_all_angles([
    (rot) => {
      var ahead = rot[right ? 2 : 0];
      var behind = rot[right ? 8 : 6];
      if(
        colourBand.contains(view[behind].color) &&
        !protectedCols.contains(view[ahead].color) &&
        !colourBand.contains(view[ahead].color) &&
        !colourBand.contains(view[rot[right ? 6 : 8]].color)
      ) {
        return {cell: ahead, color: colourBand.next(view[behind].color)};
      }
    }
  ]);
}

function follow_dotted_path(colourBand, side, direction) {
  var forwards = (direction === DIR_REVERSE) ? 7 : 1;
  var right = (side === SIDE_RIGHT);

  return try_all_angles([
    // Cell on our side? advance
    (rot) => {
      if(
        colourBand.contains(view[rot[right ? 5 : 3]].color) &&
        // Prevent sticking / trickery
        !colourBand.contains(view[rot[right ? 3 : 5]].color) &&
        !colourBand.contains(view[rot[0]].color) &&
        !colourBand.contains(view[rot[2]].color)
      ) {
        return {cell: rot[forwards]};
      }
    },

    // Cell ahead and behind? advance
    (rot) => {
      var passedCol = view[rot[right ? 8 : 6]].color;
      var nextCol = view[rot[right ? 2 : 0]].color;
      if(
        colourBand.contains(passedCol) &&
        nextCol === colourBand.next(passedCol) &&

        // Prevent sticking / trickery
        !colourBand.contains(view[rot[right ? 3 : 5]].color) &&
        !colourBand.contains(view[rot[right ? 0 : 2]].color)
      ) {
        return {cell: rot[forwards]};
      }
    }
  ]);
}

function escape_dotted_path(colourBand, side, newColourBand) {
  var right = (side === SIDE_RIGHT);
  if(!newColourBand) {
    newColourBand = colourBand;
  }

  return try_all_angles([
    // Escape from beside the line
    (rot) => {
      var approachingCol = view[rot[right ? 2 : 0]].color;
      if(
        !colourBand.contains(view[rot[right ? 8 : 6]].color) ||
        !colourBand.contains(approachingCol) ||
        colourBand.contains(view[rot[7]].color) ||
        colourBand.contains(view[rot[right ? 6 : 8]].color)
      ) {
        // not oriented, or in a corner
        return null;
      }
      return best_of([
        {cell: rot[right ? 0 : 2], color: newColourBand.next(approachingCol)},
        {cell: rot[right ? 3 : 5]},
        {cell: rot[right ? 0 : 2]},
        {cell: rot[right ? 6 : 8]},
        {cell: rot[right ? 2 : 0]},
        {cell: rot[right ? 8 : 6]},
        {cell: rot[right ? 5 : 3]}
      ]);
    },

    // Escape from inside the line
    (rot) => {
      if(
        !colourBand.contains(view[rot[7]].color) ||
        !colourBand.contains(view[rot[1]].color) ||
        colourBand.contains(view[CENTRE].color)
      ) {
        return null;
      }
      return best_of([
        {cell: rot[3]},
        {cell: rot[5]},
        {cell: rot[0]},
        {cell: rot[2]},
        {cell: rot[6]},
        {cell: rot[8]}
      ]);
    }
  ]);
}

function latch_to_dotted_path(colourBand, side) {
  var right = (side === SIDE_RIGHT);

  return try_all_angles([
    (rot) => {
      var approachingCol = view[rot[right ? 2 : 0]].color;
      if(
        colourBand.contains(approachingCol) &&
        view[rot[right ? 8 : 6]].color === colourBand.next(approachingCol) &&
        !colourBand.contains(view[rot[right ? 5 : 3]].color)
      ) {
        // We're on the wrong side; go inside the line
        return {cell: rot[right ? 5 : 3]};
      }
    },

    // Inside the line? pick a side
    (rot) => {
      var passedCol = view[rot[7]].color;
      var approachingCol = view[rot[1]].color;
      if(
        !colourBand.contains(passedCol) ||
        !colourBand.contains(approachingCol) ||
        colourBand.contains(view[CENTRE].color)
      ) {
        return null;
      }
      if((approachingCol === colourBand.next(passedCol)) === right) {
        return best_of([{cell: rot[3]}, {cell: rot[6]}, {cell: rot[0]}]);
      } else {
        return best_of([{cell: rot[5]}, {cell: rot[2]}, {cell: rot[8]}]);
      }
    }
  ]);
}


// == High-level logic begins here ==


var QUEEN_COL = colour_band(generate_band(3, 3));
var WORKER_COL = colour_band(generate_band(6, 3));
var AVOID_COL = colour_band([2]);
var INVERT_COL = colour_band([WHITE, 2]);

var MIN_FOOD = 5;
var MAX_WORKER_FOOD = 10;

function decide() {
  var me = view[CENTRE].ant;
  var queen = me.type === QUEEN;

  if(queen && me.food > MIN_FOOD && me.food < MAX_WORKER_FOOD) {
    var m = try_all_cells((i) => {
      if(view[i].food && !foe_near(i)) {
        // Try to spawn a worker next to the food;
        // the worker will pick up the food on the next turn
        return try_all_cells_near(i, (j) => ({cell: j, type: 1}));
      }
    }, true);
    if(sanity_check(m)) {
      return m;
    }
  }

  if(!queen && me.food) {
    return best_of([
      // Look for queen
      follow_dotted_path.bind(null, QUEEN_COL, SIDE_RIGHT, DIR_FORWARDS),
      latch_to_dotted_path.bind(null, QUEEN_COL, SIDE_RIGHT),

      // Failed to find queen's trail; try following worker trails backwards
      follow_dotted_path.bind(null, WORKER_COL, SIDE_RIGHT, DIR_REVERSE),
      latch_to_dotted_path.bind(null, WORKER_COL, SIDE_RIGHT),

      // Failed to find any trail; cover ground as quickly as possible
      fast_diagonal.bind(null, AVOID_COL)
    ]);
  }

  var myCol = queen ? QUEEN_COL : WORKER_COL;
  return best_of([
    grab_nearby_food,

    // Disperse workers away from queen
    !queen && escape_dotted_path.bind(null, QUEEN_COL, SIDE_RIGHT, WORKER_COL),

    // Follow our own path
    follow_dotted_path.bind(null, myCol, SIDE_RIGHT, DIR_FORWARDS),

    // If our path looks suspicious, it could have wrapped; try to escape it
    escape_dotted_path.bind(null, myCol, SIDE_RIGHT),

    // Explore
    // Laying a path causes us to move at 2/3 c, so workers can catch up.
    lay_dotted_path.bind(null, myCol, SIDE_RIGHT, QUEEN_COL),
    start_dotted_path.bind(null, myCol, SIDE_RIGHT, QUEEN_COL),

    // Fall-back to white dots if we're inside a colour block
    lay_dotted_path.bind(null, myCol, SIDE_RIGHT, INVERT_COL),
    start_dotted_path.bind(null, myCol, SIDE_RIGHT, INVERT_COL),

    // Stuck for some reason; try to escape
    fast_diagonal.bind(null, AVOID_COL)
  ]);
}

return play_safe([
  decide,

  // No valid moves; try to find *anywhere* we can go.
  go_anywhere,

  // Try changing a nearby cell's colour for the heck of it.
  {cell: 1, color: view[1].color % 8 + 1}
]);

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

यदि आप सोच रहे हैं कि चींटियाँ किसी भी समय केवल 3x3 ग्रिड को देखने और अपनी स्वयं की दिशा जानने में सक्षम नहीं होने के बावजूद एक बिंदीदार रेखा का पालन करने में सक्षम हैं: वे अपनी वास्तविक यात्रा की रेखा पर नहीं, बल्कि अपने दाईं ओर रेखा खींचते हैं। इसलिए यदि (उदाहरण के लिए) चींटी उत्तर के लिए एक भरे हुए वर्ग को देखती है, तो उसे पता है कि मार्ग उसके ऊपर होना चाहिए, जिसका अर्थ है कि यात्रा की दिशा पश्चिम (दाईं ओर का रास्ता रखना) होनी चाहिए। यदि चींटी पूर्वोत्तर के लिए एक भरा हुआ वर्ग देखती है, लेकिन उत्तर-पश्चिम या दक्षिण-पूर्व में नहीं है, तो वह लाइन के अंत में चली गई होगी, इसलिए सेल को उत्तर-पश्चिम तक ले जाती है और पश्चिम की ओर जाती है। एक बार भोजन मिल जाने के बाद स्विचिंग दिशा के आसपास अधिक जटिलता होती है, लेकिन यह इसका सार है।

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

यह आश्चर्यजनक रूप से प्रदर्शन नहीं करता है, और चींटियों को अपने स्वयं के पैरों को फिर से ट्रेस करने की आदत होती है (वे पर्याप्त नहीं जानते हैं कि क्या वे जिस रास्ते का अनुसरण कर रहे हैं वह एक पुराना है, या एक जो वे प्रक्रिया में हैं ड्राइंग!), जो कभी-कभी अनंत छोरों की ओर जाता है।

अंत में, किसी भी आउटपुट पर लागू होने वाली एक पवित्रता जाँच विधि है जो यह सुनिश्चित करती है कि यह अयोग्य नहीं हो सकती है (उम्मीद है!)


अपडेट किया गया संस्करण तेजी से विकर्ण यात्रा के लिए यादृच्छिक चलना बंद कर देता है, बग का एक गुच्छा ठीक करता है, और सफेद सड़कों का उपयोग करके चलने में कुछ प्रयास जोड़ता है यदि कोई चींटी एक बड़े रंगीन क्षेत्र के अंदर फंस जाती है। उच्च-स्तरीय-सोच / निम्न-स्तरीय-क्षमताओं को अलग करने के लिए इसे परिवर्तित करते समय अधिकांश बग पाए गए थे।


(यहाँ एक मैंने इसे तैयार किया था जबकि यह बीटा में था )
डेव

मोटे तौर पर ऑर्डर के लिए: मैंने बस इसे चलाया और 30 भोजन + 6 कार्यकर्ता चींटियों को मिला। इसे विकसित करने के दौरान मैंने जो संख्या देखी उसके अनुरूप है।
डेव

यह एक 50% गति को बढ़ावा देने के लिए सड़क में अंतराल छोड़ने वाली एक साफ सुथरी चाल है। इसका मतलब यह है कि सड़कों को पहली बार में देखना मुश्किल है - मुझे आपका चींटी खोजने में थोड़ा समय लगा ... लेकिन यह आसानी से उदाहरण के खिलाड़ियों को बेहतर बना देता है, खासकर जब श्रमिक वापस लौटने लगते हैं। श्रमिकों में से कुछ पीले और सफेद रंग की बिसात के पैटर्न का निर्माण करते हैं - निश्चित नहीं है कि क्या यह योजना का हिस्सा है?
ट्राइकोप्लाक्स

1
@trichoplax oops; मैं स्पष्टीकरण में डाल देना भूल गया (भूल गया कि उन्होंने ऐसा किया है!)। मैंने स्पष्टीकरण को अपडेट कर दिया है। संक्षेप में: यह योजना का हिस्सा है, लेकिन यह एक शानदार योजना नहीं है।
डेव

महान व्याख्या!
ट्राइकोप्लाक्स

7

मोनोरेल

अभी भी एक कार्य प्रगति पर है, लेकिन मैं अभी कुछ बाहर धकेलना चाहता हूं क्योंकि मैं पागल हूं कि प्रतियोगिता समाप्त होने से पहले मैं समाप्त हो जाऊंगा।

var c0=5 //red
var c1=4 //cyan
var c2=6 //green
var c3=3 //magenta
var c4=7 //blue
var c5=8 //black
var c6=2 //yellow
var cN=1 //white

var ws=4 //support
var wb=3 //bodyguard
var wg=1 //gather
var wq=5 //queen

var v=[[0, 1, 2, 3, 4, 5, 6, 7, 8],
       [8, 7, 6, 5, 4, 3, 2, 1, 0],
       [6, 3, 0, 7, 4, 1, 8, 5, 2],
       [2, 5, 8, 1, 4, 7, 0, 3, 6]]

var x1=[0,2,6,8]
var x2=[8,6,2,0]

var r1=[1,7,3,5]
var r2=[5,3,7,1]

switch(view[4].ant.type)
{
 case 5: return queen()
 case 4: return support()
 case 3: return bodyguard()
 case 1: return gather()
 default: return {cell:4}
}

function queen()
{
 if(fAlly(ws)<0)
 {
  if(view[4].color==c1&&view[4].ant.food>0)
  {
   var o=findOrient(c1,c2,c3)
   if(sOpen(v[o][7])) return {cell:v[o][7],type:ws}
   return doThing()
  }
  else if(view[4].color==c0&&view[4].ant.food>=6)
  {
   var o=findOrient(c1,c2,c3)
   if(view[v[o][1]].color!=c1) return {cell:v[o][1],color:c1}
   if(view[v[o][0]].color!=c2) return {cell:v[o][0],color:c2}
   if(view[v[o][2]].color!=c3) return {cell:v[o][2],color:c3}
   if(sOpen(v[o][7])) return {cell:v[o][7],type:ws}
  }
  return wander(c0)
 }
 else
 {
  if(view[4].color==c0&&view[4].ant.food<7)
  {
   if(view[4].ant.food >=5)
   {
    var o=findOrient(c1,c2,c3)
    if(sOpen(v[o][1])) return {cell:v[o][1],type:wb}
    if(sOpen(v[o][0])) return {cell:v[o][0],type:wb}
    if(sOpen(v[o][2])) return {cell:v[o][2],type:wb}
   }
   if(view[4].ant.food>0)
   {
    var op=fOpen()
    if(op>=0) return {cell:op,type:wg}
   }
  }
  return doThing()
 }
}

function doThing()
{
 if(view[4].color!=c1) return {cell:4,color:c1}
 var o=findOrient(c1,c2,c3)
 if(view[4].ant.food>0&&fAlly(wg)>=0&&o==0)
 {
  var op=fOpen()
  if(op>=0) return {cell:op,type:wg}
 }
 if(view[v[o][1]].color!=c1&&pootis(v[o][1])) return {cell:v[o][1],color:c1}
 if(view[v[o][0]].color!=c2&&pootis(v[o][0])) return {cell:v[o][0],color:c2}
 if(view[v[o][2]].color!=c3&&pootis(v[o][2])) return {cell:v[o][2],color:c3}
 if(mOpen(v[o][1])) return {cell:v[o][1]}
 if(view[v[o][3]].color!=c2&&pootis(v[o][3])) return {cell:v[o][3],color:c2}
 if(view[v[o][5]].color!=c3&&pootis(v[o][5])) return {cell:v[o][5],color:c3}
 if(view[v[o][6]].color!=c2&&pootis(v[o][6])) return {cell:v[o][6],color:c2}
 if(view[v[o][8]].color!=c3&&pootis(v[o][8])) return {cell:v[o][8],color:c3}
 if(view[v[o][7]].color!=c1&&pootis(v[o][7])) return {cell:v[o][7],color:c1}
 return {cell:4}
}

function support()
{
 var o = findOrient(c1,c2,c3)
 var p = fAlly(wq)

 switch(p)
 {
  case v[o][0]:
   //if(mOpen(v[o][3])) return {cell:v[o][3]}
   //if(mOpen(v[o][1])) return {cell:v[o][1]}
   break
  case v[o][1]:
   //if(view[v[o][0]].food&&mOpen([v[o][0]])) return {cell:v[o][0]}
   //if(view[v[o][2]].food&&mOpen([v[o][2]])) return {cell:v[o][2]}
   break
  case v[o][2]:
   //if(mOpen(v[o][5])) return {cell:v[o][5]}
   //if(mOpen(v[o][1])) return {cell:v[o][1]}
   break
  case v[o][3]:
   //if(mOpen(v[o][6])) return {cell:v[o][6]}
   break
  case v[o][5]:
   //if(mOpen(v[o][8])) return {cell:v[o][8]}
   break
  case v[o][6]: break
  case v[o][7]: break
  case v[o][8]: break
  default:
   if(sOpen(v[o][1])) return {cell:v[o][1]}
   break
 }
 return {cell:4}
}

function bodyguard()
{
 var o=0
 switch(view[4].color)
 {
  case c1: o=findOrient(c1,c2,c3);break
  case c2: o=findOrient(c2,c6,c1);break
  case c3: o=findOrient(c3,c1,c6);break
  default: return {cell:4}
 }
 var p = fAlly(wq)
 if(view[4].ant.food>0)
 {
  switch(p)
  {
   case v[o][0]:
    if(sOpen(v[o][1])) return {cell:v[o][1]}
    if(sOpen(v[o][3])) return {cell:v[o][3]}
    break
   case v[o][1]:
    if(sOpen([v[o][0]])) return {cell:v[o][0]}
    if(sOpen([v[o][2]])) return {cell:v[o][2]}
    break
   case v[o][2]:
    if(sOpen(v[o][1])) return {cell:v[o][1]}
    if(sOpen(v[o][5])) return {cell:v[o][5]}
    break
   case v[o][3]:
    if(sOpen([v[o][0]])) return {cell:v[o][0]}
    if(sOpen([v[o][1]])) return {cell:v[o][1]}
    break
   case v[o][5]:
    if(sOpen([v[o][2]])) return {cell:v[o][2]}
    if(sOpen([v[o][1]])) return {cell:v[o][1]}
    break
   case v[o][6]:
    if(sOpen([v[o][0]])) return {cell:v[o][0]}
    if(sOpen([v[o][1]])) return {cell:v[o][1]}
    if(sOpen([v[o][3]])) return {cell:v[o][3]}
    break
   case v[o][7]:
    if(sOpen([v[o][1]])) return {cell:v[o][1]}
    if(sOpen([v[o][0]])) return {cell:v[o][0]}
    if(sOpen([v[o][2]])) return {cell:v[o][2]}
    break
   case v[o][8]:
    if(sOpen([v[o][2]])) return {cell:v[o][2]}
    if(sOpen([v[o][1]])) return {cell:v[o][1]}
    if(sOpen([v[o][5]])) return {cell:v[o][5]}
    break
   default:
  }
 }
 else
 {
  switch(p)
  {
   case v[o][0]:
    if(mOpen(v[o][1])) return {cell:v[o][1]}
    if(mOpen(v[o][3])) return {cell:v[o][3]}
    break
   case v[o][1]:
    if(view[v[o][2]].food&&mOpen([v[o][2]])) return {cell:v[o][2]}
    if(mOpen([v[o][0]])) return {cell:v[o][0]}
    if(mOpen([v[o][2]])) return {cell:v[o][2]}
    break
   case v[o][2]:
    if(mOpen(v[o][1])) return {cell:v[o][1]}
    if(mOpen(v[o][5])) return {cell:v[o][5]}
    break
   case v[o][3]:
    if(view[v[o][1]].food&&mOpen([v[o][1]])) return {cell:v[o][1]}
    if(mOpen([v[o][0]])) return {cell:v[o][0]}
    if(mOpen([v[o][1]])) return {cell:v[o][1]}
    break
   case v[o][5]:
    if(view[v[o][1]].food&&mOpen([v[o][1]])) return {cell:v[o][1]}
    if(mOpen([v[o][2]])) return {cell:v[o][2]}
    if(mOpen([v[o][1]])) return {cell:v[o][1]}
    break
   case v[o][6]:
    if(view[v[o][1]].food&&mOpen([v[o][1]])) return {cell:v[o][1]}
    if(mOpen([v[o][0]])) return {cell:v[o][0]}
    if(mOpen([v[o][1]])) return {cell:v[o][1]}
    if(mOpen([v[o][3]])) return {cell:v[o][3]}
    break
   case v[o][7]:
    if(view[v[o][0]].food&&mOpen([v[o][0]])) return {cell:v[o][0]}
    if(view[v[o][2]].food&&mOpen([v[o][2]])) return {cell:v[o][2]}
    if(mOpen([v[o][1]])) return {cell:v[o][1]}
    if(mOpen([v[o][0]])) return {cell:v[o][0]}
    if(mOpen([v[o][2]])) return {cell:v[o][2]}
    break
   case v[o][8]:
    if(view[v[o][1]].food&&mOpen([v[o][1]])) return {cell:v[o][1]}
    if(mOpen([v[o][2]])) return {cell:v[o][2]}
    if(mOpen([v[o][1]])) return {cell:v[o][1]}
    if(mOpen([v[o][5]])) return {cell:v[o][5]}
    break
   default:
  }
 }
 if(view[4].color==c1)
 {
  if(view[v[o][1]].color!=c1&&pootis(v[o][1])) return {cell:v[o][1],color:c1}
  if(view[v[o][0]].color!=c2&&pootis(v[o][0])) return {cell:v[o][0],color:c2}
  if(view[v[o][2]].color!=c3&&pootis(v[o][2])) return {cell:v[o][2],color:c3}
  if(view[v[o][3]].color!=c2) return {cell:v[o][3],color:c2}
  if(view[v[o][5]].color!=c3) return {cell:v[o][5],color:c3}
  if(view[v[o][6]].color!=c2) return {cell:v[o][6],color:c2}
  if(view[v[o][8]].color!=c3) return {cell:v[o][8],color:c3}
  if(view[v[o][7]].color!=c1) return {cell:v[o][7],color:c1}
 }
 return {cell:4}
}

function gather()
{
 if(view[4].ant.food>0)
 {
  if(view[4].color==c1&&(testSQ(c1,c2)||testSQ(c1,c3))) return gDoThing(c1,c3,c2)
  if(view[4].color==c2&&testSQ(c2,c1)) return gDoThing(c2,c1,c6)
  if(view[4].color==c3&&testSQ(c3,c1)) return gDoThing(c3,c6,c1)
  return wander(c5)
 }
 var n=fAlly(wq)
 if(n<0) return wander(c4)
 switch(n)
 {
  case 0:
   if(mOpen(8)) return {cell:8}
   if(mOpen(7)) return {cell:7}
   if(mOpen(5)) return {cell:5}
   break
  case 1:
   if(mOpen(6)) return {cell:6}
   if(mOpen(8)) return {cell:8}
   if(mOpen(7)) return {cell:7}
   break
  case 2:
   if(mOpen(6)) return {cell:6}
   if(mOpen(3)) return {cell:3}
   if(mOpen(7)) return {cell:7}
   break
  case 3:
   if(mOpen(8)) return {cell:8}
   if(mOpen(2)) return {cell:2}
   if(mOpen(5)) return {cell:5}
   break
  case 5:
   if(mOpen(0)) return {cell:0}
   if(mOpen(6)) return {cell:6}
   if(mOpen(3)) return {cell:3}
   break
  case 6:
   if(mOpen(2)) return {cell:2}
   if(mOpen(5)) return {cell:5}
   if(mOpen(1)) return {cell:1}
   break
  case 7:
   if(mOpen(2)) return {cell:2}
   if(mOpen(0)) return {cell:0}
   if(mOpen(1)) return {cell:1}
   break
  case 8:
   if(mOpen(0)) return {cell:0}
   if(mOpen(1)) return {cell:1}
   if(mOpen(3)) return {cell:3}
   break
  default:
   break
 }
 return {cell:4}
}

function testSQ(ac1,ac2)
{
 for(var i=0;i<4;i++)
 {
  if(view[r1[i]].color==ac1)
  {
   if(view[v[i][0]].color==ac2&&view[v[i][3]].color==ac2) return 1
   if(view[v[i][2]].color==ac2&&view[v[i][5]].color==ac2) return 1
  }
 }
 return 0
}

function gDoThing(ac1,ac2,ac3)
{
 var o=findOrient(ac1,ac2,ac3)
 if(view[v[o][1]].color!=ac1&&pootis(v[o][1])) return {cell:v[o][1],color:ac1}
 if(view[v[o][0]].color!=ac2&&pootis(v[o][0])) return {cell:v[o][0],color:ac2}
 if(view[v[o][2]].color!=ac3&&pootis(v[o][2])) return {cell:v[o][2],color:ac3}
 if(sOpen(v[o][1])) return {cell:v[o][1]}
 if(ac1==c2)
 {
  if(sOpen(v[o][0])) return {cell:v[o][0]}
  if(sOpen(v[o][3])) return {cell:v[o][3]}
  if(sOpen(v[o][6])) return {cell:v[o][6]}
 }
 else if(ac1==c3)
 {
  if(sOpen(v[o][2])) return {cell:v[o][2]}
  if(sOpen(v[o][5])) return {cell:v[o][5]}
  if(sOpen(v[o][8])) return {cell:v[o][8]}
 }
 else
 {
  if(sOpen(v[o][0])) return {cell:v[o][0]}
  if(sOpen(v[o][2])) return {cell:v[o][2]}
  if(sOpen(v[o][3])) return {cell:v[o][3]}
  if(sOpen(v[o][5])) return {cell:v[o][5]}
 }
 return {cell:4}
}

function pootis(p)
{
 var a=view[p].ant
 if(a!=null&&a.friend&&a.type==wg&&(view[p].color==c4||view[p].color==c5)) return 0
 return 1
}

function fAlly(t)
{
 var a=view[4].ant
 for(var i=0;i<9;i++)
 {
  if(i==4) i++
  a=view[i].ant
  if(a!=null&&a.friend&&a.type==t) return i
 }
 return -1
}

function fOpen()
{
 for(var i=0;i<9;i++)
 {
  if(i==4) i++
  if(sOpen(i)) return i
 }
 return -1
}

function sOpen(p)
{
 return (view[p].ant==null&&!view[p].food)
}

function mOpen(p)
{
 return (view[p].ant==null)
}

function wander(ac)
{
 if(view[4].ant.type==5||view[4].ant.food==0)
 {
  var vf = vFood()
  if(vf>=0) return {cell:vf}
  if(view[4].color!=ac) return {cell:4,color:ac}
  for(var i=0;i<4;i++)
  {
   if(view[x1[i]].color==ac&&view[x2[i]].color!=ac&&view[x2[i]].color!=c1&&mOpen(x2[i])) return {cell:x2[i]}
  }
  for(var i=0;i<4;i++)
  {
   if(mOpen(x1[i])&&view[x1[i]].color!=c1) return {cell:x1[i]}
  }
 }
 else
 {
  if(view[4].color!=ac) return {cell:4,color:ac}
  for(var i=0;i<4;i++)
  {
   if(view[x1[i]].color==ac&&view[x2[i]].color!=ac&&sOpen(x2[i])) return {cell:x2[i]}
  }
  for(var i=0;i<4;i++)
  {
   if(sOpen(x1[i])) return {cell:x1[i]}
  }
 }
 return {cell:4}
}

function findOrient(ac1,ac2,ac3)
{
 var w=[0,0,0,0]
 w[0]=DI(view[0].color,view[1].color,view[2].color,0,ac1,ac2,ac3)
 w[1]=DI(view[8].color,view[7].color,view[6].color,1,ac1,ac2,ac3)
 w[2]=DI(view[6].color,view[3].color,view[0].color,2,ac1,ac2,ac3)
 w[3]=DI(view[2].color,view[5].color,view[8].color,3,ac1,ac2,ac3)
 var t=[0,0,0,0]
 for(var i=0;i<4;i++)
 {
  switch(w[i])
  {
   case 4: t[0]++;break
   case 5: t[1]++;break
   case 6: t[2]++;break
   case 7: t[3]++;break
   case 8: t[0]+=2;break
   case 9: t[1]+=2;break
   case 10: t[2]+=2;break
   case 11: t[3]+=2;break
   case 12: t[0]+=3;break
   case 13: t[1]+=3;break
   case 14: t[2]+=3;break
   case 15: t[3]+=3;break
   default: break
  }
 }
 var m=Math.max(...t)
 for(var i=0;i<4;i++)
 {
  if(t[i]==m) return i
 }
 return 0
}

function DI(v1,v2,v3,d,ac1,ac2,ac3)
{
 var t=[0,0,0,0]
 switch(v1)
 {
  case ac2: t[0]++;t[3]++;break
  case ac3: t[1]++;t[2]++;break
  default: break
 }
 switch(v2)
 {
  case ac1: t[0]++;t[1]++;break
  case ac2: t[3]++;break
  case ac3: t[2]++;break
  default: break
 }
 switch(v3)
 {
  case ac2: t[1]++;t[3]++;break
  case ac3: t[0]++;t[2]++;break
  default: break
 }
 var m=Math.max(...t)
 if(m==0) return 0
 var n=0
 for(var i=0;i<4;i++)
 {
  if(t[i]==m){n=i;break}
 }
 if((d==2&&n==2)||(d==3&&n==3)) n=1
 else if((d==2&&n==3)||(d==3&&n==2)) n=0
 else n^=d
 return m*4+n
}

function vFood()
{
 for(var i=0;i<9;i++)
 {
  if(view[i].food) return i
 }
 return -1
}

function nColor(c)
{
 var t=0
 for(var i=0;i<9;i++)
 {
  if(view[i].color==c) t++
 }
 return t
}

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

सब ठीक है, यहाँ संस्करण 2। अब इकट्ठा करने वाले वास्तव में कुछ करते हैं।

संस्करण 2.1 अब। किसी भी समय एक ही खेल में एक साथ दिखाई देने पर पूरे तिल खाने से ब्लैक होल को रोकने के लिए पीले / सियान के निशान को चारों ओर घुमाया गया है।

संस्करण 3. बॉडीगार्ड को सामने से अतिरिक्त सुरक्षा प्रदान करने के लिए (और रेल पर भोजन हड़पने के लिए) जोड़ा गया है, जबकि अब ट्रैकर इरेज़र को दूर करने के लिए काले किनारों को आकर्षित करते हैं और संभवतः ब्लैक होल से बचाने में मदद करते हैं। इसके अलावा रानी समय से पहले तैनाती को रोकने के लिए एकत्रित मोड में सियान टाइल से बचती है।

संस्करण 3.1 के लिए सब ठीक है, समय। Wildfire के प्रकोप को उकसाए बिना खाड़ी में ट्रेल इरेज़र रखने के लिए रंगों को फिर से बदल दिया गया है । रेल को बेहतर रखने और उसकी पहचान करने के लिए इकट्ठा किया गया है (कम रेलिंग बाहर / नई रेल बनाना)। वहाँ के रूप में अच्छी तरह से उल्लेख करने के साथ परेशान नहीं कर सकता है कि वहाँ कुछ अन्य छोटी चीजें हैं।

संस्करण 3.2: बॉडीगार्ड के साथ कुछ मुद्दों को तय किया। यह अब भोजन को हथियाने का प्रयास नहीं करता है अगर इसमें पहले से ही कुछ है, अटक जाने का खतरा कम है, और यह रानी को नहीं मिल सकता है, तो रेल को आकर्षित करेगा।


जब तक लीडरबोर्ड कैसा दिखता है, यह देखने के लिए नई प्रविष्टियाँ / संपादन मैं नए टूर्नामेंट चला रहा हूँ। कोई समापन तिथि नहीं है। वर्तमान टूर्नामेंट को अद्वितीय 1, 2 और 3 वें स्थान पर परिवर्तित होने से पहले शायद कुछ दिन शेष हैं, फिर मैं इस नए खिलाड़ी सहित एक नया टूर्नामेंट शुरू करूंगा। मुझे डर है कि एक सप्ताह से अधिक समय लग जाएगा, इससे पता चलता है कि आप किस स्थिति में पहुँचते हैं, लेकिन मैं आपको बता देता हूँ कि यह कब होता है।
ट्राइकोप्लाक्स

@QuoteBeta मैं आपके व्यामोह को समझता हूं ... मैंने अभी इस चुनौती को देखा है इसलिए मैं चुनौती बंद होने से पहले एक प्रविष्टि बनाने की प्रक्रिया में हूं।
मोगी

सब ठीक तो। मुझे यकीन नहीं था कि यह जल्द ही समाप्त होने वाला था या नहीं, अपडेट के साथ थोड़ा धीमा हो रहा था।
QuoteBeta

ज्यादातर लोग शायद कर रहे हैं, लेकिन हम लीडरबोर्ड पर इंतजार कर रहे हैं। और उन लोगों को थोड़ी देर हो रही है।
ड्रेको 18s

लगता है कि आपके चींटियों को मेरे कुछ निशान-समाशोधन कोड (ब्लैक होल देखें, कि चींटियों ने पुराने ट्रेल्स को कैसे साफ किया है) में खो सकते हैं। i.stack.imgur.com/DTmA6.png
ड्रेको 18s

6

क्लेस्ट्रोफोबिक क्वीन

एक रानी-केवल दृष्टिकोण जो रंगीन क्षेत्रों से बचने का प्रयास करते हुए एक यादृच्छिक चलना करता है। शीर्ष दावेदार नहीं है, लेकिन मध्यम रूप से सफल और छेड़छाड़ करने वाला है। पैरामीटर प्रगति में है।

var i, j
var orthogonals = [1, 3, 7, 5]  // These are the non-diagonal cells
var move;
var scores = [];   // An array of how desirable each potential move is
var score, neighbor, claustrophobia, newColor;
var crowdedNeighbors = null;   // How many diagonal neighbors are colored CROWDED?
var runningFrom = null;    // When in running phase, which direction did we come from?
var runningTo = null;      // When in running phase, which direction should we head?

// Assign color magic numbers to variables
var EMPTY = 1;
var VISITED = 4;
var CROWDED = 7;
var RUNNING = 8;

function neighbors(cell) {
    switch (cell) {
        case 0: return [1, 3];
        case 1: return [0, 2];
        case 2: return [1, 5];
        case 3: return [0, 6];
        case 4: return orthogonals;
        case 5: return [2, 8];
        case 6: return [3, 7];
        case 7: return [6, 8];
        case 8: return [7, 5];
        default: return null;
    }
}

function isHungry(ant) {
    if (ant.type === 5 || ant.food === 0) {
        return true;
    } else {
        return false;
    }
}

// Color own cell based on the number of neighbors that are colored
claustrophobia = 0;
for (i=0; i<9; i++) {
    if (view[i].color !== EMPTY || i === 4) {
        claustrophobia++;
    }
    if (i % 2 === 0 && i !== 4) {
        if (view[i].color === CROWDED) {
            crowdedNeighbors++;
        } else if (view[i].color === RUNNING) {
            crowdedNeighbors++;
            runningFrom = i;
        }
    }
}

if (claustrophobia > 4) {
    if (crowdedNeighbors > 1 || runningFrom !== null) {
        // We're entering or currently in a straight-line running state
        // in which we keep going until we find sufficient whitespace
        newColor = RUNNING;
    } else {
        newColor = CROWDED;
    }
} else {
    newColor = VISITED;
}
if (view[4].color !== newColor) {
    return {cell:4, color:newColor}
}

// If we've already colored the current cell properly, and we're in running mode,
// then move diametrically away from the runningFrom cell
switch (runningFrom) {
    case 0:
        runningTo = 8;
        break;
    case 2:
        runningTo = 6;
        break;
    case 6:
        runningTo = 2;
        break;
    case 8:
        runningTo = 0;
        break;
    default:
        break;
}

// Calculate a score for each potential move
// Lower numbers are better; null means illegal move
// Unexplored areas are better; food is the best (as long as ant can eat); don't move onto other ants
for (i=0; i<9; i++) {
    // Base score of tile is 2 times color of tile
    score = 2 * (view[i].color);
    // Add colors of neighboring tiles
    for (neighbor of neighbors(i)) {
        score += view[neighbor].color;
    }
    // Give very good score to runningTo tile, unless it's also RUNNING color
    if (i === runningTo && view[i].color !== RUNNING) {
        score -= 4;   // Magic number, possibly to be tweaked
    }
    if (i!==4 && view[i].ant) {
        // Tile contains another ant; give very bad score
        score = null;
    } else if (view[i].food) {
        // If a tile contains food, it's either highly desirable if the ant can eat, or illegal if it can't
        if (isHungry(view[4].ant)) {
            // Ant can eat; give food tile very good score
            score = -1;
        } else {
            // Ant cannot eat; give food tile very bad score
            score = null;
        }
    }
    scores.push(score);
}

// Select best move based on the scores array
move = 4;   // By default, stay put (this probably won't be the best move)
for (i=0; i<9; i++) {
    if (scores[i] !== null && scores[i] < scores[move]) {
        move = i;
    }
}

return {cell:move};

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

यहाँ छवि विवरण दर्ज करें


छेड़छाड़-सबूत नहीं; निशान-इरेज़र अपने निशान को मिटा सकता है, जो चींटी को चारों ओर से घेरे में ले जाएगा
pppery

1
एर, वर्गों में?
पप्परी जूल

1
@ppperry मैंने कहा " मध्यम रूप से ... छेड़छाड़-सबूत।" ;) केवल एक चीज जो ट्रेल-इरेज़र कर सकती है, वह जमीन को कवर करने की अधिक संभावना है जो पहले से ही कवर की गई है; लेकिन यह बस के रूप में आसानी से बेरोज़गार क्षेत्र में आगे बढ़ सकता है।
२२:२२ पर DLosc

6

Hoppemaur

सबसे पहले मैं इस भयानक चुनौती को बनाने के लिए त्रिचोप्लेक्स को धन्यवाद देना चाहता हूं, जिसने मुझे इस साइट पर साइन अप किया और जावास्क्रिप्ट में प्रोग्रामिंग शुरू की। मैं आपको धन्यवाद देना चाहता हूं कि अन्य लोग अभी भी इस प्रश्न के बारे में बात कर रहे हैं, यहां तक ​​कि इसके पूछे जाने के 3 महीने बाद भी।

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

चित्रित पैटर्न के साथ होपेमोर बॉट विस्तार

कोड

//Hoppemaur
//å hoppe: to jump
//maur: ant

var WHITE = 1;
var OWN = 2;
var FOOD = 6;
var ESCAPE = 3;
var paint = 0;
var score = {0:2,1:-3,2:2,3:-3,4:-1,5:-3,6:2,7:-3,8:2}; 
// The ant should only walk diagonal (except when feeding)
var highest = 0;
var scoreindex;
var diagonals = [0, 2, 6, 8];
var diagonalsandself = [0, 2, 4, 6, 8]
var inversdiagonals = [8, 6, 2, 0];
var orthogonals = [1, 3, 5, 7];
var inverseorthogonals = [7, 5, 3, 1];
var rotate1orthogonals = [3, 1, 7, 5];
var rotate2orthogonals = [5, 7, 1, 3];

//checks if one of the diagonals or the own tile are painted
function checkforemptypattern() {
  for (var i=0; i<diagonalsandself.length; i++) {
    if (view[diagonalsandself[i]].color == OWN){
     return false;}
  }
  return true;
}

//counts the diagonals painted in the requestest colour
function checktrapped(pattern) {
  var diags=0;
  for (var i=0; i<diagonals.length; i++) {
    if (view[diagonals[i]].color == pattern){
     diags=diags+1;
    }
  }
return diags;
}

//Biggest threat to this ant is food on orthogonals,
//it messes up the pattern if not dealt with it
if (view[4].color !== FOOD){
    for (var i=0; i<orthogonals.length; i++) {
        if (view[orthogonals[i]].food) {
            return {cell:4, color:FOOD};
            }
        }
    }

if (view[4].color == FOOD){
    for (var i=0; i<orthogonals.length; i++) {
        if (view[orthogonals[i]].food) {
        if (!view[orthogonals[i]].ant){
            return {cell:orthogonals[i]};
            }
        }
        }
    }

//If food shows up on diagonals while out of pattern,
//before grabbing food, the pattern must be painted
for (var i=0; i<diagonals.length; i++){
    if (view[diagonals[i]].food){
        if (checkforemptypattern()){
            return {cell:4, color: OWN}
            }
        }
    }


//Otherwise, food can easily be grabbed if not ant in way
for (var i=0; i<9; i++) {
    if (view[i].food) {
        if(!view[i].ant){
        return {cell:i}
        }
    }
}


//After food has been grabbed orthogonal, back to food pile
if (view[4].color == WHITE){
    for (i=0; i<orthogonals.length; i++) {
        if (view[orthogonals[i]].color == FOOD && checktrapped(FOOD) == 0 && view[inverseorthogonals[i]].color !== FOOD && view[rotate1orthogonals[i]].color !== FOOD && view[rotate2orthogonals[i]].color !== FOOD){
                 if (!view[orthogonals[i]].ant){
                     return {cell:orthogonals[i]};
                     }
                 }
        }
    }

//First part of scoring
// Scoring to determine next move
// Scoring everything higher than own pattern and escape
for (var i=0; i<9; i++) {
  if (view[i].color !== OWN) {
      score[i] = score[i]+3;
  }
  if (view[i].color !== ESCAPE){
      score[i] = score[i]+5;
  }
}

// Scoring while in painted area (f.e. wildfire)

var l = 0;
for (var i=2; i<9; i++) {
                          var k = 0;
    for (var j=0; j<9; j++) {
                             if (view[j].color == i) {
            k=k+1;
            if (k > 6){
            paint=i;
            }
        if (view[j].color !==WHITE) {
          l=l+1;

        }
    }
}
}

if (paint !== OWN && l >7) {
    for (var i=0; i<diagonals.length; i++){
        if (view[diagonals[i]].color == OWN) {
            score[inversdiagonals[i]]=score[inversdiagonals[i]]+7;
            }
        if (view[diagonals[i]].color == WHITE) {
          score[diagonals[i]]=score[diagonals[i]]+7
        }
        }
    }


if (paint == OWN && l >7) {
    for (var i=0; i<diagonals.length; i++){
        if (view[diagonals[i]].color == ESCAPE) {
            score[inversdiagonals[i]]=score[inversdiagonals[i]]+7;
            }
        if (view[diagonals[i]].color == WHITE) {
          score[diagonals[i]]=score[diagonals[i]]+7
        }
        }
    }

// the following might lead to some traps?
// score diagonals adjactant to white higher
  if (view[1].color === WHITE) {
    score[0] = score[0]+1;
    score[2] = score[2]+1;
   }
  if (view[3].color === WHITE) {
    score[0] = score[0]+1;
    score[6] = score[6]+1;
   }
  if (view[5].color === WHITE) {
    score[2] = score[2]+1;
    score[8] = score[8]+1;
   }
  if (view[7].color === WHITE) {
    score[6] = score[6]+1;
    score[8] = score[8]+1;
   }


//Don't move next to others, they steal your food!
  if (view[0].ant || view[1].ant || view[2].ant){
      score[6] = score [6]+10;
      score[8] = score [8]+10;
  }

  if (view[0].ant || view[3].ant || view[6].ant){
      score[2] = score [2]+10;
      score[8] = score [8]+10;
  }

  if (view[6].ant || view[7].ant || view[8].ant){
      score[0] = score [0]+10;
      score[2] = score [2]+10;

  }
   if (view[2].ant || view[5].ant || view[8].ant){
      score[0] = score [0]+10;
      score[6] = score [6]+10;

  }
//don't step on others!
for (var i=0; i<9; i++) {
  if (i!==4 && view[i].ant) {
        score[i] = -5;
 }
}

//end of scoring, calculate best
for (var i=0; i<9; i++) {
  if (score[i] > highest) {
    highest = score[i];
    scoreindex = i;
    }
  }

//Basic enemy avoidance
for (var i=0; i<9; i++) {
  if (i!==4 && view[i].ant) {
        return {cell:scoreindex}
        }
  }

//basic movement

//when surrounded by other paint
if (paint == ESCAPE && l>7){
    if(view[4].color == OWN){
      return{cell:scoreindex}
    }
}

if (paint !== OWN && paint !== 0 && l>7){
  if(view[4].color !== OWN){
    return{cell:4, color:OWN}
  }
}


if (paint == OWN && l>7){
  if(view[4].color !== ESCAPE){
    return{cell:4, color:ESCAPE}
  }
}

//a) when off pattern
if (view[4].color !== OWN) {
    if (view[4].color == ESCAPE){
         if (checktrapped(ESCAPE)==4){
            return{cell:scoreindex}
            }
        }
        if (view[4].color == ESCAPE){
         if (checktrapped(ESCAPE)==3){
            return{cell:scoreindex}
            }
        }
    if (checkforemptypattern()) {
    return{cell:4, color:OWN};
    }

    //Am I trapped? Different possible traps follow here
    if (view[4].color !== ESCAPE){
         if (checktrapped(OWN)==4){
            return{cell:4, color:ESCAPE}
            }
    }
    if (view[4].color !== ESCAPE){
         if (checktrapped(OWN)==3 && checktrapped(ESCAPE)==1){
            return{cell:4, color:ESCAPE}
            }
    }
    if (view[4].color !== ESCAPE){
         if (checktrapped(OWN)==2 && checktrapped(ESCAPE)==1){
            return{cell:4, color:ESCAPE}
            }
    }
    if (view[4].color !== ESCAPE){
         if (checktrapped(OWN)==2 && checktrapped(ESCAPE)==2){
            return{cell:4, color:ESCAPE}
            }
    }
    if (view[4].color !== ESCAPE){
         if (checktrapped(OWN)==1 && checktrapped(ESCAPE)==2){
            return{cell:4, color:ESCAPE}
            }
    }
    if (view[4].color !== ESCAPE){
         if (checktrapped(OWN)==1 && checktrapped(ESCAPE)==1){
            return{cell:4, color:ESCAPE}
            }
    }
    if (view[4].color !== ESCAPE){ //when the orthogonals are painted, some other guy was here before and movement traps are likely
         if (view[1].color == OWN || view[7].color == OWN || view[3].color == OWN || view[5].color == OWN){
            return{cell:4, color:ESCAPE}
            }
    }
    if (view[4].color !== ESCAPE){ //when the orthogonals are painted, some other guy was here before and movement traps are likely
         if (view[1].color == ESCAPE || view[7].color == ESCAPE || view[3].color == ESCAPE || view[5].color == ESCAPE){
            return{cell:4, color:ESCAPE}
            }
    }
}

//b) when on pattern check surroundings for escape route
if (checktrapped(ESCAPE)==3){
    return{cell:4, color:ESCAPE}
}
if (checktrapped(ESCAPE)==4){
    return{cell:4, color:ESCAPE}
}

//otherwise just move on
return{cell:scoreindex}

व्याख्या

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

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

इसके अलावा, पहले से ही चित्रित क्षेत्रों में बुनियादी दुश्मन से बचाव और एक विकर्ण आंदोलन भी शामिल है (लेकिन वास्तव में अभी तक परीक्षण नहीं किया गया है)।

अंतिम लेकिन कम से कम, बॉट कुछ सुंदर सार पैटर्न खींचता है, जब अकेला छोड़ दिया जाता है:

खेल के अंत में होप्पमौर बॉट अवलोकन पैटर्न


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

धन्यवाद, @ Draco18s! मैं उन पुरानी चुनौतियों की जांच कर सकता हूं, लेकिन इससे पहले कि मैं एक कॉलोनी चींटी बॉट बनाने में कामयाब नहीं हुआ हूं :-)
पेले लुंडकविस्ट

6

निर्माण

यह सबमिशन एक github रिपॉजिटरी में होस्ट किया गया है

var marcher_count;var gatherer_count;var excess_gatherers;var tcell;var lh_cell;var rh_cell;var ant_off;var alt_cell;var cell_off;function debug(message)
{}
const MARCHER_A=1;const MARCHER_B=2;const GATHERER=3;const QUEEN=5;const S_END=[6,5,7,4,0,2,1,3];const S_FRONT=[7,5,6,0,4,1,3,2];const S_SIDE=[7,3,5,1,6,2,0,4];const S_GATHERER=[7,6,5,4,0,3,2,1];const SCAN_MOVES=[0,1,2,3,5,6,7,8];const CORNERS=[0,2,6,8];const EDGES=[1,3,5,7];const CCW=[[0,3,6,7,8,5,2,1],[1,0,3,6,7,8,5,2],[2,1,0,3,6,7,8,5],[3,6,7,8,5,2,1,0],[4,4,4,4,4,4,4,4],[5,2,1,0,3,6,7,8],[6,7,8,5,2,1,0,3],[7,8,5,2,1,0,3,6],[8,5,2,1,0,3,6,7]];const NEARS=[[6,5,3,5,4,2,3,2,1],[5,6,5,4,5,4,2,3,2],[3,5,6,2,4,5,1,2,3],[5,4,2,6,5,3,5,4,2],[4,5,4,5,6,5,4,5,4],[2,4,5,3,5,6,2,4,5],[3,2,1,5,4,2,6,5,3],[2,3,2,4,5,4,5,6,5],[1,2,3,2,4,5,3,5,6]];const SAN_ORD=[[1,3,6,2,5,7,8],[0,2,5,3,6,8,7],[5,1,0,8,7,3,6],[6,0,1,7,8,2,5],[],[2,8,7,1,0,6,3],[3,7,8,0,1,5,2],[8,6,3,5,2,0,1],[7,5,2,6,3,1,0]];const D_MARCH=1;const D_FOOD=2;const D_STALLED=3;const D_GATHERER=4;const U_REALIGN=5;const U_SENTINEL=6;const U_READY=7;const U_PANIC=8;const PUPS=[[0,1,2,3,4,5,6,7,8],[1,1,0,0,0,1,1,0,1],[2,0,2,0,4,2,2,0,2],[3,0,0,3,4,3,3,0,3],[4,0,4,4,4,4,0,0,4],[5,1,2,3,4,5,5,0,5],[6,1,2,3,0,5,5,0,6],[7,0,0,0,0,0,0,7,7],[8,1,2,3,4,5,6,7,8]];const PDOWNS=[[0,1,2,3,4,5,6,7,8],[1,1,0,3,4,5,5,0,1],[2,0,2,3,4,5,5,0,2],[3,3,3,3,3,3,3,3,3],[4,4,4,3,4,0,0,0,4],[5,5,5,3,0,5,5,0,5],[6,5,5,3,0,5,5,0,6],[7,0,0,3,0,0,0,7,7],[8,1,2,3,4,5,6,7,8]];const PSIDES=[[0,1,2,3,4,5,6,7,8],[1,1,0,3,4,1,1,0,1],[2,0,2,0,4,5,5,0,2],[3,3,0,3,3,3,3,3,3],[4,4,4,3,4,0,0,0,4],[5,1,5,3,0,5,5,0,5],[6,1,5,3,0,5,5,0,6],[7,0,0,3,0,0,0,7,7],[8,1,2,3,4,5,6,7,8]];const INIT_SEED=3734978372;const FINAL_SEED=2338395782;const SRECOLOR_PROB=0.7;const SONSTRIDE_PROB=0.5;const QFSPAWNP_MAX=0.05;const QFSPAWNP_MIN=0.00;const QFSPAWNP_DECAY=0.005;const QBSPAWNP_MAX=0.65;const QBSPAWNP_MIN=0.55;const QBSPAWNP_DECAY=0.01;const QFORMP_MAX=0.5;const QFORMP_MIN=0.3;const QFORMP_DECAY=0.01;const DISCOLORT=35;const ERASET=20;const SOBSTRUCT_FUZZ=6;const SSTRIDE_FUZZ=6;const OBSTRUCT_QWT=3;const SPREFWT=2;var state=null;function rand_init()
{state=INIT_SEED;for(var cell=0;cell<9;cell++)
{var v=view[cell];state^=v.color;state^=v.food<<3;if(v.ant!==null)
{state^=v.ant.friend<<4;state^=v.ant.type<<5;state^=v.ant.food<<8;}
ant_rand();}
state^=FINAL_SEED;if(state===0)state=1;}
function ant_rand()
{if(state===null)rand_init();state^=state<<13;state^=state>>>17;state^=state<<5;return state>>>0;}
function rand_choice(prob)
{return ant_rand()/4294967296<prob;}
function rand_sub(array,num)
{var return_array=array.slice();for(var i=0;i<num;i++)
{var rand_index=i+ant_rand()%(array.length-i);var x_val=return_array[rand_index];return_array[rand_index]=return_array[i];return_array[i]=x_val;}
return return_array.slice(0,num);}
function rand_perm(array)
{var return_array=array.slice();for(var i=0;i<array.length-1;i++)
{var rand_index=i+ant_rand()%(array.length-i)
var x_val=return_array[rand_index];return_array[rand_index]=return_array[i];return_array[i]=x_val;}
return return_array;}
function index_sort(arr)
{var index_array=[];for(var i=0;i<arr.length;i++)index_array.push(i);index_array.sort((a,b)=>(arr[a]===arr[b])?(a-b):(arr[a]-arr[b]));return index_array;}
function this_ant()
{return view[4].ant;}
function c_at(cell)
{return view[cell].color;}
function is_ally(cell)
{return view[cell].ant!==null&&view[cell].ant.friend===true;}
function is_enemy(cell)
{return view[cell].ant!==null&&view[cell].ant.friend===false;}
function is_harvestable(cell)
{return is_enemy(cell)&&view[cell].ant.type===QUEEN&&view[cell].ant.food>0;}
function lchk(c)
{if(is_ally(CCW[c][6])&&view[CCW[c][6]].ant.type===GATHERER)
if(is_ally(CCW[c][5])&&view[CCW[c][5]].ant.type!==GATHERER)return D_GATHERER;if(is_ally(CCW[c][7])&&view[CCW[c][7]].ant.type===GATHERER&&is_ally(CCW[c][1]))return D_GATHERER;if(is_ally(CCW[c][5])&&view[CCW[c][5]].ant.type===GATHERER)
if(is_ally(CCW[c][3])&&c_at(4)===D_MARCH)return D_STALLED;if(view[CCW[c][6]].food===1&&is_ally(CCW[c][5])&&view[CCW[c][5]].ant.type!==GATHERER)return D_FOOD;if(view[CCW[c][7]].food===1&&is_ally(CCW[c][1])&&c_at(CCW[c][1])===D_FOOD)return D_FOOD;if(view[CCW[c][5]].food===1&&is_ally(CCW[c][3])&&view[CCW[c][3]].ant.type!==QUEEN&&c_at(4)===D_MARCH)return U_REALIGN;return null;}
function lchk2(c)
{if(is_ally(CCW[c][6])&&view[CCW[c][6]].ant.type===GATHERER)
if(is_ally(CCW[c][5])&&view[CCW[c][5]].ant.type!==GATHERER)return D_GATHERER;if(is_ally(CCW[c][7])&&view[CCW[c][7]].ant.type===GATHERER&&is_ally(CCW[c][1]))return D_GATHERER;if(is_ally(CCW[c][5])&&view[CCW[c][5]].ant.type===GATHERER)
if(is_ally(CCW[c][3])&&c_at(4)===D_MARCH)return D_STALLED;if(is_ally(CCW[c][2])&&view[CCW[c][2]].ant.type===GATHERER)
if(is_ally(CCW[c][1])&&view[CCW[c][1]].ant.type!==GATHERER)return D_GATHERER;if(is_ally(CCW[c][3])&&view[CCW[c][3]].ant.type===GATHERER)
if(is_ally(CCW[c][5])&&c_at(CCW[c][5])===D_GATHERER)return D_GATHERER;if(is_ally(CCW[c][1])&&view[CCW[c][1]].ant.type===GATHERER)
if(is_ally(CCW[c][7])&&c_at(4)===D_MARCH)return D_STALLED;if(view[CCW[c][6]].food===1&&is_ally(CCW[c][5])&&view[CCW[c][5]].ant.type!==GATHERER)return D_FOOD;if(view[CCW[c][7]].food===1&&is_ally(CCW[c][1])&&c_at(CCW[c][1])===D_FOOD)return D_FOOD;if(view[CCW[c][5]].food===1&&is_ally(CCW[c][3])&&view[CCW[c][3]].ant.type!==QUEEN&&c_at(4)===D_MARCH)return U_REALIGN;if(view[CCW[c][2]].food===1&&is_ally(CCW[c][1])&&view[CCW[c][1]].ant.type!==GATHERER)return D_FOOD;if(view[CCW[c][3]].food===1&&is_ally(CCW[c][5])&&c_at(CCW[c][5])===D_FOOD)return{cell:4,color:D_FOOD};if(view[CCW[c][1]].food===1&&is_ally(CCW[c][7])&&view[CCW[c][7]].ant.type!==QUEEN&&c_at(4)===D_MARCH)return U_REALIGN;return null;}
function sigc(output,order,c)
{if(c_at(4)===output)
for(cell_off of order)
{var tcell=CCW[c][cell_off];if(!is_ally(tcell)&&c_at(tcell)!==D_MARCH)
{if(view[tcell].food!==0&&view[tcell].color===D_FOOD)
{for(alt_cell of SCAN_MOVES)
{var n_wt=NEARS[tcell][alt_cell];if(n_wt>3&&n_wt<6&&is_ally(alt_cell))
if(view[alt_cell].ant.type===QUEEN||view[alt_cell].ant.type===GATHERER)
continue;}}
return{cell:tcell,color:D_MARCH};}}
return{cell:4,color:output};}
function is_gatherer_marcher(cell)
{if(!is_ally(cell)||view[cell].ant.food>0||view[cell].ant.type!==GATHERER)return false;if(this_ant().type===QUEEN)return true;lh_cell=CCW[cell][1];rh_cell=CCW[cell][7];if(is_ally(lh_cell)&&view[lh_cell].ant.type===QUEEN)return!is_ally(rh_cell)
else if(is_ally(rh_cell)&&view[rh_cell].ant.type===QUEEN)return!is_ally(lh_cell)
else return false;}
function is_like(cell)
{if(c_at(cell)===U_PANIC)return false;if(is_ally(CCW[cell][1])&&c_at(CCW[cell][1])===U_PANIC)return false;if(is_ally(CCW[cell][7])&&c_at(CCW[cell][7])===U_PANIC)return false;if(CORNERS.includes(cell)&&is_ally(cell))
{switch(view[cell].ant.type)
{case MARCHER_A:return view[cell].ant.food===0&&this_ant().type!==MARCHER_B;case MARCHER_B:return view[cell].ant.food===0&&this_ant().type!==MARCHER_A;case GATHERER:return is_gatherer_marcher(cell)&&this_ant().type!==GATHERER;case QUEEN:return true;default:return false;}}
return false;}
function is_other(cell)
{if(c_at(cell)===U_PANIC)return false;if(EDGES.includes(cell)&&is_ally(cell))
{switch(view[cell].ant.type)
{case MARCHER_A:return view[cell].ant.food===0&&this_ant().type!==MARCHER_A;case MARCHER_B:return view[cell].ant.food===0&&this_ant().type!==MARCHER_B;case GATHERER:return this_ant().type===QUEEN
case QUEEN:return true;default:return false;}}
return false;}
function view_corner()
{var scores=[0,0,0,0];for(var i=0;i<4;i++)
for(var j=0;j<8;j++)
{scores[i]*=2;var tcell=CCW[CORNERS[i]][j];if(is_ally(tcell)&&(is_like(tcell)||is_other(tcell)))scores[i]++;}
if(scores[0]>scores[1]&&scores[0]>scores[2]&&scores[0]>scores[3])return CORNERS[0];else if(scores[1]>scores[2]&&scores[1]>scores[3])return CORNERS[1];else if(scores[2]>scores[3])return CORNERS[2];else return CORNERS[3];}
const ONE_EDGE=10;const ONE_CORNER=11;const EE_BENT=20;const EE_STRAIGHT=21;const EC_LEFT=22;const EC_RIGHT=23;const EC_SKEWED=24;const EC_SPAWN=25;const CC_EDGED=26;const CC_LINE=27;const THREE_MARCH=30;const THREE_STAND=31;const THREE_RECOVER=32;const THREE_UNSTAND=33;const THREE_BLOCK=34;const THREE_HANG=35;const THREE_UNHANG=36;const THREE_SIDE=37;const FOUR_Z=40;const FOUR_STAIRS=41;const FOUR_BENT=42;function neighbor_type(top_left)
{var corners=[];for(tcell of CORNERS)
if(is_ally(tcell)&&is_like(tcell))corners.push(tcell);var edges=[];for(tcell of EDGES)
if(is_ally(tcell)&&is_other(tcell))edges.push(tcell);if(corners.length===1&&edges.length===0)return ONE_CORNER;if(corners.length===0&&edges.length===1)return ONE_EDGE;if(corners.length===0&&edges.length===2)return(edges[1]===CCW[edges[0]][4])?EE_STRAIGHT:EE_BENT;if(corners.length===2&&edges.length===0)return(corners[1]===CCW[corners[0]][4])?CC_LINE:CC_EDGED;else if(corners.length===1&&edges.length===1)
{if(edges[0]===CCW[top_left][1])return EC_LEFT;if(edges[0]===CCW[top_left][3])return EC_SPAWN;if(edges[0]===CCW[top_left][5])return EC_SKEWED;if(edges[0]===CCW[top_left][7])return EC_RIGHT;return null;}
else if(corners.length===1&&edges.length===2)
{if(edges.includes(CCW[top_left][1])&&edges.includes(CCW[top_left][3]))return THREE_MARCH;if(edges.includes(CCW[top_left][3])&&edges.includes(CCW[top_left][7]))return THREE_STAND;if(edges.includes(CCW[top_left][1])&&edges.includes(CCW[top_left][5]))return THREE_RECOVER;if(edges.includes(CCW[top_left][5])&&edges.includes(CCW[top_left][7]))return THREE_UNSTAND;if(edges.includes(CCW[top_left][1])&&edges.includes(CCW[top_left][7]))return THREE_BLOCK;return null;}
else if(corners.length===2&&edges.length===1)
{if(corners.includes(CCW[top_left][4])&&edges.includes(CCW[top_left][3]))return THREE_HANG;if(corners.includes(CCW[top_left][4])&&edges.includes(CCW[top_left][1]))return THREE_UNHANG;if(corners.includes(CCW[top_left][2])&&edges.includes(CCW[top_left][1]))return THREE_SIDE;}
else if(corners.length===2&&edges.length===2)
{if(edges.includes(CCW[top_left][3])&&edges.includes(CCW[top_left][7])&&corners.includes(CCW[top_left][4]))
return FOUR_Z;if(edges.includes(CCW[top_left][1])&&edges.includes(CCW[top_left][3])&&corners.includes(CCW[top_left][4]))
return FOUR_STAIRS;if(edges.includes(CCW[top_left][1])&&edges.includes(CCW[top_left][3])&&corners.includes(CCW[top_left][2]))
return FOUR_BENT;return null;}
return null;}
function sok(cand)
{if(cand===4)return true;if(view[cand].food!==0&&this_ant().food!==0)return false;if(view[cand].ant!==null)return false;return true;}
function spref(cand)
{var okscore=0;if(cand===4)okscore-=9;if(this_ant().type===GATHERER)
{for(tcell of SCAN_MOVES)
if(NEARS[cand][tcell]>1)
if(is_ally(tcell)&&view[tcell].ant.type===QUEEN)okscore-=1;}
else
{if(this_ant().food===0&&view[cand].food!==0)
{for(tcell of SCAN_MOVES)
if(is_ally(tcell)&&view[tcell].ant.food===0)
{if([MARCHER_A,MARCHER_B].includes(view[tcell].ant.type))
{var has_common_enemy=false;for(var i=0;i<9;i++)
if(is_enemy(i)&&NEARS[tcell][i]>=4)has_common_enemy=true;if(!has_common_enemy)
{var wt=(view[tcell].ant.type===this_ant().type)?1:-1;if(NEARS[4][tcell]===5)okscore+=wt;if(NEARS[4][tcell]===4)okscore-=wt;if(NEARS[cand][tcell]===5)okscore-=wt;if(NEARS[cand][tcell]===4)okscore+=wt;}}}
if(okscore>0)okscore=0;}}
return okscore*SPREFWT;}
function ssep()
{var has_ally=false;var cands=[0,0,0,0,0,0,0,0,0];for(var i=0;i<9;i++)cands[i]+=spref(i);for(tcell of SCAN_MOVES)
{if(is_ally(tcell))
{has_ally=true;var wt=(is_like(tcell)||is_other(tcell))?3:1;for(var i=0;i<9;i++)cands[i]-=NEARS[tcell][i]*wt;}}
if(!has_ally)return null;var prox_order=index_sort(cands);for(var i=8;i>=0;i--)
{var i_cell=prox_order[i];if(sok(i_cell))return{cell:i_cell};}
return null;}
function sstep(col)
{if(c_at(4)===1)return{cell:4,color:col};var cands=[0,0,0,0,0,0,0,0,0];for(tcell of SCAN_MOVES)
if(c_at(tcell)===col)
for(var i=0;i<9;i++)cands[i]-=NEARS[tcell][i];for(var i=0;i<9;i++)cands[i]+=spref(i);var prox_order=index_sort(cands);for(var i=8;i>=0;i--)
{var i_cell=prox_order[i];if(sok(i_cell))return{cell:i_cell};}
return{cell:4,color:col};}
function smove()
{for(tcell of rand_perm(SCAN_MOVES))
if(sok(tcell))return{cell:tcell};return{cell:4};}
function sdec_alone()
{var try_sep=ssep();if(try_sep!==null)return try_sep;var c=U_PANIC;for(tcell of rand_sub(SCAN_MOVES,7))
if(c_at(tcell)>1&&c_at(tcell)!==c)
{c=c_at(tcell);break;}
return sstep(c);}
function sdec_erase()
{var try_sep=ssep();if(try_sep!==null)return try_sep;for(tcell of rand_perm(SCAN_MOVES))
if(c_at(tcell)!==1)return{cell:tcell,color:1};if(c_at(4)!==1)return{cell:4,color:1};return sdec_alone();}
function sdec_discolor()
{if(c_at(1)!==c_at(6)&&c_at(6)!==1)return{cell:1,color:c_at(6)};if(c_at(2)!==c_at(3))return{cell:3,color:c_at(2)};var proximities=[0,0,0,0,0,0,0,0,0];for(var i=0;i<9;i++)proximities[i]+=ant_rand()%SOBSTRUCT_FUZZ+spref(i);for(tcell of SCAN_MOVES)
if(is_ally(tcell))
for(var i=0;i<9;i++)proximities[i]+=NEARS[tcell][i];var prox_order=index_sort(proximities);for(var i=8;i>=0;i--)
if(sok(prox_order[i]))return{cell:prox_order[i]};return smove();}
function sdec_stride()
{if(rand_choice(SONSTRIDE_PROB))
{var stride_scores=[0,0,0,0,0,0,0,0,0];for(tcell of SCAN_MOVES)
{for(var i=0;i<9;i++)
if(c_at(tcell)!==c_at(i)&&c_at(i)!==1)stride_scores[i]+=NEARS[tcell][i];}
for(var i=0;i<9;i++)
stride_scores[i]+=ant_rand()%SSTRIDE_FUZZ+spref(i);var prox_order=index_sort(stride_scores);for(var i=8;i>=0;i--)
if(sok(prox_order[i]))return{cell:prox_order[i]};}
return smove();}
function sdec_obstruct_textured()
{var proximities=[0,0,0,0,0,0,0,0,0];for(tcell of SCAN_MOVES)
{if(is_enemy(tcell))
{var wt=(view[tcell].ant.type===QUEEN)?OBSTRUCT_QWT:1;for(var i=0;i<9;i++)proximities[i]+=NEARS[tcell][i]*wt;}}
for(var i=0;i<9;i++)proximities[i]+=ant_rand()%SOBSTRUCT_FUZZ;var prox_order;if(rand_choice(SRECOLOR_PROB))
{prox_order=index_sort(proximities);for(var i=8;i>0;i--)
{var i_cell=prox_order[i];for(var j=0;j<i;j++)
{var j_cell=prox_order[j];if(c_at(i_cell)!==c_at(j_cell))return{cell:i_cell,color:c_at(j_cell)};}}}
for(tcell of SCAN_MOVES)
if(is_ally(tcell))
for(var i=0;i<9;i++)proximities[i]+=NEARS[tcell][i];for(var i=0;i<9;i++)proximities[i]+=spref(i);prox_order=index_sort(proximities);for(var i=8;i>=0;i--)
if(sok(prox_order[i]))return{cell:prox_order[i]};return{cell:4,color:1};}
function sdec_obstruct_flat()
{var proximities=[0,0,0,0,0,0,0,0,0];for(tcell of SCAN_MOVES)
{if(is_enemy(tcell))
{var wt=(view[tcell].ant.type===QUEEN)?OBSTRUCT_QWT:1;for(var i=0;i<9;i++)proximities[i]+=NEARS[tcell][i]*wt;}}
for(var i=0;i<9;i++)proximities[i]+=ant_rand()%SOBSTRUCT_FUZZ;var prox_order;if(rand_choice(SRECOLOR_PROB))
{prox_order=index_sort(proximities);for(var i=8;i>0;i--)
{var i_cell=prox_order[i];if(c_at(i_cell)!==D_MARCH)return{cell:i_cell,color:D_MARCH};}}
for(tcell of SCAN_MOVES)
if(is_ally(tcell))
for(var i=0;i<9;i++)proximities[i]+=NEARS[tcell][i];for(var i=0;i<9;i++)proximities[i]+=spref(i);prox_order=index_sort(proximities);for(var i=8;i>=0;i--)
if(sok(prox_order[i]))return{cell:prox_order[i]};return{cell:4,color:1};}
function saboteur()
{var colored_neighbors=0;for(tcell of SCAN_MOVES)
if(c_at(tcell)>1)colored_neighbors++;if(colored_neighbors<=2)return sdec_alone();else
{var num_enemies=0;for(tcell of SCAN_MOVES)
if(is_enemy(tcell))num_enemies++;var diversity=0;var counts=[0,0,0,0,0,0,0,0,0];for(var i=0;i<9;i++)
{diversity+=5-counts[c_at(i)];counts[c_at(i)]++;}
if(num_enemies>0)
{if(diversity>=ERASET)return sdec_obstruct_textured();else return sdec_obstruct_flat();}
else
{if(diversity>=DISCOLORT)return sdec_discolor();else if(diversity>=ERASET)return sdec_stride();else return sdec_erase();}}}
function gwatch(cand)
{if(cand.cell===4)return cand;if(cand.hasOwnProperty("color"))return cand;if(view[cand.cell].food!==0&&this_ant().food!==0)return sigc(U_PANIC,S_SIDE,0);if(view[cand.cell].ant!==null)return sigc(U_PANIC,S_SIDE,0);return cand;}
function egwatch(cand)
{if(cand.cell===4)return cand;if(cand.hasOwnProperty("color"))return cand;if(view[cand.cell].food!==0&&this_ant().food!==0)return gwatch(sdec_erase());if(view[cand.cell].ant!==null)return gwatch(sdec_erase());return cand;}
function gdec_ee_bent(c)
{return{cell:CCW[c][4]};}
function gdec_ec_left(c)
{if(c_at(c)===D_FOOD&&c_at(CCW[c][1])===D_FOOD)return{cell:CCW[c][7]};if(c_at(c)===D_STALLED&&c_at(CCW[c][1])===D_STALLED)return sigc(U_READY,S_GATHERER,c);if(c_at(c)===D_MARCH&&c_at(CCW[c][1])===D_MARCH)return sigc(D_MARCH,S_GATHERER,c);return sigc(c_at(4),S_GATHERER,c);}
function gdec_ec_right(c)
{if([D_MARCH,D_FOOD].includes(c_at(c))&&[D_MARCH,D_FOOD].includes(c_at(CCW[c][7])))
return{cell:CCW[c][6]};if(is_ally(c)&&view[c].ant.type===QUEEN)
return{cell:CCW[c][1]};if(c_at(c)===D_STALLED&&c_at(CCW[c][7])===D_STALLED)
return sigc(U_READY,S_GATHERER,c);return sigc(c_at(4),S_GATHERER,c);}
function gdec_cc_edged(c)
{if(view[CCW[c][2]].ant.type!==QUEEN)return saboteur();return{cell:CCW[c][1]};}
function gdec_three_block(c)
{if(c_at(CCW[c][7])==D_FOOD)return{cell:CCW[c][6]};return{cell:CCW[c][2]};}
function gdec_three_unstand(c)
{if(view[CCW[c][5]].ant.type!==QUEEN)return saboteur();return{cell:CCW[c][4]};}
function gdec_four_bent(c)
{return{cell:CCW[c][4]};}
function early_gatherer()
{var qcell=null;var food_count=0;for(tcell of SCAN_MOVES)
{if(is_ally(tcell)&&view[tcell].ant.type===QUEEN)qcell=tcell;else if(is_enemy(tcell))return saboteur();}
if(qcell===null)return saboteur();if(c_at(qcell)===D_FOOD)return{cell:CCW[qcell][7]};if(this_ant().food===0)
{for(tcell of rand_perm(CORNERS))
if(view[tcell].food>0&&NEARS[tcell][qcell]===5)
{if(c_at(tcell)===D_FOOD)return{cell:tcell};else return{cell:tcell,color:D_FOOD};}
for(tcell of rand_perm(EDGES))
if(view[tcell].food>0)
{if(c_at(tcell)!==D_FOOD&&NEARS[tcell][qcell]===4)
return{cell:tcell,color:D_FOOD};}}
return{cell:CCW[qcell][1]};}
function gatherer_retrieve()
{if(c_at(4)===U_PANIC)return saboteur();var c=view_corner();switch(neighbor_type(c))
{case EC_LEFT:return gwatch({cell:CCW[c][2]});case THREE_BLOCK:{if(c_at(CCW[c][7])===D_FOOD)return gwatch({cell:CCW[c][6]});return gwatch({cell:CCW[c][2]});}
case FOUR_BENT:return gwatch(sigc(c_at(4),S_FRONT,c));default:return early_gatherer();}}
function gatherer_return()
{if(c_at(4)===U_PANIC)return saboteur();var c=view_corner();switch(neighbor_type(c))
{case EC_LEFT:return gwatch({cell:CCW[c][2]});case THREE_BLOCK:return gwatch({cell:CCW[c][2]});case FOUR_BENT:return gwatch({cell:CCW[c][4]});default:return early_gatherer();}}
function gatherer_formation()
{if(c_at(4)===U_PANIC)return saboteur();var c=view_corner();switch(neighbor_type(c))
{case EC_LEFT:return gwatch(gdec_ec_left(c));case EC_RIGHT:return gwatch(gdec_ec_right(c));case CC_EDGED:return gwatch(gdec_cc_edged(c));case EE_BENT:return gwatch(gdec_ee_bent(c));case THREE_BLOCK:return gwatch(gdec_three_block(c));case THREE_UNSTAND:return gwatch(gdec_three_unstand(c));case FOUR_BENT:return gwatch(gdec_four_bent(c));default:return egwatch(early_gatherer());}}
function gatherer_decision()
{var marcher_count=0;var gatherer_count=0;var queen_pos=null;for(tcell of SCAN_MOVES)
if(is_ally(tcell))
{if(view[tcell].ant.type===MARCHER_A||view[tcell].ant.type===MARCHER_B)marcher_count++;if(view[tcell].ant.type===GATHERER)gatherer_count++;if(view[tcell].ant.type===QUEEN)queen_pos=tcell;}
if(gatherer_count>0)return saboteur();if(this_ant().food>0&&marcher_count>0)return gwatch(gatherer_return());else if(queen_pos!==null&&marcher_count>0)return gwatch(gatherer_formation());else if(marcher_count>0)return gwatch(gatherer_retrieve());else if(queen_pos!==null)return egwatch(early_gatherer());else return saboteur();}
function mdec_one_corner(c)
{if(view[c].ant.type===QUEEN)
return sigc(c_at(4),S_SIDE,c);else return saboteur();}
function mdec_one_edge(c)
{if([U_REALIGN,D_MARCH].includes(c_at(CCW[c][1])))
{if(view[CCW[c][2]].food===1)return{cell:c};if(is_ally(CCW[c][2])&&view[CCW[c][2]].ant.type===GATHERER)return{cell:c};}
return saboteur();}
function mdec_ee_bent(c)
{if(view[CCW[c][1]].ant.type===GATHERER&&view[CCW[c][3]].ant.type===QUEEN)return saboteur();if(view[CCW[c][1]].ant.type===QUEEN&&view[CCW[c][3]].ant.type===GATHERER)return saboteur();var u_sig=c_at(CCW[c][1]);var d_sig=c_at(CCW[c][3]);if(is_ally(c)&&view[c].ant.type===GATHERER)return sigc(c_at(4),S_SIDE,CCW[c][4]);var provisional=lchk(c);if(provisional!==null)
{if(provisional===U_REALIGN)return sigc(U_SENTINEL,S_END,c);return sigc(provisional,S_END,c);}
if(u_sig===D_STALLED)
{if([D_STALLED,U_READY,D_GATHERER].includes(d_sig)&&[D_STALLED,U_READY].includes(c_at(4)))
return sigc(D_STALLED,S_SIDE,c);if(d_sig===U_REALIGN&&c_at(4)===D_STALLED)
return sigc(D_STALLED,S_SIDE,c);}
if(view[CCW[c][1]].ant.type===QUEEN)
{var provisional=lchk(CCW[c][4]);if(provisional!==null)return sigc(provisional,S_END,CCW[c][4]);if(u_sig===D_GATHERER&&d_sig===U_REALIGN&&c_at(4)===D_GATHERER)
return sigc(D_GATHERER,S_END,CCW[c][4]);}
if(u_sig===U_SENTINEL)
{if(d_sig===U_REALIGN&&[D_MARCH,U_SENTINEL].includes(c_at(4)))return sigc(U_SENTINEL,S_SIDE,c);if(d_sig===D_STALLED&&[U_SENTINEL,D_STALLED].includes(c_at(4)))return sigc(U_SENTINEL,S_SIDE,c);if(d_sig===D_MARCH&&[U_SENTINEL,D_MARCH].includes(c_at(4)))return sigc(D_MARCH,S_SIDE,c);}
if(u_sig===D_GATHERER&&d_sig===D_STALLED&&c_at(4)===D_GATHERER)return sigc(D_STALLED,S_SIDE,c);return{cell:CCW[c][2]};}
function mdec_ee_straight(c)
{return sigc(U_REALIGN,S_SIDE,c);}
function mdec_ec_left(c)
{if(view[CCW[c][1]].ant.type===GATHERER&&view[c].ant.type===QUEEN)return saboteur();if(view[CCW[c][1]].ant.type===QUEEN&&view[c].ant.type===GATHERER)return saboteur();if(is_other(CCW[c][1])&&view[c].ant.type===QUEEN)return{cell:CCW[c][3]};var d_sig=PDOWNS[c_at(c)][c_at(CCW[c][1])];if(is_ally(CCW[c][4])&&view[CCW[c][4]].ant.type===GATHERER&&d_sig===D_STALLED&&c_at(4)===D_STALLED)
return sigc(D_STALLED,S_END,c);var provisional=lchk(CCW[c][4]);if(provisional!==null)
{if(provisional===U_REALIGN)return sigc(U_SENTINEL,S_END,CCW[c][4]);return sigc(provisional,S_END,CCW[c][4]);}
if(d_sig===U_REALIGN)
{if(c_at(4)===D_MARCH)return sigc(U_SENTINEL,S_END,CCW[c][4]);if(c_at(4)===U_SENTINEL)
{if(c_at(c)===D_MARCH)return{cell:CCW[c][2]};return sigc(U_SENTINEL,S_END,CCW[c][4]);}}
if(d_sig===D_STALLED)
{if([D_MARCH,D_STALLED].includes(c_at(4)))return sigc(D_STALLED,S_END,CCW[c][4]);if(c_at(4)===U_SENTINEL)return sigc(U_SENTINEL,S_END,CCW[c][4]);}
if(d_sig===D_GATHERER)
{if(c_at(4)===D_FOOD)return sigc(D_GATHERER,S_END,CCW[c][4]);if(c_at(4)===D_GATHERER)return sigc(D_STALLED,S_END,CCW[c][4]);}
if(d_sig===U_READY)
{if(c_at(4)===D_STALLED)
{if(c_at(CCW[c][2])!==D_MARCH)return{cell:CCW[c][2],color:D_MARCH};return sigc(D_MARCH,S_END,CCW[c][4]);}
if(c_at(4)===U_SENTINEL)return sigc(D_MARCH,S_END,CCW[c][4]);}
return{cell:CCW[c][2]};}
function mdec_ec_right(c)
{if(view[c].ant.type===GATHERER&&view[CCW[c][7]].ant.type===QUEEN)
if(is_ally(CCW[c][4])&&view[CCW[c][4]].ant.type!==this_ant().type)return{cell:CCW[c][5]};var d_sig=PDOWNS[c_at(c)][c_at(CCW[c][7])];var provisional=lchk(CCW[c][4]);if(provisional!==null)
{if(provisional===U_REALIGN)return sigc(U_SENTINEL,S_END,CCW[c][4]);return sigc(provisional,S_END,CCW[c][4]);}
if(d_sig===D_MARCH)
{if(c_at(4)===D_MARCH)return sigc(D_MARCH,S_END,CCW[c][4]);if([D_FOOD,D_GATHERER,U_READY].includes(c_at(4)))return sigc(D_MARCH,S_END,CCW[c][4]);}
if(d_sig===D_FOOD)
{if([U_SENTINEL,D_STALLED].includes(c_at(4)))return sigc(D_STALLED,S_END,CCW[c][4]);if([D_FOOD,D_GATHERER,U_READY].includes(c_at(4)))return sigc(D_STALLED,S_END,CCW[c][4]);}
if(d_sig===D_GATHERER)
{if([D_FOOD,D_GATHERER,U_READY].includes(c_at(4)))return sigc(D_MARCH,S_END,CCW[c][4]);if([U_SENTINEL,D_STALLED].includes(c_at(4)))return sigc(D_STALLED,S_END,CCW[c][4]);}
if(d_sig===D_STALLED)
{if(c_at(4)===D_STALLED)return sigc(D_STALLED,S_END,CCW[c][4]);if([D_FOOD,D_GATHERER,U_READY].includes(c_at(4)))return sigc(D_STALLED,S_END,CCW[c][4]);}
if(d_sig===U_READY)
{if(c_at(4)===D_STALLED)return sigc(D_MARCH,S_END,CCW[c][4]);if([D_FOOD,D_GATHERER,U_READY].includes(c_at(4)))return sigc(D_MARCH,S_END,CCW[c][4]);}
if(d_sig===U_REALIGN)
{if(c_at(4)===U_SENTINEL)return{cell:CCW[c][6]};if([D_FOOD,D_GATHERER,U_READY].includes(c_at(4)))return sigc(D_STALLED,S_END,CCW[c][4]);}
return sigc(d_sig,S_END,CCW[c][4]);}
function mdec_ec_spawn(c)
{if(view[c].ant.type===QUEEN&&c_at(c)===D_MARCH&&c_at(CCW[c][3])===D_STALLED)
if(c_at(4)===D_STALLED)return sigc(D_STALLED,S_SIDE,c);return saboteur();}
function mdec_three_march(c)
{var d_sig=PDOWNS[c_at(c)][c_at(CCW[c][1])];var u_sig=c_at(CCW[c][3]);var provisional=lchk2(c);if(provisional!==null)return sigc(provisional,S_FRONT,c);if(u_sig===U_SENTINEL)
{if(d_sig===D_GATHERER&&[D_GATHERER,D_STALLED].includes(c_at(4)))return sigc(D_STALLED,S_FRONT,c);if(d_sig===D_STALLED&&[D_MARCH,D_STALLED].includes(c_at(4)))return sigc(D_STALLED,S_FRONT,c);}
if(u_sig===U_REALIGN)
{if(d_sig===U_REALIGN&&c_at(4)===U_REALIGN)
if(c_at(c)===U_SENTINEL)
{if(c_at(CCW[c][7])===D_MARCH)return sigc(U_REALIGN,S_FRONT,c);return{cell:CCW[c][2]};}
if(d_sig===D_FOOD&&[D_MARCH,D_FOOD].includes(c_at(4)))return sigc(D_FOOD,S_FRONT,c);if(d_sig===U_READY&&c_at(4)===D_STALLED)return sigc(D_MARCH,S_FRONT,c);if(d_sig===D_STALLED&&[D_MARCH,D_STALLED].includes(c_at(4)))return sigc(D_STALLED,S_FRONT,c);if(d_sig===D_GATHERER&&[D_GATHERER,D_STALLED].includes(c_at(4)))return sigc(D_STALLED,S_FRONT,c);if(d_sig===D_MARCH&&c_at(4)===D_STALLED)return sigc(D_STALLED,S_FRONT,c);}
if(u_sig===D_MARCH)
{if(d_sig===D_FOOD&&c_at(4)===D_FOOD)return sigc(D_FOOD,S_FRONT,c);if(d_sig===U_REALIGN&&c_at(4)===D_MARCH)
if(c_at(c)===U_SENTINEL)return sigc(U_REALIGN,S_FRONT,c);if(d_sig===U_READY&&c_at(4)===U_READY)return sigc(D_MARCH,S_FRONT,c);}
if(u_sig===D_STALLED)
{if(d_sig===U_READY&&c_at(4)===D_STALLED)return sigc(U_READY,S_FRONT,c);if(d_sig===D_STALLED&&[D_STALLED,D_MARCH].includes(c_at(4)))return sigc(D_STALLED,S_FRONT,c);if(d_sig===D_GATHERER&&c_at(4)===D_GATHERER)return sigc(D_STALLED,S_FRONT,c);if(d_sig===D_MARCH&&c_at(4)===D_STALLED)return sigc(D_STALLED,S_FRONT,c);if(d_sig===U_REALIGN&&[D_STALLED,D_MARCH].includes(c_at(4)))return sigc(D_STALLED,S_FRONT,c);}
if(u_sig===D_GATHERER)
{if(d_sig===D_STALLED&&c_at(4)===D_GATHERER)
if(view[CCW[c][3]].ant.type===QUEEN)return sigc(D_STALLED,S_FRONT,c);if(d_sig===D_GATHERER&&c_at(4)===D_GATHERER)return sigc(D_GATHERER,S_FRONT,c);if(d_sig===D_FOOD&&c_at(4)===D_GATHERER)return sigc(D_FOOD,S_FRONT,c);}
if(u_sig===D_FOOD)
{if(d_sig===D_FOOD&&c_at(4)===D_FOOD)return sigc(D_FOOD,S_FRONT,c);if(d_sig===D_GATHERER&&c_at(4)===D_GATHERER)return sigc(D_GATHERER,S_FRONT,c);}
return{cell:CCW[c][2]};}
function mdec_three_stand(c)
{var provisional=lchk2(c);if(provisional!==null)return sigc(provisional,S_SIDE,c);var u_sig=c_at(CCW[c][3]);var d_sig=PSIDES[c_at(c)][c_at(CCW[c][7])];if(u_sig===U_REALIGN)
{if([D_MARCH,D_STALLED].includes(d_sig)&&c_at(4)===D_MARCH)return sigc(U_REALIGN,S_SIDE,CCW[c][4]);if(c_at(4)===U_REALIGN)return sigc(U_REALIGN,S_SIDE,CCW[c][4]);}
if(u_sig===D_MARCH&&d_sig===U_REALIGN&&c_at(4)===D_MARCH)return sigc(U_REALIGN,S_SIDE,CCW[c][4]);if(u_sig===D_STALLED&&[D_STALLED,U_REALIGN].includes(d_sig)&&c_at(4)===D_STALLED)
return sigc(D_STALLED,S_SIDE,CCW[c][4]);return sigc(D_MARCH,S_SIDE,CCW[c][4]);}
function mdec_three_unstand(c)
{if(view[CCW[c][5]].ant.type===QUEEN)
{var provisional=lchk(c);if(provisional!==null)return sigc(provisional,S_FRONT,c);var d_sig=PUPS[c_at(c)][c_at(CCW[c][7])];return sigc(d_sig,S_FRONT,c);}
else
{var provisional=lchk(CCW[c][4]);if(provisional!==null)return sigc(provisional,S_FRONT,CCW[c][4]);var u_sig=c_at(CCW[c][5]);var d_sig=PDOWNS[c_at(c)][c_at(CCW[c][7])];if(u_sig===D_MARCH)
{if(d_sig===U_READY&&c_at(4)===U_READY)return sigc(D_MARCH,S_FRONT,CCW[c][4]);if(d_sig===D_FOOD&&c_at(4)===D_MARCH)return sigc(U_REALIGN,S_FRONT,CCW[c][4]);if([D_FOOD,D_GATHERER].includes(c_at(4)))return sigc(D_MARCH,S_FRONT,CCW[c][4]);}
if(u_sig===D_FOOD)
{if(d_sig===D_FOOD&&c_at(4)===D_MARCH)return sigc(U_REALIGN,S_FRONT,CCW[c][4]);if([D_FOOD,D_GATHERER].includes(c_at(4)))return sigc(D_STALLED,S_FRONT,CCW[c][4]);}
if(u_sig===D_GATHERER)
{if(d_sig===D_FOOD&&c_at(4)===D_MARCH)return sigc(U_REALIGN,S_FRONT,CCW[c][4]);if([D_FOOD,D_GATHERER].includes(c_at(4)))return sigc(D_STALLED,S_FRONT,CCW[c][4]);}
if(u_sig===D_STALLED)
{if(d_sig===U_READY)
{if(c_at(4)===D_STALLED)return sigc(U_READY,S_FRONT,CCW[c][4]);if(c_at(4)===D_GATHERER)return sigc(D_STALLED,S_FRONT,CCW[c][4]);}
if(d_sig===D_FOOD)
{if(c_at(4)===D_MARCH)return sigc(U_REALIGN,S_FRONT,CCW[c][4]);if(c_at(4)===D_GATHERER)return sigc(D_STALLED,S_FRONT,CCW[c][4]);}
if(d_sig===D_STALLED)
{if(c_at(4)===D_STALLED)return sigc(D_STALLED,S_FRONT,CCW[c][4]);if(c_at(4)===D_GATHERER)return sigc(D_STALLED,S_FRONT,CCW[c][4]);}
if(d_sig===D_GATHERER&&c_at(4)===D_GATHERER)return sigc(D_STALLED,S_FRONT,CCW[c][4]);if([D_MARCH,U_REALIGN].includes(d_sig)&&c_at(4)===D_GATHERER)
return sigc(D_STALLED,S_FRONT,CCW[c][4]);if(c_at(4)===D_FOOD)return sigc(D_STALLED,S_FRONT,CCW[c][4]);}
if(u_sig===U_REALIGN)
{if(d_sig===D_FOOD&&c_at(4)===D_MARCH)return sigc(U_REALIGN,S_FRONT,CCW[c][4]);if([D_FOOD,D_GATHERER].includes(c_at(4)))return sigc(D_STALLED,S_FRONT,CCW[c][4]);}
if(u_sig===U_SENTINEL)
{if(d_sig===D_FOOD)
{if(c_at(4)===U_REALIGN)return sigc(D_STALLED,S_FRONT,CCW[c][4]);if(c_at(4)===D_MARCH)return sigc(U_REALIGN,S_FRONT,CCW[c][4]);}
if(d_sig===D_GATHERER&&c_at(4)===U_REALIGN)return sigc(D_STALLED,S_FRONT,CCW[c][4]);if(d_sig===D_MARCH&&c_at(4)===U_SENTINEL)return sigc(D_MARCH,S_FRONT,CCW[c][4]);if(d_sig===D_STALLED&&c_at(4)===U_SENTINEL)return sigc(D_STALLED,S_FRONT,CCW[c][4]);if(d_sig===U_READY&&c_at(4)===D_STALLED)return sigc(U_READY,S_FRONT,CCW[c][4]);if([D_FOOD,D_GATHERER].includes(c_at(4)))return sigc(D_STALLED,S_FRONT,CCW[c][4]);}
if(u_sig===U_READY)
{if(d_sig===D_FOOD&&c_at(4)===D_MARCH)return sigc(U_REALIGN,S_FRONT,CCW[c][4]);if([D_FOOD,D_GATHERER].includes(c_at(4)))return sigc(D_MARCH,S_FRONT,CCW[c][4]);}
return sigc(c_at(4),S_FRONT,CCW[c][4]);}}
function mdec_three_recover(c)
{return sigc(U_SENTINEL,S_FRONT,c);}
function mdec_three_hang(c)
{return sigc(c_at(4),S_SIDE,CCW[c][4]);}
function mdec_three_unhang(c)
{return sigc(c_at(4),S_SIDE,c);}
function mdec_four_z(c)
{var provisional=lchk2(CCW[c][4]);if(provisional!==null)return sigc(provisional,S_SIDE,CCW[c][4]);var u_sig=PSIDES[c_at(c)][c_at(CCW[c][7])];var d_sig=PSIDES[c_at(CCW[c][4])][c_at(CCW[c][3])];if(u_sig===D_FOOD)
{if([D_FOOD,D_STALLED,U_REALIGN].includes(d_sig)&&c_at(4)===U_REALIGN)
return sigc(U_REALIGN,S_SIDE,CCW[c][4]);if(d_sig===D_GATHERER&&[U_REALIGN,D_GATHERER].includes(c_at(4)))
return sigc(U_REALIGN,S_SIDE,CCW[c][4]);}
if(u_sig===D_STALLED)
{if(d_sig===U_REALIGN)return sigc(U_REALIGN,S_SIDE,CCW[c][4]);if(d_sig===D_FOOD&&c_at(4)===U_REALIGN)return sigc(U_REALIGN,S_SIDE,CCW[c][4]);}
if(u_sig===D_GATHERER)
{if(d_sig===U_REALIGN&&c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,CCW[c][4]);if(d_sig===D_FOOD&&[U_REALIGN,D_GATHERER].includes(c_at(4)))
return sigc(U_REALIGN,S_SIDE,CCW[c][4]);}
if(u_sig===U_REALIGN)
{if(d_sig===D_FOOD&&c_at(4)===U_REALIGN)return sigc(U_REALIGN,S_SIDE,CCW[c][4]);if(d_sig===D_STALLED)return sigc(U_REALIGN,S_SIDE,CCW[c][4]);if(d_sig===D_GATHERER&&c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,CCW[c][4]);if(d_sig===U_READY&&c_at(4)===U_REALIGN)return sigc(D_MARCH,S_SIDE,CCW[c][4]);}
if(u_sig===U_READY&&d_sig===U_REALIGN&&c_at(4)===U_REALIGN)
return sigc(D_MARCH,S_SIDE,CCW[c][4]);return sigc(D_MARCH,S_SIDE,CCW[c][4]);}
function mdec_four_stairs(c)
{var provisional=lchk2(c);if(provisional!==null)return sigc(provisional,S_SIDE,c);var u_sig=PSIDES[c_at(c)][c_at(CCW[c][1])];var d_sig=PSIDES[c_at(CCW[c][4])][c_at(CCW[c][3])];if(u_sig===D_MARCH)
{if(d_sig===D_FOOD)
{if(c_at(4)===D_MARCH)return sigc(D_FOOD,S_SIDE,c);if(c_at(4)===U_REALIGN)return sigc(D_MARCH,S_SIDE,c);}
if(d_sig===U_READY)
{if(c_at(4)===U_READY)return sigc(D_MARCH,S_SIDE,c);if(c_at(4)===U_REALIGN)return sigc(D_MARCH,S_SIDE,c);}
if(d_sig===D_STALLED)
{if(c_at(4)===D_MARCH)return sigc(D_STALLED,S_SIDE,c);if(c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,c);}
if(d_sig===D_GATHERER&&c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,c);if([D_MARCH,U_REALIGN].includes(d_sig)&&c_at(4)===U_REALIGN)return sigc(D_MARCH,S_SIDE,c);}
if(u_sig===D_FOOD)
{if(d_sig===D_MARCH)
{if(c_at(4)===U_REALIGN)return sigc(D_MARCH,S_SIDE,c);if(c_at(4)===D_MARCH)return sigc(D_FOOD,S_SIDE,c);}
if(d_sig===U_READY)
{if(c_at(4)===U_REALIGN)return sigc(D_MARCH,S_SIDE,c);if(c_at(4)===D_STALLED)return sigc(D_STALLED,S_SIDE,c);}
if(d_sig===D_GATHERER&&[U_REALIGN,D_GATHERER].includes(c_at(4)))return sigc(D_FOOD,S_SIDE,c);if([U_REALIGN,D_STALLED].includes(d_sig)&&c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,c);}
if(u_sig===D_STALLED)
{if(d_sig===D_STALLED)
{if(c_at(4)===D_STALLED)return sigc(D_STALLED,S_SIDE,c);if(c_at(4)===D_MARCH)return sigc(D_STALLED,S_SIDE,c);if(c_at(4)===U_REALIGN)return sigc(D_MARCH,S_SIDE,c);}
if(d_sig===D_MARCH)
{if(c_at(4)===D_MARCH)return sigc(D_STALLED,S_SIDE,c);if(c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,c);}
if(d_sig===D_GATHERER)
{if(c_at(4)===U_REALIGN)return sigc(D_MARCH,S_SIDE,c);if([D_STALLED,D_GATHERER].includes(c_at(4)))return sigc(D_STALLED,S_SIDE,c);}
if(d_sig===U_READY)
{if(c_at(4)===D_STALLED)return sigc(U_READY,S_SIDE,c);if(c_at(4)===U_REALIGN)return sigc(D_MARCH,S_SIDE,c);}
if(d_sig===U_REALIGN&&[U_REALIGN,D_MARCH].includes(c_at(4)))return sigc(D_STALLED,S_SIDE,c);if(d_sig===D_FOOD&&c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,c);}
if(u_sig===D_GATHERER)
{if(d_sig===D_STALLED)
{if([D_STALLED,D_GATHERER].includes(c_at(4)))return sigc(D_STALLED,S_SIDE,c);if(c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,c);}
if(d_sig===U_READY)
{if(c_at(4)===D_STALLED)return sigc(D_STALLED,S_SIDE,c);if(c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,c);}
if(d_sig===D_FOOD&&[D_GATHERER,U_REALIGN].includes(c_at(4)))return sigc(D_FOOD,S_SIDE,c);if([D_MARCH,U_REALIGN].includes(d_sig)&&c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,c);if(d_sig===D_GATHERER&&c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,c);}
if(u_sig===U_REALIGN)
{if(d_sig===U_REALIGN)
{if(c_at(4)===D_MARCH)return sigc(D_STALLED,S_SIDE,c);if(c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,c);}
if(d_sig===D_STALLED)
{if(c_at(4)===D_MARCH)return sigc(D_STALLED,S_SIDE,c);if(c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,c);}
if(d_sig===D_MARCH&&c_at(4)===U_REALIGN)return sigc(D_MARCH,S_SIDE,c);if([D_FOOD,D_GATHERER,U_READY].includes(d_sig)&&c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,c);}
if(u_sig===U_READY)
{if(d_sig===D_MARCH)
{if(c_at(4)===U_READY)return sigc(D_MARCH,S_SIDE,c);if(c_at(4)===U_REALIGN)return sigc(U_READY,S_SIDE,c);}
if([D_FOOD,D_GATHERER].includes(d_sig))
{if(c_at(4)===D_STALLED)return sigc(D_STALLED,S_SIDE,c);if(c_at(4)===U_REALIGN)return sigc(U_READY,S_SIDE,c);}
if(d_sig===D_STALLED&&c_at(4)===D_STALLED)return sigc(U_READY,S_SIDE,c);if(d_sig===U_REALIGN&&c_at(4)===U_REALIGN)return sigc(D_STALLED,S_SIDE,c);if(d_sig===U_READY&&c_at(4)===U_REALIGN)return sigc(U_READY,S_SIDE,c);}
return sigc(c_at(4),S_SIDE,c);}
function mwatch(cand)
{if(cand.cell===4)return cand;if(cand.hasOwnProperty("color"))return cand;if(view[cand.cell].food!==0)return sigc(D_FOOD,S_SIDE,0);if(is_harvestable(cand.cell))return sigc(D_FOOD,S_SIDE,0);if(view[cand.cell].ant!==null)return sigc(U_PANIC,S_SIDE,0);return cand;}
function marcher_decision()
{if(c_at(4)===U_PANIC||this_ant().food>0)return saboteur();var gatherer_count=0;var enemy_count=0;for(tcell of SCAN_MOVES)
{if(is_ally(tcell)&&view[tcell].ant.type===GATHERER)gatherer_count++;else if(is_enemy(tcell)&&!is_harvestable(tcell))enemy_count++;}
if(gatherer_count>1||enemy_count>0)return saboteur();var colored_neighbors=0;for(tcell of SCAN_MOVES)
if(c_at(tcell)>1)colored_neighbors++;if(colored_neighbors>5)return saboteur();var c=view_corner();switch(neighbor_type(c))
{case ONE_CORNER:return mwatch(mdec_one_corner(c));case ONE_EDGE:return mwatch(mdec_one_edge(c));case EE_BENT:return mwatch(mdec_ee_bent(c));case EE_STRAIGHT:return mwatch(mdec_ee_straight(c));case EC_LEFT:return mwatch(mdec_ec_left(c));case EC_RIGHT:return mwatch(mdec_ec_right(c));case EC_SPAWN:return mwatch(mdec_ec_spawn(c));case THREE_MARCH:return mwatch(mdec_three_march(c));case THREE_STAND:return mwatch(mdec_three_stand(c));case THREE_RECOVER:return mwatch(mdec_three_recover(c));case THREE_UNSTAND:return mwatch(mdec_three_unstand(c));case THREE_HANG:return mwatch(mdec_three_hang(c));case THREE_UNHANG:return mwatch(mdec_three_unhang(c));case FOUR_Z:return mwatch(mdec_four_z(c));case FOUR_STAIRS:return mwatch(mdec_four_stairs(c));default:return saboteur();}}
function opening_queen()
{for(tcell of rand_perm(SCAN_MOVES))
if(view[tcell].food===1)return{cell:tcell};var has_ally=false;var proxs=[0,0,0,0,0,0,0,0,0];for(tcell of SCAN_MOVES)
{if(view[tcell].ant!==null)
{has_ally=true;for(var i=0;i<9;i++)proxs[i]-=NEARS[tcell][i];}}
if(has_ally)
{var prox_order=index_sort(proxs);for(var i=8;i>=0;i--)
{var i_cell=prox_order[i];if(view[i_cell].ant===null&&view[i_cell].food===0)return{cell:i_cell};}}
if(this_ant().food>0)
{var num_ants=0;for(tcell of SCAN_MOVES)
if(view[tcell].ant!==null)num_ants++;if(num_ants===0)
{var is_clear=true;var num_black_corners=0;var black_corner=null;for(var tcell=0;tcell<9;tcell++)
{if(CORNERS.includes(tcell))
{if(c_at(tcell)===8)
{num_black_corners++;black_corner=tcell;}
else if(c_at(tcell)!==1)is_clear=false;}
else if(c_at(tcell)!==1)is_clear=false;}
if(num_black_corners===1&&is_clear)return{cell:CCW[black_corner][7],type:GATHERER};}}
if(c_at(4)!==8)return{cell:4,color:8};var cands=[0,0,0,0,9,0,0,0,0];for(tcell of SCAN_MOVES)
if(c_at(tcell)===8)
for(var i=0;i<9;i++)cands[i]-=NEARS[tcell][i];var cand_order=index_sort(cands);for(var i=8;i>=0;i--)
{var i_cell=cand_order[i];if(view[i_cell].ant===null&&view[i_cell].food===0)return{cell:i_cell};}
return{cell:4,color:8};}
function early_queen()
{var gcell=null;var ally_count=0;for(tcell of rand_perm(SCAN_MOVES))
{if(is_ally(tcell))
{ally_count++;if(view[tcell].ant.type===GATHERER&&EDGES.includes(tcell))gcell=tcell;}}
if(gcell===null)return opening_queen();for(tcell of rand_perm(CORNERS))
if(view[tcell].food>0&&NEARS[tcell][gcell]===5)
{if(c_at(tcell)===D_FOOD)return{cell:tcell};else return{cell:tcell,color:D_FOOD};}
for(tcell of rand_perm(EDGES))
if(view[tcell].food>0)
{if(c_at(tcell)!==D_FOOD&&NEARS[tcell][gcell]===4)
return{cell:tcell,color:D_FOOD};}
if(c_at(4)===D_FOOD)
{if(c_at(CCW[gcell][2])===D_FOOD&&view[CCW[gcell][2]].food===0)
return{cell:CCW[gcell][2],color:D_MARCH};return{cell:4,color:D_MARCH};}
if(c_at(CCW[gcell][6])===D_FOOD&&view[CCW[gcell][6]].food===0)
return{cell:CCW[gcell][6],color:D_MARCH};if(EDGES.includes(gcell)&&this_ant().food>2&&ally_count===1)
{var num_clear_cells=0;var num_down_food=0;var is_valid=true;for(var tcell=0;tcell<9;tcell++)
{if(c_at(tcell)===D_FOOD)
{num_down_food++;if(tcell!==4&&tcell!==gcell)is_valid=false;}
if(c_at(tcell)===D_MARCH)num_clear_cells++;}
if(is_valid&&num_down_food===1&&num_clear_cells===8)
{var food_factor=QFORMP_MAX-QFORMP_MIN
var food_coefficient=QFORMP_DECAY/food_factor
var actual_prob=food_factor/(food_coefficient*(this_ant().food-3)+1)+QFORMP_MIN;if(rand_choice(actual_prob))return{cell:CCW[gcell][1],type:rand_choice(.5)?MARCHER_A:MARCHER_B};else return{cell:gcell,color:D_MARCH};}}
return{cell:CCW[gcell][7]};}
function qwatch(cand)
{if(cand.hasOwnProperty("type")&&this_ant().food===0)return sigc(U_PANIC,S_SIDE,0);if(cand.hasOwnProperty("type")&&view[cand.cell].food!==0)return sigc(U_PANIC,S_SIDE,0);if(cand.cell===4)return cand;if(cand.hasOwnProperty("color"))return cand;if(is_enemy(cand.cell))return sigc(U_PANIC,S_SIDE,0);if(is_ally(cand.cell))return sigc(c_at(4),S_SIDE,0);return cand;}
function eqwatch(cand)
{if(cand.hasOwnProperty("type")&&this_ant().food===0)return qwatch(opening_queen());if(cand.hasOwnProperty("type")&&view[cand.cell].food!==0)return qwatch(opening_queen());if(cand.cell===4)return cand;if(cand.hasOwnProperty("color"))return cand;if(is_enemy(cand.cell))return qwatch(opening_queen());if(is_ally(cand.cell))return qwatch(opening_queen());return cand;}
function qdec_ee_straight(c)
{return sigc(c_at(4),S_SIDE,c);}
function qdec_ee_bent(c)
{return{cell:CCW[c][2]};}
function qdec_ec_skewed(c)
{if(view[CCW[c][5]].ant.type!==GATHERER)return opening_queen();if(this_ant().food>0&&view[c].ant.type===MARCHER_A)return{cell:CCW[c][7],type:MARCHER_B};if(this_ant().food>0&&view[c].ant.type===MARCHER_B)return{cell:CCW[c][7],type:MARCHER_A};return opening_queen();}
function qdec_ec_spawn(c)
{if(view[CCW[c][3]].ant.type!==GATHERER)return opening_queen();if(this_ant().food>0&&view[c].ant.type===MARCHER_A)return{cell:CCW[c][1],type:MARCHER_B};if(this_ant().food>0&&view[c].ant.type===MARCHER_B)return{cell:CCW[c][1],type:MARCHER_A};return opening_queen();}
function qdec_cc_edged(c)
{if(view[c].ant.type!==GATHERER)return opening_queen();if(this_ant().food>0&&view[CCW[c][2]].ant.type===MARCHER_A)return{cell:CCW[c][1],type:MARCHER_B};if(this_ant().food>0&&view[CCW[c][2]].ant.type===MARCHER_B)return{cell:CCW[c][1],type:MARCHER_A};return opening_queen();}
function qdec_three_march(c)
{var u_sig=PUPS[c_at(c)][c_at(CCW[c][1])];if(u_sig===D_STALLED)
{if(c_at(CCW[c][3])===D_MARCH&&[D_MARCH,D_GATHERER].includes(c_at(4)))
return sigc(D_STALLED,S_FRONT,c);if(c_at(CCW[c][3])===U_READY&&c_at(4)===D_STALLED)return sigc(U_READY,S_FRONT,c);}
if(u_sig===D_MARCH&&c_at(CCW[c][3])===U_READY&&c_at(4)===U_READY)
return sigc(D_MARCH,S_FRONT,c);if(u_sig===U_READY&&c_at(CCW[c][3])===U_REALIGN&&c_at(4)===U_READY)
if(c_at(CCW[c][1])===D_MARCH)return sigc(D_MARCH,S_FRONT,c);return sigc(c_at(4),S_FRONT,c);}
function qdec_three_stand(c)
{var u_sig=PUPS[c_at(c)][c_at(CCW[c][7])];if(u_sig===D_STALLED)
{if(c_at(CCW[c][3])===D_MARCH&&c_at(4)===D_GATHERER)return sigc(D_STALLED,S_FRONT,c);if(c_at(CCW[c][3])===U_READY&&c_at(4)===D_STALLED)return sigc(U_READY,S_FRONT,c);}
if(u_sig===D_MARCH&&c_at(CCW[c][3])===U_READY&&c_at(4)===U_READY)
return sigc(D_MARCH,S_FRONT,c);if(u_sig===U_READY&&c_at(CCW[c][3])===U_REALIGN&&c_at(4)===U_READY)
if(c_at(CCW[c][1])===D_MARCH)return sigc(D_MARCH,S_FRONT,c);return sigc(c_at(4),S_FRONT,c);}
function qdec_three_recover(c)
{var u_sig=PUPS[c_at(c)][c_at(CCW[c][1])];if(u_sig===D_FOOD)return sigc(D_FOOD,S_FRONT,c);if(this_ant().food>0&&[D_STALLED,U_READY].includes(u_sig))
{var food_factor=QFSPAWNP_MAX-QFSPAWNP_MIN
var food_coefficient=QFSPAWNP_DECAY/food_factor
var actual_prob=food_factor/(food_coefficient*(this_ant().food-1)+1)+QFSPAWNP_MIN;if(rand_choice(actual_prob))return{cell:CCW[c][3]};}
var provisional=lchk(c)
if(provisional!==null)return sigc(provisional,S_FRONT,c);return sigc(c_at(4),S_FRONT,c);}
function qdec_three_unstand(c)
{var u_sig=PUPS[c_at(c)][c_at(CCW[c][7])];if(this_ant().food>0&&u_sig===D_STALLED&&c_at(CCW[c][5])===D_MARCH&&c_at(4)===D_STALLED)
{var food_factor=QBSPAWNP_MAX-QBSPAWNP_MIN
var food_coefficient=QBSPAWNP_DECAY/food_factor
var actual_prob=food_factor/(food_coefficient*(this_ant().food-1)+1)+QBSPAWNP_MIN;if(rand_choice(actual_prob))return{cell:CCW[c][3]};}
if(u_sig===D_STALLED&&c_at(CCW[c][5])===U_READY&&c_at(4)===D_STALLED)
return sigc(U_READY,S_FRONT,c);return sigc(u_sig,S_FRONT,c);}
function qdec_three_block(c)
{var u_sig=PUPS[c_at(c)][c_at(CCW[c][1])];return sigc(u_sig,S_FRONT,c);}
function qdec_three_side(c)
{var u_sig=PUPS[c_at(CCW[c][1])][c_at(CCW[c][2])];return sigc(u_sig,S_FRONT,CCW[c][2]);}
function queen_wait()
{var c=view_corner();switch(neighbor_type(c))
{case ONE_EDGE:{if(this_ant().food>1)return{cell:CCW[c][3],type:GATHERER};}
break;case EC_LEFT:{var u_sig=PUPS[c_at(c)][c_at(CCW[c][1])];if(u_sig===D_GATHERER)return sigc(D_GATHERER,S_FRONT,c);if(u_sig===U_REALIGN&&[U_REALIGN,U_SENTINEL].includes(c_at(c)))
if([U_REALIGN,U_SENTINEL].includes(c_at(CCW[c][1])))
return eqwatch(early_queen());var provisional=lchk(c);if(provisional!==null)return sigc(provisional,S_FRONT,c);if(this_ant().food>1)
{if(c_at(CCW[c][3])!==D_MARCH)return{cell:CCW[c][3],color:D_MARCH};return{cell:CCW[c][3],type:GATHERER};}}
break;case EC_RIGHT:{var u_sig=PUPS[c_at(c)][c_at(CCW[c][7])];if(u_sig===D_GATHERER)return sigc(D_GATHERER,S_FRONT,c);if(u_sig===U_REALIGN&&[U_REALIGN,U_SENTINEL].includes(c_at(c)))
if([U_REALIGN,U_SENTINEL].includes(c_at(CCW[c][7])))
return eqwatch(early_queen());var provisional=lchk(c);if(provisional!==null)return sigc(provisional,S_FRONT,c);if(this_ant().food>1)
{if(c_at(CCW[c][5])!==D_MARCH)return{cell:CCW[c][5],color:D_MARCH};return{cell:CCW[c][5],type:GATHERER};}}
break;}
if(c_at(4)!==U_PANIC)return sigc(U_PANIC,S_SIDE,c);else return opening_queen();}
function queen_march()
{var c=view_corner();switch(neighbor_type(c))
{case EE_STRAIGHT:return qwatch(qdec_ee_straight(c));case EE_BENT:return qwatch(qdec_ee_bent(c));case EC_SKEWED:return qwatch(qdec_ec_skewed(c));case EC_SPAWN:return qwatch(qdec_ec_spawn(c));case CC_EDGED:return qwatch(qdec_cc_edged(c));case THREE_MARCH:return qwatch(qdec_three_march(c));case THREE_STAND:return qwatch(qdec_three_stand(c));case THREE_RECOVER:return qwatch(qdec_three_recover(c));case THREE_UNSTAND:return qwatch(qdec_three_unstand(c));case THREE_BLOCK:return qwatch(qdec_three_block(c));case THREE_SIDE:return qwatch(qdec_three_side(c));default:return eqwatch(early_queen());}}
function queen_decision()
{marcher_count=0;gatherer_count=0;excess_gatherers=0;for(tcell of SCAN_MOVES)
{if(is_ally(tcell))
{if(view[tcell].ant.type===MARCHER_A||view[tcell].ant.type===MARCHER_B)marcher_count++;if(view[tcell].ant.type===GATHERER)
{if(EDGES.includes(tcell)||is_gatherer_marcher(tcell))gatherer_count++;else excess_gatherers++;}}
else if(is_enemy(tcell))return opening_queen();}
if(marcher_count>0&&gatherer_count===1&&excess_gatherers===0)return qwatch(queen_march());else if(marcher_count>0&&gatherer_count===0&&excess_gatherers===0)return qwatch(queen_wait());else if(gatherer_count===1&&excess_gatherers===0)return eqwatch(early_queen());else return opening_queen();}
function main_decide()
{switch(this_ant().type)
{case QUEEN:return queen_decision();case GATHERER:return gatherer_decision();case MARCHER_A:case MARCHER_B:return marcher_decision();default:return sanitize(saboteur());}}
return main_decide();

अवलोकन

इस सबमिशन का उद्देश्य चींटियों की एक पंक्ति तैयार करना है जो इस क्षेत्र को झाडू कर सके। रंगों का उपयोग संकेतों के रूप में किया जाता है ताकि रानी रेखा को समन्वयित करने में मदद कर सकें, न कि ट्रेलमार्कर्स के रूप में।

यह प्रस्तुतिकरण रानी के अतिरिक्त तीन प्रकार के श्रमिकों का उपयोग करता है:

  • टाइप 1: गठन मार्चर, एक चरण
  • टाइप 2: गठन मार्चर, बी चरण
  • टाइप 3: गैदरर
  • टाइप 4: भविष्य के उपयोग के लिए आरक्षित

चींटियों को पूर्ण-चौड़ाई वाली विकर्ण रेखा में बनाया जाता है:

    A
    BA
     BA
      BA
       BA
        BA
         BA
          QG

बनाए गए पहले चार चींटियों चींटियों और एक मार्चर हैं, ए या बी समान संभावना के साथ, फिर प्रत्येक में से एक। उसके बाद, भोजन खोजने के बाद, ए और बी के बीच बारी-बारी से चींटियों को संभावना के साथ बनाया जाता है। निर्माण में, रानी इकट्ठाकर्ता मार्च के दो चरणों के बीच बारी-बारी से बनाता है, जो कि पिछले बने मार्च के आधार पर होता है।

प्रारंभिक चरण

जब रानी भागती है, तो वह अपने रास्ते से पीछे हटने से बचने की कोशिश करते हुए एक बोगी-मानक हाफ-लाइटस्पीड स्ट्रेट-लाइन वॉक करती है। एक बार जब उसे भोजन का एक टुकड़ा मिलता है, तो वह एक इकट्ठा करने वाले को जन्म देती है। भोजन के 3 टुकड़ों को इकट्ठा करने के बाद, भोजन के हर अतिरिक्त टुकड़े के लिए, रानी को हार्ड-कोडेड गठन सृजन दिनचर्या में 3 श्रमिकों को पैदा करने की एक मध्यम संभावना है, और लाइन बंद हो जाती है।

सामान्य व्यवहार

स्टॉप और चरण बी के बीच चींटियों को स्टॉप और स्टेप के साथ बारी-बारी से लॉकस्टेप में मार्च करते हैं। चरण को उनके पड़ोसी सहयोगियों के पैटर्न के मिलान के माध्यम से पहचाना जाता है, क्योंकि चींटियां राज्य को स्टोर करने में असमर्थ हैं। चींटियाँ हमेशा इस तरह चलती हैं कि वे कम से कम दो अन्य चींटियों से सटे रहें।

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

श्रमिकों को लाइन से अलग किया गया (या तो गलती से या एक आतंक संकेत द्वारा) तोड़फोड़ करने वाले, घोंसले को चीरने और दुश्मन के श्रमिकों को बाधित करने का प्रयास करते हुए वे आते हैं। वे सक्रिय रूप से गठन से बचेंगे यदि वे इसे भर में चलाते हैं, क्योंकि पुन: निगमन अव्यवहारिक है।

खाद्य संग्रह

जब भोजन का सामना होता है, तो लाइन रुक जाती है। हालाँकि, क्योंकि सिग्नल केवल लाइटस्पेड अपस्ट्रीम का प्रबंधन कर सकते हैं, सिग्नल को ऊपर की ओर फैलने में समय लगता है, जिससे अपस्ट्रीम एक सीधी रेखा में झुक जाती है। अंत में चींटियां इसे हुक में झुकने से पूरी तरह से सीधा होने से रोकती हैं, लेकिन वे भी रुके हुए हैं।

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

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

एक बार जब रेखा मार्च करने के लिए वापस जाती है, तो स्टाल्ड श्रमिक अपना मार्च फिर से शुरू कर देते हैं क्योंकि लाइन उनके पास पहुंच जाती है। यह प्रक्रिया चींटियों के पास होती है क्योंकि सिग्नल उनके पास आते हैं, इसलिए यह पूरी तरह से व्यावहारिक है (और ऐसा होता है) कि रेखा फिर से शुरू होती है जब वास्तविक संकेत लाइन के अंत तक पहुंचता है, या लाइन के ऊपर के हिस्से के लिए नीचे की तरफ रुकने से पहले। यह एक वास्तविक संकेत डाउनस्ट्रीम प्राप्त करता है।

लाइन से बाहर

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

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

तोड़फोड़ करने वाले कार्यकर्ता एक गठन में गंभीर रूप से समाप्त हो सकते हैं, लेकिन एक रानी की कमी के सही अंत का मतलब यह होना चाहिए कि वे जल्द ही अलग हो जाएं। यदि ऐसा नहीं है, तो बग दर्ज करें।

अतिरिक्त

रानी लूटपाट का काम प्रगति पर है। श्रमिक दुश्मन श्रमिकों के बजाय भोजन के रूप में दुश्मन रानियों को पहचानेंगे, लेकिन ठीक है कि यह बाद में कैसे परस्पर क्रिया करता है और अछूता नहीं है।

मौजूदा रंग संकेतों को लाइन में हस्तक्षेप करने से रोकने के लिए, कार्यकर्ता आसपास के क्षेत्रों को सफेद रंग में रंग देंगे, यदि वे रंग संकेत भेजेंगे, लेकिन पहले से ही रंग संकेत पर खड़े हैं जो वे भेजना चाहते हैं। यह परिवेश समाशोधन इतना शक्तिशाली है कि एक मार्चिंग गठन समस्याओं के बिना पूरी गति से एक रंगीन घोंसले से ऊब सकता है।

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

करने के लिए

  • तार्किक cruft को साफ करें
  • टेस्ट और रिफाइनिंग क्वीन लूट
  • देखें कि दुश्मन के कार्यकर्ताओं को इधर से उधर किया जा सकता है या नहीं
  • सिग्नल स्थिति में कमी की जांच करें
  • देखें कि क्या अंत में कर्मी की मदद करने के लिए जानबूझकर मदद की जा रही है

रिलीज नोट्स

1.0: पहला संस्करण प्रस्तुत करने के लिए रखा गया, प्रारंभिक रिलीज

1.0.1: तार्किक कटौती का प्रदर्शन किया, अधिक नियंत्रकों के साथ संगत बनाया

1.1: सामान का एक गुच्छा संकुचित, त्रुटि के मामलों से संबंधित बेहतर तर्क

1.1.1: अयोग्यता समस्या को हल करने के लिए हॉटफ़िक्स

1.2: आगे के गतिरोधों को दूर किया, सबोटूर को अब समाप्त कर दिया गया

1.3: रानी की दर में कमी, तोड़फोड़ करने वालों को एक धुन दी

१.३.१: रानी क्वॉन्टेट को और कम कर दिया, और एक अयोग्य बग को ठीक कर दिया

1.4: पैरामीटर ट्यूनिंग


5

स्टीमर चींटियों

/*Ants will try to move diagonally in the following fashion:
 * 2
 * 51
 *
 *Type 1 and queen are the two core ants
 */


switch (view[4].ant.type) {

  case 1: //Guiding ant
    //Look for queen, try to move diagonally
    if (view[7].ant && view[7].ant.friend && view[7].ant.type === 5 && !view[8].ant) return {cell: 8};
    else if (view[5].ant && view[5].ant.friend && view[5].ant.type === 5 && !view[2].ant) return {cell: 2};
    else if (view[3].ant && view[3].ant.friend && view[3].ant.type === 5 && !view[6].ant) return {cell: 6};
    else if (view[1].ant && view[1].ant.friend && view[1].ant.type === 5 && !view[0].ant) return {cell: 0};
    else return {cell: 4};
  case 2: //Other wing
    //Look for queen, try to move diagonally. If there is food, rotate the other way to start rotating procedure
    if (view[7].ant && view[7].ant.friend && view[7].ant.type === 5 && !view[6].ant) {
      if (view[6].food) {
        if (!view[8].ant) return {cell: 8};
        else return {cell: 4};
      } else return {cell: 6};
    } else if (view[5].ant && view[5].ant.friend && view[5].ant.type === 5 && !view[8].ant) {
      if (view[8].food) {
        if (!view[2].ant) return {cell: 2};
        else return {cell: 4};
      } else return {cell: 8};
    } else if (view[3].ant && view[3].ant.friend && view[3].ant.type === 5 && !view[0].ant) {
      if (view[0].food) {
        if (!view[6].ant) return {cell: 6};
        else return {cell: 4};
      } else return {cell: 0};
    } else if (view[1].ant && view[1].ant.friend && view[1].ant.type === 5 && !view[2].ant) {
      if (view[2].food) {
        if (!view[0].ant) return {cell: 0};
        else return {cell: 4};
      } else return {cell: 2};
    } else return {cell: 4};
  case 5: //Queen ant

    //If forever alone
    if (!view[1].ant && !view[3].ant && !view[5].ant && !view[7].ant) {
      if (view[4].color === 2) { //If on colored square, try to move
        if (view[0].color === 2 && !view[8].ant) return {cell: 8};
        else if (view[2].color === 2 && !view[6].ant) return {cell: 6};
        else if (view[6].color === 2 && !view[2].ant) return {cell: 2};
        else if (view[8].color === 2 && !view[0].ant) return {cell: 0};
        //Can't find color, or path is blocked? try diagonals regardless of color
        else if (!view[0].ant) return {cell: 0};
        else if (!view[2].ant) return {cell: 2};
        else if (!view[6].ant) return {cell: 6};
        else if (!view[8].ant) return {cell: 8};
        //Everything else failed? Stay put.
        else return {cell: 4};
      } else { //If not on colored square, look for food, or set current color to 2.
        if (view[4].ant.food >= 1) { //Try to make Guiding ant
          if (!view[1].ant && !view[1].food) return {cell: 1, type: 1};
          else if (!view[3].ant && !view[3].food) return {cell: 3, type: 1};
          else if (!view[5].ant && !view[5].food) return {cell: 5, type: 1};
          else if (!view[7].ant && !view[7].food) return {cell: 7, type: 1};
        }
        for (var i = 0; i < 9; i++) { //Look for food
          if (view[i].food) return {cell: i};
        }
        return {cell: 4, color:2};
      }
    } else { //Queen has partner
      //Make other wing
      if (view[4].ant.food >= 1) {
        if (view[1].ant && view[1].ant.friend && view[1].ant.type === 1 && !view[3].ant && !view[3].food && !view[5].ant) return {cell: 3, type: 2};
        else if (view[3].ant && view[3].ant.friend && view[3].ant.type === 1 && !view[7].ant && !view[7].food && !view[1].ant) return {cell: 7, type: 2};
        else if (view[5].ant && view[5].ant.friend && view[5].ant.type === 1 && !view[1].ant && !view[1].food && !view[7].ant) return {cell: 1, type: 2};
        else if (view[7].ant && view[7].ant.friend && view[7].ant.type === 1 && !view[5].ant && !view[5].food && !view[3].ant) return {cell: 5, type: 2};
      }

      //If food is orthogonal to Queen, stay put
      if (view[1].food || view[3].food || view[5].food || view[7].food) return {cell: 4};

      //Look for guiding type 1 ant, try to move diagonally
      else if (view[7].ant && view[7].ant.friend && view[7].ant.type === 1 && !view[6].ant) return {cell: 6};
      else if (view[5].ant && view[5].ant.friend && view[5].ant.type === 1 && !view[8].ant) return {cell: 8};
      else if (view[3].ant && view[3].ant.friend && view[3].ant.type === 1 && !view[0].ant) return {cell: 0};
      else if (view[1].ant && view[1].ant.friend && view[1].ant.type === 1 && !view[2].ant) return {cell: 2};
    }
  default: return {cell: 4};
}

ये चींटियां डेव के फॉरेंसिक चींटियों के समान अवधारणा से दूर काम करती हैं । हालाँकि, वे तिरछे चलते हैं, और 3 के समूहों में चलते हैं।

चरण 1: खाद्य हाथापाई

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

चरण 2: 2 चींटियों

रानी एक नया प्रकार 1 "मार्गदर्शक" चींटी बनाती है, जो रानी के साथ मिलकर तिरछे कदम के साथ चलती है। वे प्रत्येक यह पता लगाते हैं कि कौन सा तरीका उनके संबंधित भागीदारों के सापेक्ष आगे है।

चरण 3: स्टीमरोलिंग

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

घूर्णन

यदि टाइप 2 चींटी देखती है कि वह कुछ खाने में चली जाएगी, तो वह दूसरी दिशा में चली जाएगी, जहां टाइप 1 चींटी हुआ करती थी। इसका मतलब यह है कि सभी चींटियों ने उस दिशा को घुमाया होगा जिसमें वे चलती हैं, और इसलिए चींटियों को अपने शुरुआती बिंदु पर वापस लपेटने की बहुत कम संभावना होनी चाहिए।

नोट: यदि किसी कारण से (शायद एक अन्य चींटी के साथ टकराव?) टाइप 2 चींटी का जन्म टाइप 1 चींटी से पहले हुआ था, तो इस घुमाव के परिणामस्वरूप टाइप 2 चींटी टाइप 1 चींटी पर जाने की कोशिश करेगी। इसे हल करने के लिए, टाइप 2 चींटी इसके बजाय खुद को पीछे छोड़ देगी, और रानी को दूसरी प्रकार की 2 चींटी बनाने देंगी।


अपने एक प्रयोग के दौरान मैंने पाया कि भोजन की तलाश करते समय बेतरतीब ढंग से बदलती दिशा अनंत लपेटने से बचने के लिए काफी प्रभावी हो सकती है। यह नई जमीन को कवर करने वाले हर कदम की संभावना को कम करता है, लेकिन शायद यह यहां उपयोगी हो सकता है?
डेव

@ दिशा बदलने के बारे में बताएं कि मुझे क्या चिंता है। अगर मैं अपने किसी भी कार्यकर्ता को खोए बिना दिशा बदलने का रास्ता खोज सकता हूं, तो यह विचार निश्चित रूप से काम करेगा। यदि नहीं, तो मैं एक कार्यकर्ता के पीछे जाने के लिए एक मार्कर के रूप में एक रंग रखने की कोशिश कर सकता हूं, और रानी की दिशा बदल सकती है।
के झांग

@trichoplax क्या आप उस बीज को जानते हैं जो उस अयोग्यता के दौरान इस्तेमाल किया गया था, और शायद चाल संख्या भी? उस मुद्दे को जानने के लिए उन परिस्थितियों को जानना बहुत फायदेमंद होगा।
के

@trichoplax Nevermind, मैं अभी गया और कुछ अतिरिक्त पवित्रता जांच जोड़े। यह (उम्मीद है कि) अब अयोग्य नहीं होगा।
के झांग

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

5

मेडुसा

function clean(move) {
    if (move["color"] == undefined) {
        if (view[move["cell"]].ant != null) {
            move = {
                cell: 4
            }
        }
        if (move["type"] == undefined) {
            if (view[4].ant.type == 5 && move["cell"] != 4 && view[move["cell"]].color > 2) {
                move["color"] = 1
            }
            if (view[move["cell"]].food == 1 && view[4].ant.type < 5 && view[4].ant.food > 0) {
                move = {
                    cell: 4
                }
            }
        } else if (view[4].ant.type != 5 || view[4].ant.food == 0 || view[move["cell"]].food != 0) {
            move = {
                cell: 4
            }
        }
    }
    return move
}

function coord(cell) {
    var x = (cell % 3) - 1
    var y = 1 - (cell - (cell % 3)) / 3
    return {
        x: x,
        y: y
    }
}

function getcell(x, y) {
    return (x + 1) + (1 - y) * 3
}

var diags = [0, 2, 8, 6]

var colorcounts = [0, 0, 0, 0, 0, 0, 0, 0, 0];
for (var i = 0; i < 9; i++) {
    colorcounts[view[i].color]++
}

var queen = -1
for (var i = 0; i < 9; i++) {
    if (view[i].ant != null && view[i].ant.friend == true && view[i].ant.type == 5) {
        queen = i
    }
}

var guard = -1
for (var i = 0; i < 9; i++) {
    if (view[i].ant != null && view[i].ant.friend == true && view[i].ant.type == 1) {
        guard = i
    }
}

var forager = -1
for (var i = 0; i < 9; i++) {
    if (view[i].ant != null && view[i].ant.friend == true && view[i].ant.type == 2) {
        forager = i
    }
}

var black = -1
for (var i = 0; i < 9; i++) {
    if (view[i].color == 8) {
        black = i
    }
}

var yellow = -1
for (var i = 0; i < 9; i++) {
    if (view[i].color == 2) {
        yellow = i
    }
}


if (view[4].ant.type == 5) {
    if (forager >= 0 && view[forager].color == 8) {
        return clean({
            cell: forager,
            color: 2
        })
    }

    if (guard == -1) {
        if (view[4].color == 3) {
            if (view[4].ant.food > 1) {
                return clean({
                    cell: 0,
                    type: 2
                })
            }
            return clean({
                cell: 0,
                type: 1
            })
        }
        if (view[4].ant.food >= 3) {
            return clean({
                cell: 4,
                color: 3
            })
        }
        if (view[4].color == 1) {
            return clean({
                cell: 4,
                color: 2
            })
        }
        for (var i = 0; i < 9; i++) {
            if (view[i].food == 1) {
                return clean({
                    cell: i
                })
            }
        }
        for (var i = 0; i < 4; i++) {
            if (view[diags[i]].color != 2 && view[diags[(i + 2) % 4]].color == 2) {
                return clean({
                    cell: diags[i]
                })
            }
        }
        return clean({
            cell: 0
        })
    }

    var state = 3
    var max = 0
    for (var i = 3; i <= 4; i++) {
        if (colorcounts[i] > max) {
            max = colorcounts[i]
            state = i
        }
    }

    if (state == 3) {
        if (black >= 0 && forager == -1) {
            return clean({
                cell: black,
                type: 2
            })
        }
        if (forager >= 0 && view[forager].color != 2) {
            return clean({
                cell: 0,
                color: 8
            })
        }
        if (colorcounts[3] == 9) {
            return clean({
                cell: 4,
                color: 4
            })
        }
    }
    if (state == 4) {
        if (colorcounts[4] == 9) {
            return clean({
                cell: 4,
                color: 3
            })
        }
    }
    return clean({
        cell: 4
    })
}
if (view[4].ant.type == 1) {
    var dest = 0
    var destmap = [1, 0, 1, 1, 4, 1, 7, 8, 7]
    dest = destmap[queen]
    if (view[queen].color != view[dest].color && (view[queen].color == view[4].color || view[4].color == view[dest].color)) {
        if (queen < 4 && view[dest].color > 2 && view[dest].color < 5) {
            return clean({
                cell: queen,
                color: view[dest].color
            })
        }
        return clean({
            cell: dest,
            color: view[queen].color
        })
    }
    return clean({
        cell: dest
    })
}
if (view[4].ant.type == 2) {
    if (queen >= 0 && view[4].color == 8) {
        return clean({
            cell: 4
        })
    }
    var state = 3
    var max = 0
    for (var i = 5; i <= 7; i++) {
        if (colorcounts[i] > max) {
            max = colorcounts[i]
            state = i
        }
    }
    var flowx = 0
    var flowy = 0
    for (var i = 0; i < 9; i++) {
        for (var j = i + 1; j < 9; j++) {
            var loci = coord(i)
            var locj = coord(j)
            var dx = locj.x - loci.x
            var dy = locj.y - loci.y
            var cyc = 0
            if (view[i].color >= 5 && view[i].color <= 7 && view[j].color >= 5 && view[j].color <= 7) {
                var cyc = ((view[j].color - view[i].color) % 3 + 3) % 3
                if (cyc == 2) {
                    cyc = -1
                }
            } else if (view[i].color >= 5 && view[i].color <= 7) {
                cyc = 0.1
            } else {
                cyc = -0.1
            }
            flowx += cyc * dx / (dx * dx + dy * dy)
            flowy += cyc * dy / (dx * dx + dy * dy)

        }
    }
    if (flowx * flowx > flowy * flowy) {
        flowy = 0
    } else {
        flowx = 0
    }
    if (flowx < 0) {
        flowx = -1
    }
    if (flowy < 0) {
        flowy = -1
    }
    if (flowx > 0) {
        flowx = 1
    }
    if (flowy > 0) {
        flowy = 1
    }
    if (queen >= 0) {
        var locq = coord(queen)
        flowx = -locq.x
        flowy = -locq.y
        state = 5
    }
    if (view[4].ant.food > 0) {
        if (guard >= 0) {
            var destmap = [1, 0, 1, 1, 4, 1, 7, 8, 7]
            return clean({
                cell: destmap[guard]
            })
        }
        dest = getcell(-flowx, -flowy)
        if (dest != 7) {
            dest = 1
        }
        if (view[dest].color >= 5 && view[dest].color <= 7) {
            return clean({
                cell: dest
            })
        }
        if (view[dest - 1].color >= 5 && view[dest - 1].color <= 7) {
            return clean({
                cell: dest - 1
            })
        }
        return clean({
            cell: 4
        })
    }
    if (view[4].color >= 5 && view[4].color <= 7) {
        state = view[4].color
    }
    var nextc = ((state - 4) % 3 + 5)
    var prevc = ((state - 3) % 3 + 5)
    var centerdest
    centerdest = getcell(flowx, flowy)
    if (view[centerdest].color != state && view[centerdest].color != nextc) {
        return clean({
            cell: centerdest,
            color: nextc
        })
    }
    for (var dest = 1; dest < 9; dest++) {
        var locd = coord(dest)
        var net = locd.x * flowx + locd.y * flowy
        if (net > 0 && view[dest].color != view[centerdest].color) {
            return clean({
                cell: dest,
                color: view[centerdest].color
            })
        }
    }
    for (var dest = 0; dest < 9; dest++) {
        if (view[dest].food == 1) {
            if (view[dest].color >= 5 && view[dest].color <= 7) {
                return clean({
                    cell: dest
                })
            }
            return clean({
                cell: dest,
                color: state
            })
        }
    }
    if (centerdest == 4 && view[0].color >= 5 && view[0].color <= 7) {
        return clean({
            cell: 0
        })
    }
    if (centerdest > 0 && view[centerdest - 1].color >= 5 && view[centerdest - 1].color <= 7) {
        return clean({
            cell: centerdest - 1
        })
    }
    return clean({
        cell: centerdest
    })
}

यह बॉट ... अच्छा नहीं है, लेकिन यह कई शांत रणनीतियों का उपयोग करता है जो मुझे लगता है कि मेरे भविष्य के एंट बॉट में शामिल होंगे। इसका नाम उस आकार से आता है जो कॉलोनी गेम बोर्ड पर बनाती है।

कार्रवाई में मेडुसा

चरण 1: प्रारंभिक निवेश

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

चरण 2: उपनिवेश

यहाँ, तीन प्रकार की चींटियाँ विभिन्न भूमिकाएँ निभाती हैं:

रानी

गार्ड की सहायता से रानी धीरे-धीरे दो राज्यों के बीच दोलन करती है। वर्तमान स्थिति वह है जो निर्धारित करती है कि भोजन का एक नया अधिग्रहीत टुकड़ा एक श्रमिक में बदल गया है या नहीं, इसलिए लगभग 50% भोजन कॉलोनी में पुनः निवेश किया जाता है। रानी युक्त पूरे 3x3 क्षेत्र का उपयोग राज्य को संग्रहीत करने के लिए किया जाता है, ताकि किसी भी क्षरण को पूर्ववत किया जा सके और राज्य को पुनः प्राप्त किया जा सके।

रक्षक

गार्ड रानी के बगल में अपना पूरा जीवन जीता है, इसे बेतरतीब ढंग से चक्कर लगाता है।

रानी की स्थिति बनाए रखने में गार्ड की अहम भूमिका होती है। यह रानी के 3x3 क्षेत्र में किसी भी त्रुटि को ठीक करने का प्रयास करता है। जब क्षेत्र में दो वैध वैकल्पिक रंग होते हैं, तो दोनों में से कौन सा रंग "सुधारा गया" राज्य अपेक्षाकृत यादृच्छिक है। एक बार जब कोई सहमति बन जाती है, तो रानी अपने वर्ग को विपरीत रंग में ला देती है, फिर से प्रक्रिया शुरू कर देती है। यह वही है जो रानी के राज्य के दोलन का कारण बनता है, और यह बहुत ही त्रुटि-प्रतिरोधी तरीके से किया जाता है।

गार्ड रानी के "महल" के द्वारपाल के रूप में भी काम करता है। जब एक फोरगार्ड गार्ड को देखता है, तो वह रानी के बगल में जा सकता है, भले ही रानी दृश्य सीमा से बाहर हो।

foragers

जब वे कॉलोनी छोड़ते हैं, तो ग्रामीण चक्रीय लाल-हरे-नीले पैटर्न का पालन करते हैं, और जब वे भोजन ले जा रहे होते हैं, तो पीछे की ओर जाते हैं। वे काफी विस्तृत क्षेत्र को चित्रित करते हैं, क्योंकि वास्तव में व्यापक पथ यह सुनिश्चित करने के लिए आवश्यक हैं कि रास्ते बहुत पेचीदा न हों और कुछ कोशिकाओं के क्षतिग्रस्त होने पर भी वे अपना रास्ता वापस पा सकें।

एक वनपाल का विशिष्ट पथ:

फोरगर पथ

ध्यान दें कि यह आमतौर पर एक सीधी रेखा में कैसे यात्रा करता है लेकिन कभी-कभी 90 डिग्री पर मुड़ता है। यह जिस तरह से बेतरतीब ढंग से अपने रास्ते के भीतर चलता है, इसका एक परिणाम है क्योंकि यह इसे नीचे रख रहा है।


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

@ppperry कभी-कभी ऐसा करता है।
PhiNotPi

क्या केवल साइकिल r-> b-> g-> r में जाने से श्रमिकों को अधिक कुशलता से वापस करना संभव होगा?
कैलक्यूलेटरफैलन

@trichoplax मुझे एहसास नहीं था कि ऐसा कुछ था जिसे करने की अनुमति नहीं थी। अब जो भी तय हो।
PhiNotPi

यह "अयोग्यता" के तहत था: "एक श्रमिक का उत्पादन करने के लिए सेल खाली नहीं है।" लेकिन मैंने इसे अब और अधिक स्पष्ट करने के लिए कल्पना को संपादित किया है: "एक श्रमिक का उत्पादन करने के लिए सेल खाली नहीं है (भोजन या एक चींटी शामिल है)।"
ट्राइकोप्लाक्स

5

ब्राउनियन जिग

यह खिलाड़ी कोई श्रमिक नहीं पैदा करता है, और रानी बेतरतीब ढंग से चलती है। रैंडम मोशन इसलिए होता है क्योंकि हर बार रानी एक ही दिशा में लौटती है, लेकिन इनपुट दिखाई देने वाली कोशिकाओं को प्रत्येक चाल में एक यादृच्छिक अभिविन्यास में प्रस्तुत किया जाता है, जिससे गति सीधी रेखा में होती है।

एक उत्तर में पहला कोड ब्लॉक होता है, जो स्वचालित रूप से खेल में शामिल होता है:

// Full version that won't be disqualified for moving onto another ant

// Move to food if visible
for (var i=0; i<9; i+=1) {
    if (view[i].food) {
        return {cell:i}
    }
}

// Otherwise move to one of the diagonal cells if not occupied
for (var i=0; i<9; i+=2) {
    if (!view[i].ant) {
        return {cell:i}
    }
}

// Otherwise one of the vertical or horizontal cells if not occupied
for (var i=1; i<9; i+=2) {
    if (!view[i].ant) {
        return {cell:i}
    }
}

// Otherwise don't move at all
return {cell:4}

यहाँ एक सरल संस्करण है जो अन्य चींटियों के लिए जाँच नहीं करता है, लेकिन जब तक यह एक और चींटी पर कदम रखने की कोशिश करने के लिए अयोग्य नहीं हो जाता है तब तक समान व्यवहार होता है:

// Basic version for an intuitive understanding

// Move to food if visible
for (var i=0; i<9; i+=1) {
    if (view[i].food) {
        return {cell:i}
    }
}

// Otherwise move "up and left", which will be a random direction
return {cell:0}

यह दूसरा कोड ब्लॉक गेम द्वारा नहीं उठाया जाएगा - इसका मतलब है कि आप अपने जवाब के विवरण के हिस्से के रूप में अतिरिक्त कोड ब्लॉक शामिल कर सकते हैं। बस यह सुनिश्चित करें कि गेम में जिस कोड ब्लॉक को आप प्रतिस्पर्धा करना चाहते हैं, वह उत्तर में पहला है।

इनपुट के यादृच्छिक अभिविन्यास के बावजूद सीधी रेखा आंदोलन के उत्पादन के उदाहरण के लिए, रोमनस्को रोड देखें ।


रंगों को चिह्नित करने की आवश्यकता क्यों है?
सोलोमन उको

1
अच्छा प्रश्न। यह लोगों को नियमों को लेने में मदद करने के लिए कुछ देने के लिए केवल एक प्रारंभिक उदाहरण उत्तर है। यह केवल किसी भी रंग को चिह्नित नहीं करके दो बार उच्च स्कोर कर सकता है, लेकिन एक उदाहरण के रूप में मैं चाहता था कि इसका रास्ता समझ सहायता के लिए स्पष्ट रूप से दिखाई दे।
त्रिकोप्लक्स

मैं देखता हूं, समझ में आता है।
सोलोमन उको

मैंने अब रंग अंकन को हटाने के लिए संपादित किया है, क्योंकि यह एक अनावश्यक (और निरर्थक) व्याकुलता थी। दिखाई देने पर रानी अब भोजन की ओर बढ़ेगी, और अधिक जमीन को ढकने के लिए विकर्ण चाल का समर्थन करेगी। किसी भी रंग का इस्तेमाल नहीं किया जाता है।
ट्राइकोप्लाक्स

4

ला रेने ब्ल्यू

var Queen = 5;
var QueenTrail = [];
var EnemyAnts = [];
var EnemyColors = [];
var QueenTrailColor = 7;
var QueenTrailColor2 = 8;
var QueensPosition = -1; //Future use...

var rotations =   
[ 0,1,2,
  3,4,5,
  6,7,8,

  6,3,0,
  7,4,1,
  8,5,2,

  8,7,6,
  5,4,3,
  2,1,0,

  2,5,8,
  1,4,7,
  0,3,6];

var moves = [];
getMoves();
return findBestMove();

function getMoves()
{
    var matchIdx = -1;
    //Initialization of current state
    for(ii = 0; ii < 9; ii++)
    {
        if(ii != 4)
        {
            if(view[ii].color == QueenTrailColor)
            {
                QueenTrail.push(ii);
            }
            else if(view[ii].color == QueenTrailColor2)
            {
                QueenTrail.push(ii);
            }
            else if(view[ii].color != 1)
            {
                EnemyColors.push(ii);
            }
        }

        if(ii != 4 && view[ii].ant != null)
        {
            if(view[ii].ant.friend)
            {
                if(view[ii].ant.type == Queen)
                {
                    QueensPosition = ii * ii;
                }
            }
            else
            {
                EnemyAnts.push(ii);
            }
        }
    }

    switch (view[4].ant.type) 
    {
        case Queen:
        {        
            //first get the food
            for (var ii = 0; ii < 9; ii++) 
            {
                if (view[ii].food > 0 && view[ii].ant == null) 
                {
                    moves.push(getCell(ii)) ;
                }
            }
            if(EnemyAnts.length == 0)
            {
                lm(AA(-QueenTrailColor),AA(4), {cell:4, color:QueenTrailColor});
            }

            if(QueenTrail.length >= 5 || EnemyAnts.length > 0)
            {
                lm(AA(-QueenTrailColor), AA(0,1,2),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,1,3),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,1,5),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,1,6),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,1,7),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,1,8),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,2,3),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,2,6),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,2,7),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,3,7),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,3,8),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,5,7),{cell:0});
                lm(AA(-QueenTrailColor), AA(1,2,7),{cell:1});
                lm(AA(-QueenTrailColor), AA(1,3,5),{cell:1});
                lm(AA(-QueenTrailColor), AA(0,1),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,2),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,3),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,5),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,7),{cell:0});
                lm(AA(-QueenTrailColor), AA(0,8),{cell:0});
                lm(AA(-QueenTrailColor), AA(1,3),{cell:1});
                lm(AA(-QueenTrailColor), AA(1,7),{cell:1});
            }
            if(QueenTrail.length == 4)
            {
                lmQT(AA(0,1,2,3),{cell:7});
                lmQT(AA(0,1,2,5),{cell:7});
                lmQT(AA(0,1,2,6),{cell:7});
                lmQT(AA(0,1,2,7),{cell:5});
                lmQT(AA(0,1,2,8),{cell:7});
                lmQT(AA(0,1,3,5),{cell:7});
                lmQT(AA(0,1,3,7),{cell:8});
                lmQT(AA(0,1,3,8),{cell:2});
                lmQT(AA(0,1,5,6),{cell:8});
                lmQT(AA(0,1,5,7),{cell:6});
                lmQT(AA(0,1,5,8),{cell:3});
                lmQT(AA(0,1,6,7),{cell:8});
                lmQT(AA(0,1,6,8),{cell:2});
                lmQT(AA(0,1,7,8),{cell:2});
                lmQT(AA(0,2,3,7),{cell:8});
                lmQT(AA(0,2,3,8),{cell:6});
                lmQT(AA(0,2,6,8),{cell:1});
                lmQT(AA(0,3,5,7),{cell:2});
                lmQT(AA(0,3,5,8),{cell:2});
                lmQT(AA(1,3,5,7),{cell:0});
            }
            if(QueenTrail.length == 1)
            {                
                lmQT(AA(0), {cell:8});
                lmQT(AA(1), {cell:7});
            }
            else if(QueenTrail.length == 0)
            {
                moves.push(getCell(1));
            }

            if(QueenTrail.length == 0) // starting out or someone is messing with us
            {
                moves.push( getCellColor(1, QueenTrailColor));
            }    
            else if (QueenTrail.length >= 5) //queen is stuck? move her randomly until we get a straight trail
            {    
                moves.push( getCellColor(1, QueenTrailColor2));
            }
            else if (QueenTrail.length >= 3)
            {
                lmQT(AA(0,1,2),{cell:3});
                lmQT(AA(0,1,3),{cell:7});
                lmQT(AA(0,1,5),{cell:3});
                lmQT(AA(0,1,6),{cell:7});
                lmQT(AA(0,1,7),{cell:3});
                lmQT(AA(0,1,8),{cell:3});
                lmQT(AA(0,2,3),{cell:6});
                lmQT(AA(0,2,6),{cell:3});
                lmQT(AA(0,2,7),{cell:1});
                lmQT(AA(0,3,7),{cell:8});
                lmQT(AA(0,3,8),{cell:5});
                lmQT(AA(0,5,7),{cell:6});
                lmQT(AA(1,2,7),{cell:0});
                lmQT(AA(1,3,5),{cell:6});
            }
            else if(QueenTrail.length == 2)
            {
                lmQT(AA(0,1),{cell:7});
                lmQT(AA(0,2),getCellColor(1, QueenTrailColor));
                lmQT(AA(0,3),{cell:6});
                lmQT(AA(0,5),{cell:1});
                lmQT(AA(0,7),{cell:3});
                lmQT(AA(0,8),{cell:3});
                lmQT(AA(1,3),{cell:6});
                lmQT(AA(1,7),{cell:0});
            }
            else if(QueenTrail.length == 1) //we are either going in a straight line or trapped?
            {    
                if(view[4].ant.food > 0)
                {
                    lmQT(AA(0), getCell(0));
                    //clear out the area for the ants
                    if(EnemyColors.length > 0)
                    {
                        moves.push( getCellColor(EnemyColors[0],1));
                    }
                }
                lmQT(AA(0), getCell(8));
                lmQT(AA(1), getCell(7));
                lmQT(AA(2), getCell(6));
            }
            break;
        }
    }
    moves.push( getCell(4));
}

function leftOfPos(x)
{
    if (x == 0)
    {
        return 3;
    }
    else if (x == 1)
    {
        return 0;
    }
    else if (x == 2)
    {
        return 1;
    }
    else if (x == 3)
    {
        return 6;
    }
    else if (x == 5)
    {
        return 2;
    }
    else if (x == 6)
    {
        return 7;
    }
    else if (x == 7)
    {
        return 8;
    }
    else if (x == 8)
    {
        return 5;
    }
}

function findBestMove() 
{
    var keeper = 0;
    for(var ii = 0; ii < moves.length ; ii++)
    {
        if(moves[ii].cell < 0 || moves[ii].cell > 8 || (moves[ii].cell != 4 && (moves[ii].color == null || moves[ii].color == 0) && view[moves[ii].cell].ant != null) || (view[moves[ii].cell].food > 0 && (view[4].ant.food > 0 && view[4].ant.type < 5))) 
        {
            continue;
        }
        else if(moves[ii].type != null && (view[moves[ii].cell].ant != null || view[moves[ii].cell].food > 0 || view[0].color == 1)) //semi random here. 
        {
            continue;
        }
        else
        {
            keeper = ii;
            break;
        }
    }
    return moves[keeper];
}

function lm(matchingColors, coords, matchCell)
{
    var matchTarget = coords.length ;
    var matchCount = [0,0,0,0];
    var returnVal = -1;
    for(var ii = 0; ii < coords.length; ii++)
    {        
        for(var jj = 0; jj < 4; jj++)
        {
            var actualIndex = rotations[coords[ii] + (jj * 9)];
            var foundMatch = false;
            for(var kk = 0; kk < matchingColors.length; kk++)
            {
                var matchingColor = matchingColors[kk];

                if(matchingColor >= 1 && matchingColor <= 8 && view[actualIndex].color == matchingColor)
                {
                    foundMatch = true;
                    break;
                }    
                else if(matchingColor < 0 && view[actualIndex].color != -matchingColor)
                {
                    foundMatch = true;
                    break;
                }
            }
            if(foundMatch)
            {
                matchCount[jj] = matchCount[jj] + 1;
                if(matchCount[jj] == matchTarget)
                {
                    matchCell.cell = rotations[matchCell.cell + (jj * 9)];
                    moves.push(matchCell);
                    returnVal = jj;
                }
            }
        }
    }
    return returnVal;
}

function lmQT(coords, matchCell)
{
    return lm(AA(QueenTrailColor, QueenTrailColor2), coords,matchCell);
}

function AA()
{
    return arguments;
}

function getCell(x)
{
    return {cell:x};
}

function getCellColor(x, y)
{
    return {cell:x, color:y};
}

नीली रानी एक नीले निशान को छोड़ देगी, वह काले रंग से बचती है और अगर 'अटक' जाती है तो काले टुकड़ों को छोड़ देती है।

वह सभी 4 घुमावों का उपयोग करके विशिष्ट नीले / काले "आकार" की तलाश करती है और संभावित चालों की एक सूची बनाती है। अयोग्य चाल को हटा दिया जाता है और एक एकल परिणाम चुना जाता है। रानी कुछ अनुमान लगाने योग्य है, लेकिन कुछ आकार यादृच्छिकता का कारण बनेंगे। वह इस तथ्य के कारण भोजन खोजने के बाद ज्यादातर दिशाओं को बदल देगा कि अभिविन्यास बदल जाएगा जो पहले खोजे जाते हैं।


3
साइट पर आपका स्वागत है! :)
DJMcMayhem

यहाँ रहना अच्छा है!
कुछ धावक पुरुष

4

FireFlyMkII

ध्यान दें कि जब तक मेरा प्रवेश पूरा नहीं हो जाता है, यह कोड बदसूरत होगा क्योंकि यह मेरे मास्टर डेवलपमेंट स्रोत से ट्रांस-संकलित है जो जावा में किया जा रहा है।

    // maps current view's cells' indecies to the rotated cell's location's indecies for each direction
    var rotate = 
            [[0,1,2,3,4,5,6,7,8],
             [2,5,8,1,4,7,0,3,6],
             [8,7,6,5,4,3,2,1,0],
             [6,3,0,7,4,1,8,5,2]];

    // the colours that form the pattern of the trail back to the queen
    var TRAIL_COLOR_A = 8;
    var TRAIL_COLOR_B = 2;
    var TRAIL_COLOR_C = 5;
    var trailColours = [TRAIL_COLOR_A,TRAIL_COLOR_B,TRAIL_COLOR_C];
    var trailColoursLookUp = [-1,-1,1,-1,-1,2,-1,-1,0];

    var ORIENTATION_MARKER = 8;

    // Queens Modes
    var QUEEN_MODE_HUNTING_MOVING = 6;
    var QUEEN_MODE_HUNTING_PAINTING = 1;
    var QUEEN_MODE_RESETTING = 5;
    var QUEEN_MODE_RESETTING_SPAWNING = 3;
    var QUEEN_MODE_COUNTING_EVEN = 7;
    var QUEEN_MODE_COUNTING_ODD = 4;
    var QUEEN_MODE_NESTING = 2;

    // the number of non-blank (i.e. not colour 1 ) colours to used to encode the queen's worker spawn counter. Min of 1. Max of 7
    var SPAWN_COUNTER_NON_BLANK_COLOURS_COUNT = 7;


    // the maximum number that can be encoded using the queen's worker spawn counter
    var SPAWN_COUNTER_MAX = SPAWN_COUNTER_NON_BLANK_COLOURS_COUNT*SPAWN_COUNTER_NON_BLANK_COLOURS_COUNT*SPAWN_COUNTER_NON_BLANK_COLOURS_COUNT -1;//SPAWN_COUNTER_NON_BLANK_COLOURS_COUNT * SPAWN_COUNTER_USED_CELLS_COUNT_MAX;

    // the minimum game ticks between spawning a worker. Min of 0, Max of SPAWN_COUNTER_MAX
    var TICKS_BETWEEN_FOOD_RETURN_MAX = 50;

    // No Operation... i.e. stay put do nothing
    var NO_OP = {cell:4};

    var ANT_TYPE_WORKER = 1; 
    var ANT_TYPE_QUEEN = 5;

    var orientationMarkerRotation = -1;

    var i=0;
    var j=0;

    // returns true of the provided colour is a trail colour
function isTrailColour(colour)
    {
        return colour === trailColours[0] || colour === trailColours[1] || colour === trailColours[2];
    }

    // returns the colour of the colour in the trail away from queen
function nextTrailColor(currentTrailColour)
    {
        return trailColours[(trailColoursLookUp[currentTrailColour]+1)%3];
    }

    // returns the colour of the colour in the trail toward from queen
function prevTrailColor(currentTrailColour)
    {
        return trailColours[(3+trailColoursLookUp[currentTrailColour]-1)%3];
    }

    // RNG
function randomNumberGenerator(seed)
    {
        return (1103515245 * seed + 12345) % 2147483647;
    }

    // returns a positive random integer based on the provided ant's view and seed
function randomInt(view,seed)
    {
        for (var i=0;i<9;i++)
        {
            if (view[i].ant !=null)
            {
                seed=randomNumberGenerator(seed+view[i].ant.food);
                seed=randomNumberGenerator(seed+view[i].ant.type);
                seed=randomNumberGenerator(seed+(view[i].ant.friend?1:0));
            }
            seed=randomNumberGenerator(seed+view[i].color);
            seed=randomNumberGenerator(seed+view[i].food);
        }
        return seed<0?-seed:seed;
    }

    // SHUFFLE *NOT* IMPLEMENTED 
function shuffleIndecies(view,seed,range)
    {
        var indecies = new Array(range);

        for (var i=0;i<range;i++)
        {
            indecies[i]=i;
        }

        return indecies;
    }

function processOrientation(view)
    {
        // count orientation markers
        var orientationMarkerCount = 0;
        for (var i=0; i<rotate.length;i++)
        {
            if (view[rotate[i][1]].color === ORIENTATION_MARKER)
            {
                orientationMarkerCount++;
                orientationMarkerRotation = i;
            }
        }

        // corruption detected
        if (orientationMarkerCount >1)
        {
            return {cell:4, color: QUEEN_MODE_RESETTING};
        }

        // place the orientation marker
        if (orientationMarkerCount === 0)
        {
            return {cell:1, color: ORIENTATION_MARKER};
        }
        return null;
    }

function incrementSpawnCounter(view)
    {
        var action = processOrientation(view);
        if (action != null)
        {
            return action;
        }

        var newCount = decodeThreeCellsToInt(view) + 1;

        var MSD = view[rotate[orientationMarkerRotation][3]].color-1;
        var NSD = view[rotate[orientationMarkerRotation][7]].color-1;
        var LSD = view[rotate[orientationMarkerRotation][5]].color-1;

        var MSDisEven =(MSD & 1) ===0;
        var NSDisEven =(NSD & 1) ===0; 

        var MSDdelta =  Math.floor(newCount / 49) - MSD;
        var NSDdelta =  (MSDisEven ? Math.floor(Math.floor(newCount%49)/7) :( 6 - Math.floor(Math.floor(newCount%49)/7))) - NSD;
        var LSDdelta =  (((MSDisEven && NSDisEven) || (!MSDisEven && !NSDisEven)) ? Math.floor(newCount%7) :( 6 - Math.floor(newCount%7))) - LSD;

        // check for roll over 
        if (MSDdelta > 6)
        {
            return {cell:rotate[orientationMarkerRotation][3], color:1};
        }

        // Most Significant Digit (cell) update
        if (MSDdelta != 0)
        {
            return {cell:rotate[orientationMarkerRotation][3], color:(MSD+MSDdelta)+1};
        }

        // Next Significant Digit (cell) update
        if (NSDdelta != 0)
        {
            return {cell:rotate[orientationMarkerRotation][7], color:(NSD+NSDdelta)+1};
        }

        // Least Significant Digit (cell) update
        if (LSDdelta != 0)
        {
            return {cell:rotate[orientationMarkerRotation][5], color:(LSD+LSDdelta)+1};
        }

        return null;
    }

function decodeThreeCellsToInt(view)
    {
        var MSD = view[rotate[orientationMarkerRotation][3]].color-1;
        var NSD = view[rotate[orientationMarkerRotation][7]].color-1;
        var LSD = view[rotate[orientationMarkerRotation][5]].color-1;

        var MSDisEven =(MSD & 1) ===0;
        var NSDisEven =(NSD & 1) ===0; 
        return MSD * 49 + 
               (MSDisEven?NSD:6-NSD) * 7 + 
               ((MSDisEven && NSDisEven) || (!MSDisEven && !NSDisEven)?LSD:6-LSD);
    }
    // Performs a paint command to reset the queen's worker spawn counter to 0.
    // NOTE that is may take multiple calls on sequential game ticks to complete the reset.
    // returns null if the counter is reset
function resetSpawnCounter(view)
    {
        var orientationMarkerCount = 0;
        for (i=1; i<9; i+=2) 
        {
            if (view[i].color === ORIENTATION_MARKER && orientationMarkerCount ===0)
            {
                orientationMarkerCount++;
            }
            else if (view[i].color!=1)
            {
                return {cell:i, color:1};
            }
        }

        // place the orientation marker
        if (orientationMarkerCount === 0)
        {
            return {cell:1, color: ORIENTATION_MARKER};
        }

        return null;
    }


function spawnNewWorker(view,type,defaultAction)
    {
        // ensure that we do not try and create a worker when having no food
        if (view[4].ant.food > 0)
        {
            // now try to spawn an ant
            if (view[1].ant===null && view[1].food===0)
            {
                return {cell:1, type:type};
            }

            // previous spawn cell was blocked, try another 
            if (view[3].ant===null && view[3].food===0)
            {
                return {cell:3, type:type};
            }

            // previous spawn cell was blocked, try another
            if (view[5].ant===null && view[5].food===0)
            {
                return {cell:5, type:type};
            }

            // previous spawn cell was blocked, try another
            if (view[7].ant===null && view[7].food===0)
            {
                return {cell:7, type:type};
            }
        }
        return defaultAction;
    }

function isCellTrailToQueen(cell,currentAntCellColour)
    {
        // is cell containing our queen, or is the cell the next cell colour on the trail back
        return (cell.ant!=null && cell.ant.friend && cell.ant.type === ANT_TYPE_QUEEN) ||
                cell.color === prevTrailColor(currentAntCellColour);
    }

    // entry point into ant logic
function getAction(view)
    {
        var random = 1;
        var food = view[4].ant.food;
        var currentCellColour = view[4].color;

/////////////////////////////////////// QUEEN ///////////////////////////////////////
        if (view[4].ant.type === ANT_TYPE_QUEEN)
        {
            // move to visible food. this queen is greedy!
            for (i=0; i<9; i++) 
            {
                if (view[i].food>0) {
                    return {cell:i};
                }
            }

            // see if we have spawned a worker in the last few turns
            var workerSpawned = false;
            // look in orthogonal cells
            for (i=1; i<9; i+=2) 
            {
                // ant detected and is friendly and of worker type
                if (view[i].ant !=null && view[i].ant.friend && view[i].ant.type===ANT_TYPE_WORKER)
                {
                    workerSpawned=true;
                    break;
                }
            }

            var queenMode = currentCellColour;
            var foodModRemainder=1;

            var minFoodLatch = 0;
            if (food>=500) minFoodLatch = 500;
            else if (food>=400) minFoodLatch = 400;
            else if (food>=300) minFoodLatch = 300;
            else if (food>=200) minFoodLatch = 200;
            else if (food>=100) minFoodLatch = 100;
            else if (food>=50) minFoodLatch = 50;
            else if (food>=20) minFoodLatch = 30;
            else if (food>=20) minFoodLatch = 20;
            else if (food>=10) minFoodLatch = 10;
            else if (food>=5) minFoodLatch = 5;

            switch (queenMode)
            {
                case QUEEN_MODE_HUNTING_MOVING:
                {


                    // move to the cell mirror of the trail cell
                    for (i=0; i<9; i++) {
                        if (view[i].ant===null && view[i].color===QUEEN_MODE_HUNTING_MOVING) {
                            if (view[8-i].ant==null)
                            {
                                return {cell:8-i};
                            }
                        }
                    }

                    // Otherwise move to one of the diagonal cells if not occupied
                    for (i=0; i<9; i+=2) 
                    {
                        if (view[i].ant===null) 
                        {
                            return {cell:i};
                        }
                    }

                    // Otherwise move to one of the vertical or horizontal cells if not occupied
                    for (i=1; i<9; i+=2)
                    {
                        if (view[i].ant===null)
                        {
                            return {cell:i};
                        }
                    }
                    return {cell:4};
                }
                case QUEEN_MODE_HUNTING_PAINTING:
                {
                    // no food found, change to move mode
                    if (food ===0)
                    {
                        // Queenie places a trail
                        return {cell:4, color:QUEEN_MODE_HUNTING_MOVING};
                    }
                    // found food, now change to nesting mode
                    else
                    {
                        return {cell:4, color:QUEEN_MODE_NESTING};
                    }
                }

                // initialise colony
                case QUEEN_MODE_NESTING:
                {
                    // we have spawned a worker so change to counting mode
                    if (workerSpawned===true)
                    {
                        return {cell:4, color:QUEEN_MODE_COUNTING_ODD};
                    }

                    var action = processOrientation(view);
                    if (action != null)
                    {
                        return action;
                    }

                    // ensure that we have the initial band constructed around the queen
                    for (i=0; i<9; i+=2) 
                    {
                        if (i!=4 && view[i].color!=TRAIL_COLOR_A)
                        {
                            return {cell:i, color:TRAIL_COLOR_A};
                        }
                    }

                    // ensure that the counter cells are reset.
                    action = resetSpawnCounter(view);
                    if (action != null)
                    {
                        return action;
                    }

                    // spawn initial worker
                    return spawnNewWorker(view, ANT_TYPE_WORKER, NO_OP);
                }


                case QUEEN_MODE_RESETTING_SPAWNING:

                    // spawn the worker if we have not spawned a worker in the last few turns 
                    if (!workerSpawned===true)
                    {
                        return spawnNewWorker(view, ANT_TYPE_WORKER, NO_OP);
                    }
                    // must have spawned a worker previously, so reset the counter 
                    var action = resetSpawnCounter(view);

                    // still in process of resetting counter...
                    if (action != null)
                    {
                        return action;
                    }


                    // spawn counter as been reset. We will set the queen back to counting mode;
                    return {cell:4, color:food%2===0?QUEEN_MODE_COUNTING_EVEN:QUEEN_MODE_COUNTING_ODD};

                case QUEEN_MODE_RESETTING:

                    action = resetSpawnCounter(view);

                    // still in process of resetting counter...
                    if (action != null)
                    {
                        return action;
                    }


                    // spawn counter as been reset. We will set the queen back to counting mode;
                    return {cell:4, color:food%2===0?QUEEN_MODE_COUNTING_ODD:QUEEN_MODE_COUNTING_EVEN};

                case QUEEN_MODE_COUNTING_ODD:
                    foodModRemainder = 2;
                case QUEEN_MODE_COUNTING_EVEN:
                {
                    foodModRemainder--;

                    action = processOrientation(view);
                    if (action != null)
                    {
                        return action;
                    }

                    var spawnCounter = decodeThreeCellsToInt(view);

                    // repair any damage to the initial band constructed around the queen
                    for (i=0; i<9; i+=2) 
                    {
                        if (i!=4 && view[i].color!=TRAIL_COLOR_A)
                        {
                            return {cell:i, color:TRAIL_COLOR_A};
                        }
                    }

//                    // spawn interval time threshold as been reached and we have food to convert into workers...
//                    if (spawnCounter>=TICKS_BETWEEN_FOOD_RETURN_MAX && food>minFoodLatch)
//                    {
//                        // change to reset spawn counter mode to spawn a new worker
//                        return new Paint(4,QUEEN_MODE_RESETTING_SPAWNING);
//                    }
//
//                    // Check to see if a worker has just returned some food.
//                    if (food>0 && food%2 == foodModRemainder)
//                    {
//                        // change to reset spawn counter mode
//                        return new Paint(4,QUEEN_MODE_RESETTING);
//                    }

                    // Check to see if a worker has just returned some food.
                    if (food>0 && food%2 === foodModRemainder)
                    {

                        // spawn interval time threshold as been reached and we have food to convert into workers...
                        if (spawnCounter>=TICKS_BETWEEN_FOOD_RETURN_MAX && food>0)
                        {
                            // change to reset spawn counter mode to spawn a new worker
                            return {cell:4, color:QUEEN_MODE_RESETTING_SPAWNING};
                        }

                        // change to reset spawn counter mode
                        return {cell:4, color:QUEEN_MODE_RESETTING};
                    }


                    if (spawnCounter < SPAWN_COUNTER_MAX)
                    {
                        // simply increment the counter
                        return incrementSpawnCounter(view);
                    }

                    return NO_OP;
                }
                default:
                {
                }

            }


        }

/////////////////////////////////////// WORKER ///////////////////////////////////////



        var expectedNextPathColourToEdge = nextTrailColor(currentCellColour);

        // worker is looking for food
        if (food===0)
        {
/////////////////////////////////// WORKER HUNTNING //////////////////////////////////    

            // determine whether we are a recently spawned worker
            for (var i=1;i<9;i+=2)
            {
                // are we orthogonal to the queen?
                if (view[i].ant!=null && view[i].ant.friend && view[i].ant.type === ANT_TYPE_QUEEN)
                {
                    // test to see whether queen's counter has reset so worker is free to move
                    if (view[i].color === QUEEN_MODE_COUNTING_ODD || view[i].color === QUEEN_MODE_COUNTING_EVEN )
                    {
                        for (var j=1;j<9;j+=2)
                        {
                            if (view[j].ant===null && view[j].color===TRAIL_COLOR_A)
                            {
                                return {cell:j};
                            }
                        }
                    }
                    // wait until queen's counter has reset
                    return NO_OP;
                }
            }

//            // this is to try and unstick stuck ants... not overly well i might add
//            if (randomInt(view,1)%20==1)
//            {
//                // attempt to pick an empty random trail-cell
//                for (i = randomInt(view,666)%9;i>0;i--)
//                {
//                    if (view[i].ant==null && view[i].food==0 && isTrailColour(view[i].color))
//                    {
//                        return new Move(i);
//                    }
//                }
//            }

            // see if there is any food off band that is enclosed or almost enclosed by trail cells
            // if so, then move to claim the food
            if (view[1].food>0 &&
                isTrailColour(view[0].color) &&
                isTrailColour(view[2].color))
            {
                return {cell:1};
            }

            if (view[3].food>0 &&
                isTrailColour(view[0].color) &&
                isTrailColour(view[6].color))
            {
                return {cell:3};
            }

            if (view[5].food>0 &&
                isTrailColour(view[2].color) &&
                isTrailColour(view[8].color))
            {
                return {cell:5};
            }

            if (view[7].food>0 &&
                isTrailColour(view[6].color) &&
                isTrailColour(view[8].color))
            {
                return {cell:7};
            }


            // if not on trail, attempt see if cells surrounding are trail colours... and set our own cell accordingly
            if (!isTrailColour(currentCellColour))
            {
                for (var priority = 0; priority <4;priority++)
                {
                    // repeat for each rotation
                    var indecies = shuffleIndecies(view,random,4);
                    for (var j=0;j<4;j++)
                    {
                        var r = indecies[j];
                        switch(priority)
                        {
                        // C??  ...
                        // ???  .P.
                        // P?N  ...
                        case 0:
                            if (isTrailColour(view[rotate[r][0]].color) && 
                                nextTrailColor(view[rotate[r][0]].color) === view[rotate[r][8]].color &&
                                prevTrailColor(view[rotate[r][0]].color) === view[rotate[r][6]].color)
                            {
                                return {cell:4, color: view[rotate[r][6]].color};
                            }
                            break;

                        // ??C  ...
                        // ???  .C.
                        // N?C  ...
                        case 1:
                            if (isTrailColour(view[rotate[r][2]].color) && 
                                view[rotate[r][2]].color === view[rotate[r][8]].color &&
                                nextTrailColor(view[rotate[r][2]].color) === view[rotate[r][6]].color)
                            {
                                return {cell:4, color: view[rotate[r][2]].color};
                            }
                            break;

                        // C??  ...
                        // ???  .C.
                        // P??  ...
                        case 2:
                            if (isTrailColour(view[rotate[r][0]].color) && 
                                prevTrailColor(view[rotate[r][0]].color) === view[rotate[r][6]].color)
                            {
                                return {cell:4, color: view[rotate[r][0]].color};
                            }
                            break;

                        // C??  ...
                        // ???  .C.
                        // ???  ...
                        case 3:
                            if (isTrailColour(view[rotate[r][0]].color))
                            {
                                return {cell:4, color: view[rotate[r][0]].color};
                            }
                            break;
                        }
                    }
                }
                // we are completely lost! lets perform a random walk and hopefully find the surface again
                return {cell:view[2].ant === null?2:4};
            }

            // decide worker action...
            for (var priority = 0; priority <13;priority++)
            {
                // repeat for each rotation
                var indecies = shuffleIndecies(view,random,4);
                for (var j=0;j<4;j++)
                {
                    var r = indecies[j];
                    var cellToMoveTo =-1;

                    switch(priority)
                    {
                    /////// AVOID MOVING/PAINTING LOCK-STEP ///////

                    // X?X  ...
                    // ?C?  .M.
                    // C?W  ...

                    case 0:
                        if (view[rotate[r][6]].color === currentCellColour &&
                            !isTrailColour(view[rotate[r][0]].color) &&
                            !isTrailColour(view[rotate[r][2]].color) &&
                            view[rotate[r][8]].ant!=null &&
                            view[rotate[r][8]].ant.type!=ANT_TYPE_QUEEN) 
                        {
                            // step back on path back to queen
                            return NO_OP;
                        }
                        break;

                    /////// REPAIR PATH ///////

                    // P?X  ..C
                    // ?C?  ...
                    // C??  ...

                    case 1:
                        if (view[rotate[r][2]].color != currentCellColour &&
                            view[rotate[r][6]].color === currentCellColour &&
                            isCellTrailToQueen(view[rotate[r][0]],currentCellColour))
                        {
                            return {cell:rotate[r][2], color:currentCellColour};
                        }
                        break;

                    // ??C  N..
                    // ?C?  ...
                    // X?P  ...

                    case 2:
                        if (view[rotate[r][2]].color === currentCellColour &&
                            isCellTrailToQueen(view[rotate[r][8]],currentCellColour) &&
                            !isTrailColour(view[rotate[r][6]].color) &&
                            view[rotate[r][0]].color != expectedNextPathColourToEdge)
                        {
                            return {cell:rotate[r][0], color:expectedNextPathColourToEdge};
                        }
                        break;

                    // C?N  ...
                    // ?C?  .N.
                    // ??P  ...

                    case 3:
                        if (view[rotate[r][0]].color === currentCellColour &&
                            view[rotate[r][2]].color === expectedNextPathColourToEdge &&
                            isCellTrailToQueen(view[rotate[r][8]],currentCellColour))
                        {
                            return {cell:4, color:expectedNextPathColourToEdge};
                        }
                        break;

                    // C??  N..
                    // ?C?  ...
                    // ??P  ...

                    case 4:
                        if (view[rotate[r][0]].color === currentCellColour &&
                            isCellTrailToQueen(view[rotate[r][8]],currentCellColour))
                        {
                            return {cell:rotate[r][0], color:expectedNextPathColourToEdge};
                        }
                        break;

                    /////// MOVING ///////

                    // C?P  ...
                    // ?C?  ...
                    // ??C  N..
                    case 5:
                        if (view[rotate[r][0]].color === currentCellColour &&
                            view[rotate[r][8]].color === currentCellColour &&
                            isCellTrailToQueen(view[rotate[r][2]],currentCellColour) &&
                            view[rotate[r][6]].color != expectedNextPathColourToEdge)
                        {

                            if (view[rotate[r][6]].ant === null)
                            {
                                return {cell:rotate[r][6], color:expectedNextPathColourToEdge};
                            }
                            else
                            {
                                return NO_OP;
                            }
                        }
                        break;

                    // C?P  ...
                    // ?C?  ...
                    // N?C  M..
                    case 6:
                        if (view[rotate[r][0]].color === currentCellColour &&
                            view[rotate[r][8]].color === currentCellColour &&
                            isCellTrailToQueen(view[rotate[r][2]],currentCellColour) &&
                            view[rotate[r][6]].color === expectedNextPathColourToEdge)
                        {
                            cellToMoveTo = rotate[r][6];
                        }
                        break;

                    // Special case. we need to first paint the cell prior to moving other wise will cause corruption
                    // C??  ...
                    // ?C?  ...
                    // C??  ..N
                    case 7:
                        if (view[rotate[r][0]].color === currentCellColour &&
                            view[rotate[r][6]].color === currentCellColour &&
                            view[rotate[r][8]].color != expectedNextPathColourToEdge)
                        {
                            if (view[rotate[r][8]].ant === null)
                            {
                                return {cell:rotate[r][8], color:expectedNextPathColourToEdge};
                            }
                            else
                            {
                                return NO_OP;
                            }
                        }
                        break;
                    // C??  ...
                    // ?C?  ...
                    // C?N  ..M
                    case 8:
                        if (view[rotate[r][0]].color === currentCellColour &&
                            view[rotate[r][6]].color === currentCellColour &&
                            view[rotate[r][8]].color === expectedNextPathColourToEdge)
                        {
                            cellToMoveTo = rotate[r][8];
                        }
                        break;
                    // C??  ..M
                    // ?C?  ...
                    // P?C  ...
                    case 9:
                        if (view[rotate[r][0]].color === currentCellColour &&
                            view[rotate[r][8]].color === currentCellColour &&
                            isCellTrailToQueen(view[rotate[r][6]],currentCellColour))
                        {
                            cellToMoveTo = rotate[r][2];
                        }
                        break;
                    // C??  ...
                    // ?C?  ...
                    // P??  ..M
                    case 10:
                        if (view[rotate[r][0]].color === currentCellColour &&
                            isCellTrailToQueen(view[rotate[r][6]],currentCellColour))
                        {
                            cellToMoveTo = rotate[r][8];
                        }
                        break;
                    // C??  ...
                    // ?C?  ...
                    // ???  M..
                    case 11:
                        if (view[rotate[r][0]].color === currentCellColour)

                        {
                            cellToMoveTo = rotate[r][6];
                        }
                        break;
                    // ???  ...
                    // ?C?  ...
                    // P??  ?.M
                    case 12:
                        if (isCellTrailToQueen(view[rotate[r][6]],currentCellColour))

                        {
                            cellToMoveTo = rotate[r][8];
                        }
                        break;
                    }
                    if (cellToMoveTo>-1)
                    {
                        return {cell:view[cellToMoveTo].ant === null?cellToMoveTo:4};
                    }
                }
            }
            return NO_OP;
        }

        // worker is transporting food
        else
        {
            // worker deadlock avoidance
            for (i=0; i<9; i+=2)
            {
                // does the cell have another ant in it?
                if (i!=4 && view[i].ant!=null && !(view[i].ant.type===ANT_TYPE_QUEEN && view[i].ant.friend))
                {
                    // attempt to pick an empty random trail-cell
                    for (i = randomInt(view,54321)%9;i>0;i--)
                    {
                        if (view[i].ant===null && view[i].food===0 && isTrailColour(view[i].color))
                        {
                            return {cell:i};
                        }
                    }

                    // no luck... just pick a random empty cell
                    for (i = randomInt(view,12345)%9;i>0;i--)
                    {
                        if (view[i].ant===null && view[i].food===0)
                        {
                            return {cell:i};
                        }
                    }

                    // deadlock unavoidable!
                    return NO_OP;
                }
            }

//            // this is to try and unstick stuck ants
//            if (randomInt(view,1)%20==1)
//            {
//                // attempt to pick an empty random trail-cell
//                for (i = randomInt(view,666)%9;i>0;i--)
//                {
//                    if (view[i].ant==null && view[i].food==0 && isTrailColour(view[i].color))
//                    {
//                        return new Move(i);
//                    }
//                }
//            }


            // decide move action
            for (var priority = 0; priority <14;priority++)
            {
                // repeat for each rotation
                var indecies = shuffleIndecies(view,random,4);
                for (var j=0;j<4;j++)
                {
                    var r = indecies[j];
                    var cellToMoveTo =-1;

                    switch(priority)
                    {
                        // PRE-EMPTIVE PATH PRUNING

                    // C?X  X..
                    // ?X?  ...
                    // P?X  ...
                    case 0:
                        if (isTrailColour(view[rotate[r][0]].color) &&
                            !isTrailColour(view[rotate[r][2]].color) &&
                            !isTrailColour(view[rotate[r][4]].color) && 
                            prevTrailColor(view[rotate[r][0]].color) === view[rotate[r][5]].color)
                        {
                            return {cell:rotate[r][0], color: 1};
                        }
                        break;


                        // ?C?  ...
                        // CXN  X..
                        // ?X?  ...
                        case 1:
                            if (!isTrailColour(view[rotate[r][4]].color) &&
                                !isTrailColour(view[rotate[r][7]].color) &&
                                isTrailColour(view[rotate[r][1]].color) && 
                                view[rotate[r][3]].color === view[rotate[r][1]].color &&
                                nextTrailColor(view[rotate[r][1]].color) === view[rotate[r][5]].color)
                            {
                                return {cell:rotate[r][3], color: 1};
                            }
                            break;

                        // ?C?  ...
                        // PXC  ..X
                        // ?X?  ...
                        case 2:
                            if (!isTrailColour(view[rotate[r][4]].color) &&
                                !isTrailColour(view[rotate[r][7]].color) &&
                                isTrailColour(view[rotate[r][1]].color) && 
                                view[rotate[r][5]].color === view[rotate[r][1]].color &&
                                prevTrailColor(view[rotate[r][1]].color) === view[rotate[r][3]].color)
                            {
                                return {cell:rotate[r][5], color: 1};
                            }
                            break;

                        // N??  ..N
                        // ?C?  ...
                        // C?C  ...

                        case 3:
                            if (isTrailColour(view[rotate[r][4]].color) &&
                                view[rotate[r][2]].color != expectedNextPathColourToEdge &&
                                view[rotate[r][8]].color === currentCellColour &&
                                view[rotate[r][0]].color === expectedNextPathColourToEdge &&
                                view[rotate[r][6]].color === currentCellColour)
                            {
                                return {cell:rotate[r][2], color:expectedNextPathColourToEdge};
                            }
                            break;

                        // N??  ...
                        // ?X?  .C.
                        // C?C  ...


                        case 4:
                            if (!isTrailColour(view[rotate[r][4]].color) && 
                                isTrailColour(view[rotate[r][8]].color) &&
                                view[rotate[r][0]].color === nextTrailColor(view[rotate[r][8]].color) &&
                                view[rotate[r][8]].color === view[rotate[r][6]].color)
                            {
                                return {cell:rotate[r][4], color:view[rotate[r][8]].color};
                            }
                            break;

                        // N??  ..C
                        // ?C?  ...
                        // C?P  ...

                        case 5:
                            if (isTrailColour(view[rotate[r][4]].color) && 
                                view[rotate[r][0]].color === expectedNextPathColourToEdge &&
                                view[rotate[r][6]].color === currentCellColour &&
                                isCellTrailToQueen(view[rotate[r][8]],currentCellColour) &&
                                view[rotate[r][2]].color != currentCellColour)
                            {
                                return {cell:rotate[r][2], color:currentCellColour};
                            }
                            break;

                        // C?N  ...
                        // ?X?  .N.
                        // ??P  ...

                        case 6:
                            if (!isTrailColour(view[rotate[r][4]].color) && 
                                isTrailColour(view[rotate[r][0]].color) && 
                                view[rotate[r][2]].color === nextTrailColor(view[rotate[r][0]].color) &&
                                view[rotate[r][8]].color === prevTrailColor(view[rotate[r][0]].color))
                            {
                                return {cell:rotate[r][4], color:nextTrailColor(view[rotate[r][0]].color)};
                            }
                            break;

                        // ??P  ...
                        // ?X?  .N.
                        // ??N  ...

                        case 7:
                            if (!isTrailColour(view[rotate[r][4]].color) && 
                                isTrailColour(view[rotate[r][2]].color) &&
                                nextTrailColor(view[rotate[r][2]].color) === view[rotate[r][8]].color)
                            {
                                return {cell:4, color:view[rotate[r][8]].color};
                            }
                            break;



                        // if we are on the corner of a trail band... move opposite to the apex
                        case 8:
                            if (isTrailColour(currentCellColour) &&
                                view[rotate[r][0]].color === currentCellColour &&
                                view[rotate[r][2]].color === currentCellColour)
                            {
                                if (randomInt(view,currentCellColour)%2 === 0)
                                {
                                    cellToMoveTo = rotate[r][0];
                                }
                                else
                                {
                                    cellToMoveTo = rotate[r][2];
                                }
                            }
                            break;

                        // if we on the opposite corner of a trail band... move back toward the apex
                        case 9:
                            if (isTrailColour(currentCellColour) &&
                                isCellTrailToQueen(view[rotate[r][0]],currentCellColour) &&
                                isCellTrailToQueen(view[rotate[r][2]],currentCellColour))
                            {
                                if (randomInt(view,currentCellColour)%2 === 0)
                                {
                                    cellToMoveTo = rotate[r][0];
                                }
                                else
                                {
                                    cellToMoveTo = rotate[r][2];
                                }
                            }
                            break;
                        // if an adjacent cell is a trail to the queen, move that way
                        case 10:
                            if (isTrailColour(currentCellColour) &&
                                isCellTrailToQueen(view[rotate[r][0]],currentCellColour))
                            {
                                cellToMoveTo = rotate[r][0];
                            }
                            break;
                        // if we are not on a trail and an adjacent cell is a trail, then move that way
                        case 11:
                            if (!isTrailColour(currentCellColour) && isTrailColour(view[rotate[r][8]].color))
                            {
                                cellToMoveTo = rotate[r][8];
                            }
                            break;
                        // are we on a cell between trail cells? if so then move onto a cell on the trail.
                        case 12:
                            if (isTrailColour(view[rotate[r][1]].color))
                            {
                                cellToMoveTo = rotate[r][1];
                            }
                            break;
                        // are we on a terminal trail cell? if so then move onto a cell on the trail.
                        case 13:
                            if (isTrailColour(view[rotate[r][0]].color))
                            {
                                cellToMoveTo = rotate[r][0];
                            }
                            break;

                    }
                    if (cellToMoveTo>-1)
                    {
                        if (view[cellToMoveTo].ant != null || view[cellToMoveTo].food > 0) continue;
                        return {cell:cellToMoveTo};
                    }
                }
            }
            return NO_OP;
        }

    }

    return getAction(view);

संस्करण 1

संस्करण 1

इस प्रविष्टि का मूल आधार कभी विस्तार वाले सर्पिल में खोजना होगा। चौकोर परिधि विस्तार खोज एक तीन बैंड दोहराता पैटर्न बनाएगा जो त्वरित भोजन वितरण और परिधि पर लौटने की अनुमति देगा।

प्रविष्टि का नाम क्लासिक पहेली गेम बोल्डरडैश में "जुगनू" दुश्मन से है, दोहराता तीन रंग पैटर्न दुश्मन की याद दिलाता है।

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

हालांकि अगले संस्करण के लिए मुझे लगता है कि मैं मूल रूप से रास्ता बदलूंगा और चींटियों को आगे बढ़ने / पेंट करने का आदेश दूंगा: पेंट से, फिर कदम, पेंट को स्थानांतरित करने के लिए। जब मैं निश्चित नहीं हो सकता, मुझे लगता है कि सेल के कुछ रंग पैटर्न भ्रष्टाचार उन कोशिकाओं से उत्पन्न हो रहे हैं जिनमें चींटियों को आसन्न चींटियों द्वारा फिर से चित्रित किया जा रहा है। आदेश बदलने से उस जोखिम को कम करने में मदद मिलनी चाहिए ... लेकिन पेंटिंग से पहले स्थानांतरित करने के लिए संभवतः अधिक जटिल / जोखिम भरा होगा।

संस्करण 2

संस्करण 2

यह संस्करण बेहतर है, इसे अब 45 डिग्री घुमाया जाता है, जो प्रति कार्यकर्ता चींटी के अधिक अन्वेषण की अनुमति देता है।

यह अब भोजन भी एकत्र करता है (यदि यह विचलित नहीं होता है)

हालांकि, यह मजबूत नहीं है और आसानी से अन्य चींटी के ट्रेल्स से बाधित हो जाता है। इसलिए यह एक अच्छा दावेदार नहीं है क्योंकि यह वर्तमान में खड़ा है।

हालाँकि जब इसे अकेला छोड़ दिया जाता है, तो यह 300 श्रमिकों के साथ औसतन 700 भोजन एकत्र करता है।

संस्करण 2.1

जोड़ा गया कि यह सुनिश्चित करने के लिए कि किसी भी भोजन के नहीं होने पर रानी एक श्रमिक बनाने की कोशिश नहीं करती है।

संस्करण 2.1.1

2.1 में फिक्स को ठीक किया (मैं वास्तव में चींटी के दृश्य के "भोजन" क्षेत्र का उपयोग नहीं करता था और इसलिए एक अशक्त वस्तु का संदर्भ दे रहा था।

संस्करण 2.1.1.1

/ मैं हाथों में सिर छिपा लेता हूं

मुझे स्पैनिंग फंक्शन में एक साधारण इंडेक्सिंग बग मिला, जिसका मतलब था कि रानी खुद के ऊपर स्पॉन करने की कोशिश कर सकती है ... यह कहने की आवश्यकता नहीं कि अयोग्यता के लिए आधार है। अब तय हो गया।

संस्करण 2.2

फिक्स्ड कॉपी पेस्ट त्रुटि जो अवैध स्पॉन बग को फिर से पेश करती है

संस्करण 2.2.1

रानी के भोजन के पहले टुकड़े को खोजने का प्रयास करते समय शुरुआत में हाथापाई में निश्चित अवैध कदम।


आपकी रणनीति भी Zigurrat: चोरी के रूप में एक ही कमजोरी से ग्रस्त है। मैं लगभग 90 सेकंड में जुगनू को निशाना बनाने के लिए वैम्पायर में जिगुरैट पहचान कोड को ट्विक कर सकता हूं। यह शाब्दिक होगा "कोड की 60 लाइनें कॉपी करें, कोड की 60 लाइनें पेस्ट करें, 3 नंबर बदलें।" हालांकि, मैं इसके बजाय जिगुर्रैट-आईडी कोड मॉड्यूलर बनाना पसंद करूंगा ("इन रंगों के साथ ऐसा करो")।
ड्रेको 18s

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

@ Draco18s हाँ, इस प्रारंभिक संस्करण के साथ कुछ खामियां हैं :-) लेकिन यह एक जगह से शुरू करना है। चोरी के खतरे के बारे में: मैं एक गार्ड चींटी बनाने की योजना बना रहा हूं, जो दुश्मन को रानी और "चोरी" वापस लेने की तलाश करेगी। इससे नुकसान कम से कम होना चाहिए।
मोगी

ओह, मुझे एहसास है कि यह शुरू करने के लिए एक जगह है, बस कुछ अवलोकन कर रहे हैं। :)
Draco18s

1
यह हो गया? क्या मैं अंदर जा सकता हूं और एक पिशाचपूर्ण बल्ले से जगह को तोड़ सकता हूं? : डी
ड्रेको १

4

Mandelbrant

मेरे सभी उत्तरों में फॉर्मिक फ़ंक्शंस फ्रेमवर्क के रूप में समान स्तर के तर्क हैं।

"हाई-लेवल लॉजिक स्टार्स यहां" फ्रेमवर्क के कोड के अंत को चिह्नित करता है।

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

// FORMIC FRAMEWORK \\
//  Version 7.0.4   \\
const QUEEN = 5;
const HERE = view[4];
const ME = HERE.ant;
const ORTHOGONALS = [1, 3, 5, 7];
const DIAGONALS = [0, 2, 6, 8];
const DIAGONALS_ORTHOGONALS = [0, 2, 6, 8, 1, 3, 5, 7];
const DIRECTIONS = [0, 1, 2, 3, 5, 6, 7, 8];
const CLOCKWISE_DIRECTIONS = [0, 1, 2, 5, 8, 7, 6, 3];
const ROTATIONS = [
    [0, 1, 2,
     3, 4, 5,
     6, 7, 8],

    [6, 3, 0,
     7, 4, 1,
     8, 5, 2],

    [8, 7, 6,
     5, 4, 3,
     2, 1, 0],

    [2, 5, 8,
     1, 4, 7,
     0, 3, 6]
];
const NEIGHBORS = [
    [1, 4, 3],
    [2, 5, 4, 3, 0],
    [5, 4, 1],
    [0, 1, 4, 7, 6],
    [0, 1, 2, 5, 8, 7, 6, 3],
    [8, 7, 4, 1, 2],
    [3, 4, 7],
    [6, 3, 4, 5, 8],
    [7, 4, 5]
];
const HORIZONTAL_FLIP = [2, 1, 0, 5, 4, 3, 8, 7, 6];
const VERTICAL_FLIP = [6, 7, 8, 3, 4, 5, 0, 1, 2];

const DEBUG_MODE = false;
const log = DEBUG_MODE ? console.log : () => { };

function cells(...indices) {
    return indices.map(i => view[i]);
}
function colors(...indices) {
    return cells(...indices).map(c => c.color);
}
function ants(...indices) {
    return cells(...indices).map(c => c.ant);
}

function isColor(color, index) {
    return view[index].color === color;
}
function isAnyColor(colors, index) {
    return colors.includes(view[index].color);
}
function hasFood(index) {
    return view[index].food === 1;
}
function hasAnt(qualifies, index) {
    const a = view[index].ant;
    return a && (!(qualifies instanceof Function) || qualifies(a));
}
function hasFriend(type, index) {
    return hasAnt(a => a.friend && (!type || a.type === type), index);
}
const hasAnyFriend = bind(hasFriend, null);
function bind(f, ...args) {
    return f.bind(null, ...args);
}

function noTransform() {
    return { revert() { }, detransformAction() { } };
}
function indexTransform(indices) {
    const revertedIndices = new Array(9);
    for (let i = 0; i < 9; ++i) {
        revertedIndices[indices[i]] = i;
    }

    view = indices.map(index => view[index]);

    return { revert() { view = revertedIndices.map(index => view[index]); }, detransformAction(action) { action.cell = indices[action.cell]; } };
}

const rotationTransformers = [noTransform, ...ROTATIONS.slice(1).map(r => bind(indexTransform, r))];

function bestTransformers(transformers, scorer) {
    let bestScore = 0;
    const bestIndices = [];
    const bestTransformers = [];
    for (let i = 0; i < transformers.length; ++i) {
        const t = transformers[i];
        const {revert} = t();
        const score = scorer();
        revert();
        if (score > bestScore) {
            bestScore = score;
            bestIndices.length = 0;
            bestTransformers.length = 0;
        }
        if (score >= bestScore) {
            bestIndices.push(i);
            bestTransformers.push(t);
        }
    }

    return {score: bestScore, indices: bestIndices, transformers: bestTransformers};
}
function* withBestTransformation(transformers, scorer, continuation) {
    const best = bestTransformers(transformers, scorer);
    if (best.score > 0) {
        const {revert, detransformAction} = best.transformers[0]();
        for (const output of continuation(best)) {
            if (isAction(output)) {
                detransformAction(output);
            }
            yield output;
        }
        revert();
    }
}
const withBestRotation = bind(withBestTransformation, rotationTransformers);

const wait = {cell: 4};
function move(index) {
    return index >= 0 && index < 9 && view[index].ant === null && (view[index].food === 0 || ME.food === 0 || ME.type === QUEEN) ? { cell: index } : null;
}
function moveMany(...indices) {
    return indices.map(move);
}
function paint(color, index) {
    return index >= 0 && index < 9 && color >= 1 && color <= 8 && view[index].color !== color ? { cell: index, color } : null;
}
function paintMany(colors, ...indices) {
    return pairMap(indices, colors, paint);
}
function spawn(type, index) {
    return index >= 0 && index < 9 && view[index].ant === null && view[index].food === 0 && ME.food > 0 && ME.type === QUEEN && type >= 1 && type <= 4 ? { cell: index, type } : null;
}
function spawnMany(types, ...indices) {
    return pairMap(indices, types, spawn);
}
function pairMap(mainArr, sideArr, func) {
    return mainArr.map((v, i) => func(sideArr[i % sideArr.length], v));
}

function isAction(value) {
    return value instanceof Object && value.cell !== undefined; // TODO: Make this more strict.
}

log('=== start logic ===');
for (const output of main()) {
    if (isAction(output)) {
        log('=== end logic ===');
        return output;
    }
}

throw 'Decision was omitted.';

function* main() {
    // HIGH-LEVEL LOGIC STARTS HERE \\

    // TARGET SIZE:  2^21 pixels -- SUPPORTED
    // STRETCH GOAL: 2497 x 996
    // MAX POSSIBLE: 2500 x 1000

    // How long the painting triplet will go on for until they begin returning to the shifting station.
    // This value should not exceed 997 for the painter to work in all cases, or 2497 if you don't care about being positioned vertically.
    // It also shouldn't be too low. The exact lowest value is unclear, but it's likely to be in the teens.
    const LENGTH = 6 * 11;

    // Which function will be used for painting in the pixels.
    const getPictureColorAt = mandelbrot;

    function notReallyRainbow(index) {
        return index % 6 + 2;
    }
    function fromColorString(index) {
        // Input your own color string ({ a, b, c, d, e, f, g, h } => { 8, 7, 6, 4, 5, 3, 2, 1 }).
        const colorString = '';

        return [8, 7, 6, 4, 5, 3, 2, 1][colorString.charCodeAt(index % colorString.length) - 'a'.charCodeAt(0)];
    }
    function mandelbrot(index) {
        const ESCAPE = 2 ** 2, MAX_I = 8 * 10 - 1;
        const x0 = (index % LENGTH) / (LENGTH - 1) * 3 - 2, y0 = Math.floor(index / LENGTH) / (Math.floor(LENGTH * 2 / 3) - 1) * 2 - 1;
        let x = 0, y = 0;
        for (let i = 0; i < MAX_I; ++i) {
            [x, y] = [x * x - y * y + x0, 2 * x * y + y0];
            if (x * x + y * y > ESCAPE) {
                return (i + 1) % 8 + 1;
            }
        }
        return 8;
    }

    // WARNING! Beyond likely lies awful code.
    // There are no more tunable parameters.
    // Continue reading at your own risk.

    const L1_OVERFLOW = 4096;
    const FILL_ORDER_INDEX = [1, 2, 3, 6];
    const FILL_ORDER_DIGIT = [0, 1, 2, 4];

    function parseNumber(...indices) {
        return indices.reduceRight((a, index) => (a << 3) + (index !== -1 ? view[index].color - 1 : 0), 0);
    }

    function colorAtDigit(n, d) {
        return ((n >>> (d * 3)) & 7) + 1;
    }

    function paintPictureFragment(number) {
        log(`initialized painter with ${number}`);
        return paint(getPictureColorAt(number), 0);
    }

    const COPIER = 1;
    const COUNTER = 2;
    const MAJOR = 3;
    const MINOR = 4;

    function* moveWait(index) {
        yield move(index);
        yield wait;
    }

    log(`type: ${ME.type}`);
    switch (ME.type) {
        case COPIER: {
            yield* withBestRotation(() => Math.max(hasFriend(QUEEN, 7) + hasFriend(MINOR, 3), hasFriend(QUEEN, 6) + hasFriend(MINOR, 0)) - 1, bind(moveWait, 5));
            yield* withBestRotation(bind(hasFriend, COUNTER, 7), function*() {
                if ([6, 3].findIndex(hasAnyFriend) === -1) {
                    yield paint(8, 3);
                    yield move(3);
                }
                yield wait;
            });
            yield* withBestRotation(bind(hasFriend, COUNTER, 8), function*() {
                const targetIndex = FILL_ORDER_INDEX[view[4].color - 3];
                yield paint(view[5].color, targetIndex);
                yield wait;
            });
            yield wait;
        }

        case COUNTER: {
            yield* withBestRotation(() => hasFriend(COPIER, 2) + hasFriend(MAJOR, 0) - 1, bind(moveWait, 5));
            yield* withBestRotation(bind(hasFriend, COPIER, 1), function*() {
                if (hasFriend(MAJOR, 0)) {
                    yield paint(view[6].color, 8);
                }
                yield wait;
            });
            yield* withBestRotation(bind(hasFriend, COPIER, 0), function*() {
                if (!hasAnyFriend(6)) {
                    const progress = view[0].color;
                    if (progress === 8) {
                        const number = parseNumber(8, 7, 4, 1) + 1;
                        yield* paintMany([1, 2, 3].map(bind(colorAtDigit, number)), 3, 5, 2);
                        yield paint(7, 0);
                    } else if (progress === 7) {
                        const number = parseNumber(8) + 1;
                        yield paint(colorAtDigit(number, 0), 4);
                        yield paint(6, 0);
                    } else {
                        const number = parseNumber(...progress === 6 ? [4, 3] : [7, 8], 5, 2) * LENGTH;
                        if (progress > 2) {
                            if (progress === 6) {
                                yield* paintMany(colors(4, 3), 7, 8);
                            } else if (progress === 5) {
                                yield* paintMany([5, 6].map(bind(colorAtDigit, number)), 3, 4);
                            }
                            yield paint(colorAtDigit(number, FILL_ORDER_DIGIT[progress - 3]), 1);
                            if (progress !== 3) {
                                yield paint(progress - 1, 0);
                            } else {
                                yield paint(number + 1 === L1_OVERFLOW ? 2 : 1, 0);
                            }
                        } else {
                            yield paint(colorAtDigit(number, 3), 1);
                            yield wait;
                        }
                    }
                }
            });
            yield wait;
        }

        case MAJOR: {
            yield* withBestRotation(bind(hasFriend, COPIER, 5), bind(moveWait, 6));
            yield* withBestRotation(() => hasFriend(QUEEN, 7) + hasFriend(MINOR, 1) - 1, bind(moveWait, 5));
            yield* withBestRotation(bind(hasFriend, QUEEN, 2), bind(moveWait, 1));
            yield* withBestRotation(bind(hasFriend, MINOR, 2), function*() {
                const number = parseNumber(-1, -1, -1, -1, 3, 4, 5) + (isColor(2, 1) ? L1_OVERFLOW : 0);
                yield* paintMany([4, 5, 6].map(bind(colorAtDigit, number)), 6, 7, 8);
                yield move(7);
            });
            yield wait;
        }

        case MINOR: {
            yield* withBestRotation(() => hasFriend(COPIER, 8) + hasFriend(QUEEN, 6) - hasFriend(MAJOR, 3) - 1, bind(moveWait, 7));
            yield* withBestRotation(() => hasFriend(MAJOR, 6) + hasFriend(QUEEN, 7) - 1, bind(moveWait, 3));
            yield* withBestRotation(() => hasFriend(MAJOR, 8) - hasFriend(QUEEN, 7), bind(moveWait, 5));
            yield* withBestRotation(() => hasFriend(MAJOR, 7) + hasFriend(QUEEN, 5) - 1, bind(moveWait, 1));
            yield* withBestRotation(bind(hasFriend, QUEEN, 6), function*() {
                if (hasFriend(MAJOR, 3)) {
                    yield wait;
                }
                const number = parseNumber(0, 1) + 1;
                yield* paintMany([0, 1].map(bind(colorAtDigit, number)), 3, 4);
                yield move(7);
            });
            yield wait;
        }

        case QUEEN: {
            if (DIRECTIONS.some(hasAnyFriend)) {
                yield* withBestRotation(bind(hasFriend, COPIER, 5), function*() {
                    if (!hasFriend(COUNTER, 7)) {
                        yield spawn(COUNTER, 8);
                    }
                    if (!hasFriend(MAJOR, 3) && !hasFriend(MAJOR, 0)) {
                        yield spawn(MAJOR, 6);
                    }
                    yield spawn(MINOR, 0);
                    if (!hasFriend(MAJOR, 0) && hasFriend(MAJOR, 3)) {
                        yield move(7);
                    }
                    yield wait;
                });

                yield* withBestRotation(bind(hasFriend, MAJOR, 2), function*() {
                    if (!hasFriend(MINOR, 8)) {
                        yield move(1);
                    }
                    yield wait;
                });

                yield* withBestRotation(bind(hasFriend, MINOR, 0), function*() {
                    if (hasFriend(MAJOR, 3)) {
                        yield move(1);
                        yield wait;
                    } else if (hasFriend(MAJOR, 6)) {
                        yield wait;
                    }
                });

                yield* withBestRotation(bind(hasFriend, MAJOR, 7), function*() {
                    if (!hasFriend(COPIER, 6)) {
                        yield paintPictureFragment(parseNumber(1, 2, 3, 5, 6, 7, 8));
                    }
                    yield wait;
                });

                yield* withBestRotation(bind(hasFriend, MINOR, 5), function*() {
                    if (isColor(3, 4)) {
                        const number = parseNumber(1, 2, 3, 5) + 1;
                        yield* paintMany([colorAtDigit(number, 2), number + 1 === L1_OVERFLOW ? 2 : 1, colorAtDigit(number, 3)], 6, 7, 8);
                        yield move(7);
                        yield wait;
                    } else {
                        const number = parseNumber(1, 2, 3, 5, 6, 7, 8);
                        yield paintPictureFragment(number);
                        if ((number + 1) % LENGTH === 0) {
                            yield move(8);
                            yield wait;
                        }
                        yield paint(3, 4);
                    }

                    throw 'illogical failure 1';
                });

                throw 'illogical failure 2';
            }

            yield* moveMany(...DIAGONALS_ORTHOGONALS.filter(hasFood));

            if (ME.food >= 4) {
                yield* spawnMany([COPIER], ...ORTHOGONALS);
            }

            yield* moveMany(...DIAGONALS_ORTHOGONALS.filter(bind(isColor, 1)), ...DIAGONALS_ORTHOGONALS); // TODO: Watch out for accidental entrapment.
            yield wait;
        }
    }
}

गेलरी

मैंडलब्रॉट फुल मैंडलब्रोट टिनी


व्याख्या

मैं स्पष्टीकरण को बहुत कम रखूंगा, लेकिन ध्यान रखें कि बहुत सारे नॉटी विवरण हैं जिन्हें मुझे यह बनाते समय पता लगाना था कि मैं इसमें नहीं जाऊंगा।

चरण 1

सबसे पहले, रानी 4 श्रमिकों को बनाने के लिए 4 भोजन एकत्र करती है, प्रत्येक एक अलग उद्देश्य के लिए। पेंटिंग को बर्बाद करने की संभावना को कम करने के लिए उसने कोई रंग नहीं छोड़ा। आप देखेंगे कि शीघ्र ही ऐसा क्यों है।

2 चरण

4 श्रमिकों को जगाने के बाद, प्रविष्टि का मूल लूप तुरंत शुरू होता है। अब से मैं एक सुसंगत दृश्य अभिविन्यास ग्रहण करूंगा, क्योंकि प्रविष्टि भी यही करती है।

पेंटिंग के लिए सही अभिविन्यास प्राप्त करने के लिए पहले एक समन्वित 5-चींटी नृत्य किया जाता है। यह संभवतः सबसे अस्थिर चरण है, और यह संभावना है कि प्रविष्टि यहां दुश्मन के हस्तक्षेप के कारण अयोग्य हो जाएगी। बाद में चींटियाँ अलग हो गईं।

3 चींटियों (रानी और 2 श्रमिक) एक पेंटिंग लूप में जाते हैं। वे अपने साथ रंगों के रूप में एक 21-बिट (7 सेल * 3 बिट प्रति सेल) पूर्णांक ले जाते हैं, जिसे वांछित किसी भी छवि में अनुक्रमित करने के लिए उपयोग किया जा सकता है। डिफ़ॉल्ट रूप से, यह छवि मैंडलब्रॉट सेट है। इसके अतिरिक्त, शीर्ष-बाएँ कक्ष को पिक्सेल के रंग के लिए आरक्षित किया गया है, और केंद्रीय सेल इस स्पष्टीकरण के दायरे से बाहर की चीज़ों के लिए आरक्षित है। तीनों को मार्गदर्शन करने के लिए किसी भी रंग की आवश्यकता नहीं है, क्योंकि वे एक दूसरे को खोजकर अभिविन्यास का पता लगाते हैं। प्रत्येक चक्र वे पूर्णांक को 1 सेल द्वारा नीचे की ओर शिफ्ट करते हैं, जिससे यह सुनिश्चित होता है कि हर बार वे ऐसा करते हैं। लूप समाप्त हो जाता है जब चित्रित रेखा के अंत तक पहुंच जाता है, जिसे द्वारा कॉन्फ़िगर किया गया हैLENGTHस्थिर। उस समय, एक 3-चींटी समन्वित नृत्य शुरू होता है और तीनों में अजीब रिटर्निंग कॉन्फ़िगरेशन समाप्त होता है। नृत्य के दौरान रानी सही एक सेल में भी जाती है। वे ऊपर की ओर यात्रा करते हैं जब तक कि वे चींटियों की जोड़ी के साथ उनका इंतजार नहीं करते।

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

चक्र तब पूरा होता है जब तीन चींटियाँ जोड़ी में लौटती हैं और फिर से 5-चींटी नृत्य करना शुरू करती हैं।


इस प्रविष्टि में पैरामीटर हैं। यह वर्तमान में एक छोटे मैंडलब्रॉट सेट को खींचने के लिए तैयार है। आप LENGTHचित्र को एडजस्ट कर सकते हैं , पिक्चर पेंटिंग फंक्शन को स्वैप कर सकते हैं या अपना स्वयं का रोल भी कर सकते हैं। मज़े करो!

अनुशंसित नियंत्रक: dzaima है


बदलाव का

संस्करण 1.0

  • आरंभिक रिलीज

वाह। मैंने विशेष रूप से इस चुनौती को सीमित करने और कम जानकारी के लिए डिज़ाइन किया है, और मैं अभी भी चकित हूं कि यह चींटियों के बीच सहयोग के साथ कितना काम किया जा सकता है।
ट्राइकोप्लाक्स

मैं इसकी सराहना करता हूं कि यह एक प्रतिस्पर्धी प्रविष्टि के बजाय अवधारणा का प्रमाण है, लेकिन यह मुझे आश्चर्यचकित भी करता है कि क्या यह रानी जाल के रूप में एक व्यावहारिक अनुप्रयोग हो सकता है, जिसमें अन्य रानियों को अपने भोजन को चोरी करने के लिए नेतृत्व करने के लिए एक उपयुक्त पैटर्न है।
ट्राइकोप्लाक्स 13

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

1
क्यों? क्यों? आप ऐसा क्यों करेंगे? क्राइक, इस चुनौती के उत्तर पोस्ट किए गए हैं जबकि मैं तीन अलग-अलग नौकरियों
ड्रेक 18s

1
@ Draco18s मुझे इस चुनौती से बहुत प्यार है: P
Alion

3

अकेला भेड़िया

मेरे सभी उत्तर निम्न-स्तरीय सहायक कार्यों के समान सेट को साझा कर रहे हैं। इस उत्तर के लिए विशिष्ट कोड को देखने के लिए "उच्च-स्तरीय तर्क यहां शुरू होता है"।

// == Shared low-level helpers for all solutions ==

var QUEEN = 5;

var WHITE = 1;
var COL_MIN = WHITE;
var COL_LIM = 9;

var CENTRE = 4;

var NOP = {cell: CENTRE};

var DIR_FORWARDS = false;
var DIR_REVERSE = true;
var SIDE_RIGHT = true;
var SIDE_LEFT = false;

function sanity_check(movement) {
  var me = view[CENTRE].ant;
  if(!movement || movement.cell < 0 || movement.cell > 8) {
    return false;
  }
  if(movement.type) {
    if(movement.color) {
      return false;
    }
    if(movement.type < 1 || movement.type > 4) {
      return false;
    }
    if(view[movement.cell].ant || view[movement.cell].food) {
      return false;
    }
    if(me.type !== QUEEN || me.food < 1) {
      return false;
    }
    return true;
  }
  if(movement.color) {
    if(movement.color < COL_MIN || movement.color >= COL_LIM) {
      return false;
    }
    if(view[movement.cell].color === movement.color) {
      return false;
    }
    return true;
  }
  if(view[movement.cell].ant) {
    return false;
  }
  if(view[movement.cell].food + me.food > 1 && me.type !== QUEEN) {
    return false;
  }
  return true;
}

function as_array(o) {
  if(Array.isArray(o)) {
    return o;
  }
  return [o];
}

function best_of(movements) {
  var m;
  for(var i = 0; i < movements.length; ++ i) {
    if(typeof(movements[i]) === 'function') {
      m = movements[i]();
    } else {
      m = movements[i];
    }
    if(sanity_check(m)) {
      return m;
    }
  }
  return null;
}

function play_safe(movement) {
  // Avoid disqualification: no-op if moves are invalid
  return best_of(as_array(movement)) || NOP;
}

var RAND_SEED = (() => {
  var s = 0;
  for(var i = 0; i < 9; ++ i) {
    s += view[i].color * (i + 1);
    s += view[i].ant ? i * i : 0;
    s += view[i].food ? i * i * i : 0;
  }
  return s % 29;
})();

var ROTATIONS = [
  [0, 1, 2, 3, 4, 5, 6, 7, 8],
  [6, 3, 0, 7, 4, 1, 8, 5, 2],
  [8, 7, 6, 5, 4, 3, 2, 1, 0],
  [2, 5, 8, 1, 4, 7, 0, 3, 6],
];

function try_all(fns, limit, wrapperFn, checkFn) {
  var m;
  fns = as_array(fns);
  for(var i = 0; i < fns.length; ++ i) {
    if(typeof(fns[i]) !== 'function') {
      if(checkFn(m = fns[i])) {
        return m;
      }
      continue;
    }
    for(var j = 0; j < limit; ++ j) {
      if(checkFn(m = wrapperFn(fns[i], j))) {
        return m;
      }
    }
  }
  return null;
}

function identify_rotation(testFns) {
  // testFns MUST be functions, not constants
  return try_all(
    testFns,
    4,
    (fn, r) => fn(ROTATIONS[r]) ? ROTATIONS[r] : null,
    (r) => r
  );
}

function near(a, b) {
  return (
    Math.abs(a % 3 - b % 3) < 2 &&
    Math.abs(Math.floor(a / 3) - Math.floor(b / 3)) < 2
  );
}

function try_all_angles(solverFns) {
  return try_all(
    solverFns,
    4,
    (fn, r) => fn(ROTATIONS[r]),
    sanity_check
  );
}

function try_all_cells(solverFns, skipCentre) {
  return try_all(
    solverFns,
    9,
    (fn, i) => ((i === CENTRE && skipCentre) ? null : fn(i)),
    sanity_check
  );
}

function try_all_cells_near(p, solverFns) {
  return try_all(
    solverFns,
    9,
    (fn, i) => ((i !== p && near(p, i)) ? fn(i) : null),
    sanity_check
  );
}

function ant_type_at(i, friend) {
  return (view[i].ant && view[i].ant.friend === friend) ? view[i].ant.type : 0;
}

function friend_at(i) {
  return ant_type_at(i, true);
}

function foe_at(i) {
  return ant_type_at(i, false);
}

function foe_near(p) {
  for(var i = 0; i < 9; ++ i) {
    if(foe_at(i) && near(i, p)) {
      return true;
    }
  }
  return false;
}

function move_agent(agents) {
  var me = view[CENTRE].ant;
  var buddies = [0, 0, 0, 0, 0, 0];
  for(var i = 0; i < 9; ++ i) {
    ++ buddies[friend_at(i)];
  }

  for(var i = 0; i < agents.length; i += 2) {
    if(agents[i] === me.type) {
      return agents[i+1](me, buddies);
    }
  }
  return null;
}

function grab_nearby_food() {
  return try_all_cells((i) => (view[i].food ? {cell: i} : null), true);
}

function go_anywhere() {
  return try_all_cells((i) => ({cell: i}), true);
}

function colours_excluding(cols) {
  var r = [];
  for(var i = COL_MIN; i < COL_LIM; ++ i) {
    if(cols.indexOf(i) === -1) {
      r.push(i);
    }
  }
  return r;
}

function generate_band(start, width) {
  var r = [];
  for(var i = 0; i < width; ++ i) {
    r.push(start + i);
  }
  return r;
}

function colour_band(colours) {
  return {
    contains: function(c) {
      return colours.indexOf(c) !== -1;
    },
    next: function(c) {
      return colours[(colours.indexOf(c) + 1) % colours.length];
    }
  };
}

function random_colour_band(colours) {
  return {
    contains: function(c) {
      return colours.indexOf(c) !== -1;
    },
    next: function() {
      return colours[RAND_SEED % colours.length];
    }
  };
}

function fast_diagonal(colourBand) {
  var m = try_all_angles([
    // Avoid nearby checked areas
    (rot) => {
      if(
        !colourBand.contains(view[rot[0]].color) &&
        colourBand.contains(view[rot[5]].color) &&
        colourBand.contains(view[rot[7]].color)
      ) {
        return {cell: rot[0]};
      }
    },

    // Go in a straight diagonal line if possible
    (rot) => {
      if(
        !colourBand.contains(view[rot[0]].color) &&
        colourBand.contains(view[rot[8]].color)
      ) {
        return {cell: rot[0]};
      }
    },

    // When in doubt, pick randomly but avoid doubling-back
    (rot) => (colourBand.contains(view[rot[0]].color) ? null : {cell: rot[0]}),

    // Double-back when absolutely necessary
    (rot) => ({cell: rot[0]})
  ]);

  // Lay a colour track so that we can avoid doubling-back
  // (and mess up our foes as much as possible)
  if(!colourBand.contains(view[CENTRE].color)) {
    var prevCol = m ? view[8-m.cell].color : WHITE;
    return {cell: CENTRE, color: colourBand.next(prevCol)};
  }

  return m;
}

function follow_edge(obstacleFn, side) {
  // Since we don't know which direction we came from, this can cause us to get
  // stuck on islands, but the random orientation helps to ensure we don't get
  // stuck forever.

  var order = ((side === SIDE_LEFT)
    ? [0, 3, 6, 7, 8, 5, 2, 1, 0]
    : [0, 1, 2, 5, 8, 7, 6, 3, 0]
  );
  return try_all(
    [obstacleFn],
    order.length - 1,
    (fn, i) => (fn(order[i+1]) && !fn(order[i])) ? {cell: order[i]} : null,
    sanity_check
  );
}

function start_dotted_path(colourBand, side, protectedCols) {
  var right = (side === SIDE_RIGHT);
  return try_all_angles([
    (rot) => ((
      !protectedCols.contains(view[rot[right ? 5 : 3]].color) &&
      !colourBand.contains(view[rot[right ? 5 : 3]].color) &&
      !colourBand.contains(view[rot[right ? 2 : 0]].color) &&
      !colourBand.contains(view[rot[1]].color)
    )
      ? {cell: rot[right ? 5 : 3], color: colourBand.next(WHITE)}
      : null)
  ]);
}

function lay_dotted_path(colourBand, side, protectedCols) {
  var right = (side === SIDE_RIGHT);
  return try_all_angles([
    (rot) => {
      var ahead = rot[right ? 2 : 0];
      var behind = rot[right ? 8 : 6];
      if(
        colourBand.contains(view[behind].color) &&
        !protectedCols.contains(view[ahead].color) &&
        !colourBand.contains(view[ahead].color) &&
        !colourBand.contains(view[rot[right ? 6 : 8]].color)
      ) {
        return {cell: ahead, color: colourBand.next(view[behind].color)};
      }
    }
  ]);
}

function follow_dotted_path(colourBand, side, direction) {
  var forwards = (direction === DIR_REVERSE) ? 7 : 1;
  var right = (side === SIDE_RIGHT);

  return try_all_angles([
    // Cell on our side? advance
    (rot) => {
      if(
        colourBand.contains(view[rot[right ? 5 : 3]].color) &&
        // Prevent sticking / trickery
        !colourBand.contains(view[rot[right ? 3 : 5]].color) &&
        !colourBand.contains(view[rot[0]].color) &&
        !colourBand.contains(view[rot[2]].color)
      ) {
        return {cell: rot[forwards]};
      }
    },

    // Cell ahead and behind? advance
    (rot) => {
      var passedCol = view[rot[right ? 8 : 6]].color;
      var nextCol = view[rot[right ? 2 : 0]].color;
      if(
        colourBand.contains(passedCol) &&
        nextCol === colourBand.next(passedCol) &&

        // Prevent sticking / trickery
        !colourBand.contains(view[rot[right ? 3 : 5]].color) &&
        !colourBand.contains(view[rot[right ? 0 : 2]].color)
      ) {
        return {cell: rot[forwards]};
      }
    }
  ]);
}

function escape_dotted_path(colourBand, side, newColourBand) {
  var right = (side === SIDE_RIGHT);
  if(!newColourBand) {
    newColourBand = colourBand;
  }

  return try_all_angles([
    // Escape from beside the line
    (rot) => {
      var approachingCol = view[rot[right ? 2 : 0]].color;
      if(
        !colourBand.contains(view[rot[right ? 8 : 6]].color) ||
        !colourBand.contains(approachingCol) ||
        colourBand.contains(view[rot[7]].color) ||
        colourBand.contains(view[rot[right ? 6 : 8]].color)
      ) {
        // not oriented, or in a corner
        return null;
      }
      return best_of([
        {cell: rot[right ? 0 : 2], color: newColourBand.next(approachingCol)},
        {cell: rot[right ? 3 : 5]},
        {cell: rot[right ? 0 : 2]},
        {cell: rot[right ? 6 : 8]},
        {cell: rot[right ? 2 : 0]},
        {cell: rot[right ? 8 : 6]},
        {cell: rot[right ? 5 : 3]}
      ]);
    },

    // Escape from inside the line
    (rot) => {
      if(
        !colourBand.contains(view[rot[7]].color) ||
        !colourBand.contains(view[rot[1]].color) ||
        colourBand.contains(view[CENTRE].color)
      ) {
        return null;
      }
      return best_of([
        {cell: rot[3]},
        {cell: rot[5]},
        {cell: rot[0]},
        {cell: rot[2]},
        {cell: rot[6]},
        {cell: rot[8]}
      ]);
    }
  ]);
}

function latch_to_dotted_path(colourBand, side) {
  var right = (side === SIDE_RIGHT);

  return try_all_angles([
    (rot) => {
      var approachingCol = view[rot[right ? 2 : 0]].color;
      if(
        colourBand.contains(approachingCol) &&
        view[rot[right ? 8 : 6]].color === colourBand.next(approachingCol) &&
        !colourBand.contains(view[rot[right ? 5 : 3]].color)
      ) {
        // We're on the wrong side; go inside the line
        return {cell: rot[right ? 5 : 3]};
      }
    },

    // Inside the line? pick a side
    (rot) => {
      var passedCol = view[rot[7]].color;
      var approachingCol = view[rot[1]].color;
      if(
        !colourBand.contains(passedCol) ||
        !colourBand.contains(approachingCol) ||
        colourBand.contains(view[CENTRE].color)
      ) {
        return null;
      }
      if((approachingCol === colourBand.next(passedCol)) === right) {
        return best_of([{cell: rot[3]}, {cell: rot[6]}, {cell: rot[0]}]);
      } else {
        return best_of([{cell: rot[5]}, {cell: rot[2]}, {cell: rot[8]}]);
      }
    }
  ]);
}


// == High-level logic begins here ==


var COLOURS = random_colour_band(colours_excluding([1]));
return play_safe([
  grab_nearby_food,
  fast_diagonal.bind(null, COLOURS),
  go_anywhere,
  {cell: 1, color: COLOURS.next()}
]);

तो यह मेरे लिए हुआ कि मेरे कुछ जवाबों में मैंने खाना शुरू करने के लिए एक ही शुरुआती कदम का इस्तेमाल किया। यदि कोई चींटी पूरे खेल के लिए उस रणनीति का उपयोग करती है तो क्या होगा? वैसे यह पता चला है कि वे अच्छी तरह से करते हैं।

यह सिर्फ प्रकाश की आधी गति से मैदान के चारों ओर दौड़ता है, पास के किसी भी भोजन को पकड़ लेता है। मौका है कि भोजन को हथियाने पर दिशा बेतरतीब ढंग से बदल जाएगी, और यह किसी भी क्षेत्र को पहले से ही स्वयं या दूसरों द्वारा कवर से बचने की कोशिश करेगा। कोई भी श्रमिक चींटियाँ कभी उत्पन्न नहीं होती हैं।

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

मैं अब जवाब के साथ इस चुनौती स्पैमिंग को रोकने का वादा ...


नवीनतम अपडेट से कवर किए गए मैदान को फिर से खोज करने की संभावना कम हो जाती है, जिससे यह अधिक प्रकार के भरे हुए क्षेत्रों से दूर धकेल देता है।


यह स्पैम नहीं है जब वे सभी अलग और दिलचस्प रणनीति हैं!
ट्राइकोप्लाक्स

ब्लैक होल के साबोटूर में कौन सी प्रविष्टि है?
ड्रेको 18s

@ Draco18s को यकीन नहीं है कि यह कौन है, लेकिन यह जल्दी से विकर्ण नीली रेखाएं खींचता है जो अक्सर ब्लैक होल को स्पॉनिंग श्रमिकों को पहले की तुलना में बनाना चाहते हैं, और यह सुपर लम्बी हो जाती है, जिससे सभी श्रमिकों को कहीं भी पाने के लिए हमेशा के लिए लग जाता है। व्हाइट-पेंट-मिसाइल एक भी है जो सभी के लिए शोक पैदा कर रहा है, जो ब्लैक होल पर अपने हाथों को प्राप्त करने पर वास्तव में एमोक चला सकता है।
डेव

@ द बॉट जो ऐसा करता है वह Antdom Walking Artist
pppery

3

प्रवेश करना

यह बॉट लगातार 90 के करीब भोजन प्राप्त करता है, अन्य बॉट्स में से अधिकांश को हरा देता है।

var ORTHOGONALS = [1,3,5,7];
var CORNERS = [0,2,6,8];
var CENTER = 4;

var QUEEN = 5;

var no_op = {cell:CENTER};
var me = view[4].ant;

var ants;
var food;
var friendlies;
var unfriendlies;
var colors;

var j = 0;
var i = 0;
var cell = 0;
var rotation;

var out;

init_arrays();
var seed = rSeed();

var response;

var adjacents_all = {0:[1,3,4],1:[0,2,3,4,5],2:[1,4,5],3:[0,1,4,6,7],4:[0,1,2,3,4,5,6,7,8],5:[1,2,4,7,8],6:[3,4,7],7:[3,4,5,6,8],8:[4,5,7]};
var adjacents_ortho = {0:[1,3],1:[0,2,4],2:[1,5],3:[0,4,6],4:[1,3,5,7],5:[2,4,8],6:[3,7],7:[4,6,8],8:[5,7]};
var adjacents_diag = {0:[4],1:[3,5],2:[4],3:[1,7],4:[0,2,6,8],5:[1,7],6:[4],7:[3,5],8:[4]};

function valid_move(move) {
  if(!move || move.cell == undefined || move.cell < 0 || move.cell > 8) {return false;}
  if(move.type) {
    if(move.color) {return false;}
    if(move.type < 1 || move.type > 4) {return false;}
    if(view[move.cell].ant || view[move.cell].food) {return false;}
    if(me.type != QUEEN || me.food < 1) {return false;}
    return true;
  }
  if(move.color) {
    if(move.color < 1 || move.color > 8) {return false;}
    return true;
  }
  if(view[move.cell].ant){return false;}
  if(view[move.cell].food && me.food&& me.type != 5) {return false;}
  return true;
}

function steal_then_road(){
  if(count(unfriendlies, 5)>=1 && me.food==0){
    //steal from a queen with more than 30 food
    if(ants[unfriendlies.indexOf(5)].food>30){
      for(i=0;i<adjacents_ortho[unfriendlies.indexOf(5)].length;i++){
        if(ants[adjacents_ortho[unfriendlies.indexOf(5)][i]]==null){
          return {cell:adjacents_ortho[unfriendlies.indexOf(5)][i]};
        }
      }
    }
  }
  return road();
}

function try_corners(){
  for(i=0;i<4;i++){
    if(view[CORNERS[i]].ant==null){
      return {cell:CORNERS[i]};
    }
  }
}

function try_ortho(){
  for(i=0;i<4;i++){
    if(view[ORTHOGONALS[i]].ant==null){
      return {cell:ORTHOGONALS[i]};
    }
  }
}

function corner_then_ortho(){
  if(try_corners()){return try_corners();}
  if(try_ortho()){return try_ortho();}
  return {cell:4}; //PANIC!
}

function ortho_then_corner(){
  if(try_ortho()){return try_ortho();}
  if(try_corners()){return try_corners();}
  return {cell:4}; //PANIC!
}

function road(color){
  if (colors[color] != color) {
      return {cell:CENTER,color:color};
    }
  for (i = 0; i < 9; i++) {
    if (colors[i] == color && ants[8 - i] == null && i != color) {
      return {cell:8-i};
    }
  }
}

function color_self(color){
  return {cell:4,color:color};
}

function make_valid_move(move){
  if(valid_move(move)){return move;}
  return no_op;
  //return{cell:seed%9,color:seed%7+1};
}

function count(array, element) {
  out = 0;
  for (j = 0; j < array.length; j++) {
    if (array[j] == element) {
      out++;
    }
  }
  return out;
}

function target_ant(ant_type, location) {
  for (i = 0; i < 4; i++) {
    if (ants[location] != null) {
      if (ants[location].type == ant_type) {
        return i;
      }
    }
    ants = rot_left(ants);
    friendlies = rot_left(friendlies);
    unfriendlies = rot_left(unfriendlies);
    food = rot_left(food);
    colors = rot_left(colors);
  }
}


function target_color(color, location) {
  for (i = 0; i < 4; i++) {
    if (colors[location] != null) {
      if (colors[location].type == color) {
        return i;
      }
    }
    ants = rot_left(ants);
    friendlies = rot_left(friendlies);
    unfriendlies = rot_left(unfriendlies);
    food = rot_left(food);
    colors = rot_left(colors);
  }
}

function init_arrays() {
    ants = new Array(9);
  for (cell = 0; cell < 9; cell++) {ants[cell] = view[cell].ant;}


  food = new Array(9);
  for (cell = 0; cell < 9; cell++) {food[cell] = view[cell].food;}

  colors = new Array(9);
  for (cell = 0; cell < 9; cell++) {colors[cell] = view[cell].color;}

  friendlies = new Array(9);
  for (cell = 0; cell < 9; cell++) {
    if (ants[cell] != null) {
      if (ants[cell].friend) {friendlies[cell] = ants[cell].type;}
    }
  }

  unfriendlies = new Array(9);
  for (cell = 0; cell < 9; cell++) {
    if (ants[cell] != null) {
      if (!ants[cell].friend) {unfriendlies[cell] = ants[cell].type;}
    }
  }
}

function rot_n_pos(pos, n) {
  for (i = 0; i < n; i++) {
    pos = [2, 5, 8, 1, 4, 7, 0, 3, 6][pos];
  }
  return pos;
}

function rot_left(a) {
  return [a[2], a[5], a[8], a[1], a[4], a[7], a[0], a[3], a[6]];
} 

function rot_right(a) {
  return [a[6], a[3], a[0], a[7], a[4], a[1], a[8], a[5], a[2]];
}

function rSeed(){
  out=23;
  for(i=0;i<9;i++){
    if(food[i]){
      out+=17;
    }
    out += 3 * colors[i];
    if(ants[i]){
      out *= 19;
    }
  }
  return out;
}

function get_response(){
  if (me.type == 5) { //Queen Case:
    return type5();
  }
  else if (me.type == 1) {
    return type1();
  }
  else if (me.type == 2) {
    return type2();
  }
  else if (me.type == 3) {
    return type3();
  }
  else if(me.type == 4){
    return type4();
}

function type5(){
  if (me.food == 0 && count(friendlies, 1) == 0 && count(friendlies, 2) == 0) {
    if (count(food, 1) > 0) {
      for (j = 0; j < 9; j++) {
        if (food[j]) {
          return {cell: j};
        }
      }
    }
    // travel up
    // color own cell if not 4

    if(road()){return road();}

    //move
    for (i = 0; i < 9; i++) {
      if (ants[i] == null && i != 4) {
        return {cell:i};
      }
    }
    return corner_then_ortho();
  }
  if (me.food >= 1 && count(friendlies, 1) == 0 && count(friendlies, 2) == 0) {
    if (ants[5] == null) {
      return {cell:5,type:1};
    }
    if (ants[1] == null) {
      return {cell:5, type:1};
    }
    if (ants[3] == null) {
      return {cell:5,type:1};
    }
    if (ants[7] == null) {
      return {cell:5, type:1};
    }
    return color_self(5);
  }
  if (me.food == 0 && count(friendlies, 1) == 1 && count(friendlies, 2) == 0) {
    if (friendlies.indexOf(1) % 2 == 0) {
      return ortho_then_corner();//PANIC!!! TODO: FIX
    }
    rotation = target_ant(1, 1);
    if (ants[0] == null) {
      return {cell: rot_n_pos(0, rotation)};
    } else {
      return corner_then_ortho;
    }
  }
  if (me.food >= 1 && count(friendlies, 1) == 1 && count(friendlies, 2) == 0) {
    if (friendlies.indexOf(1) % 2 == 0) {
      return corner_then_ortho(); //PANIC!!! TODO: FIX
    }
    rotation = target_ant(1, 1);
    if (ants[3] == null) {
      return {cell: rot_n_pos(3, rotation),type: 2};
    }
    if (ants[0] == null) {
      return { cell: rot_n_pos(0, rotation)};
    }
    return {cell: 4};
  }
  if (count(friendlies, 1) == 1 && count(friendlies, 2) == 1) {
    if (friendlies.indexOf(1) % 2 == 0) {
      return ortho_then_corner();
    }
    rotation = target_ant(1, 1);
    if(food[0] || food[8]){
      return no_op;
    }
    if(ants[5]!=null){
      if(ants[5].type == 2 && ants[2]==null){
        return {cell: rot_n_pos(2, rotation)};
      }
    }
    return corner_then_ortho();
  }
  return corner_then_ortho();
}

function type1(){
//right flank
  if (count(friendlies, 5) == 0 && count(friendlies, 2) == 0 && count(friendlies,1) == 1) {
    //no friends = destruction
    return steal_then_road();
  }
  if (count(friendlies, 5) == 1 && count(friendlies, 2) == 0 && count(friendlies,1) == 1) {
    if (friendlies.indexOf(5) % 2 == 0) {
      return ortho_then_corner();
    }
    rotation = target_ant(5, 3);
    if (ants[0] == null) {
      return {cell: rot_n_pos(0, rotation)};
    }
    return corner_then_ortho(); // PANIC!! TODO: FIX
  }
  if (count(friendlies, 5) == 1 && count(friendlies, 2) == 1 && count(friendlies,1) == 1) {
    if (friendlies.indexOf(5) % 2 == 0) {
      return ortho_then_corner(); 
    }
    rotation = target_ant(5, 3);
    if(friendlies[8] !=null){
      if(friendlies[8].type==2){
        if (ants[0] == null){
          return {cell: rot_n_pos(0, rotation)};
        }
      }
    }
    if (ants[0] != null) {
      if (ants[0].type == 2 && ants[6] == null) {
        return {cell: rot_n_pos(6, rotation)};
      }
    }
    if (ants[6] != null) {
      if (ants[6].type == 2 && ants[0] == null) {
        return {cell: rot_n_pos(0, rotation)};
      }
    }
    return corner_then_ortho();
  }
  return corner_then_ortho();
}

function type2(){
  //left flank
  if (count(friendlies, 5) == 0 && count(friendlies, 1) == 0  && count(friendlies,2) == 1) {
    return steal_then_road();
  }
  if (count(friendlies, 5) == 1 && count(friendlies, 1) == 0  && count(friendlies,2) == 1) {
    if (friendlies.indexOf(5) % 2 == 0) {
      return ortho_then_corner();
    }
    rotation = target_ant(5, 1);
    if (ants[0] == null) {
      return {cell: rot_n_pos(2, rotation)};
    }
    return corner_then_ortho();
    }
    if (count(friendlies, 5) == 1 && count(friendlies, 2) == 1) {
      return {cell: 4,color:2};
    }
    }
  return corner_then_ortho();
}

function type3(){}
function type4(){}

response = get_response();

return make_valid_move(response);

रणनीति।

चरण 1: रानी हाथापाई।

रोमन खाने के लिए रानी रोमस्को सड़क ( road()फ़ंक्शन का उपयोग करता है ) के समान तकनीक का उपयोग करती है। जब भी वह एक भोजन देखती है तो वह उसे लेती है और चरण 1 को सक्रिय करते हुए एक प्रकार का 1 श्रमिक पैदा करती है।

चरण 2: रानी-साथी हाथापाई।

रानी और साथी एक दूसरे को उन्मुख करने के लिए उपयोग करते हैं, इसलिए वे प्रकाश की गति से यात्रा करते हैं। वे अपने आस-पास के किसी भी भोजन को अनदेखा कर देते हैं और बस वही प्राप्त करते हैं जो उन्हें हिट करता है। जब रानी को खाना मिलता है, तो वह चरण 3 को सक्रिय करते हुए एक टाइप 2 कार्यकर्ता को जन्म देती है।

चरण 3: पियर्स।

प्रकाश की गति से यात्रा करते हुए, तीन चींटियाँ एक दूसरे का उपयोग करती हैं। जब भी रानी ऐसा भोजन देखती है, जिसे कोई भी श्रमिक प्राप्त नहीं कर सकता, तो वह रुक जाती है, जिससे श्रमिक उसके चारों ओर घूमते हैं और गठन को 90 डिग्री तक मोड़ देते हैं।

ताकत:

तीन-चींटी गठन कोई निशान नहीं बनाता है, लपेटता नहीं है, और प्रकाश की गति से यात्रा करता है, प्रति कदम औसतन 0.1% * 3 = 0.003 भोजन प्राप्त करता है। यह औसतन प्रति गेम 0.003 * 30000 = 90 भोजन के बराबर है, जो आमतौर पर प्राप्त होता है।

कमजोरियों:

बॉट में दो कमजोरियां हैं। मुख्य एक गठन के सामने चलने वाली चींटी है। उस के लिए हैंडलिंग सबसे अच्छा नहीं है और कभी-कभी रानी को अत्यधिक मात्रा में श्रमिकों का निर्माण करने का कारण बनता है। सौभाग्य से, श्रमिकों को अन्य रानियों ( steal_then_road()) से चोरी करने के लिए प्रोग्राम किया जाता है । लेकिन चूंकि गठन कोई राह नहीं बनाता है, इसलिए इसे ढूंढना व्यावहारिक रूप से असंभव है।

एक और कमजोरी road()एल्गोरिथ्म है जिसमें समस्याएं हैं जो मैं फिक्सिंग पर काम कर रहा हूं। ब्राउनियन गति वाली सड़क अच्छी नहीं है। इसका मतलब है बहुत धीमी शुरुआत और अस्वास्थ्यकर स्थितियों से बुरा पलायन।


ये चींटियाँ व्यावहारिक रूप से मेरे स्टीमर वाली चींटियों के समान हैं , लेकिन मेरे परीक्षण में और भी बुरा लग रहा है। एकमात्र अंतर जो मैंने देखा है कि आपकी चींटियाँ तब मुड़ती हैं जब रानी भोजन देखती है जो दूसरे श्रमिक तक नहीं पहुँच सकते हैं, जबकि मेरा तब मुड़ता है जब टाइप 2 का कार्यकर्ता कुछ भोजन खाएगा। मुझे लगता है कि आपकी चींटियों को भी अच्छा प्रदर्शन करना चाहिए, लेकिन मुझे समझ में नहीं आता कि यह कभी-कभी प्रदर्शन के तहत क्यों होता है।
के झांग

@KZhang दिलचस्प। मेरे परीक्षण पर, पियर्स आम तौर पर बेहतर करता है, सिवाय इसके कि जब चींटियों का एक बड़ा हस्तक्षेप (वाइल्डफायर? ब्लैक होल?) होता है, जब यह अनावश्यक रूप से दसियों चींटियों का निर्माण करता है। केवल समय और परीक्षण बताएगा।
फायरफ्लेम 241

एडिट के बाद अगले लीडरबोर्ड के लिए तैयार वर्तमान टूर्नामेंट में फिर से शामिल किया गया।
ट्राइकोप्लाक्स

2
मैंने देखा है कि दुर्लभ स्थितियों में यह पैटर्न अंतहीन लूप में फंस सकता है। विशेष रूप से, अगर भोजन के दो टुकड़े होते हैं जो 1 स्थान से अलग हो जाते हैं, और फिर रानी उन दोनों के निकट एक स्थिति में प्रवेश करती है; जब ऐसा होता है तो पैटर्न लगातार बदल जाता है, संभवतः क्योंकि यह केवल "भोजन के लिए प्रतिक्रिया करता है जो कि अगर हम नहीं मुड़ते हैं तो" छूट जाएगा "और" भोजन जो कि अगर हम
मोड़ते हैं

3

एकल रानी

var C = 5;

for(var i = 0; i<9; i++)
{
  if(view[i].food === 1)
    return {cell:i};
}


if(view[4].color != 5 && !view[0].ant && !view[1].ant && !view[2].ant && !view[3].ant && !view[5].ant && !view[6].ant && !view[7].ant && !view[8].ant)
  return {cell:4, color:C};

if(!view[0].ant && 
   view[0].color != C && view[8].color === C && view[1].color != C && view[3].color != C && view[2].color != C && view[6].color != C)

      return {cell:0};

if(!view[2].ant && 
   view[2].color != C && view[6].color === C && view[1].color != C && view[5].color != C  && view[0].color != C && view[8].color != C)

     return {cell:2};

if(!view[6].ant && 
   view[6].color != C && view[2].color ===  C && view[3].color != C && view[7].color != C  && view[0].color != C && view[8].color != C)

     return {cell:6};

if(!view[8].ant && 
   view[8].color != C && view[0].color === C && view[5].color != C && view[7].color != C  && view[2].color != C && view[6].color != C)

     return {cell:8};


if(!view[0].ant)
  return {cell:0};

if(!view[2].ant)
  return {cell:2};

if(!view[6].ant)
  return {cell:6};

if(!view[8].ant)
  return {cell:8};


return {cell:4};

सरल कोड भोजन के लिए तिरछे खोज। यह पुराने क्षेत्र को खोजने से बचने की कोशिश करता है, लेकिन अन्य क्षेत्रों की कोशिश करेगा और अपने क्षेत्रों से गुजरने के लिए खुले स्थान की उम्मीद करेगा।

लोन वुल्फ (अनजाने) की समान रणनीति प्रतीत होती है।


3

एक्सप्लोरर

फैली गंगा!

एक्सप्लोरर एक 5 मैन टीम है जिसका उद्देश्य जहां तक ​​संभव हो फैलाना है, जबकि अभी भी रानी को भोजन वापस लाना है।

रानी

रानी स्वयं एक 3 चरण सेटअप का उपयोग करती है।

चरण 1।

एक मैच की शुरुआत में, यह किसी भी अच्छी रानी की तरह भोजन के लिए एक जंगली पानी का छींटा है। यह बस एक सीधी रेखा में तिरछे रास्तों से गुजरती है जब तक कि यह भोजन नहीं पाता है, तब बेतरतीब ढंग से दिशा बदलता है। जब इसमें 4 भोजन होते हैं, तो यह चरण 2 में चला जाता है।

चरण 2।

यह संभवतः 8 से अधिक चाल नहीं लेगा। यह चारों ओर चार टाइलों को चार विशिष्ट रंगों में सेट करता है, और उन पर चींटियों को उनके संबंधित प्रकारों के साथ स्थापित करता है। बाद में वे सभी जागे, चरण 3 को स्थानांतरित कर दिया गया।

स्टेज 3।

सभी चरण 3 करता है बाकी मैच के लिए अभी भी बैठते हैं, यह सुनिश्चित करता है कि चारों ओर की टाइलें सही ढंग से सेट हैं।

कामगार

श्रमिक स्वयं बहुत ही सरल दो चरण के प्राणी हैं। सबसे पहले, वे रानी को संकेत देने के लिए प्रतीक्षा करते हैं कि वह स्टेज 2 समाप्त हो गई है। दूसरा चरण बहुत अधिक जटिल है (लेकिन अभी भी काफी सरल है)। यह अपने पथ के चारों ओर दक्षिणावर्त चलता है जब तक कि इसका अंत नहीं मिल जाता है, तब तक इसका विस्तार जारी है। जब उसे भोजन मिल जाता है, तो वह उसके पास पहुंचता है, फिर से रास्ते के चारों ओर दक्षिणावर्त परिक्रमा करता है, जो उसे वापस रानी की ओर ले जाता है।

var me = view[4].ant
var turf = view[4].color

var queenHolder = 2 // "Queen Holder", the turf colour for the queen in stage 3.
var queenBuild = 7 // "Queen Build", the turf colour for the queen in stage 2.
var antTrail = [3, 4, 5, 6] // Various colours of the ant's trails.
var orth = [1, 3, 5, 7] // Orthogonal Directions.
var rotates = [[1,3,5,7],[3,7,1,5],[5,1,7,3],[7,5,3,1]] // These are the orthogonal directions rotated so 0 is the first position, used in the queen build stage.
var outside = [1,2,3,5,6,7,8] // Every tile but the center one.
var diag = [0,2,6,8] // Diagonal Directions.

// Define a move function to avoid throwing an error.
function move(dir){
    if(view[dir].ant)   // If we're going to move onto an ant.
        dir = 4 // Don't move anywhere.
    if(view[dir].food && me.type < 5 && me.food > 0)    // If we're going to over-eat.
        dir = 4 // Don't move anywhere.
    return {cell: dir}  // Build the move output.
}

if(me.type == 5){ // If we're the queen.
    var invDiag = [8,6,2,0] // Inverse of diagonals, using the indexing of diag. So 0 becomes 8, and such.
    if(turf == 1 || turf == 8){
        // Stage 1.
        // Find enough food to start a hive.
        for(var i=0; i < view.length; i++){ // Check every tile in view
            if(view[i].food){   // Is it food?
                return move(i)  // Move to it.
            }
        }
        if(me.food > 3) // Do we have 4 food?
            return {cell:4, color:queenBuild}   // Move to stage 2.
        if(turf == 1)   // Are we on a white tile?
            return {cell:4, color:8}    // Set the tile to black.
        for(var i=0; i < diag.length; i++)  // Check all diagonals.
            if(view[diag[i]].color == 8)    // Is it black?
                return move(invDiag[i]) // Move in the opposite direction. This creates a straight diagonal line.
        return move(2)  // When in doubt, move randomly diagonally.
    }else if(turf == queenBuild){
        // Stage 2.
        // Spawn ants around, and set up their movement paths.
        if(me.food < 1) // Have we used all our food?
            return {cell:4, color:queenHolder}  // Move to stage 3.

        var firstHolder = -1; // Stores which way we're facing.
        for(var i=0; i < orth.length; i++){ // Check orthogonals.
            if(view[orth[i]].color == antTrail[0]){ // Is it the first trail colour?
                firstHolder = i // THIS WAY UP
                break;
            }
        }
        if(firstHolder==-1) // No way is up?
            return {cell:1, color:antTrail[0]} // Set a random direction to up.

        var orthRot = rotates[firstHolder]  // Get the rotated orthogonal set for the current up direction.
        for(var i=0; i < orthRot.length; i++){  // For each of them.
            if(!view[orthRot[i]].ant)   // Is there an ant on this tile yet?
                return {cell:orthRot[i], type:(i+1)}    // If not, place one down with the correct type.
            if(view[orthRot[i]].color!=antTrail[i]) // Otherwise, is the turf set correctly yet?
                return {cell:orthRot[i], color:antTrail[i]} // If not, set the turf.
        }
        return {cell:4, color:queenHolder}; // After all's said and done, move to stage 3. Probably won't happen this way.
    }else if(turf == queenHolder){
        // Stage 3.
        // Sit still, ensure rails exist around.

        var firstHolder = -1;   // Same behavoir of which way is up from stage 2.
        for(var i=0; i < orth.length; i++){
            if(view[orth[i]].color == antTrail[0]){
                firstHolder = i
                break;
            }
        }
        if(firstHolder==-1)
            return {cell:1, color:antTrail[0]}

        var orthRot = rotates[firstHolder]
        for(var i=0; i < orthRot.length; i++)   // Basically stage 2 without the spawning of ants.
            if(view[orthRot[i]].color!=antTrail[i])
                return {cell:orthRot[i], color:antTrail[i]}

        return {cell:4, color:queenHolder}  // And if there's nothing better to do, waste your time.
    }else{
        return {cell:4, color:1}    // We're lost, go back to stage 1, and try again.
        // I could probably add logic to check if we're stage 3 or something, but meh.
    }

}else{  // If we're a worker!

    for(var i=0; i < orth.length; i++)  // Check around.
        if(view[orth[i]].ant && view[orth[i]].ant.type == 5 && view[orth[i]].ant.friend && view[orth[i]].color == queenBuild)   // Is there a queen, in build mode, around us?
            return move(4)  // Wait politely for her to finish.

    var col = antTrail[me.type-1] // Which colour I use.

    if(me.food < 1){    // If we have no food.
        for(i=0; i < orth.length; i++){ // Check Orthogonals
            if(view[orth[i]].food){ // Is there food there?
                if(turf != col) // If we're not standing on our trail.
                    return {cell: 4, color: col}    // Place our trail here, so we can still find our way back.
                return move(orth[i])    // Otherwise, move to the food!
            }
        }
    }

    if(turf == col) // If we're sitting on our trail.
        return move(2) // Move off it randomly

    var corq = (t)=>t.color == col || (t.ant && t.ant.type == 5 && t.ant.friend)    // Helper function, does this tile contain our trail or the queen?
    var corqorf = (t)=>corq(t) || t.food    // Helper function, odes this tile contain our trail, the queen, or a piece of food?
    var queenInView = false;
    for(var i=0; i < view.length; i++)  // Check the entire view.
        if(view[i].ant && view[i].ant.type == 5 && view[i].ant.friend) // Can we see the queen?
            queenInView = true; // Remember this.

    // Using food > 0 behavoir if we see a queen, makes it so that we don't accidentally build our path over the queen or something silly.

    if(me.food > 0 || queenInView){ // If we have food, or we can see the queen.
        // DON'T build paths, just orbit our path clockwise.
        var orthmov = [3,7,1,5] // Directions to move if we see a path on an orthogonal.
        var diagC = [3,1,7,5]   // Directions to move if we see a path on a diagonal.
        for(var i=0; i < orth.length; i++)  // For each Orthogonal, which takes preference.
            if(corqorf(view[orth[i]]))  // Is there the queen, a trail, or food here?
                return move(orthmov[i]) // move CW to it.
        for(var i=0; i < diag.length; i++)  // Ditto for Diagonals.
            if(corqorf(view[diag[i]]))
                return move(diagC[i])

    }else{
        // EXTEND paths, or continue orbiting clockwise.
        var orthM = [0,6,2,8]   // Directions a path should be when we check an orthogonal.
        var orthMo = [3,7,1,5]  // Directions to move if we see an orthogonal, and the diagonal is there.
        var diagC = [3,1,7,5]   // Directions to place a path if we only see an orthogonal.
        for(var i=0; i < orth.length; i++){ // In each Orthogonal.
            var v = view[orth[i]]
            if(corq(v)){    // Is there a trial?
                if(corq(view[orthM[i]]))    // Is there a trail in the after it position?
                    return move(orthMo[i])  // Move in the correct direction.
                return {cell:orthM[i], color:col}   // Place the trail in the after it position.
            }
        }
        for(var i=0; i < diag.length; i++)  // Check diagonals as a last resort.
            if(corq(view[diag[i]])) // Is there a path /HERE/?
                return {cell:diagC[i], color:col}   // Place the respective diagonal's orthogonal.

    }
    return move(2)  // When we're lost, scamper around. Just like Trail-eraser wants us to.
}

इस खिलाड़ी को एक टूर्नामेंट खेल में अयोग्य घोषित किया गया था और इसे ठीक करने के लिए संपादित किए जाने तक लीडरबोर्ड से बाहर रखा जाएगा। आगे की टिप्पणी में विवरण।
ट्राइकोप्लाक्स

कारण: भोजन के ऊपर नया श्रमिक नहीं बनाया जा सकता। इनपुट: [{"रंग": 7, "भोजन": 0, "चींटी": अशक्त}, {"रंग": 1, "भोजन": 0, "चींटी": अशक्त}, {"रंग": 8, * "खाना": 0, "चींटी": अशक्त}, { "रंग": 3, "खाना": 1, "चींटी": अशक्त}, { "रंग": 7, "खाना": 0, "चींटी": { "खाना": 1, "type": 5, 'मित्र': सच}}, { "रंग": 1, "खाना": 0, "चींटी": अशक्त}, { "रंग": 1, "खाना ": 0," चींटी ": अशक्त}, {" रंग ": 1," खाना ": 0," चींटी ": अशक्त}, {" रंग ": 7," खाना ": 0," चींटी ": अशक्त} ] प्रतिक्रिया: {"सेल": 3, "टाइप":

3

रोमनस्को रोड

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

एक उत्तर में पहला कोड ब्लॉक होता है, जो स्वचालित रूप से खेल में शामिल होता है:

// Full version that won't be disqualified for moving onto another ant

var i

// Color own cell if white
if (view[4].color === 1) {
    return {cell:4, color:3}
}

// Otherwise move to food if visible
for (i=0; i<9; i++) {
    if (view[i].food) {
        return {cell:i}
    }
}

// Otherwise move to a white cell opposite a colored cell
for (i=0; i<9; i++) {
    if (view[i].color === 1 && view[8-i].color > 1 && !view[i].ant) {
        return {cell:i}
    }
}

// Otherwise move to an unoccupied cell
for (i=0; i<9; i++) {
    if (!view[i].ant) {
        return {cell:i}
    }
}

// Otherwise don't move at all
return {cell:4}

यहाँ एक सरल संस्करण है जो अन्य चींटियों के लिए जाँच नहीं करता है, लेकिन जब तक यह एक और चींटी पर कदम रखने की कोशिश करने के लिए अयोग्य नहीं हो जाता है तब तक समान व्यवहार होता है:

// Basic version for an intuitive understanding

var i

// Color own cell if white
if (view[4].color === 1) {
    return {cell:4, color:3}
}

// Otherwise move to food if visible
for (i=0; i<9; i++) {
    if (view[i].food) {
        return {cell:i}
    }
}

// Otherwise move to a white cell opposite a colored cell
for (i=0; i<9; i++) {
    if (view[i].color === 1 && view[8-i].color > 1) {
        return {cell:i}
    }
}

// Otherwise move "left and up", which will be a random direction
return {cell:0}

यह दूसरा कोड ब्लॉक गेम द्वारा नहीं उठाया जाएगा - इसका मतलब है कि आप अपने जवाब के विवरण के हिस्से के रूप में अतिरिक्त कोड ब्लॉक शामिल कर सकते हैं। बस यह सुनिश्चित करें कि गेम में जिस कोड ब्लॉक को आप प्रतिस्पर्धा करना चाहते हैं, वह उत्तर में पहला है।

एक सीधी रेखा के बजाय यादृच्छिक आंदोलन के उत्पादन के उदाहरण के लिए, ब्राउनियन जिग देखें ।


3

VinceAnt

क्या आपको लगता है कि नौ महीने के बाद, अखाड़ा अभी भी थोड़ा धुंधला दिखता है?

क्या आपको लगता है कि Antdom Walking Artist और अनाथ फ़ार्मेशन कार्यकर्ता इसे आकर्षक रूप से सजाने में थोड़ी मदद कर सकते हैं?

तब आप इस एक को पसंद करेंगे!

ए हाइवे, रिफंडेड

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

क्लाउड और जीन

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

इसकी प्रकृति से, यह प्रविष्टि लाइट्सपीड को हरा नहीं सकती है, लेकिन इसके सभी असाधारण के लिए यथोचित प्रदर्शन करने की उम्मीद है - वर्तमान (अप्रैल 2018 के अनुसार) दावेदारों में पांचवां।

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

var ANV=1;var AMK=2;var AGS=3;var AWM=4;var AQ=5;var THC=1;var THP=[0,0,0,0,0,0];THP[AMK]=19;THP[AGS]=17;THP[AWM]=15;var RM=15;var SPDAT =[0,AMK,AGS,0,AWM,0,AGS,AWM,0,AMK,0,AWM,AMK,0,AGS];var PW=1;var PY=2;var PP=3;var PC=4;var PR=5;var PG=6;var PB=7;var PK=8;var LCLR=PW;var LT=PY;var LLSF=PG;var TN=8;var POSC=4;var NOP={cell:POSC};var CCW=[6,7,8,5,2,1,0,3,6,7,8,5,2,1,0,3,6,7,8,5,2,1];
var xn=-1;var here=view[POSC];var mC=here.color;var myself=here.ant;var mT=myself.type;var mF=myself.food;var mS=(mT!=AQ&&mF>0);var dOK=[true,true,true,true,true,true,true,true,true];
var uo=true;var sL=[0,0,0,0,0,0,0,0,0];var sD=[0,0,0,0,0,0,0,0,0];var sN=[0,0,0,0,0,0,0,0,0];var sT=[0,0,0,0,0,0,0,0,0];var fdL=0;var fdD=0;var fdT=0;sT[mC]++;for (var i=0; i<TN; i+=2){var cell=view[CCW[i]];sD[cell.color]++;sN[cell.color]++;sT[cell.color]++;if (cell.food>0){fdD++;fdT++;if (mS){dOK[CCW[i]]=false;uo=false;}}}for (var i=1; i<TN; i+=2){var cell=view[CCW[i]];sL[cell.color]++;sN[cell.color]++;sT[cell.color]++;if (cell.food>0){fdL++;fdT++;if (mS){dOK[CCW[i]]=false;uo=false;}}}var aF=[0,0,0,0,0,0];var aLF=[0,0,0,0,0,0];var aUF=[0,0,0,0,0,0];var fT=0;var mQ=0;var aE=[0,0,0,0,0,0];var aLE=[0,0,0,0,0,0];var aUE=[0,0,0,0,0,0];var eT=0;for (var i=0; i<TN; i++){var cell=view[CCW[i]];if (cell.ant){if (cell.ant.friend){aF[cell.ant.type]++;fT++;if (cell.ant.type==AQ){xn=i&6;mQ=i&1;}if (cell.ant.food>0){aLF[cell.ant.type]++;} else {aUF[cell.ant.type]++;}} else {aE[cell.ant.type]++;eT++;if (cell.ant.food>0){aLE[cell.ant.type]++;} else {aUE[cell.ant.type]++;}}dOK[CCW[i]]=false;uo=false;}}switch (mT){case AQ:return (rQSs());case ANV:return (rNSs());case AMK:return (rMSs());case AGS:return (rGSs());case AWM:return (rWSs());default:return NOP;}function rQSs(){switch (aF[ANV]){case 0:return (rQScrSy());case 1:for (var i=0; i<TN; i++){var cell=view[CCW[i]];if (cell.ant&&cell.ant.friend&&cell.ant.type==ANV){xn=i&6;if (i&1){return (rQLsSy());} else {return (rQCSy());}}}break;default:return (rQCNSy());}return NOP;}function rNSs(){if (aF[AQ]>0){if (mQ==1){return (rSLSy());} else {return (rNRSy());}} else if ((mF==0)&&(fdT>0)){return (rPEgSy());} else {return (rPPgSy());}}function rMSs(){if ((aF[AQ]>0)&&(mF==0)){if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else if (dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};} else {return NOP;}} else if ((mF>0)&&(aF[AQ]+aF[ANV]>0)){return NOP;} else if ((mF==0)&&(fdT>0)){return (rPEgSy());} else if (aF[AGS]+aF[AWM]>1){return (rPMgSy());} else if (aF[AGS]==1){return (rCPgSy());} else {return (rMPgSy());}}function rGSs(){if ((aF[AQ]>0)&&(mF==0)){if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else if (dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};} else {return NOP;}} else if ((mF>0)&&(aF[AQ]+aF[ANV]>0)){return NOP;} else if ((mF==0)&&(fdT>0)){return (rPEgSy());} else if (aF[AMK]+aF[AWM]>1){return (rPMgSy());} else if (aF[AMK]==1){return (rJPgSy());} else {return (rGPgSy());}}function rWSs(){if ((aF[AQ]>0)&&(mF==0)){if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else if (dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};} else {return NOP;}} else if ((mF>0)&&(aF[AQ]+aF[ANV]>0)){return NOP;} else if ((mF==0)&&(fdT>0)){return (rPEgSy());} else if (aF[AMK]+aF[AGS]>1){return (rPMgSy());} else {return (rWPgSy());}}function rQScrSy(){if (uo){if (fdT>0){return (rQSETc());} else if (mF>=THC){for (var i=0; i<TN; i+=2){if ((view[CCW[i]].color==LT)||(view[CCW[i+1]].color==LT)){return {cell:CCW[i+1],type:ANV};}}return {cell:1,type:ANV};} else if (mC!=LT){if ((mC==LCLR)||(sN[LCLR]>=TN-1)){return {cell:POSC,color:LT};} else {return (rQSTCTc());}} else if ((sN[LCLR]>=4)&&(sN[LT]==1)){for (var i=0; i<TN; i+=2){if ((view[CCW[i]].color==LT)||(view[CCW[i+1]].color==LT)){return {cell:CCW[i+4]};}}} else if (sN[LCLR]==TN){return {cell:0};} else {return (rQSATc());}} else {if ((fdT>0)&&(eT>0)&&(eT==aE[AQ])){return (rQSSTc());} else {return (rQSEvTc());}}return NOP;}function rQLsSy(){if ((sT[LCLR]<=2)&&(mF>1)&&(eT==0)){var artist=SPDAT[mF % RM];if ((artist!=0)&&(mF>=THP[artist])&&(aF[artist]<=1)){var tc=[6,2,4,5,3];for (var i=0; i<tc.length; i++){var c=CCW[xn+tc[i]];if (dOK[c]&&(view[c].food==0)){return {cell:c,type:artist};}}}}if ((eT==0)&&(fT==1)){if (view[CCW[xn+2]].food>0){return {cell:CCW[xn+2]};} else if ((view[CCW[xn+3]].food +view[CCW[xn+4]].food>0)&&(view[CCW[xn+1]].color!=LLSF)){return NOP;} else {return {cell:CCW[xn+2]};}} else if (dOK[CCW[xn+2]]&&dOK[CCW[xn+3]]){return {cell:CCW[xn+2]};} else if (dOK[CCW[xn]]&&dOK[CCW[xn+7]]){return {cell:CCW[xn]};} else if (dOK[CCW[xn+6]]){return {cell:CCW[xn+6]};} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else {return NOP;}}function rQCNSy(){for (var i=0; i<TN; i++){var cell=view[CCW[i]];if (cell.ant&&cell.ant.friend&&cell.ant.type==ANV){if (i&1){if (dOK[CCW[i-1]]){return {cell:CCW[i-1]};} else if (dOK[CCW[i+1]]){return {cell:CCW[i+1]};} else if (dOK[CCW[i+4]]){return {cell:CCW[i+4]};} else {return NOP;}} else {if (dOK[CCW[i+7]]){return {cell:CCW[i+7]};} else if (dOK[CCW[i+1]]){return {cell:CCW[i+1]};} else if (dOK[CCW[i+4]]){return {cell:CCW[i+4]};} else {return NOP;}}}}return (rQCSy());}function rQCSy(){return NOP;}function rSLSy(){if ((eT==0)&&(fT==1)){if (view[CCW[xn]].food>0){return {cell:CCW[xn]};} else if (view[CCW[xn+7]].food +view[CCW[xn+6]].food>0){return {cell:POSC,color:LLSF};} else {return {cell:CCW[xn]};}} else if ((eT>0)&&view[CCW[xn+2]].ant&&!view[CCW[xn+2]].ant.friend){return {cell:POSC,color:LLSF};} else if ((fT>1)&&((view[CCW[xn+6]].ant&&view[CCW[xn+6]].ant.friend&&
(view[CCW[xn+6]].ant.food>0))||(view[CCW[xn+5]].ant&&view[CCW[xn+5]].ant.friend&&
(view[CCW[xn+5]].ant.food>0)))){return {cell:POSC,color:LLSF};} else {if (dOK[CCW[xn]]){return {cell:CCW[xn]};} else if (dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};}}return NOP;}function rNRSy(){if (view[CCW[xn+1]].ant&&view[CCW[xn+1]].ant.friend&&
(view[CCW[xn+1]].ant.type==mT)){if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else if (dOK[CCW[xn+6]]){return {cell:CCW[xn+6]};} else if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};} else {return NOP;}} else if (view[CCW[xn+7]].ant&&view[CCW[xn+7]].ant.friend&&(view[CCW[xn+7]].ant.type==mT)){if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else {return NOP;}} else if (dOK[CCW[xn+1]]){return {cell:CCW[xn+1]};} else if (dOK[CCW[xn+7]]){return {cell:CCW[xn+7]};} else if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else if (dOK[CCW[xn+2]]){return {cell:CCW[xn+2]};} else if (dOK[CCW[xn+6]]){return {cell:CCW[xn+6]};} else {return NOP;}}function rPPgSy(){if (aLF[AMK]+aLF[AGS] +aLF[AWM]>0){for (var i=0; i<TN; i++){if (view[CCW[i]].ant&&view[CCW[i]].ant.friend&&
(view[CCW[i]].ant.food>0)){if (dOK[CCW[i+4]]){return {cell:CCW[i+4]};} else if (dOK[CCW[i+3]]){return {cell:CCW[i+3]};} else if (dOK[CCW[i+5]]){return {cell:CCW[i+5]};}}}} else if (aF[mT]>0){return (rSPTc());}return (rPPgTc());}function rMPgSy(){if (aF[mT]>0){return (rSPTc());}return (rMPgTc());}function rGPgSy(){if (aF[mT]>0){return (rSPTc());}return (rGPgTc());}function rWPgSy(){if (aF[mT]>0){return (rSPTc());}return (rWPgTc());}function rCPgSy(){var phase=0;for (var i=0; i<TN; i++){if (view[CCW[i]].ant&&view[CCW[i]].ant.friend&&
(view[CCW[i]].ant.type==AGS)){xn=i&6;phase=i&1;break;}}if ((phase==1)&&(mC==view[CCW[xn+7]].color)&&(view[CCW[xn]].color==view[CCW[xn+1]].color)){if (dOK[CCW[xn+3]]){return {cell:CCW[xn+3]};} else if (dOK[CCW[xn]]){return {cell:CCW[xn]};} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+6]]){return {cell:CCW[xn+6]};} else {return NOP;}} else {return {cell:CCW[xn+7],color:mC};}return NOP;}function rJPgSy(){var phase=0;for (var i=0; i<TN; i++){if (view[CCW[i]].ant&&view[CCW[i]].ant.friend&&
(view[CCW[i]].ant.type==AMK)){xn=i&6;phase=i&1;break;}}if (phase==0){if (dOK[CCW[xn+7]]){return {cell:CCW[xn+7]};} else if (dOK[CCW[xn+1]]){return {cell:CCW[xn+1]};} else if (dOK[CCW[xn+4]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else if (dOK[CCW[xn+6]]){return {cell:CCW[xn+6]};} else {return NOP;}} else {return {cell:CCW[xn+3],color:mC};}return NOP;}function rPEgSy(){for (var i=0; i<TN; i++){if ((view[CCW[i]].food>0)&&dOK[CCW[i]]){return {cell:CCW[i]};}}return NOP;}function rPMgSy(){for (var i=0; i<TN; i+=2){if (view[CCW[i]].ant&&view[CCW[i]].ant.friend&&
(view[CCW[i]].ant.type!=mT)){if (dOK[CCW[i+1]]&&!view[CCW[i+7]].ant&&!view[CCW[i+2]].ant&&!view[CCW[i+3]].ant){return {cell:CCW[i+1]};} else if (dOK[CCW[i+7]]&&!view[CCW[i+1]].ant&&
!view[CCW[i+6]].ant&&!view[CCW[i+5]].ant){return {cell:CCW[i+7]};}}}for (var i=1; i<TN; i+=2){if (view[CCW[i]].ant&&view[CCW[i]].ant.friend&&
(view[CCW[i]].ant.type!=mT)){if (dOK[CCW[i-1]]&&!view[CCW[i+6]].ant){return {cell:CCW[i-1]};} else if (dOK[CCW[i+1]]&&!view[CCW[i+2]].ant){return {cell:CCW[i+1]};}}}for (var i=0; i<TN; i++){if (dOK[CCW[i]]){return {cell:CCW[i]};}}return {cell:POSC,color:view[CCW[0]].color};}function rQSETc(){if (mC!=LT){return {cell:POSC,color:LT};}for (var i=0; i<TN; i++){if (view[CCW[i]].food>0){return {cell:CCW[i]};}}return NOP;}function rQSSTc(){for (var i=0; i<TN; i++){if ((view[CCW[i]].food>0)&&(dOK[CCW[i]])){return {cell:CCW[i]};}}return NOP;}function rQSTCTc(){if ((mC!=LCLR)&&(sN[mC]>=4)){if (sN[LT]==0){return {cell:POSC,color:LT};} else if (sN[LT]>=3){return {cell:POSC,color:LT};} else {for (var i=0; i<TN; i++){if ((view[CCW[i]].color==LT)&&(view[CCW[i+2]].color!=LT)){return {cell:CCW[i+2],color:LT};}}return NOP;}} else if (sN[LT]==1){for (var i=0; i<TN; i++){if ((view[CCW[i]].color==LT)&&(view[CCW[i+4]].color!=LCLR)){if (view[CCW[i+1]].color==LCLR){return { cell:CCW[i+1]};} else if (view[CCW[i+7]].color==LCLR){return { cell:CCW[i+7]};} else {return {cell:POSC,color:LT};}}}return {cell:POSC,color:LT};} else {return {cell:POSC,color:LT};}return NOP;}function rQSATc(){for (var i=0; i<TN; i++){if ((view[CCW[i]].color==LCLR)&&(view[CCW[i+1]].color==LCLR)&&(view[CCW[i+2]].color==LCLR)){if ((view[CCW[i+3]].color==LCLR)&&(view[CCW[i+4]].color==LCLR)){return {cell:CCW[i+2]};}return {cell:CCW[i+1]};}}for (var i=TN-1; i>=0; i--){if (view[CCW[i]].color!=LT){return {cell:CCW[i]};}}for (var i=0; i<TN; i++){if (view[CCW[i]].color!=LT){return {cell:CCW[i],color:LCLR};}}return {cell:0,color:LCLR};}function rQSEvTc(){if (sN[LT]>0){for (var i=0; i<TN; i++){if (view[CCW[i]].color==LT){xn=i&6;}}if ( dOK[CCW[xn+7]]&&dOK[CCW[xn]]&&dOK[CCW[xn+1]]&&dOK[CCW[xn+2]]&&dOK[CCW[xn+3]] ){return {cell:CCW[xn+1]};} else if (dOK[CCW[xn+5]]&&dOK[CCW[xn+6]]&&dOK[CCW[xn+7]]&&dOK[CCW[xn]]&&dOK[CCW[xn+1]]){return {cell:CCW[xn+7]};} else if (dOK[CCW[xn+3]]&&dOK[CCW[xn+4]]&&dOK[CCW[xn+5]]){return {cell:CCW[xn+4]};} else if (dOK[CCW[xn+5]]&&dOK[CCW[xn+6]]&&dOK[CCW[xn+7]]){return {cell:CCW[xn+6]};} else if (dOK[CCW[xn+1]]&&dOK[CCW[xn+2]]&&dOK[CCW[xn+3]]){return {cell:CCW[xn+2]};} else if (dOK[CCW[xn+7]]&&dOK[CCW[xn]]&&dOK[CCW[xn+1]]){return {cell:CCW[xn]};} else {for (var i=0; i<TN; i++){if (dOK[CCW[i]]){return {cell:CCW[i]};}}return NOP;}} else {for (var i=0; i<TN; i++){if (dOK[CCW[i]]&&dOK[CCW[i+1]]&&dOK[CCW[i+2]]&&dOK[CCW[i+3]]&&dOK[CCW[i+4]]){return {cell:CCW[i+2]};}}for (var i=0; i<TN; i++){if (dOK[CCW[i]]&&dOK[CCW[i+1]]&&dOK[CCW[i+2]]){return {cell:CCW[i+1]};}}for (var i=0; i<TN; i++){if (dOK[CCW[i]]){return {cell:CCW[i]};}}return NOP;}return NOP;}function rPPgTc(){if (sL[mC]==0){return {cell:1,color:mC};}for (var i=1; i<TN; i+=2){if (view[CCW[i]].color==mC){xn=i&6;break;}}var col1=(mC+1) % 8+1;if ((view[CCW[xn+5]].color==mC)&&(view[CCW[xn+3]].color==col1)&&(view[CCW[xn+7]].color!=col1)){xn=(xn+4) % 8;}if (view[CCW[xn+7]].color!=col1){return {cell:CCW[xn+7],color:col1};} else if (view[CCW[xn]].color!=col1){return {cell:CCW[xn],color:col1};}var col2=(mC+5) % 8+1;if (view[CCW[xn+3]].color!=col2){return {cell:CCW[xn+3],color:col2};} else if (view[CCW[xn+2]].color!=col2){return {cell:CCW[xn+2],color:col2};} else if (view[CCW[xn+5]].color!=mC){return {cell:CCW[xn+5],color:mC};} else if (view[CCW[xn+4]].color!=col2){return {cell:CCW[xn+4],color:col2};} else if (dOK[CCW[xn+5]]){return {cell:CCW[xn+5]};} else {return (rWgPTc());}}function rMPgTc(){switch (sT[mC]){case 9:var col=((mC+2) % 8)+1;return {cell:CCW[0],color:col};case 8:for (var i=0; i<TN; i++){var col=view[CCW[i]].color;if (col!=mC){if (i==0){return {cell:POSC,color:col};} else if ((i==1)&&dOK[CCW[i+3]]){return {cell:CCW[i+3]};} else if ((i==2)&&dOK[CCW[i+5]]){return {cell:CCW[i+5]};} else {return {cell:CCW[i-1],color:col};}}}break;case 7:return rWgPTc();case 6:for (var i=0; i<TN; i++){if (view[CCW[i]].color!=mC){if ((i==0)&&dOK[CCW[i+5]]){return {cell:CCW[i+5]};} else if ((i==1)&&dOK[CCW[i+4]]){return {cell:CCW[i+4]};} else {return {cell:CCW[i],color:mC};}}}break;case 5:case 4:case 3:for (var i=0; i<TN; i++){if (view[CCW[i]].color!=mC){return {cell:CCW[i],color:mC};}}break;case 2:case 1:default:for (var i=TN-1; i>=0; i--){var col=view[CCW[i]].color;if ((col==mC)&&(sT[view[CCW[i+4]].color]==7)&&dOK[CCW[i+4]]){return {cell:CCW[i+4]};}if (sT[col]>=3){return {cell:POSC,color:col};}}var col=view[CCW[1]].color;if (view[CCW[0]].color!=col){return {cell:CCW[0],color:col};} else if (view[CCW[2]].color!=col){return {cell:CCW[2],color:col};}break;}return (rWgPTc());}function rGPgTc(){var col=0;for (var c0=view[CCW[0]].color; c0<view[CCW[0]].color+8; c0++){var c=(c0 % 8)+1;if (sN[c]==0){col=c;}}if (col==0){return (rWgPTc());}for (var i=0; i<TN; i++){if (sN[view[CCW[i]].color]>1){return {cell:CCW[i],color:col};}}return (rWgPTc());}function rWPgTc(){var col=((mC+6) % 8)+1;if (sT[mC]==9){return {cell:CCW[0],color:col};}var myRand=(view[CCW[0]].color+sT[view[CCW[2]].color]) % 3;
switch (myRand){case 0:for (var i=0; i<TN; i+=2){if (dOK[CCW[i]]){return {cell:CCW[i]};}}break;case 1:if (view[CCW[1]].color!=view[CCW[7]].color){return {cell:CCW[1],color:view[CCW[7]].color};} else if (view[CCW[5]].color!=view[CCW[3]].color){return {cell:CCW[5],color:view[CCW[3]].color};}break;case 2:if (view[CCW[5]].color!=view[CCW[3]].color){return {cell:CCW[5],color:view[CCW[3]].color};} else if (view[CCW[1]].color!=view[CCW[7]].color){return {cell:CCW[1],color:view[CCW[7]].color};}break;default:break;}for (var i=1; i<TN; i+=2){if (dOK[CCW[i]]){return {cell:CCW[i]};}}return (rWgPTc());}function rSPTc(){for (var i=0; i<TN; i++){if (view[CCW[i]].ant&&view[CCW[i]].ant.friend&&
(view[CCW[i]].ant.type==mT)){if (dOK[CCW[i+4]]){return {cell:CCW[i+4]};} else if (dOK[CCW[i+3]]){return {cell:CCW[i+3]};} else if (dOK[CCW[i+5]]){return {cell:CCW[i+5]};} else if (dOK[CCW[i+2]]){return {cell:CCW[i+2]};} else if (dOK[CCW[i+6]]){return {cell:CCW[i+6]};} else if (dOK[CCW[i+1]]){return {cell:CCW[i+1]};}}}return NOP;}function rWgPTc(){for (var i=0; i<TN; i++){if (dOK[CCW[i]]){return {cell:CCW[i]};}}return NOP;}

का आनंद लें!

** v1.0.1 अब सख्त-मोड नियंत्रकों के साथ संगत है।

** v1.0.2 एक अयोग्य टाइपो को ठीक करता है।


ध्यान दें कि यदि चींटियां "रचनात्मक" पर्याप्त हैं और अधिक उन्नत चींटियों को भ्रमित करने का प्रबंधन करती हैं, तो इस प्रविष्टि में वास्तव में लाइट्सपीड को पार करने का मौका हो सकता है - कम मजबूत प्रतियोगी = उच्च स्कोर। शायद यहाँ ऐसा नहीं होगा, हालाँकि, यहाँ तक कि हाईवे आमतौर पर कलाकारों के इलाज के लिए बच जाता है ...
Alion

@ एलियन विंसेंट पेंटर कभी-कभी विंडमिल चींटियों को दूसरों के बीच भ्रमित करने के लिए प्रबंधन करते हैं, और कभी-कभी दुश्मन के कार्यकर्ताओं को ब्लॉक करते हैं, या गलत स्थानों पर नई रेल शुरू करने के लिए स्लाइडिंग माइनर या विंडमिल खनिक का कारण बनते हैं - लेकिन अगर लाइटस्पीड एक ही खेल में खेल रहे हैं, तो
लाइट्सपीड

गठन का indev संस्करण दुश्मन के कार्यकर्ताओं के आसपास चढ़ने और उन्हें कचरे से बाहर निकालने का प्रयास करता है, लेकिन यहां तक ​​कि यह हमेशा रेलिंग के लिए नेतृत्व नहीं करता है। और जब यह होता है, तब भी यह असामान्य है कि यह रानी के पास और वहां से जाने के लिए अन्य श्रमिकों की क्षमता में सेंध लगा देता है। इसे मुझसे ले लो, रेल घोंसलों को गुमराह करना काफी कठिन है।
eaglgenes101

@trichoplax फिक्स्ड - खेद और धन्यवाद!
GNiklasch

2

HalfThere

if(view[4].ant.type==5&&view[4].food>1)
{
    for(var i = 0; i<9; i++)
    {
        if(!view[i].ant)
        {
            return{cell:i,type: 1};
        }
    }
}
if(view[4].color != 3){
    return {cell: 4, color: 3};
}
for(var i = 0; i<9; i++)
{
    if(view[i].food==1)
    {
        return({cell:i})
    }

}


var i, j
var orthogonals = [1, 3, 7, 5]  // These are the non-diagonal cells



// Otherwise move to a white cell opposite a colored cell
for (i=0; i<4; i++) {
    j = (i+2) % 4
    if (view[orthogonals[i]].color === 1 &&
        view[orthogonals[j]].color > 1 && !view[orthogonals[i]].ant) {
        return {cell:orthogonals[i]}
    }
}

// Otherwise move to one of the vertical or horizontal cells if not occupied
for (i=1; i<9; i+=2) {
    if (!view[i].ant) {
        return {cell:i}
    }
}

// Otherwise move to one of the diagonal cells if not occupied
for (i=0; i<9; i+=2) {
    if (!view[i].ant) {
        return {cell:i}
    }
}


for(var i = 0; i<9; i++)
{
    if(view[i].color==1)
    {
        return {cell:i};
    }
}
for(var i = 0; i<9; i++)
{
    if(view[i].ant==null)
    {
        return {cell:i};
    }
}

यह बॉट वहां आधा है ... मूल रूप से यह सिर्फ एक रेखा बनाता है और एक सीधी रेखा में जाता है और यदि यह दूसरी रेखा को देखता है तो थोरा चारों ओर घूमता है।

इस कार्यक्रम में एक काम है।


यह विदेशी परिस्थितियों में भोजन पर कार्यकर्ताओं बनाने के लिए अयोग्य घोषित कर दिया प्राप्त कर सकते हैं
pppery

@ वास्तव में यह नहीं हो सकता। कभी कामगार नहीं बनाता: /
क्रिस्टोफर

वास्तव में, यह नहीं हो सकता है, क्योंकि "कार्यकर्ता का तर्क बनाएं" सिर्फ मृत कोड है। फिर भी इंगित करने लायक है
pppery

मैं मृत view[4].food > 1जाँच से उलझन में था , जो कि मैंने एक बार खुद से की थी
pppery

1
बदले view[4].food > 1के लिए view[4].ant.food > 1पर पहली पंक्ति
pppery
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.