भूख गेमिंग - खाओ या मरो


60

भूख गेमिंग - खाओ या मरो

यदि आप नहीं खाते हैं, तो आप मर जाते हैं। यदि आप खाते हैं, तो आप जीते हैं (जब तक आप मर नहीं जाते) तुम मर जाओगे , इसलिए आखिरी मरने की कोशिश करो।

अवलोकन

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

कैसे खेलें

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

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

टूर्नामेंट 64 बिट लिनक्स सिस्टम पर आयोजित किया जाएगा। कोई भी आवश्यक दिशा निर्देश देते समय इसका ध्यान रखें।

विवरण

  • प्रत्येक प्राणी की स्थिति और दिशा क्रमशः doubleउनके xऔर yनिर्देशांक का प्रतिनिधित्व करने वाले दोहरे-सटीक फ़्लोटिंग पॉइंट नंबरों (जैसे ) की एक जोड़ी के रूप में होती है ।

  • प्रत्येक प्राणी एक बिंदु माना जाता है। इसका मतलब है कि वे एक ही स्थान पर ओवरलैप और कब्जा कर सकते हैं। आप एक तरफ टकराएंगे नहीं, और अन्य प्राणियों के साथ टकराव की कोई अवधारणा नहीं है।

  • द्वीप एक वर्ग है, एक तरफ 500 इकाइयाँ हैं। यदि आप उन सीमाओं से परे उद्यम करने की कोशिश करते हैं, तो आपको किनारे पर जकड़ दिया जाएगा। मूल {0,0}ऊपरी-बाएँ में है, xदाईं ओर yबढ़ने और नीचे की ओर बढ़ने के साथ । फिर से, नक्शा लपेट नहीं करता है

  • खेल 1500 + (packCount * 50) शिकार जानवरों के साथ शुरू होता है। उन्हें द्वीप के केंद्र में इकट्ठा किया जाएगा, लेकिन जल्दी से चलना शुरू करने का फैसला किया।

  • परिधि के चारों ओर समान रूप से दूरी वाले सर्कल में पैक्स की व्यवस्था की जाएगी। पैक ऑर्डर में फेरबदल किया गया है, इसलिए किसी विशेष स्थान पर शुरू करने पर भरोसा न करें।

  • प्रिही जानवर 30 यूनिट के दायरे में अन्य सभी जानवरों को देख सकते हैं । वे अधिकतम 6.0 यूनिट प्रति मोड़ पर जा सकते हैं।

  • शिकारी 50 इकाई के दायरे में अन्य सभी जानवरों को देख सकते हैं। वे अधिकतम 6.1 यूनिट प्रति मोड़ पर जा सकते हैं। इसका मतलब है कि वे शिकार होने से पहले देख सकते हैं और (बमुश्किल) उन्हें पीछे छोड़ सकते हैं।

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

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

  • हर 1000 मोड़, अधिक शिकार होगा। नए शिकार की संख्या में रहने वाले शिकारियों की संख्या माइनस एक होगी।

  • शिकारी दूसरे शिकारियों पर हमला नहीं कर सकते। जब वे इसे पकड़ते हैं तो वे शिकार करते हैं। बस।

  • एक मोड़ के भीतर आदेश है:

    • सभी शिकार निर्णय लेते हैं
    • सभी शिकारी निर्णय लेते हैं
    • सभी शिकार करते हैं
    • सभी शिकारी चलते / खाते हैं
  • प्रत्येक पैक उनके आदेश / चालों को प्रत्येक मोड़ पर यादृच्छिक रूप से व्यवस्थित करता है।

प्रोटोकॉल (सामान्य)

सभी संचार स्ट्रिंग प्रारूप में किए जाते हैं US-ASCII। जावा Double.toString()या का उपयोग करके संख्याओं को स्ट्रिंग में बदल दिया जाता है Integer.toString()। आपके आउटपुट को स्वरूपित किया जाना चाहिए ताकि इसे जावा के द्वारा पढ़ा जा सके Double.valueOf(String)(आप पूर्णांक आउटपुट नहीं कर रहे हैं)। पार्स करने योग्य प्रारूपों के विवरण के लिए, के लिए प्रलेखनDouble देखें । एक पंक्ति के सभी फ़ील्ड मानक \tवर्ण द्वारा अलग किए जाते हैं , और नए अंक होते हैं \n। पूरे स्ट्रिंग को समाप्त कर दिया जाएगा एक अशक्त बाइट \0

नीचे दिए गए उदाहरणों में, मैं <>पठनीयता के लिए खेतों को चिह्नित करने के लिए उपयोग कर रहा हूं । ये वास्तविक तारों में मौजूद नहीं हैं।

प्रोटोकॉल (इनपुट)

इनपुट स्ट्रिंग लंबाई में भिन्न होती है, जो इस बात पर निर्भर करती है कि आपके पैक में कितने जीव दिखाई दे रहे हैं। यह 100k अक्षरों को पार कर सकता है, इसलिए इसके लिए तैयार रहें। मूल सेटअप है:

  • लाइन 0: खेल के बारे में बुनियादी जानकारी। turnवर्तमान मोड़ संख्या है, और क्षेत्र में शिकार और शिकारियों की कुल संख्या को छोड़ दिया जाता है। ये integerस्ट्रिंग रूप में हैं।

    <turn>\t<preyCount>\t<predatorCount>\n
    
  • पंक्ति 1: आपके पैक सदस्यों की विशिष्ट आईडी और भूख का स्तर। ये हर इनपुट के लिए समान क्रम में नहीं दिए गए हैं । व्यक्तिगत सदस्यों को ट्रैक करने के लिए अद्वितीय आईडी का उपयोग करें, कि उस क्रम में जिसमें वे इनपुट में दिखाई देते हैं। फिर, ये integerतार के समान हैं। दो पैक के लिए, यह होगा:

    <id[0]>\t<hunger[0]>\t<id[1]>\t<hunger[1]>\n
    
  • पंक्ति 2: आपके पैक सदस्यों के स्थान, उसी क्रम में जैसे पंक्ति 1 पर दिए गए हैं । ये doubleस्ट्रिंग के रूप में हैं :

    <x[0]>\t<y[0]>\t<x[1]>\t<y[1]>\n
    

निम्न पंक्तियाँ प्रत्येक पैक सदस्य की दृश्यता हैं, उसी क्रम में जैसा कि पंक्ति 1 पर दिया गया है । इन्हें प्रति सदस्य दो लाइनों के रूप में दिया जाएगा।

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

प्रत्येक जीवित सदस्य के लिए:

<prey[0].x>\t<prey[0].y>\t<prey[1].x>\t<prey[1].y>\n
<predator[0].x>\t<predator[0].y>\t<predator[1].x>\t<predator[1].y>\n

अंत में, अंतिम चरित्र \0अगली पंक्ति की शुरुआत में होगा।

अपवाद: यदि आप इनपुट प्राप्त करते हैं dead\0, तो आपका पैक मृत है। कृपया अपना कार्यक्रम समाप्त करें, कृपया। नियंत्रक को बंद होने पर सभी जीवित प्रक्रियाओं को बंद कर देना चाहिए , लेकिन मेरे पास सभी जगह ज़ोंबी प्रक्रिया नहीं होगी। शिष्टाचार के रूप में, आप एक इनपुट टाइमआउट शामिल कर सकते हैं। उदाहरण के लिए, मेरा उदाहरण वर्ग तब समाप्त होता है जब उसे 15 सेकंड के लिए इनपुट प्राप्त नहीं होता है।

प्रोटोकॉल (आउटपुट)

आउटपुट सरल है। आप doubleप्रत्येक जीवित पैक सदस्य के लिए एक जोड़ी मान देंगे । ये उस आंदोलन का प्रतिनिधित्व करते हैं जो आप उन्हें इस मोड़ पर ले जाना चाहेंगे। उदाहरण के लिए, यदि आपका प्राणी वर्तमान में है {100.0, 100.0}और आप उन्हें आज्ञा देते हैं {-1.0, 1.0}, तो वे आगे बढ़ेंगे {99.0, 101.0}। सभी नंबर एक लाइन पर होंगे, जो टैब द्वारा अलग किए गए हैं।

उदाहरण के लिए, यदि आपके पास 3 पैक सदस्य जीवित हैं, तो यह एक मान्य प्रतिक्रिया होगी:

1.0\t-1.0\t2.0\t-2.0\t3.0\t-3.0\0

यह द्वारा अपने जीव कदम होगा {1.0,-1.0}, {2.0,-2.0}और {3.0,-3.0}। आदेश इनपुट में प्राप्त के समान है। अंत मत भूलना \0!

यदि आप अमान्य इनपुट देते हैं, तो बुरे परिणाम होंगे। यदि किसी एकल संख्या को a को पार्स नहीं किया जा सकता है double, तो यह शून्य हो जाएगा। यदि स्ट्रिंग को पूरी तरह से पार्स नहीं किया जा सकता है, तो कोई नया निर्देश नहीं दिया जाएगा, और आपका पूरा पैक पिछली बारी से निर्देशों का उपयोग करेगा।

सभी दिशाओं को 6.1 इकाइयों की अधिकतम दूरी तक जोड़ा जाएगा। यदि आप चाहें तो आप इसे धीमा कर सकते हैं। उदाहरण के लिए, {1, 0}आप एक इकाई को स्थानांतरित करेंगे। {6,8}(दूरी 10) केवल आपको 6.1 इकाइयों को स्थानांतरित कर देगा, और चारों ओर कम कर देगा {3.66, 4.88}। दिशा स्थिर रहती है।

महत्वपूर्ण: नियंत्रण कार्यक्रम आपके STDOUT और STDERR दोनों को पढ़ता है । यदि आप एक अपवाद को फेंकते हैं और STDERR को प्रिंट करते हैं, तो यह बहुत संभावना नहीं है कि संदेश एक मान्य प्रतिक्रिया के रूप में होगा। ऐसा करने से बचने की कोशिश करें।

नियंत्रण कार्यक्रम / परीक्षण

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

java Game "java ChaserPack" "python LazyPack.py"

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

गेम अंतिम शिकारी स्टार्स तक पहुंच जाएगा, कंसोल को भुखमरी या विलुप्त होने की घटनाओं के रूप में लिखता है। एक बार गेम पूरा होने के बाद, प्रत्येक पैक के लिए स्कोर दिया जाएगा। यदि आप भुखमरी / विलुप्त होने की घटनाओं को नहीं देखना चाहते हैं, तो आप -silentतर्क का उपयोग कर सकते हैं । तब यह केवल अंतिम स्कोर का उत्पादन करेगा। आपको इसे पहले तर्क के रूप में पारित करना होगा :

java Game -silent "java ChaserCat" "./someOtherPack"

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

भी शामिल, टेम्पलेट के आधार पर एक शिकारी है ChaserPack। यह टूर्नामेंट में शामिल नहीं होगा, और केवल परीक्षण प्रयोजनों के लिए शामिल किया गया है। जानबूझकर लक्षित दोष के कारण यह काफी खराब प्रदर्शन करता है। यदि आप इसे हरा नहीं सकते हैं, तो कोशिश करते रहें।

नीचे नियंत्रण कार्यक्रम का एक उदाहरण रन (वीडियो के लिए क्लिक करें) है। वीडियो की गुणवत्ता बढ़िया नहीं है (क्षमा करें), लेकिन आप यह महसूस कर सकते हैं कि शिकार कैसे चलता है। ( सावधानी: ऑडियो )

स्क्रीनशॉट

स्कोरिंग

विजेता को प्रत्येक राउंड में अंक प्राप्त करके, टूर्नामेंट द्वारा निर्धारित किया जाएगा।

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

प्रत्येक राउंड के लिए पहले स्थान पर 100 अंक प्राप्त होंगे। उसके बाद प्रत्येक स्थान के लिए, इनाम में 20% (गोल नीचे) की कमी होगी। यह तब तक जारी रहेगा जब तक अंक शून्य (17 वें स्थान के बाद) तक नहीं पहुंच जाते। 18+ स्थानों को गोल के लिए कोई अंक नहीं मिलेगा। टाई करने वाले पैक को बराबर अंक प्राप्त होंगे। उदाहरण के लिए:

1st : 100
2nd : 80
3rd : 64 (T)
3rd : 64 (T)
4th : 51
...
17th: 1
18th: 0
19th: 0

टूर्नामेंट के पाठ्यक्रम पर अधिकतम संभव बिंदु 1000 हैं, पहले स्थान पर सभी दस बार से।

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

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

अतिरिक्त नियम (निष्पक्ष खेलते हैं!)

  • आप किसी भी बाहरी संसाधन को पढ़ या लिख ​​नहीं सकते हैं। चूँकि आप अपने प्रोग्राम म्यूटाल्टर समय को लागू नहीं करने जा रहे हैं, किसी भी राज्य की जानकारी को आंतरिक रूप से संग्रहीत किया जा सकता है।

  • अन्य प्रक्रियाओं / प्रस्तुतियाँ में हस्तक्षेप न करें। इसका मतलब यह नहीं है कि वे अपने शिकार को चुराने की कोशिश न करें, उन्हें छोड़ दें, आदि इसका मतलब है कि इस प्रक्रिया को चलाने में हस्तक्षेप न करें। यह मेरे विवेक पर है।

  • प्रतियोगी अधिकतम तीन प्रविष्टियों तक सीमित हैं । यदि आप अधिक जमा करते हैं, तो मैं केवल पहले प्रस्तुत किए गए तीन अंक प्राप्त करूंगा। यदि आप किसी को रद्द करना चाहते हैं, तो उसे हटा दें।

  • प्रविष्टियाँ केवल अन्य प्रविष्टियों को प्रचलित करने के लिए मौजूद नहीं हो सकती हैं। प्रत्येक को अपनी योग्यता के आधार पर जीतने के लिए खेलना चाहिए।

  • आपका कार्यक्रम एक समय में अधिकतम एक बच्चे की प्रक्रिया को जन्म दे सकता है ( कुल वंशज, प्रत्यक्ष नहीं)। किसी भी तरह से, सुनिश्चित करें कि आप टाइमआउट पर नहीं जाते हैं। हो सकता है कि आप Gameकिसी भी तरह से कक्षा में प्रवेश न करें ।

परिणाम - 29 अप्रैल 2014

यहाँ नवीनतम दस-राउंड टूर्नामेंट के परिणाम हैं:

Clairvoyant         : 1000
EcoCamels           : 752
Netcats             : 688
RubySpiders         : 436
RubyVultures        : 431
CivilizedBeasts     : 382
LazyPack            : 257

09:00 EDT 2014/04/29 से पहले प्रस्तुत पैक इस रन में शामिल हैं।

आप प्रत्येक दौर के लिए विवरण भी देख सकते हैं । किसी कारण से मैंने राउंड को पीछे की ओर करने का फैसला किया, इसलिए यह "राउंड 10" से शुरू होता है।

अपडेट

2014/04/23: FGreg ने टाइमआउट से संबंधित बग की सूचना दी (धन्यवाद!)। एक फिक्स लागू किया गया है, इसलिए परीक्षक अपने नियंत्रण कार्यक्रम कोड को अपडेट करना चाहेंगे।


28
मुझे पहाड़ी सवालों के ये राजा पसंद आ रहे हैं!
क्रंचर

2
@ मैनू I ने विंडोज 7 पर उदाहरण बॉट्स लिखा, और जीत और लिनक्स दोनों पर परीक्षण किया। आपको उनसे क्या समस्याएँ हैं?
ज्योबिट्स

2
पहाड़ी सवालों के ये राजा काफी भयानक हैं, और यह निश्चित रूप से दिलचस्प है। मुझे अब कार्यों में दो अलग-अलग पैक मिले हैं!
mackthehobbit

2
@githubphagocyte मैं वास्तव में पहले टाइमआउट पर एक पैक को मारना नहीं चाहता, सिर्फ इसलिए कि मैंने हर 40k + मुड़ने या इसी तरह के सरल कार्यक्रमों को एक बार भी देखा है। मैंने नियंत्रक में नामकरण परिवर्तन किया। टर्न अब पूरे कार्यक्रम के रूप में जाने जाते हैं, जब तक कि मैं कहीं एक को याद नहीं करता।
Geobits

2
@Geobits एह, मेरे द्वारा ठीक है। तुम्हें पता है, यह वास्तव में एक अनुसंधान परियोजना के समान दिखता है, जो मेरे भौतिकी के प्रोफेसरों में से एक कर रहा है, जो शायद मैं गर्मियों में मदद कर रहा हूं। मैं उस के बारे में थोड़ा बाद में समझाता हूँ अगर मैं कर सकता हूँ।
krs013

जवाबों:


10

भेदक

AbleDogs का सामना करने के लिए कोड अपडेट किया गया

वू हू! अंत में धड़कता है कि Netcats! मैंने इस भविष्य की भविष्यवाणी करने वाले पैक को बनाने के लिए कुछ छोटे संशोधन के साथ मौजूदा कोड (क्रेडिट्स टू जियोबिट्स) का विस्तार किया। कुछ भी नहीं शिकारियों को मारता है जो जानते हैं कि शिकार कहां स्थानांतरित होगा!

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

संभवतया मैं पहले कुछ हजारों मोड़ों के दौरान प्राइसेस की संख्या को कम करने के लिए CivilizedBeasts की चाल को शामिल कर सकता हूं।

5.21 मिनट में पूरा हो गया
क्लेयरवॉयंट (1): 9270 मुड़ें: स्कोर 100
EcoCamel.pl (3): 8118 मुड़ें: स्कोर 80
नेटकैट्स (0): 6111 मुड़ें: स्कोर 64
RubyVultures.rb (5): 4249 मुड़ें: स्कोर 51
RubySpiders.rb (4): 3495 मुड़ें: स्कोर 40
सिविलाइज्डबीस्ट्स (2): टर्न 3176: स्कोर 32
चेज़रपैक (6): टर्न 2492: स्कोर 25

मेरे पैक के नाम से, आपको पता होना चाहिए कि मैं किस रणनीति का उपयोग करता हूं = डी

संपादित करें :

  • एक ही शिकार का पीछा नहीं करने के लिए अद्यतन पैक प्रबंधन प्रणाली (और सबसे अच्छा मैच खोजने की कोशिश भी!)
  • जब शिकार की संख्या छोटी हो तो भटकने की प्रक्रिया में सुधार करें (यह एक जीत के लिए महत्वपूर्ण है!)।
  • विशेष मामलों में सुधार करें जब पिछला संस्करण सिर्फ कोने पर अटक गया हो।
  • एल्गोरिथ्म का पता लगाने वाले शिकारी में एक बग फिक्स्ड (अब यह काफी सटीक है!)
  • शामिल शिकार flock[ALIGN]कारक
  • एक शिकार को पालतू जानवर के रूप में रखें अगर भोजन दुर्लभ है
  • एक ऐसी जगह बनाएं जहां पैक अपने शिकार को झुंड में ले जाएगा
  • हमारे शिकार का पीछा करने वाले शिकारी के पास लालच, जो वे नहीं जीतेंगे

मैंने गिना कि प्रत्येक पैक कितने प्री को खाता है, और यहाँ परिणाम है:

क्लेयरवॉयंट (1) ने 9270 मोड़ (0.099 प्रीस / टर्न) में 916 प्रीस का उपभोग किया
EcoCamel.pl (3) ने 8118 टर्न (0.009 प्रीस / टर्न) में 73 प्रीस का उपभोग किया
नेटकाट्स (0) ने 6111 मोड़ (0.092 प्रीस / टर्न) में 563 प्रीस का उपभोग किया
RubyVultures.rb (5) ने 4249 मोड़ (0.018 प्रीस / टर्न) में 77 शिकार किए
RubySpiders.rb (4) ने 3495 मोड़ (0.084 शिकार / मोड़) में 293 शिकार का उपभोग किया
सिविलाइज्डबीस्ट्स (2) ने 3176 टर्न (0.003 प्रीस / टर्न) में 10 प्रीस का उपभोग किया
चेज़रपैक (6) ने 2492 मोड़ (0.017 प्रीस / टर्न) में 43 प्रीस का उपभोग किया

मेरा पैक बहुत आक्रामक है, और मुझे लगता है कि रुबाईसाइडर्स की तरह, 916 में से अधिकांश गिना जाता है कि यह नेटसैट से चोरी करने से मिलता है।

इकोनामेल से केंद्र के ऊंट के कारण सभ्य नागरिक दुर्भाग्य से हार रहे हैं।

और EcoCamel (भूख महत्वपूर्ण 500 के साथ) बहुत कुशल है, यह अंत तक जीवित रहने के लिए पर्याप्त खाती है।

इसके अलावा इस अपडेटेड क्लैरवॉयंट के साथ, खेल मुश्किल से 10,000 मोड़ तक पहुंचता है।

कोड:

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.TreeSet;

public class Clairvoyant extends GenericPack {
    private static final double MAX_SPEED = 6.1;

    private TreeSet<Animal> foods = new TreeSet<Animal>(new AnimalComparator());
    private TreeSet<Animal> predators = new TreeSet<Animal>(new AnimalComparator());

    private XY abattoirCorner;
    private double abattoirRadius = 100;

    private MyMember[] myMembers = new MyMember[100];

    public class AnimalComparator implements Comparator<Animal>{

        @Override
        public int compare(Animal arg0, Animal arg1) {
            if(arg0.x < arg1.x){
                return -1;
            } else if (arg0.x > arg1.x){
                return 1;
            } else {
                if(arg0.y < arg1.y){
                    return -1;
                } else if(arg0.y > arg1.y){
                    return 1;
                } else {
                    return 0;
                }
            }
        }
    }

    public class MyMember extends Member{
        public XY target;
        public XY herdPos;
        public double herdRadius; 
        public boolean mayEat;
        public XY pos;
        public ArrayList<MyAnimal> closestPreys;
        public boolean outdated;

        public MyMember(int id) {
            super(id);
            this.pos = new XY(x, y);
            closestPreys = new ArrayList<MyAnimal>();
            mayEat = true;
            outdated = true;
        }

        public MyMember(Member member){
            super(member.id);
            this.pos = new XY(x, y);
            closestPreys = new ArrayList<MyAnimal>();
            mayEat = true;
            outdated = true;
        }

        public MyMember(Member member, Animal target){
            super(member.id);
            this.target = new XY(target.x, target.y);
            this.pos = new XY(x, y);
            closestPreys = new ArrayList<MyAnimal>();
            mayEat = true;
            outdated = true;
        }

        public void reset(Member me){
            x = me.x;
            y = me.y;
            pos = new XY(x, y);
            closestPreys.clear();
            mayEat = true;
            outdated = true;
        }
    }

    public class MyAnimal extends Animal{
        public ArrayList<MyMember> chasers;
        public XY pos;
        public boolean resolved;

        public MyAnimal(double x, double y){
            super(x, y);
            pos = new XY(x, y);
            chasers = new ArrayList<MyMember>();
            resolved = false;
        }

        public MyAnimal(Animal ani){
            super(ani.x, ani.y);
            pos = new XY(x, y);
            chasers = new ArrayList<MyMember>();
            resolved = false;
        }
    }

    public static void main(String[] args){
        new Clairvoyant().run();
    }

    public Clairvoyant(){
        for(int i=0; i<100; i++){
            nextIdx[i] = 0;
        }
        int cornerIdx = (int)Math.floor(Math.random()*4);
        switch (cornerIdx){
        case 0: abattoirCorner = new XY(0,0); break;
        case 1: abattoirCorner = new XY(500,0); break;
        case 2: abattoirCorner = new XY(500,500); break;
        case 3: abattoirCorner = new XY(0,500); break;
        }
    }

    @Override
    public void respond(){
        updateData();
        goToTarget();
    }

    private void updateData(){
        for(int i=0; i<100; i++){
            if(myMembers[i]!=null){
                myMembers[i].pos = null;
            }
        }
        foods.clear();
        predators.clear();
        for(Member me: members){
            foods.addAll(me.foods);
            predators.addAll(me.others);
            predators.add(new Animal(me.x, me.y));
            if(myMembers[me.id] != null){
                myMembers[me.id].reset(me);
            } else {
                myMembers[me.id] = new MyMember(me);
            }
        }
        for(int i=0; i<100; i++){
            if(myMembers[i]!=null && myMembers[i].pos == null){
                myMembers[i] = null;
            }
        }

        TreeSet<MyAnimal> closestPreys = new TreeSet<MyAnimal>(new AnimalComparator());
        for(int i=0; i<100; i++){
            if (myMembers[i]==null) continue;
            MyMember me = myMembers[i];
            ArrayList<Animal> animals = findClosest(foods, me.pos, members.size());
            boolean first = true;
            for(Animal ani: animals){
                MyAnimal myAni = new MyAnimal(ani);
                if(closestPreys.contains(ani)){
                    myAni = closestPreys.ceiling(myAni);
                } else {
                    closestPreys.add(myAni);
                }
                if(first){
                    myAni.chasers.add(me);
                    first = false;
                }
                me.closestPreys.add(myAni);
            }
        }
        performMatching();
        for(int i=0; i<100; i++){
            if (myMembers[i] == null) continue;
            MyMember me = myMembers[i];
            if(!me.outdated) continue;
            if(me.closestPreys.size() == 0) continue;
            MyAnimal closestPrey = me.closestPreys.get(0);
            if(closestPrey.resolved) continue;
            if(closestPrey.chasers.size() > 1){
                MyMember hungriest = me;
                MyMember closest = me;
                for(MyMember otherMe: closestPrey.chasers){
                    if(sqDist(closestPrey.pos, otherMe) < sqDist(closestPrey.pos, closest)){
                        closest = otherMe;
                    }
                    if(otherMe.hunger < hungriest.hunger){
                        hungriest = otherMe;
                    }
                }
                if(hungriest.hunger > 200){ // Nobody's critically hungry, the closest takes the prey
                    closest.target = closestPrey.pos;
                    closest.mayEat = true;
                    closest.herdPos = abattoirCorner;
                    closest.herdRadius = abattoirRadius;
                    closest.outdated = false;
                } else {
                    if(hungriest == closest){
                        closest.target = closestPrey.pos;
                        closest.mayEat = true;
                        closest.herdPos = abattoirCorner;
                        closest.herdRadius = abattoirRadius;
                        closest.outdated = false;
                    } else {
                        closest.target = closestPrey.pos;
                        closest.mayEat = false;
                        closest.herdPos = hungriest.pos;
                        closest.herdRadius = 0;
                        closest.outdated = false;
                        hungriest.target = closestPrey.pos;
                        hungriest.mayEat = true;
                        hungriest.herdPos = abattoirCorner;
                        hungriest.herdRadius = 10;
                        hungriest.outdated = false;
                    }
                }
                closestPrey.resolved = true;
            } else {
                me.target = closestPrey.pos;
                me.herdPos = abattoirCorner;
                me.herdRadius = abattoirRadius;
                me.mayEat = true;
                me.outdated = false;
            }
        }
        for(int i=0; i<100; i++){
            if (myMembers[i] == null) continue;
            MyMember me = myMembers[i];
            if(me.outdated){
                me.target = null;
                me.outdated = false;
            }
        }
    }

    private void goToTarget(){
        for(Member me: members){
            MyMember mem = myMembers[me.id];
            if(mem.target == null){
                wander(me, 2*(me.id%2)-1);
                continue;
            } else {
                nextIdx[me.id] = 0;
                XY[] nearestHostile = new XY[100];
                for(Animal other: me.others){
                    XY otherPos = new XY(other.x, other.y);
                    boolean isMember = false;
                    for(Member otherMember: members){
                        if(other.x==otherMember.x && other.y==otherMember.y){
                            isMember = true;
                            break;
                        }
                    }
                    if(!isMember){
                        if(nearestHostile[me.id] == null || XY.sqDistance(mem.pos, otherPos) < XY.sqDistance(mem.pos,  nearestHostile[me.id])){
                            nearestHostile[me.id] = otherPos;
                        }
                    }
                }

                // Go towards the target by predicting its next position
                XY target = predictNextPos(mem.target, me);

                me.dx = (target.x - me.x);
                me.dy = (target.y - me.y); 

                // Try to herd the target to our abattoir if this member is not too hungry
                // and if there is no other hostile predator who is closer to the target than us
                // This will make the other hostile predator to keep targeting this target, while
                // it is certain that we will get the target.
                // This is a win situation for us, since it will make the other predator wasting his turn.
                if((me.hunger <= 200 && XY.sqDistance(mem.target, mem.pos) > 400) || me.hunger <= 50 ||
                        (nearestHostile[me.id] != null && Math.sqrt(XY.sqDistance(mem.target, nearestHostile[me.id])) < Math.sqrt(XY.sqDistance(mem.target, mem.pos)))){
                    continue;
                }

                // Don't eat if not threatened nor hungry
                if(me.hunger > 50 && (nearestHostile[me.id] == null ||
                        Math.sqrt(XY.sqDistance(mem.target, nearestHostile[me.id])) > Math.sqrt(XY.sqDistance(mem.target, mem.pos)) + 6)){
                    mem.mayEat = false;
                }

                // Herd to abattoir corner
                double distFromHerd = Math.sqrt(XY.sqDistance(target, mem.herdPos));
                XY oppositeAbattoirCorner = new XY(500-abattoirCorner.x, 500-abattoirCorner.y);
                double distFromOpposite = Math.sqrt(XY.sqDistance(target, oppositeAbattoirCorner));
                if((me.dx*me.dx+me.dy*me.dy > 64 && distFromHerd > mem.herdRadius && distFromOpposite > abattoirRadius)
                        || (preyCount < 5*predCount)){
                    double herdDistance = 4*(distFromHerd-mem.herdRadius)/(Island.SIZE-mem.herdRadius);
                    if(!mem.mayEat) herdDistance = 4;
                    XY gradient = target.minus(abattoirCorner);
                    me.dx += gradient.x*herdDistance/distFromHerd;
                    me.dy += gradient.y*herdDistance/distFromHerd;
                }
            }
        }
    }

    private void performMatching(){
        for(int i=0; i<100; i++){
            if (myMembers[i] == null) continue;
            MyMember me = myMembers[i];
            if(me.closestPreys.size()==0) continue;
            MyAnimal closestPrey = me.closestPreys.get(0);
            if(closestPrey.chasers.size() > 1){
                resolveConflict(closestPrey);
            }
        }
    }

    private void resolveConflict(MyAnimal prey){
        ArrayList<MyMember> chasers = prey.chasers;
        MyMember winner = null;
        double closestDist = Double.MAX_VALUE;
        for(MyMember me: chasers){
            if(sqDist(prey.pos, me) < closestDist){
                closestDist = sqDist(prey.pos, me);
                winner = me;
            }
        }
        for(int i=chasers.size()-1; i>=0; i--){
            MyMember me = chasers.get(i);
            if(me!=winner){
                me.closestPreys.get(0).chasers.remove(me);
                me.closestPreys.add(me.closestPreys.remove(0));
                me.closestPreys.get(0).chasers.add(me);
            }
        }
    }

    private Animal findClosest(Collection<Animal> preys, XY me){
        Animal target = null;
        double cDist = Double.MAX_VALUE;
        double x, y, sqDist;
        for (Animal food : preys) {
            x = food.x - me.x;
            y = food.y - me.y;
            sqDist = x * x + y * y + Double.MIN_NORMAL;
            if (sqDist < cDist) {
                cDist = sqDist;
                target = food;
            }
        }
        return target;
    }

    private ArrayList<Animal> findClosest(Collection<Animal> preys, XY me, int num){
        ArrayList<Animal> result = new ArrayList<Animal>();
        for(Animal food: preys){
            int addIdx = -1;
            for(int i=0; i<num && i<result.size(); i++){
                Animal regFood = result.get(i);
                if(sqDist(me, food) < sqDist(me, regFood)){
                    addIdx = i;
                    break;
                }
            }
            if(addIdx == -1){
                result.add(food);
            } else {
                result.add(addIdx, food);
            }
            if(result.size() > num){
                result.remove(num);
            }
        }
        return result;
    }

    private Member findClosestToTarget(Collection<Member> members, Animal target){
        Member member = null;
        double cDist = Double.MAX_VALUE;
        double x, y, sqDist;
        for (Member me : members) {
            x = me.x - target.x;
            y = me.y - target.y;
            sqDist = x * x + y * y + Double.MIN_NORMAL;
            if (sqDist < cDist) {
                cDist = sqDist;
                member = me;
            }
        }
        return member;
    }

    private static final XY[] CHECKPOINTS = new XY[]{
        new XY(49.5,49.5),
        new XY(450.5,49.5),
        new XY(450.5,100),
        new XY(49.5,100),
        new XY(49.5,150),
        new XY(450.5,150),
        new XY(450.5,200),
        new XY(49.5,200),
        new XY(49.5,250),
        new XY(450.5,250),
        new XY(450.5,300),
        new XY(49.5,300),
        new XY(49.5,350),
        new XY(450.5,350),
        new XY(450.5,400),
        new XY(49.5,400),
        new XY(49.5,450.5),
        new XY(450.5,450.5)};
    private int[] nextIdx = new int[100];

    private int advanceIdx(int idx, int sign, int amount){
        return sign*(((Math.abs(idx)+CHECKPOINTS.length-1+sign*amount) % CHECKPOINTS.length) + 1);
    }

    private void wander(Member me, int sign) {
        if(preyCount > 20*predCount){
            if (me.dx == 0 && me.dy == 0) {
                me.dx = 250 - me.x;
                me.dy = 250 - me.y;
                return;
            }

            double lx, ly, px, py;
            lx = me.dx / 4;
            ly = me.dy / 4;
            boolean dir = Math.random() < 0.5 ? true : false;
            px = dir ? ly : -ly;
            py = dir ? -lx : lx;

            me.dx += px;
            me.dy += py;
        } else {
            if(nextIdx[me.id]==0){
                XY farthest = new XY(2000,2000);
                int farthestIdx = -1;
                for(int i=0; i<CHECKPOINTS.length; i++){
                    if(sign*sqDist(CHECKPOINTS[i], me) > sign*sqDist(farthest, me)){
                        farthest = CHECKPOINTS[i];
                        farthestIdx = i+1;
                    }
                }
                nextIdx[me.id] = farthestIdx*sign;
                for(Member mem: members){
                    if(mem.id == me.id) continue;
                    if(nextIdx[mem.id]==nextIdx[me.id]){
                        nextIdx[me.id] = advanceIdx(nextIdx[me.id], sign, 5); 
                    }
                }
            }
            if(sqDist(CHECKPOINTS[Math.abs(nextIdx[me.id])-1],me) < 1){
                nextIdx[me.id] = advanceIdx(nextIdx[me.id], sign, 1);
            }
            me.setDirection(CHECKPOINTS[Math.abs(nextIdx[me.id])-1].x-me.x,
                    CHECKPOINTS[Math.abs(nextIdx[me.id])-1].y-me.y);
        }
    }

    private double sqDist(XY me, Animal target){
        double dx = me.x-target.x;
        double dy = me.y-target.y;
        return dx*dx + dy*dy + Double.MIN_NORMAL;
    }

    private double sqDist(XY me, Member target){
        double dx = me.x-target.x;
        double dy = me.y-target.y;
        return dx*dx + dy*dy + Double.MIN_NORMAL;
    }

    private double sqDist(Animal target, Member me){
        double dx = me.x-target.x;
        double dy = me.y-target.y;
        return dx*dx + dy*dy + Double.MIN_NORMAL;
    }

    private List<Animal> getNeighbors(double radius, XY pos, Collection<Animal> candidates) {
        List<Animal> neighbors = new ArrayList<Animal>();
        for(Animal neighbor: candidates){
            if(sqDist(pos, neighbor) < radius * radius){
                neighbors.add(neighbor);
            }
        }
        return neighbors;
    }

    final double[] weights = { 1, 1, 0.96, 2, 4 };
    double weightSum;

    static final int ALIGN = 0;
    static final int SEPARATE = 1;
    static final int COHESION = 2;
    static final int FLEE = 3;
    static final int WALL = 4;
    static final int VISIBLE = 30;
    static final int VISIBLE_PRED = 50;

    private HashMap<Member, List<Animal>> prevPreys = new HashMap<Member, List<Animal>>();

    private XY matchPreys(List<Animal> prevs, List<Animal> curs, XY prey){
        XY result = new XY();
        double sqDist = 0;
        Animal candidate;
        XY otherPos;
        for(Animal otherPrey: curs){
            otherPos = new XY(otherPrey.x, otherPrey.y);
            sqDist = XY.sqDistance(prey, otherPos);
            if(sqDist > VISIBLE * VISIBLE)
                continue;
            candidate = findClosest(getNeighbors(6, otherPos, prevs), prey);
            if(candidate == null){
                return null;
            }
            result.add(otherPos.x-candidate.x, otherPos.y-candidate.y);
        }
        return result;
    }

    private XY predictNextPos(XY prey, Member me) {
        List<Animal> preys = getNeighbors(VISIBLE_PRED, prey, foods);
        List<Animal> preds = getNeighbors(VISIBLE, prey, predators);

        XY flock[] = new XY[weights.length];
        for (int i = 0; i < weights.length; i++)
            flock[i] = new XY();

        double dx, dy, dist, sqDist;
        for (Animal otherPrey : preys) {
            sqDist = XY.sqDistance(prey, new XY(otherPrey.x, otherPrey.y));
            if(sqDist > VISIBLE * VISIBLE)
                continue;
            dx = otherPrey.x - prey.x;
            dy = otherPrey.y - prey.y;
            flock[COHESION].add(dx*sqDist, dy*sqDist);
            flock[SEPARATE].add(-dx*(1d/sqDist), -dy*(1d/sqDist));
            flock[ALIGN].add(new XY(prey.x-me.x,prey.y-me.y));
        }

        if(sqDist(prey, me) < 400){
            if(prevPreys.get(me) == null){
                prevPreys.put(me, preys);
            } else {
                XY flockAlign = matchPreys(prevPreys.get(me), preys, prey);
                if(flockAlign == null){
                    prevPreys.put(me , null);
                } else {
                    flock[ALIGN] = flockAlign;
                    prevPreys.put(me, preys);
                }
            }
        }

        flock[ALIGN].unitize().multiply(5);
        flock[COHESION].unitize().multiply(5);
        flock[SEPARATE].unitize().multiply(5);

        for (Animal predator : preds){
            flock[FLEE].add(prey.x-predator.x, prey.y-predator.y);
        }

        dx = Island.CENTER.x - prey.x;
        dy = Island.CENTER.y - prey.y;
        dist = Math.max(Math.abs(dx), Math.abs(dy));
        if(dist > 240){
            flock[WALL].x = dx * dist;
            flock[WALL].y = dy * dist;
            flock[WALL].unitize().multiply(5);
        }

        XY vec = new XY();
        vec.x = 0;
        vec.y = 0;
        for (int i = 0; i < flock.length; i++) {
            flock[i].multiply(weights[i]);
            vec.add(flock[i]);
        }
        limitSpeed(vec);
        return vec.add(prey);
    }

    private XY limitSpeed(XY move) {
        if (move.x*move.x+move.y*move.y > MAX_SPEED*MAX_SPEED)
            move.unitize().multiply(MAX_SPEED);
        return move;
    }
}

1
बहुत अच्छा लग रहा है, तुम्हारा वास्तव में मेरे खेल में netcats से बेहतर है। लेकिन मुझे इस बात से नफरत है कि मैं दूसरे शिकारियों को नहीं मार सकता क्योंकि मेरे जानवर आपके आँकड़ों में बहुत बुरा काम करते हैं (जबकि badcamel बहुत अच्छा होता है)। शायद मुझे एक पर्ल कंपाइलर या ऐसा करने की कोशिश करनी होगी।
हरजन

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

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

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

15

Netcats

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

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

नेट अधिक छोटा शुरू होता है, लेकिन जब क्षेत्र अधिक कुशलता से फँसाने के लिए झुंड छोटा हो जाता है, तो चौड़ा हो जाता है।

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

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

यह संस्करण सवाल में जुड़े वीडियो में देखे गए भोले-भाले नेटसेक से बहुत बेहतर है ।

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

public class Netcats extends GenericPack {

    boolean seeking;
    Member head = null;
    Set<Animal> foods;

    public static void main(String[] args) {
        new Netcats().run();
    }

    @Override
    public void respond() {
        if (foods == null)
            foods = new HashSet<Animal>();
        else
            foods.clear();
        for (Member member : members)
            foods.addAll(member.foods);

        if (members.size() < 3) {
            soloRun();
        } else {
            head = setHead();
            setHeadVec();
            for (int i = 1; i < members.size(); i++) {
                setMemberVec(i);
            }
        }
    }

    Member setHead() {
        if (!members.contains(head))
            return members.get(0);

        Member hungry = head;
        int idx = 0;
        for (int i = 0; i < members.size(); i++) {
            Member me = members.get(i);
            if (me.hunger < hungry.hunger) {
                hungry = me;
                idx = i;
            }
        }

        if (hungry != head) {
            members.remove(hungry);
            members.remove(head);
            members.add(0, hungry);
            members.add(idx, head);
            return hungry;
        }
        return head;
    }

    void setHeadVec() {
        double x = 0, y = 0;

        Collection<Animal> yummy = getFoods(head);

        seeking = false;
        if (yummy.size() == 0) {
            scoutHead();
            return;
        }

        if (members.size() == 1)
            if (findFood(head))
                return;

        for (Animal food : yummy) {
            x += food.x - head.x;
            y += food.y - head.y;
        }
        x *= 10000000;
        y *= 10000000;

        head.dx = x;
        head.dy = y;
        if (members.size() > 1)
            limitSpeed(head, MAX_SPEED * HEAD_MULT);
    }

    void scoutHead() {
        seeking = true;
        head.dy = 250 - head.y;
        head.dx = round % 80 < 40 ? -head.x : 500 - head.x;
    }

    void setMemberVec(int idx) {
        Member me = members.get(idx);
        Member leader;
        leader = idx < 3 ? members.get(0) : members.get(idx - 2);
        if (findFood(me))
            return;

        double lx, ly, px, py, tx, ty, dist;
        lx = -leader.dx;
        ly = -leader.dy;
        dist = Math.sqrt(lx * lx + ly * ly) + Double.MIN_NORMAL;
        lx /= dist;
        ly /= dist;
        px = idx % 2 == 0 ? ly : -ly;
        py = idx % 2 == 0 ? -lx : lx;

        tx = leader.x + leader.dx;
        ty = leader.y + leader.dy;
        int xtrack = seeking ? COMB : preyCount > 400 ? ASIDE : MID_SIDE;
        tx += lx * BEHIND + px * xtrack;
        ty += ly * BEHIND + py * xtrack;

        me.dx = tx - me.x;
        me.dy = ty - me.y;
        limitSpeed(me, MAX_SPEED * (idx < 3 ? MID_MULT : 1));
    }

    Collection<Animal> getFoods(Member me) {
        return me.foods.size() == 0 ? foods : me.foods;
    }

    boolean findFood(Member me) {
        if (me.hunger > 500)
            return false;

        Collection<Animal> yummy = getFoods(me);
        if (yummy.size() == 0)
            return false;

        double x, y, sqDist, cDist = 10 * 10;
        Animal target = null;
        for (Animal food : me.foods) {
            x = food.x - me.x;
            y = food.y - me.y;
            sqDist = x * x + y * y + Double.MIN_NORMAL;
            if (sqDist < cDist) {
                cDist = sqDist;
                target = food;
            }
        }

        if (target == null)
            return false;

        if (cDist < 5 * 5 || me.hunger < 200) {
            me.dx = (target.x - me.x) * 10000000d;
            me.dy = (target.y - me.y) * 10000000d;
            return true;
        }
        return false;
    }

    void soloRun() {
        double x, y, sqDist, cDist;
        for (Member me : members) {
            Collection<Animal> yummy = getFoods(me);
            if (yummy.size() == 0) {
                wander(me);
                continue;
            }

            Animal target = null;
            cDist = Double.MAX_VALUE;
            for (Animal food : yummy) {
                x = food.x - me.x;
                y = food.y - me.y;
                sqDist = x * x + y * y + Double.MIN_NORMAL;
                if (sqDist < cDist) {
                    cDist = sqDist;
                    target = food;
                }
            }

            me.dx = (target.x - me.x) * 100000d;
            me.dy = (target.y - me.y) * 100000d;
        }
    }

    void wander(Member me) {
        if (me.dx == 0 && me.dy == 0) {
            me.dx = 250 - me.x;
            me.dy = 250 - me.y;
            return;
        }

        double lx, ly, px, py;
        lx = me.dx / 4;
        ly = me.dy / 4;
        boolean dir = Math.random() < 0.5 ? true : false;
        px = dir ? ly : -ly;
        py = dir ? -lx : lx;

        me.dx += px;
        me.dy += py;
    }

    void limitSpeed(Member me, double max) {
        double x = me.dx, y = me.dy;
        double dist = Math.sqrt(x * x + y * y) + Double.MIN_NORMAL;
        if (dist > max) {
            x = (x / dist) * max;
            y = (y / dist) * max;
        }
        me.dx = x;
        me.dy = y;
    }

    final static double MAX_SPEED = 6.1;
    final static double HEAD_MULT = 0.85;
    final static double MID_MULT = 0.92;
    final static int BEHIND = -25;
    final static int ASIDE = 15;
    final static int MID_SIDE = 30;
    final static int COMB = 150;
}

11

रूबी मकड़ियों

जैसा कि कभी-कभी कम होता है और कई समाधान शायद शिकार को किसी भी तरह से जोड़ने की कोशिश करेंगे ...

मुझे लगा कि मेरा पैक बस अलग हो सकता है और दूसरों को काम करने के लिए इंतजार कर सकता है।

gets
print "3.0\t3.0\t3.0\t-3.0\t-3.0\t-3.0\t-3.0\t3.0\t0.0\t0.0\0"
STDOUT.flush

कैविएट: यह वास्तव में चलता नहीं है, न ही यह इनपुट पढ़ता है क्योंकि यह न तो आता है और न ही जल्दी से प्रतिक्रिया करता है। फिर भी, जैसा कि यह नियंत्रक के साथ अच्छी तरह से काम करता है मुझे आशा है कि यह आगे समायोजन के बिना योग्य है।


4
+1 पहला परजीवी समाधान। मुझे लगता है कि इस प्रकार का उत्तर धीरे-धीरे खामियों को दूर करके अन्य उत्तरों की गुणवत्ता को आगे
बढ़ाएगा

@githubphagocyte मेरे मन में एक चालाक परजीवी था लेकिन यह कोड के लाइव समय / लाइनों के संदर्भ में अधिक कुशल है। मुझे उम्मीद है कि मुझे इसे लागू करने के लिए समय मिलेगा।
लीगेट

शायद @Synthetica मेरे विचार को अभी कोड कर रहा है। या अगर उसका विचार अभी तक एक और है, तो हम जल्द ही अधिक परजीवी हो सकते हैं फिर शिकारी;)
लेगट

1
@githubphagocyte में हमें तीन प्रविष्टियाँ करने की अनुमति है, इसलिए मैं इसके तैयार होने के बाद एक और पैक पोस्ट करूँगा। फिर भी, मुझे यह दिलचस्प लगता है कि इस बीच में एक कोड किया गया था और यह अधिक प्रभावी साबित हो सकता है। यह वास्तव में अच्छी तरह से Netcats का लाभ उठाता है और यह वास्तव में मेरे पहले शिकारी पैक की रूपरेखा तैयार करता है।
१४:१४ पर लेगेट

3
यह रूप में दर्ज कर सकते हैं, भले ही यह मुझे पता लगाने के लिए एक दूसरा क्यों लिया। ऐसा लगता है कि आपके द्वारा जोड़े गए (जो कि समझ में आता है) बेहतर Netcats करें। मेरे से +1, आइए देखें कि कोनों से बचने के लिए किस तरह के शिकारी आते हैं :)
Geobits

11

CivilizedBeasts

अंत में, मेरे जानवरों को दिखाने का समय!

मेरी नस्ल को लगता है कि शिकार कुछ आदिम है, इसलिए वे 4 की टीम में एक साथ काम करते हैं और इसलिए वे अपने 5 वें सहयोगी को छोड़ देते हैं, क्योंकि: कम शिकारियों = खुद के लिए अधिक शिकार। वे मूल रूप से क्या करते हैं मनुष्य क्या करते हैं, वे शिकार को पकड़ते हैं, और अपने मवेशियों की अच्छी देखभाल करते हैं;)

public class CivilizedBeasts extends GenericPack{

    private static int TL = 0, TR = 0, BL = 0, BR = 0; // TopLeft/BotRight
    private static int teamSize = 0, turnsWaiting = 0, turnsToWait = 20;

    private boolean out = true;
    private double maxSpeed = 6.1, mapSize = 500;

    public CivilizedBeasts(){
    }

    @Override
    public void respond(){
        if(teamSize > members.size()){

            Member check = getMemberById(TL);
            totalLoop:
            if(check == null){
                for (Member member : members) {
                    if(member.id != TR && member.id != BL && member.id != BR){
                        TL = member.id;
                        break totalLoop;
                    }
                }

                TL = 0;
            }

            check = getMemberById(TR);
            totalLoop:
            if(check == null){
                for (Member member : members) {
                    if(member.id != TL && member.id != BL && member.id != BR){
                        TR = member.id;
                        break totalLoop;
                    }
                }

                TR = 0;
            }

            check = getMemberById(BL);
            totalLoop:
            if(check == null){
                for (Member member : members) {
                    if(member.id != TL && member.id != TR && member.id != BR){
                        BL = member.id;
                        break totalLoop;
                    }
                }

                BL = 0;
            }

            check = getMemberById(BR);
            totalLoop:
            if(check == null){
                for(Member member : members) {
                    if(member.id != TL && member.id != TR && member.id != BL){
                        BR = member.id;
                        break totalLoop;
                    }
                }

                BR = 0;
            }
        }else if(teamSize < members.size()){
            for(Member member : members) {
                if(member.id != TL && member.id != TR && member.id != BL && member.id != BR){
                    if(TL == 0)
                        TL = member.id;
                    else if(TR == 0)
                        TR = member.id;
                    else if(BL == 0)
                        BL = member.id;
                    else if(BR == 0)
                        BR = member.id;
                }
            }
        }

        teamSize = members.size();

        double border = 1;
        double x, y;
        boolean reached = true;

        double distance = 16.3;

        for (Member member : members) {
            boolean doesNotCount = false;
            x = 0; y = 0;
            if(member.id == TL){
                if(out){
                    x = -(member.x - border);
                    y = -(member.y - border);
                }else{
                    x = ((mapSize/2 - distance) - member.x);
                    y = ((mapSize/2 - distance) - member.y);
                }
            }else if(member.id == TR){
                if(out){
                    x = (mapSize - member.x - border);
                    y = -(member.y - border);
                }else{
                    x = ((mapSize/2 + distance) - member.x);
                    y = ((mapSize/2 - distance) - member.y);
                }
            }else if(member.id == BL){
                if(out){
                    x = -(member.x - border);
                    y = (mapSize - member.y - border);
                }else{
                    x = ((mapSize/2 - distance) - member.x);
                    y = ((mapSize/2 + distance) - member.y);
                }
            }else if(member.id == BR){
                if(out){
                    x = (mapSize - member.x - border);
                    y = (mapSize - member.y - border);
                }else{
                    x = ((mapSize/2 + distance) - member.x);
                    y = ((mapSize/2 + distance) - member.y);
                }
            }else{
                double dist = 50, temp = 0;
                int index = -1;
                for(int i = 0; i < member.foods.size(); i++){
                    temp = (Math.abs(member.foods.get(i).x - member.x)+Math.abs(member.foods.get(i).y - member.y));
                    if(temp < dist){
                        dist = temp;
                        index = i;
                    }
                }
                if(index != -1){
                    x = (member.foods.get(index).x - member.x);
                    y = (member.foods.get(index).y - member.y);
                }
                doesNotCount = true;
            }

            if(!doesNotCount && Math.abs(x)+Math.abs(y) > maxSpeed)
                reached = false;
            member.setDirection(x,y);
        }

        if(reached){
            if(!out){ // in the middle.
                if(teamSize < 4){
                    int temp = TL;
                    TL = BR;
                    BR = temp;
                    temp = TR;
                    TR = BL;
                    BL = temp;
                    out = true;
                }else{
                    turnsWaiting++;
                }
            }else // no need to wait in the corners
                out = false;

            if(turnsWaiting >= turnsToWait){
                turnsToWait = 15;
                out = true;
                turnsWaiting = 0;
            }

        }

    }

    public static void main(String[] args){
        new CivilizedBeasts().run();
    }
}

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


3
अगर " उनकी अच्छी देखभाल करें " तो आपका मतलब है कि " उन्हें बार-बार झुंड के बीच में ले जाना और उन्हें मारना / खाना ", तो हाँ, वे भी यही करते हैं। +1
Geobits

यह अजीब है, ईविल कैमल्स के नहीं-उत्परिवर्तित (मूल) संस्करण के साथ, 'केंद्र ऊंट' की वजह से सभ्य रणनीति पूरी तरह से अक्षम है।
user2846289

1
@VadimR बकवास, अपने ऊंट को अपडेट करने के लिए धन्यवाद: PI इसका परीक्षण नहीं कर सकता क्योंकि यह जावा नहीं है, लेकिन मुझे पता है कि मेरी रणनीति मेरे क्षेत्र के मध्य में शिकारियों के साथ बेकार है: पी
हरजन

5
यह फिर से हर्जन है! इसके अलावा " 200 से कम शिकार के साथ जीवित रहना मेरे स्तनों के लिए काफी मुश्किल हो जाता है " (जोर दिया)। मुझे महसूस नहीं हुआ कि आपके स्तनों की प्राणशक्ति कंप्यूटर सिमुलेशन में शिकार की संख्या पर निर्भर करती है ....
जस्टिन

5

रूबी गिद्ध

यहां अधिक सक्रिय परजीवियों का एक पैकेट आता है । वे निकटतम चलती शिकारी को घेरने की कोशिश कर रहे हैं , ताकि वे उसके शिकार को चुरा सकें । वे थोड़े से भाग्य पर निर्भर हैं क्योंकि उनके पास चुनने का कोई स्मार्ट तरीका नहीं है लेकिन वे आमतौर पर चेज़र और कभी-कभी मकड़ियों को मार रहे हैं ।

वे काफी समाप्त नहीं हुए हैं, जैसा कि मैंने टेम्पो को धकेलने के लिए यह पोस्ट किया है :)

मैं उम्मीद कर रहा हूँ:

  • उन्हें देखने के क्षेत्र के बाहर शिकारियों की तलाश करें
  • शिकार को ध्यान में रखें - अक्सर उनमें से एक दूसरे पैक और शिकार के बीच होता है!
  • जब एक-दूसरे को अच्छी तरह से खिलाया जाए तो एक भूखे मरने से बचने के लिए उन्हें घुमाना शुरू करें

22 अप्रैल 2014: जोड़ा बोरियत है, जो उन्हें कम करता है कम चिपचिपा और उन्हें करने की अनुमति देता शिकार के लिए शिकार को अपने दम पर और शिकारियों के लिए खोज

class Animal
  attr_accessor :x, :y
end

class Hunter < Animal
  attr_accessor :id, :bored

  def initialize diff
   @diff = diff
   @lastGoal = nil
   @bored = false
  end

  def move goal
    if not goal.nil? 
      if @bored or goal != @lastGoal
        @lastGoal = goal
        return [goal.first - x + @diff.first, goal.last - y + @diff.last]
      end
    end
    [250 - x + 3*@diff.first, 250.0 - y + 3*@diff.last]
  end
end

class Pack
  def initialize
    @file = File.open "pack_log", "w"
    @count = 0
    @pack = []
    @order = []
    @hunters = []
    @closest = nil
    @random_goal = [250.0, 250.0]
    @locations = []
    @timer = 0
    d = 25.0
    diffs = [[d, d], [d, -d], [-d, -d], [-d, d], [0.0, 0.0]]
    5.times do |i|
      @pack << (Hunter.new diffs[i])
    end
    line = 0
    s = gets
    loop do
      s = gets
      if not (s =~ /dead\0/).nil?
        break
      end
      if line == 0
        get_structure s
      elsif line == 1
        get_positions s
      end
      @pack.length.times do |i|
        if line == i*2 + 3
          look_for_hunters s
          if @count <= i+1
            @closest = closest_hunter
            move
          end
        end
      end
      if not (s =~ /\0/).nil?
        line = 0
        @hunters = []
      else
        line += 1
      end
    end
  end

  def member_by_id id
    member = nil
    @pack.each do |v|
      if v.id == id
        member = v
        break
      end
    end
    member
  end

  def member_by_order index
    member_by_id @order[index]
  end

  def distance a, b
    Math.sqrt((a.first - b.first)**2 + (a.last - b.last)**2)
  end

  def bored?
    bored = true
    l1 = @locations.first
    @locations.each do |l2|
      if distance(l1, l2) > 20
        bored = false
      end
    end 
    bored
  end

  def bored_move v
    if @timer <= 0
      @random_goal = [rand(1000).to_f - 250, rand(1000).to_f - 250]
      @pack.each do |m|
        m.bored = true
      end
      @timer = 250 
    else
      @timer -= 1
    end
    v.move @random_goal
  end

  def move
    first_one = true
    answer = ""
    @order.each do |id|
      v = member_by_id id
      x, y = 0, 0
      if bored?
        x, y = (bored_move v)
      elsif @timer > 0
        @location = []
        x, y = (bored_move v)
      else
        @pack.each do |m|
          m.bored = false
        end
        @timer = 0
        x, y = v.move @closest
      end
      if not first_one
        answer << "\t"
      end
      answer << "#{x.to_i}.0\t#{y.to_i}.0"
      first_one = false
    end
    answer << "\0"
    print answer
    STDOUT.flush
  end

  def get_structure line
    @order = []
    if @pack.first.id.nil? 
      @count = 0
      line.split.each_with_index do |v, i|
        if i % 2 == 0
          @order << v.to_i
          @pack[i/2].id = v.to_i
          @count += 1
        end
      end
    else
      @count = 0
      line.split.each_with_index do |v, i|
        if i % 2 == 0
          @order << v.to_i
          @count += 1
        end
      end
    end
  end

  def get_positions line
    if not @order.empty?
      line.split.each_with_index do |v, i|
        if i % 2 == 0
          member_by_order(i/2).x = v.to_f
        else
          member_by_order(i/2).y = v.to_f
        end
      end
    end
  end

  def look_for_hunters line
    line.split.each_with_index do |v, i|
      if i % 2 == 0
        @hunters << [v.to_f]
      else
        @hunters.last << v.to_f
      end
    end
  end

  def closest_hunter
    mass_center
    closest = nil
    bestDist = 500*500
    if not @hunters.nil? and not @hunters == []
      @hunters.each do |h|
        our = false
        @pack.each do |v|
          if h.first == v.x and h.last == v.y
            our = true
          end
        end
        if our
          next
        end
        sqDist = (@mass_center.first - h.first)**2 + (@mass_center.last - h.last)**2
        if sqDist < bestDist
          closest = []
          closest << h.first
          closest << h.last
        end
      end
    end
    closest
  end

  def mass_center
    center_x = 0
    center_y = 0
    @pack.each do |v|
      center_x += v.x
      center_y += v.y
    end
    @mass_center = [center_x.to_f / @count, center_y.to_f / @count]
    if @locations.length > 30
      @locations.shift
      @locations << @mass_center
    else
      @locations << @mass_center
    end
  end
end

Pack.new

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

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

मुझे लगता है, मुझे पता है कि विशेष रूप से उन्हें क्या परेशान कर सकता है। ईविल ऊंटों का युद्ध नृत्य। @ यूट्यूब पर झगड़े डालने के बारे में कैसे? 10 राउंड बहुत अधिक नहीं रह रहे हैं। बेशक, मुख्यालय की जरूरत होगी। लाखों दर्शकों की उम्मीद नहीं है, लेकिन यह देखना मनोरंजक होगा कि आपके पैक कैसे प्रदर्शन करते हैं और शायद उनके लिए थोड़ी खुशी होती है :)
Legat

1
ध्यान रखने के लिए पूर्ण टूमनी थोड़ी लंबी (~ 8 मिनट प्रति दौर) हो सकती है, लेकिन एक "दर्शक" राउंड को रिकॉर्ड करने से काम चल सकता है। मैं इसे भविष्य के रनों के लिए एक विचार दूंगा।
भूतकाल

@Geobits 8 मिनट के राउंड के दौरान गति बहुत भिन्न होती है? मैं सोच रहा था कि यह प्रति फ्रेम एक रिकॉर्डिंग के लायक है, इसलिए उन्हें कम्प्यूटेशनल गहन भागों के दौरान धीमा होने के बजाय एक स्थिर दर पर वापस खेला जा सकता है। YouTube प्रयोजनों के लिए, मेरा मतलब है।
ट्राइकोप्लाक्स

5

ईविल इकोल कैमल

संपादित करें: उत्परिवर्तन # 2। ओह, नहीं, मुझे शिकार आंदोलन की भविष्यवाणी के अपने कार्यान्वयन के साथ देर हो गई है, नेटकैट्स को हरा देने वाला पहला व्यक्ति है। ठीक है, तो यह हो।

इस उत्परिवर्तन में $hunger_criticalपरिवर्तनशील (स्थिर) होता है। इसे 1000 से ऊपर के मूल्य में बदलना ऊंटों को हमेशा शिकार करना पड़ता है, जैसे कि क्लेयरवॉयंट्स। फिर:

Done in 11.93 minutes
camels1.pl(0)                   : Turn 23112    : Score 100
Netcats(1)                      : Turn 22508    : Score 80

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

इसका दिलचस्प, यह भी, कि flock[ALIGN]घटक का अनुमान केवल शिकारियों द्वारा लगाया जा सकता है, और मेरा कार्यान्वयन जस्टफॉल से अलग है। मुझे डर है कि जियोबिट्स कोड के मेरे चीर-फाड़ कार्यान्वयन में कुछ मामूली बग हैं , जो देखने के लिए ऊंट बनाम क्लेयरवॉयंट्स के व्यक्तिगत शिकार की तुलना करते हैं।

और कार्यक्रम एक तरह से लंबा है, क्षमा करें।


संपादित करें: उत्परिवर्तन # 1। द्वीप काफी रेडियोधर्मी निकला (जो कि 'शिकार' प्राणियों की वनस्पति और अकल्पनीय प्रकृति की कमी को बताता है), इसलिए यहाँ मेरे ऊंटों का पहला उत्परिवर्तन हुआ। उनमें से कोई भी एकल शिकारी बन सकता है, अगर भूखा हो या अगर सभी के लिए कोई मुफ्त कोना न हो। शिकारी सक्रिय रूप से पास के शिकार को आगे बढ़ाने की कोशिश करता है। यदि कोई नहीं है, तो यह द्वीप के केंद्र के चारों ओर विस्तृत सर्कल में गश्त करता है, फिर इसे खोजने पर निकटतम प्राणी का पीछा करता है। दुर्भाग्य से, शिकार की दिशा अप्रत्याशित हो जाती है जब वह अपने झुंड (जांच के लायक ...) के पास होता है, इसलिए सोलो चेस बहुत कुशल नहीं है। लेकिन अगर यह सफल हो जाता है, तो कैमल निकटतम मुक्त कोने (यदि कोई हो) को पचाने के लिए चला जाता है। जब भूख का स्तर निश्चित स्तर से नीचे होता है, तो कोई भी कैमल अपने कोने को छोड़ देता है (शायद नेकट्स को कोसता है ('भोजन कहाँ है?') )) और अपने आप मुफ्त रोमिंग पर चला जाता है। और इसी तरह।


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

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

#!/usr/bin/env perl
use strict;
use warnings;

binmode STDOUT;
binmode STDIN;
$| = 1;
$, = "\t";

my $hunger_critical = 500;
my %pack;
my ($turn, $prey_count, $predators_count);
my $patrol_radius_hunt = 150;
my $patrol_radius_corner = 16;
my $patrol_radius_center = 1;
my @roles = qw/C LL LR UL UR/; # or P (patrol if > 5), H (hunt)
my %places = (
    UL => {x =>   1 + $patrol_radius_corner, y =>   1 + $patrol_radius_corner},
    UR => {x => 499 - $patrol_radius_corner, y =>   1 + $patrol_radius_corner},
    LR => {x => 499 - $patrol_radius_corner, y => 499 - $patrol_radius_corner},
    LL => {x =>   1 + $patrol_radius_corner, y => 499 - $patrol_radius_corner},
    C  => {x => 250, y => 250},
);

sub sq_dist {
    my ($x1, $y1, $x2, $y2) = @_;
    return ($x1 - $x2)**2 + ($y1 - $y2)**2
}

sub distance {
    return sqrt(&sq_dist)
}

sub assign_role {
    my $camel = shift;
    if (@roles) {
        my %choice = (d => 1000, i => 0);
        for my $i (0..$#roles) {
            my $r = $roles[$i];
            if ($r eq 'C') {
                if ($prey_count > 700) {
                    $choice{i} = $i;
                    last
                }
                else {
                    next
                }
            }
            my $d = distance($camel->{x}, $camel->{y}, $places{$r}{x}, $places{$r}{y});
            if ($d < $choice{d}) {
                @choice{qw/d i/} = ($d, $i)
            }
        }
        return splice @roles, $choice{i}, 1
    }
    else {
        return 'P'
    }
}

sub xy_average {
    my $xy = shift;
    my $x = my $y = 0;
    if ($xy && @$xy) {
        for my $item (@$xy) {
            $x += $item ->{x};
            $y += $item->{y}
        }
        $x /= @$xy;
        $y /= @$xy
    }
    return $x, $y
}

sub patrol {
    my ($xc, $yc, $radius, $camel) = @_;
    my ($x, $y) = ($camel->{x} - $xc, $camel->{y} - $yc);
    my $d = distance(0, 0, $x, $y);
    my $a = atan2($y, $x);
    if (abs($d - $radius) < 3) {
        $a += 6 / $radius
    }
    return $radius * cos($a) - $x, $radius * sin($a) - $y
}

while (1) {

    # Get input

    my @in;
    # Line 0 - turn, counts
    $_ = <>;
    die if /dead/;
    ($turn, $prey_count, $predators_count) = /\0?(\S+)\t(\S+)\t(\S+)/;
    # Line 1 - pack's ids and hunger
    $_ = <>;
    while (/(\S+)\t(\S+)/g) {
        push @in, {id => $1, hunger => $2}
    };
    # Line 2 - positions
    $_ = <>;
    for my $animal (@in) {
        /(\S+)\t(\S+)/g;
        ($animal->{x}, $animal->{y}) = ($1, $2);
    }
    # 2 lines per member, visible prey and predators
    for my $animal (@in) {
        $_ = <>;
        my @prey;
        while (/(\S+)\t(\S+)/g) {
            push @prey, {x => $1, y => $2}
        };
        $animal->{prey} = \@prey;
        $_ = <>;
        my @beasts;
        while (/(\S+)\t(\S+)/g) {
            push @beasts, {x => $1, y => $2}
        };
        $animal->{beasts} = \@beasts
    }
    # trailing \0 zero will be prepended to next turn input

    # Update my pack

    for my $n (0..$#in) {
        my $animal = $in[$n];
        my $id = $animal->{id};
        # old average prey position
        my @opp = xy_average($pack{$id}{prey});
        # new average prey position
        my @npp = xy_average($animal->{prey});
        # average prey displacement
        my %apd = (x => $npp[0] - $opp[0], y => $npp[1] - $opp[1]);
        $pack{$id}{apd}    = \%apd;
        $pack{$id}{hunger} = $animal->{hunger};
        $pack{$id}{x}      = $animal->{x};
        $pack{$id}{y}      = $animal->{y};
        $pack{$id}{prey}   = $animal->{prey};
        $pack{$id}{beasts} = $animal->{beasts};
        $pack{$id}{num}    = $n;
        $pack{$id}{dead}   = 0
    }

    # Bury dead animals, retrieve their roles

    while (my ($id, $camel) = each %pack) {
        if ($camel->{dead}) {
            my $role = $camel->{role};
            push @roles, $role if $role ne 'P' and $role ne 'H';
            delete $pack{$id};
        }
        else {
            $camel->{dead} = 1
        }
    }

    # See that everyone has a role and lives accordingly

    my @out;
    for my $camel (values %pack) {
        my $role = $camel->{role} ||= assign_role($camel);
        if ($camel->{hunger} < $hunger_critical and $role ne 'H') {
            push @roles, $role if $role ne 'P';
            $role = $camel->{role} = 'H'
        }
        if ($camel->{hunger} > $hunger_critical and ($role eq 'H' or $role eq 'P') and $prey_count > 400) {
            $role = $camel->{role} = assign_role($camel)
        }
        my @vector = (0, 0);
        if ($role eq 'H') {
            my @prey = @{$camel->{prey}};
            if (@prey) {
                my %nearest = (p => undef, dd => 2500);
                for my $prey (@prey) {
                    my $dd = sq_dist($camel->{x}, $camel->{y}, $prey->{x}, $prey->{y});
                    if ($dd <= $nearest{dd}) {
                        @nearest{qw/p dd/} = ($prey, $dd)
                    }
                }
                my $target = $nearest{p};
                if ($nearest{dd} > 900) {
                    @vector = ($target->{x} - $camel->{x}, $target->{y} - $camel->{y})
                }
                else {
                    my @vect = map{{x => 0, y => 0}}1..5;
                    my $n = 0;
                    for my $prey (@prey) {
                        next if $prey eq $target;
                        my $dd = sq_dist($target->{x}, $target->{y}, $prey->{x}, $prey->{y}) + 1/(~0);
                        next if $dd > 900;
                        $n ++;
                        my $dx = $prey->{x} - $target->{x};
                        my $dy = $prey->{y} - $target->{y};
                        $vect[1]{x} -= $dx / $dd;
                        $vect[1]{y} -= $dy / $dd;
                        $vect[2]{x} += $dx * $dd;
                        $vect[2]{y} += $dy * $dd
                    }
                    $vect[0] = {x => $n * $camel->{apd}{x}, y => $n * $camel->{apd}{y}};
                    my $dx = abs(250 - $target->{x});
                    my $dy = abs(250 - $target->{y});
                    my $d = $dx > $dy ? $dx : $dy;
                    if ($d > 240) {
                        $vect[4]{x} = $dx * $d;
                        $vect[4]{y} = $dy * $d;
                    }
                    for my $v (@vect) {
                        my $d = sqrt($v->{x}**2 + $v->{y}**2) + 1/(~0);
                        $v->{x} /= $d;
                        $v->{y} /= $d;
                    }
                    for my $beast (@{$camel->{beasts}}, $camel) {
                        my $dd = sq_dist($target->{x}, $target->{y}, $beast->{x}, $beast->{y});
                        next if $dd > 900;
                        $vect[3]{x} += $target->{x} - $beast->{x};
                        $vect[3]{y} += $target->{y} - $beast->{y};
                    }
                    $vector[0] = 5 * 1   * $vect[0]{x}
                               + 5 * 1   * $vect[1]{x}
                               + 5 * .96 * $vect[2]{x}
                               + 1 * 2   * $vect[3]{x}
                               + 5 * 4   * $vect[4]{x};
                    $vector[1] = 5 * 1   * $vect[0]{y}
                               + 5 * 1   * $vect[1]{y}
                               + 5 * .96 * $vect[2]{y}
                               + 1 * 2   * $vect[3]{y}
                               + 5 * 4   * $vect[4]{y};
                    my $dd = $vector[0]**2 + $vector[1]**2;
                    if ($dd > 36) {
                        my $d = sqrt($dd);
                        @vector = map {$_ * 6.1 /$d} @vector
                    }
                }
            }
            else {
                @vector = patrol(250, 250, $patrol_radius_hunt, $camel)
            }
        }
        elsif ($role eq 'P') {
            @vector = patrol(250, 250, $patrol_radius_hunt, $camel)
        }
        else {
            my $r = $role eq 'C' 
                ? $patrol_radius_center 
                : $patrol_radius_corner;
            @vector = patrol($places{$role}{x}, $places{$role}{y}, $r, $camel)
        }
        my $id_x = $camel->{num} << 1;
        my $id_y = $id_x + 1;
        @out[$id_x, $id_y] = @vector
    }

    # And let the cruel world know about it

    print @out;
    print "\0"
}

__END__

5
यह मुझे आज तक इस साइट पर देखी गई सबसे अधिक सुगम पर्ल स्क्रिप्ट है।
ज्योबिट्स

आपको उन्हें प्रभावी रूप से चमकाने के लिए बिल्कुल कोने में जाने की आवश्यकता है, अन्यथा आप वास्तव में नेटकैट्स के कसाई में भाग लेंगे, हाहा
जस्टफुल

@ अन्याय, यह ऐसा है जैसा मैंने कहा: योजना काम नहीं की। कोनों में बैठे परजीवी शिकार को दूर नहीं भगाते हैं। एचएम-एम, शायद एक कोने में गश्त करने वाले 2 या अधिक जानवर मदद करेंगे।
user2846289

आपके ऊंट वास्तव में बहुत अच्छे हैं! शुक्र है (मेरे लिए) मैंने अपने क्लेयरवॉयंट्स में सुधार किया है, इसलिए ज्यादातर समय (हमेशा नहीं), मेरा पैक आखिरी लड़ाई के दौरान आपके खिलाफ जीतता है। दिलचस्प!
१४:१४

1
यदि आप शिकार से 8 (20-2 * 6) इकाई के करीब हैं, तो हम वर्तमान में बदले में हमारे शिकार के 30 इकाइयों के भीतर अन्य सभी शिकार के किसी भी आंदोलन को देख सकते हैं। और vecसंपत्ति मूल रूप से पिछले मोड़ से वर्तमान मोड़ तक विस्थापन है। और जैसा कि मैंने कहा, हम यह पता लगाने के लिए पिछले मोड़ से मिलान करते हैं कि कौन सा रास्ता किस रास्ते पर जाता है, हम शिकार के आदेश पर भरोसा नहीं कर सकते। यह संभव है क्योंकि आमतौर पर प्रीसिस (विशिष्ट परिदृश्य में) एक दूसरे (> 12 इकाइयों) से पर्याप्त दूरी बनाए रखते हैं, और इसलिए अधिकांश समय हम पिछली बारी में करंट को चालू मोड़ से मिला सकते हैं।
1

4

AbleDogs - PHP

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

कोड को एक AbleDogsफ़ाइल में डालें और इसके साथ चलाएंphp AbleDogs

<?php
// simulation parameters

define ("ARENA_SIZE", 500);

define ("HUNGER_MAX", 1000);

define ("PREY_SPEED", 6);
define ("PRED_SPEED", 6.1);

define ("PREY_VISION", 30);
define ("PRED_VISION", 50);

define ("WALL_BOUNCE", 10); // distance from a wall from which a prey starts bouncing

// derived constants

define ("PRED_SPEED2" , PRED_SPEED  * PRED_SPEED );
define ("PRED_VISION2", PRED_VISION * PRED_VISION);
define ("PREY_VISION2", PREY_VISION * PREY_VISION);

// grid to speedup preys lookup

define ("GRID_SIZE", ceil (ARENA_SIZE/PRED_VISION));
define ("GRID_STEP", ARENA_SIZE/GRID_SIZE);

// search patterns

define ("SEARCH_OFFSET", WALL_BOUNCE+PRED_VISION/sqrt(2));
define ("SEARCH_WIDTH" , 2*sqrt(PRED_VISION2-PRED_SPEED2/4));
define ("SEARCH_HEIGHT", ARENA_SIZE-2*SEARCH_OFFSET);
define ("SEARCH_SIZE"  , ceil(SEARCH_HEIGHT/SEARCH_WIDTH));
define ("SEARCH_STEP"  , SEARCH_HEIGHT/SEARCH_SIZE);
define ("SEARCH_LEGS"  , 2*SEARCH_SIZE+1);

// tracking

define ("MAX_TRACK_ERROR", 10); // max abs distance for prey tracking correlation
define ("TRACKING_HUNGER_START", HUNGER_MAX*.9); // hunger limit to try and eat the tracked prey (start of game)
define ("TRACKING_HUNGER_END", 4);     // idem, for endgame
define ("TRACKING_DISTANCE", PREY_SPEED*2.5);
define ("TRACKING_DISTANCE2", TRACKING_DISTANCE * TRACKING_DISTANCE);

class Point {
    public $x = 0;
    public $y = 0;

    function __construct ($x=0, $y=0)
    {
        $this->x = (float)$x;
        $this->y = (float)$y;
    }

    function __toString() // for comparisons
    {
        return "$this->x,$this->y";
    }

    function multiply ($scalar)
    {
        return new Point ($this->x * $scalar, $this->y * $scalar);
    }

    function add ($v)
    {
        return new Point ($this->x + $v->x, $this->y + $v->y);
    }

    function dot($v)
    {
        return $this->x * $v->x + $this->y * $v->y;
    }

    function rotate90()
    {
        return new Point (-$this->y, $this->x);
    }

    function vector_to ($goal)
    {
        return new Point ($goal->x - $this->x, $goal->y - $this->y);
    }

    function norm2 ()
    {
        return $this->dot ($this);
    }

    function norm ()
    {
        return sqrt ($this->norm2());
    }

    function normalize ($norm = 1)
    {
        $n = $this->norm();
        if ($n != 0) $n = $norm/$n;
        return $this->multiply ($n);
    }

    function limit ($norm)
    {
        return $this->norm() > $norm
             ? $this->normalize($norm)
             : clone $this;
    }
}

class Search {

    function __construct ($direction)
    {
        switch ($direction % 4)
        {
            case 0: $this->pos = new Point (          0,           0); break;
            case 1: $this->pos = new Point (SEARCH_SIZE,           0); break;
            case 2: $this->pos = new Point (SEARCH_SIZE, SEARCH_SIZE); break;
            case 3: $this->pos = new Point (          0, SEARCH_SIZE); break;
        }
        $this->start();
    }

    private function start ()
    {
        $this->dir = $this->pos->x == $this->pos->y;
        $this->adj = $this->pos->x ? -1 : 1;
        $this->target = new Point ($this->pos->x * SEARCH_STEP + SEARCH_OFFSET,
                                   $this->pos->y * SEARCH_STEP + SEARCH_OFFSET);
        $this->leg = 0;
    }

    function point ($pos)
    {
        if ($pos == $this->target)
        {
            if ($this->leg % 2)
            {
                if ($this->dir) $this->pos->y+= $this->adj;
                else            $this->pos->x+= $this->adj;
            }
            else
            {
                if ($this->dir) $this->pos->x = $this->pos->x ? 0 : SEARCH_SIZE;
                else            $this->pos->y = $this->pos->y ? 0 : SEARCH_SIZE;
            }
            $this->leg++;
            if ($this->leg == SEARCH_LEGS) $this->start();
            $this->target = new Point ($this->pos->x * SEARCH_STEP + SEARCH_OFFSET,
                                       $this->pos->y * SEARCH_STEP + SEARCH_OFFSET);
        }
        return $this->target;
    }
}

class Pack {

    public static $turn;   // turn number
    public static $size;   // number of live members
    public static $member; // array of members

    public static $prev_preys;     // previous coordinates of all preys
    public static $prev_preds;     // previous coordinates of foreign predators

    public static $n_preys; // total number of preys     (including those not currently seen)
    public static $n_preds; // total number of predators (including those not currently seen)

    public static $preys;     // coordinates of all preys
    public static $preds;     // coordinates of all predators
    public static $own_preds; // coordinates of all predators in our pack
    public static $foe_preds; // coordinates of all foreign predators

    public static $arena_center; // arena center

    private static $output_order; // to send output according to input order

    function init ()
    {
        Pack::$member = array();
        Pack::$arena_center = new Point (ARENA_SIZE/2, ARENA_SIZE/2);
    }

    function read_line ($line)
    {
        $values = array();
        if ($line == "") return $values;
        $input = explode ("\t", $line);
        $num = count($input);
        if ($num % 2) panic ("read_line: invalid input $line num $num");
        $num /= 2;
        for ($i = 0 ; $i != $num ; $i++)
        {
            $values[] = new Point ($input[$i*2  ], $input[$i*2+1]);
        }
        return $values;
    }

    function read_input ()
    {
        // read controller input (blocking)
        $input = "";
        while (($in = fread(STDIN, 1)) !== false)
        {
            if ($in == "\0") break;
            $input .= $in;
        }

        // check extinction
        if ($input == "dead") return false;
        $lines = explode ("\n", $input);

        // save previous predators and preys positions
        Pack::$prev_preys = Pack::$preys;
        Pack::$prev_preds = Pack::$foe_preds;

        // line 0: turn, preys, predators
        list (self::$turn, Pack::$n_preys, Pack::$n_preds) = explode ("\t", $lines[0]);

        // line 1: list of ids and hunger levels
        $id = array();
        Pack::$size = 0;
        Pack::$output_order = array();
        foreach (Pack::read_line($lines[1]) as $i=>$v)
        {
            $id[$i] = $v->x;
            Pack::$output_order[] = $id[$i];

            if (!isset (Pack::$member[$id[$i]])) Pack::$member[$id[$i]] = static::new_member();
            Pack::$size++;
            Pack::$member[$id[$i]]->hunger = $v->y;
            Pack::$member[$id[$i]]->ttl = self::$turn;
        }

        // line 2: member positions
        Pack::$own_preds = array();
        foreach (Pack::read_line($lines[2]) as $i=>$pos)
        {
            Pack::$member[$id[$i]]->pos = $pos;
            Pack::$own_preds[] = $pos;
        }

        // lines 3 to 2*#members+3: coordinates of all visible preys and predators
        $preys = array();
        $preds = array();
        $y_seen = array();
        $d_seen = array();
        for ($i = 0 ; $i != Pack::$size ; $i++)
        {
            // visible preys
            foreach (Pack::read_line($lines[2*$i+3]) as $coords)
            {
                if (!in_array ($coords, $preys) || !isset($y_seen[(string)$coords]))
                {
                    $preys[] = $coords;
                }
            }
            foreach ($preys as $p) $y_seen[(string)$p] = true;

            // visible predators
            foreach (Pack::read_line($lines[2*$i+4]) as $coords)
            {
                if (!in_array ($coords, $preds) || !isset($d_seen[(string)$coords]))
                {
                    $preds[] = $coords;
                }
            }
            foreach ($preds as $p) $d_seen[(string)$p] = true;
        }

        // remove dead members
        foreach (Pack::$member as $k => $m)
        {
            if ($m->ttl != self::$turn)
            {
                unset (Pack::$member[$k]);
            }
        }

        // filter out own positions from predators list
        Pack::$foe_preds = array_diff ($preds, Pack::$own_preds);
        Pack::$preds = Pack::$foe_preds;
        foreach (Pack::$own_preds as $p) Pack::$preds[] = $p;
        Pack::$preys = $preys;

        // done
        return true;
    }

    function output_moves ()
    {
        $output = array();
        foreach (Pack::$output_order as $i)
        {
            $output[] = Pack::$member[$i]->move->x;
            $output[] = Pack::$member[$i]->move->y;
        }
        echo implode ("\t", $output) . "\0";
    }

    static function point_closest_to_walls ($pos)
    {
        $delta = $pos->vector_to (Pack::$arena_center);
        if (abs ($delta->x) > abs ($delta->y))
        {
            $y = $pos->y;
            $x = $delta->x > 0 ? -1 : ARENA_SIZE+1;
        }
        else
        {
            $x = $pos->x;
            $y = $delta->y > 0 ? -1 : ARENA_SIZE+1;
        }
        return new Point ($x, $y);
    }

    static function in_arena ($pos)
    {
        $delta = $pos->vector_to (Pack::$arena_center);
        return abs ($delta->x) <= ARENA_SIZE/2 && abs ($delta->y) <= ARENA_SIZE/2;
    }

    static function clamp_to_arena (&$pos)
    {
        // mimics the slightly strange behaviour of the Java engine setInZeroBounds function
        if ($pos->x >= ARENA_SIZE) $pos->x = ARENA_SIZE-1; // should rather be ARENA_SIZE
        if ($pos->x <           0) $pos->x = 0;
        if ($pos->y >= ARENA_SIZE) $pos->y = ARENA_SIZE-1;
        if ($pos->y <           0) $pos->y = 0;
    }

    function get_closest ($pos, $set, $max_dist)
    {
        // check for empty set
        if (count ($set) == 0) return null;

        // construct an array of distances with the same indexes as the points
        $dist = array();
        $max_dist *= $max_dist;
        foreach ($set as $k=>$pt)
        {
            $d = $pos->vector_to($pt)->norm2();
            if ($d <= $max_dist) $dist[$k] = $d;
        }
        if (count($dist) == 0) return false;

        // get the key of the smallest distance and use it to retrieve the closest point
        $keys = array_keys ($dist, min($dist));
        return $set[$keys[0]];
    }

    function get_visible ($pos, $set)
    {
        $res = array();
        $skipped = false;
        $pts = 0;
        foreach ($set as $point)
        {
            $d = $pos->vector_to($point)->norm2();
            if ($d == 0 && !$skipped)
            {
                $skipped = true;
                continue; // skip ourself
            }
            if ($d > PREY_VISION2) continue; // skip far points
            $res[] = $point;
            if ($pts++ > 10) break; // too many points are useless since prediction will go haywire anyway
        }
        return $res;
    }
}
Pack::init();

class PackMember {
    public $pos; // current position
    public $ttl; // last turn reported alive

    function move_to ($goal)
    {
        $this->move = $this->pos->vector_to ($goal);
    }

    function intercept ($target_pos, $target_speed)
    {
        // change reference to position difference
        $delta = $this->pos->vector_to($target_pos);
        $i = $delta->normalize();
        $j = $i->rotate90();

        // match tangential speeds
        $vj = $target_speed->dot ($j);

        // deduce axial speed
        $vi = PRED_SPEED2 - $vj*$vj; // this should always be positive since predators are faster than preys
        $vi = sqrt ($vi);

        // return intercept speed in original reference coordinates
        return $i->multiply($vi)->add($j->multiply($vj));
    }
}

class Target {
    public $pos;      // current position
    public $pos_next; // predicted position
    public $speed;    // estimated speed

    function __construct ($pos)
    {
        $this->pos    = $pos;
        $this->speed  = new Point(0,0);
        $this->predict();
    }

    private function predict()
    {
        // predators contribution
        $preds = Pack::get_visible ($this->pos, Pack::$preds);
        $this->preds = count ($preds);
        $res = new Point();
        foreach ($preds as $predator)
        {
            $res = $res->add ($predator->vector_to ($this->pos));
        }
        $res = $res->multiply (2);

        // preys contribution
        $preys = Pack::get_visible ($this->pos, Pack::$preys);
        $this->preys = count ($preys);

        $f_cohesion  = new Point;
        $f_separate  = new Point();
        foreach ($preys as $prey)
        {
            $delta = $this->pos->vector_to ($prey);
            $d2 = $delta->norm2();
            if ($d2 != 0)
            {
                $f_cohesion  = $f_cohesion ->add ($delta->multiply ($d2));
                $f_separate  = $f_separate ->add ($delta->multiply (-1/$d2));
            }
        }

        $res = $res
        ->add ($this->speed->normalize(5*.96)) // assume all preys have same speed as target
        ->add ($f_cohesion ->normalize(5*1))
        ->add ($f_separate ->normalize(5*1));
        $delta = $this->pos->vector_to(Pack::$arena_center);
        $dist = max (abs($delta->x), abs($delta->y));
        if ($dist > (ARENA_SIZE/2-WALL_BOUNCE))
        {
            $res = $res->add ($delta->normalize(5*4));
        }

        $this->raw_speed = $res;
        $this->speed = $res->limit(PREY_SPEED);
        $this->pos_next = $this->pos->add ($this->speed);
        Pack::clamp_to_arena ($this->pos_next);
    }

    function track ()
    {
        // see if we can find our prey at the start of a new turn
        $min = 1e10;
        foreach (Raptors::$free_preys as $k=>$prey)
        {
            $dist = abs ($this->pos_next->x - $prey->x) + abs ($this->pos_next->y - $prey->y);
            if ($dist < $min)
            {
                $min = $dist;
                $new_pos = $prey;
                $new_k = $k;
                if ($min < .001) break;
            }
        }
        if ($min > MAX_TRACK_ERROR) return false;

        // remove this prey from free preys
        unset(Raptors::$free_preys[$new_k]);

        $delta = $new_pos->vector_to($this->pos_next);

        // update postion and speed
        if ($this->speed->norm2() == 0)
        {
            // this can be either an endgame prey not yet moving
            // OR initial speed for a new target
            $this->speed = $this->pos->vector_to ($new_pos);
        }
        $this->pos = $new_pos;

        // predict speed and position
        $this->predict();
        return true;
    }
}

class Raptor extends PackMember {

    // possible states
    const IDLE     = 1;
    const TRACKING = 2;
    const HUNTING  = 3;
    const RUSHING  = 4;
    public $state;

    public  $target;  // current prey
    public  $patrol;  // patrol governor

    private static $id_gen;

    function __construct ()
    {
        $this->patrol = new Search (++self::$id_gen);
        $this->target  = null;
        $this->state = Raptor::IDLE;
        $this->pos = null;
        $this->hunger = HUNGER_MAX;
    }

    function __destruct ()
    {
        $this->tracking_lost();
    }

    function tracking_lost()
    {
        $this->target  = null;
        $this->state = Raptor::IDLE;
    }

    function track_prey()
    {
        // stop tracking if hunger went back to max
        if ($this->hunger == HUNGER_MAX)
        {
            $this->tracking_lost();
        }

        // try to acquire a new target
        if (!$this->target)
        {
            $victim = Pack::get_closest ($this->pos, Raptors::$free_preys, PRED_VISION);
            if (!$victim) return;
            $this->target = new Target ($victim);
            $this->state = Raptor::TRACKING;
        }

        // track prey
        if (!$this->target->track (Pack::$preys))
        {
            // prey was eaten or move prediction failed
            $this->tracking_lost();
        }
    }

    function beat_competition ()
    {
        if ($this->target === null) return;
        $pm = $this->target->pos_next->vector_to ($this->pos);
        $dm = $pm->norm2();
        foreach (Pack::$foe_preds as $f)
        {
            $pf = $this->target->pos_next->vector_to($f);
            $df = $pf->norm2();
            if ($df > PRED_VISION2) continue;
//          if ($df < ($dm*2))
            {
                $this->state = Raptor::RUSHING;
                return;
            }
        }
        if ($this->state == Raptor::RUSHING) $this->state = Raptor::TRACKING;
        return;
    }
}

class Raptors extends Pack {
    public static $free_preys; // coordinates of all preys that are not targeted

    // allows generic Pack to create a proper pack member instance
    static function new_member()
    {
        return new Raptor();
    }

    // main AI loop
    static function think ()
    {
        $hunger_limit = Pack::$n_preys > 2 * Pack::$n_preds ? TRACKING_HUNGER_START : TRACKING_HUNGER_END;
        self::$free_preys = static::$preys;

        // update targets and members states
        foreach (Pack::$member as $m)
        {
            // track current targets
            $m->track_prey();

            // rush to target if a competitor draws near
            $m->beat_competition();

            // hunt if hungry enough
            if ($m->state == Raptor::TRACKING && $m->hunger < $hunger_limit)
            {
                $m->state = Raptor::HUNTING;
            }
        }

        // move members
        foreach (Pack::$member as $m)
        {
            switch ($m->state)
            {
            case Raptor::IDLE:
                $destination = $m->patrol->point($m->pos);
                break;
            case Raptor::TRACKING:
                $wall_point = Pack::point_closest_to_walls ($m->target->pos_next);
                $destination = $wall_point->vector_to ($m->target->pos_next)->normalize (TRACKING_DISTANCE)->add($m->target->pos_next);
                break;
            case Raptor::HUNTING:
                $wall_point = Pack::point_closest_to_walls ($m->target->pos_next);
                $to_hunter = $m->target->pos_next->vector_to ($m->pos);
                $dist_to_target = $to_hunter->norm();

                if ($dist_to_target > (PREY_VISION-PREY_SPEED)) // intercept the prey
                {
                    // use actual speed (i.e. true position delta, including wall stops)
                    $target_true_speed = $m->target->pos->vector_to ($m->target->pos_next);
                    $intercept_speed = $m->intercept ($m->target->pos, $target_true_speed);
                    $destination = $m->pos->add ($intercept_speed);
                }
                else if ($dist_to_target < PRED_SPEED) // pounce on the prey!
                {
                    $destination = $m->target->pos_next;
                }
                else if ($to_hunter->dot($m->target->speed) > 0)
                {
                    $destination = $m->target->pos_next;
                }
                else // goad the prey
                {
                    $to_wall = $m->target->pos->vector_to ($wall_point);
                    $wall_point = $wall_point;
                    $raw_speed = $m->target->raw_speed->add($m->target->pos->vector_to($m->pos)->multiply(2))->multiply (-0.5);
                    $wpd_t = $m->target->pos->vector_to ($wall_point)->normalize()->rotate90(); // wpd = Wanted Prey Direction
                    $delta = $wpd_t->multiply ($raw_speed->dot ($wpd_t));
                    $destination = $delta->vector_to ($m->target->pos_next);
                    if (!Pack::in_arena ($destination)) $destination = $m->target->pos_next;
                }
                break;
            case Raptor::RUSHING:
                $destination = $m->target->pos_next;
                break;
            }
            $m->move_to ($destination);
        }
    }
}

while (Raptors::read_input())
{
    Raptors::think();
    Raptors::output_moves();
}
?>

सामान्य विचार

  • यह एंडगेम है जो मायने रखता है। यदि आप हाजिर नहीं होते हैं और विपक्ष की तुलना में तेज गति वाले आखिरी कुछ प्रीस को पकड़ते हैं, तो आप कभी भी हार सकते हैं।

  • यदि आपके शिकारी अकेले शिकार (या कम से कम जोड़े में) को नहीं पकड़ सकते हैं, तो आप जल्द से जल्द टोस्ट कर सकते हैं जैसे ही शिकार घनत्व कम हो जाता है या तो अंधे भाग्य पर निर्भर होता है या कोनों के लिए शिकार को अवरुद्ध करता है।

  • एक शिकार आंदोलन पूर्वसूचक मूल रूप से अनिवार्य है। मैं खुद के भविष्यवक्ता होने के बिना एक भविष्यवक्ता-आधारित कार्यक्रम की धड़कन की कल्पना नहीं कर सकता।

पूंछ का पीछा

शिकार को पकड़ने का सबसे अयोग्य तरीका यह है कि उसका पीछा किया जाए। एकल शिकार और कोई बाहरी प्रभाव (दीवारों, अन्य शिकार, आदि) का पीछा करते हुए एक एकल शिकारी को मानते हुए, एक पूंछ पीछा हमेशा के लिए रह सकता है। जैसे ही आप 30 इकाइयों की शिकार दृष्टि त्रिज्या में प्रवेश करते हैं, शिकार आपके 6.1 के लिए गति 6 के रूप में उड़ जाता है, इसलिए आप प्रति सेकंड .1 दूरी प्राप्त करते हैं: एक सीधी रेखा में, आपको इसे प्राप्त करने के लिए लगभग 300 घुमावों की आवश्यकता होगी।

अखाड़े के आकार को ध्यान में रखते हुए, एक शिकार एक दीवार या एक कोने को मारने से पहले 500 इकाइयों के वर्ग के अधिकांश विकर्ण पर यात्रा करेगा, जो अधिकतम 117 मोड़ लेगा।

जीतने की रणनीति स्पष्ट रूप से एक और शिकारी या उसके सामने एक दीवार / कोने होने से, शिकार को धीमा करने का एक रास्ता खोजने के लिए है।

भविष्यवक्ता

6 की शिकार की गति के साथ, एक शिकार 36 * pi इकाइयों के क्षेत्र में जा सकता है। 1 के कैचिंग त्रिज्या के साथ, एक अंधे अनुमान के रूप में जहां शिकार आगे होगा 1/36 * pi (लगभग 1%) सफल होने का मौका है। स्पष्ट रूप से कुछ को बढ़ाने के लिए किया जाना है!

सिमुलेशन इंजन कोड को देखते हुए, आप देख सकते हैं कि इनपुट हैं:

  • दिखाई शिकार और शिकारी पदों
  • पिछले शिकार की गति

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

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

गुंडे का शिकार करना

शिकार की गति गणना के सटीक ज्ञान के साथ, एक शिकारी की स्थिति को समायोजित करके, वांछित दिशा की ओर एक दिए गए शिकार को "स्टीयर" करना संभव है।

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

चोरी करना पसंद करते हैं

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

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

शिकार चुराने के लिए कम से कम शिकारियों की एक जोड़ी की जरूरत होती है। एक को मारने के लिए जाना जाएगा, और दूसरा (ओं) शिकार दृष्टि त्रिज्या के भीतर ही रहेगा, जहां तक ​​संभव हो शिकार को प्रभावित करने के लिए और शिकार को शिकारी की ओर ले जाए।

इसके अलावा, दिशा का प्रत्येक परिवर्तन प्रतियोगिता को शिकार की ओर कोने में कटौती करने की अनुमति देगा, और दावेदार को पीछे रखना केवल तभी संभव है जब कार्रवाई की शुरुआत में "गॉडर" शिकार के काफी करीब था।

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

सुझाए गए परिवर्तन

अधिक जटिल रणनीतियों के लिए अनुमति देने के लिए, शिकारियों को शिकार के शीर्ष गति से ऊपर ले जाने से भूख के बिंदुओं में लागत आ सकती है, गति को अधिक करने के लिए आनुपातिक। उदाहरण के लिए कहें कि गति 6 तक पहुंचना नि: शुल्क है और 6 से ऊपर की हर गति बिंदु पर 100 भूख बिंदु होते हैं (6.3 की लागत 30 भूख बिंदु प्रति मोड़ पर होती है, 1000 भूख बिंदु जलने से एक मोड़ के लिए गति 16 तक पहुंचने की अनुमति होगी - और मर जाते हैं अगर आप डॉन 'ऐसा करने वाले शिकार को पकड़ना मत!)।

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

पहले पैक के लिए विशेष रंग देखना मुश्किल है। मैं नीले रंग के बजाय सियान या नारंगी का सुझाव देता हूं।


अंत में एक और प्रतियोगी! मैंने शिकार चोरी के अलावा आपके द्वारा बताए गए प्रत्येक बिंदु को जानबूझकर लागू किया था, जिसके लिए मैं वर्तमान दुष्प्रभावों से संतुष्ट था। आपकी टिप्पणियों से ऐसा लगता है कि आप मेरे क्लैरवॉयंट के खिलाफ जीत रहे हैं? यह दिलचस्प है, मैं कल जाँच करूँगा। = डी। इसके अलावा, आप बेहतर देखने के लिए (कम से कम मेरे अनुसार) ग्राफिक्स के लिए मेरे GUI अपडेट को आज़मा सकते हैं।
justhalf

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

वाह, मैं सिर्फ आपका सबमिशन कर गया। यह पागल है, मुझे नहीं पता था कि आप प्रार्थना को अभी भी उसी तरह बना सकते हैं। और मुझे थोड़ा ठगा हुआ महसूस हुआ कि जब शिकार ठीक किनारे पर होगा, तो मेरे शिकारी उन्हें पहचान नहीं पाएंगे, यह निश्चित रूप से मेरे लिए एक बड़ा नुकसान है।
9

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

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

3

आलसी पैक हास्केल

import Control.Monad
import Control.Concurrent

main :: IO ()
main=do
    t<-forkIO $ forever $ (putStrLn "Pack is paralyzed with indecision.\0")
    loop
    killThread t
        where
            loop=do
                line <- getLine
                case line of
                    "dead\0" -> return ()
                    _        -> loop

इसे चलाने के लिए आपको हैसेल प्लेटफॉर्म की आवश्यकता होगी । फिर आप runhaskellइसे चलाने के लिए कमांड का उपयोग करते हैं । मेरा पैक उनके पास आने के लिए शिकार का इंतजार करता है।


एक नई भाषा में एक कंकाल समाधान के लिए +1। संभवत: आप लोगों को इस के शीर्ष पर नई रणनीति बनाने के लिए खुश हैं?
ट्राइकोप्लाक्स

जरूर, क्यों नहीं। (हालांकि, यह निरंतर उत्पादन के अलावा कुछ भी नहीं करता है और "डेड \ 0" पर छोड़ देता है, इसलिए मुझे यकीन नहीं है कि यह बहुत उपयोगी होगा।)
PyRulez

मैं अभी भी किसी को भी सलाह देता हूं जो -silentविकल्प का उपयोग करने के लिए इसे चलाता है, हालांकि ...
Geobits

3

प्रविष्टि नहीं, मैं हमेशा में भाग लेने वाले प्रत्येक प्रवेश के लिए अनुकूलित रंग जोड़ने में दिलचस्पी रखता हूं ;)

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

Game.java

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.swing.JFrame;

public class Game {

    static int preyStartCount = 0; // 0 means 1500 + (packs * 50)
    static int turn;
    static boolean silent = false;
    long startTime;

    JFrame frame;
    BufferedImage img;
    Color[] colors;

    Island map;
    List<Prey> preys;
    List<Predator> predators;
    List<Pack> packs;
    List<Pack> initPacks;

    public static void main(String[] args) throws InterruptedException {

        Game game = new Game();
        game.init(args);
        if (game.packs.size() > 0){
            game.run();
            game.score();
        }
        game.end();
    }

    void end() {
        frame.setVisible(false);
        frame.dispose();
        for (Pack pack : packs)
            pack.handler.end();
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
        } finally {
            for (Pack pack : packs)
                pack.handler.shutdown();
        }

        System.exit(0);
    }

    void score() {
        Collections.sort(initPacks);
        int score = 100;
        initPacks.get(0).score = score;
        for (int i = 1; i < initPacks.size(); i++) {
            Pack pack = initPacks.get(i);
            if (pack.extinctionTurn < initPacks.get(i - 1).extinctionTurn)
                score = score < 1 ? score : score * 80 / 100;
            pack.score = score;
        }
        print("", true);
        print("Done in " + getElapsedTime(), true);
        for (Pack pack : initPacks)
            print(pack.toString() + "\t: Turn " + pack.extinctionTurn + "\t: Score " + pack.score, true);
    }

    String getElapsedTime(){
        double elapsed = (System.currentTimeMillis() - startTime) / 1000d;
        if(elapsed < 60)
            return String.format("%.2f", elapsed) + " seconds";
        elapsed /= 60;
        if(elapsed < 60)
            return String.format("%.2f", elapsed) + " minutes";
        elapsed /= 60;
        return String.format("%.2f", elapsed) + " hours";       
    }


    public Game() {
        initPacks = new ArrayList<Pack>();
        packs = new ArrayList<Pack>();
        preys = new ArrayList<Prey>();
        predators = new ArrayList<Predator>();
    }

    void run() throws InterruptedException {
        frame.setVisible(true);
        turn = 0;
        Graphics2D g = img.createGraphics();

        printStatus();
        while (true) {
            turn++;

            getAllMoves();
            moveAll();
            spawn();
            removeDead();
            shuffle();

            if (turn % 500 == 0)
                printStatus();
            paint(frame, g);
            Thread.sleep(5);
            if (packs.size() < 1)
                break;
        }
    }

    void getAllMoves(){
        for (Prey prey : preys)
            prey.setNextMove();
        for (Pack pack : packs){    
            pack.talk(preys.size(), predators.size(), turn);
        }
        while(true){
            int doneCount = 0;
            for(Pack pack : packs)
                if(pack.doneTalking)
                    doneCount++;
            if(doneCount >= packs.size())
                break;
            try {Thread.sleep(1);}catch(InterruptedException e){}
        }
    }

    void moveAll(){
        for (Creature prey : preys) 
            prey.move();
        for(Pack pack : packs){
            for (Predator predator : pack.members) {
                predator.move();
                predator.eatOrStarve();
            }
        }
    }

    void paint(JFrame frame, Graphics2D g){
        g.setPaint(Color.BLACK);
        g.fillRect(0, 0, img.getWidth(), img.getHeight());

        for(Prey prey : preys)
            prey.paint(g);
        for(Pack pack : packs)
            for(Predator predator : pack.members)
                predator.paint(g);

        frame.repaint();
    }

    List<Prey> deadPreys;
    List<Predator> deadPredators;
    List<Pack> deadPacks;

    void removeDead(){
        deadPreys.clear();
        for (Prey prey : preys)
            if (!prey.alive)
                deadPreys.add(prey);
        preys.removeAll(deadPreys);

        deadPredators.clear();
        for (Predator predator : predators)
            if (!predator.alive)
                deadPredators.add(predator);
        predators.removeAll(deadPredators);

        deadPacks.clear();
        for (Pack pack : packs)
            if (!pack.alive)
                deadPacks.add(pack);
        packs.removeAll(deadPacks);

        for (Pack pack : packs) {
            pack.members.removeAll(deadPredators);
        }

        map.rebuildLists(preys, predators);
    }

    void shuffle(){
        Collections.shuffle(packs);
        for(Pack pack : packs)
            Collections.shuffle(pack.members);
    }

    void spawn(){
        if(turn % 5000 == 0)
            addPredators(1);
        if(turn % 1000 == 0)
            populatePrey(predators.size()-1, false);
    }

    void addPredators(int count){
        for(Pack pack : packs){
            if(!pack.alive)
                continue;
            if(pack.aliveCount == 0)
                continue;
            Predator parent = null;
            for(Predator predator : pack.members)
                if(predator.alive)
                    parent = predator;
            if(parent != null){
                for(int i=0;i<count;i++){
                    XY pos = new XY(Math.random() * 30, Math.random()   * 30);
                    pos.add(parent.pos);
                    pos.setInZeroBounds(Island.SIZE, Island.SIZE);
                    Predator child = new Predator(pack);
                    child.color = colors[pack.id];
                    child.moveTo(pos, Island.getCellByPosition(pos));
                    predators.add(child);
                    pack.members.add(child);
                    pack.aliveCount++;
                }
            }
        }
    }

    Color[] generateColors(int n){
        Color[] result = new Color[n];
        double maxR = -1000;
        double minR = 1000;
        double maxG = -1000;
        double minG = 1000;
        double maxB = -1000;
        double minB = 1000;
        double[][] colors = new double[n][3];
        for(int i=0; i<n; i++){
            double cos = Math.cos(i * 2 * Math.PI / n);
            double sin = Math.sin(i * 2 * Math.PI / n);
            double bright = 1;
            colors[i][0] = bright + sin/0.88;
            colors[i][1] = bright - 0.38*cos - 0.58*sin;
            colors[i][2] = bright + cos/0.49;
            maxR = Math.max(maxR, colors[i][0]);
            minR = Math.min(minR, colors[i][0]);
            maxG = Math.max(maxG, colors[i][1]);
            minG = Math.min(minG, colors[i][1]);
            maxB = Math.max(maxB, colors[i][2]);
            minB = Math.min(minB, colors[i][2]);
        }
        double scaleR = 255/(maxR-minR);
        double scaleG = 255/(maxG-minG);
        double scaleB = 255/(maxB-minB);
        for(int i=0; i<n; i++){
            int R = (int)Math.round(scaleR*(colors[i][0]-minR));
            int G = (int)Math.round(scaleG*(colors[i][1]-minG));
            int B = (int)Math.round(scaleB*(colors[i][2]-minB));
            result[i] = new Color(R,G,B);
        }
        return result;
    }

    void populatePredators(String[] args) {
        int start = 0;
        if(args[0].equals("-silent")){
            silent = true;
            start = 1;
        }

        colors = generateColors(args.length-start);
        if(colors.length==1){
            colors[0] = Color.BLUE;
        }

        for (int i = start; i < args.length; i++) {
            Pack pack = new Pack(args[i]);
            if (pack.handler.init()) {
                packs.add(pack);
                initPacks.add(pack);
            }
        }
        Collections.shuffle(packs);
        XY[] positions = map.getPackStartLocations(packs.size());
        XY offset = new XY(-15, -15);
        for(int i=0;i<packs.size();i++){
            Pack pack = packs.get(i);
            for (Predator predator : pack.members) {
                predator.color = colors[pack.id];
                XY pos = new XY(Math.random() * 30, Math.random()   * 30);
                pos.add(positions[i]);
                pos.add(offset);
                pos.setInZeroBounds(Island.SIZE, Island.SIZE);
                predator.moveTo(pos, Island.getCellByPosition(pos));
                predators.add(predator);
            }
        }
        deadPredators = new ArrayList<Predator>(predators.size());
        deadPacks = new ArrayList<Pack>(packs.size());
    }

    void populatePrey(int count, boolean center) {
        XY pos = new XY();
        for (int i = 0; i < count; i++) {
            Prey prey = new Prey();
            if(center){
                pos.x = Math.random() * 100 + 200;
                pos.y = Math.random() * 100 + 200;
            } else {
                pos.x = Math.random() * 500;
                pos.y = Math.random() * 500;
            }

            prey.moveTo(pos, Island.getCellByPosition(pos));
            preys.add(prey);
        }
        deadPreys = new ArrayList<Prey>(preys.size());
    }

    static void print(String txt){
        print(txt, false);
    }

    static void print(String txt, boolean override){
        if(!silent || override)
            System.out.println(txt);
    }

    void printStatus(){
        print("Turn " + turn + " : Prey " + preys.size()
                + " : Predators " + predators.size() + " (" + getElapsedTime() + " elapsed)");
    }

    @SuppressWarnings("serial")
    void init(String[] args) {
        startTime = System.currentTimeMillis();
        map = new Island();
        populatePredators(args);
        if (preyStartCount == 0)
            preyStartCount = 1500 + (packs.size() * 50);

        populatePrey(preyStartCount, true);
        map.rebuildLists(preys, predators);
        img = new BufferedImage(Island.SIZE, Island.SIZE, 1);
        frame = new JFrame() {
            @Override
            public void paint(Graphics g) {
                g.drawImage(img, 32, 32, null);
            }
        };
        frame.setSize(Island.SIZE+64, Island.SIZE+64);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                for (Pack pack : packs)
                    pack.handler.end();
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                } finally {
                    for (Pack pack : packs)
                        pack.handler.shutdown();
                }
            }
        });
    }
}

Predator.java

import java.awt.Graphics2D;


public class Predator extends Creature {

    static int count = 0;

    int id;
    int hunger;
    Pack pack;

    public Prey eatOrStarve() {
        for (Prey prey : preys) {
            if (prey.alive && pos.isCloserThan(prey.pos, eatDist)) {
                prey.die();
                hunger = MAX_HUNGER;
                return prey;
            }
        }
        if (hunger-- < 1)
            die();
        return null;
    }

    @Override
    public void die() {
        super.die();
        pack.aliveCount--;
        Game.print(pack.toString() + " starved! " + pack.aliveCount + " members remaining.");
    }

    @Override
    void paint(Graphics2D g){
        g.setPaint(color);
        int size = ((hunger + 10) > MAX_HUNGER && Game.turn > 10) ? 3+(int)Math.pow((hunger+10-MAX_HUNGER)/4,3) : 3;
        g.drawOval((int)pos.x - 1, (int)pos.y - 1, size, size);
        g.fillOval((int)pos.x - 1, (int)pos.y - 1, size, size);
    }

    Predator(Pack pack) {
        super();
        id = count++;
        this.pack = pack;
        MAX_SPEED = 6.1;
        VISIBLE = 50;
        hunger = MAX_HUNGER;
    }

    final double eatDist = 1;
    final static int MAX_HUNGER = 1000;
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.