पेट्री डिश के लिए लड़ाई


32

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

.....x....
...x...o..
...x.c..o.
.......o..

गुण

हर सेल में तीन विशेषताएँ होती हैं। खेल की शुरुआत में अपनी सेल प्रजातियों को निर्दिष्ट करते समय, आप इन विशेषताओं के बीच 12 अंक आवंटित करते हैं।

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

क्रिया

प्रत्येक मोड़, प्रत्येक कोशिका एक क्रिया कर सकती है:

  • चाल: सेल 1 ऊर्जा की लागत पर किसी भी दिशा (एन / एस / ई / डब्ल्यू / एनई / एनडब्ल्यू / एसई / एसडब्ल्यू) में एक स्थान को स्थानांतरित करता है।

    • एक सेल दूसरे जीवित सेल के कब्जे वाले स्थान पर नहीं जा सकता है।
    • एक सेल ग्रिड से दूर नहीं जा सकता है।
    • एक कोशिका लाश पर घूमना लाश को नष्ट कर देता है।
  • हमला: एक सेल एक आसन्न कोशिका पर हमला करता है, जो 1 से 3 ऊर्जा बिंदुओं को जोड़कर, 1 से 3 क्षति से निपटता है।

    • एक सेल किसी भी दिशा (एन / एस / ई / डब्ल्यू / एनई / एनडब्ल्यू / एसई / एसडब्ल्यू) में हमला कर सकता है।
    • यह अनुकूल कोशिकाओं पर हमला करने के लिए कानूनी है।
  • डिवाइड: कोशिका विभाजित होती है और 5 ऊर्जा की लागत पर आसन्न स्थान पर एक नया सेल बनाती है।

    • एक सेल किसी भी दिशा (N / S / E / W / NE / NW / SE / SW) में विभाजित हो सकता है।
    • नए सेल में आपके मूल सेल विनिर्देश के अनुसार पूर्ण एचपी है।
    • नई कोशिका में उतनी ही ऊर्जा होती है जितनी उसके मूल कोशिका में विभाजन लागत को घटाने के बाद होती है। (उदाहरण के लिए, प्रारंभिक 8 ऊर्जा बिंदुओं वाला एक मूल सेल 3 ऊर्जा तक कम हो जाएगा और 3 ऊर्जा के साथ एक बाल कोशिका का उत्पादन होगा)।
    • एक नया सेल आपके अगले मोड़ तक कार्य नहीं कर सकता है।
    • एक सेल एक जीवित कोशिका के कब्जे वाले स्थान में विभाजित नहीं हो सकता है, लेकिन यह एक मृत कोशिका लाश द्वारा कब्जा किए गए स्थान में विभाजित कर सकता है (यह लाश को नष्ट कर देता है)।
  • खाओ: एक कोशिका एक आसन्न कोशिका लाश खाती है, 4 ऊर्जा प्राप्त करती है।

    • एक सेल किसी भी दिशा (एन / एस / ई / डब्ल्यू / एनई / एनडब्ल्यू / एसई / एसडब्ल्यू) में खा सकता है।
  • आराम करें: एक सेल एक मोड़ के लिए कुछ भी नहीं करता है, जिसमें 2 ऊर्जा होती है।

  • विस्फोट: जब किसी कोशिका में HP की तुलना में 3 या उससे कम HP और अधिक ऊर्जा होती है, तो वह विस्फोट हो सकता है, जिससे आस-पास के सभी आठ कोशिकाओं को नुकसान हो सकता है।

    • प्रत्येक आसन्न कोशिका को नुकसान होता है (exploding cell HP) + (explodng cell acidity)
    • एक विस्फोट कोशिका एक लाश के पीछे मर जाती है और विस्फोट के दौरान किसी भी कोशिका को मार देती है।

मसविदा बनाना

सेट अप

आपका कार्यक्रम BEGINस्टड पर दिए गए स्ट्रिंग के साथ चलेगा । आपके प्रोग्राम को 3 गैर-नकारात्मक पूर्णांकों की अंतरिक्ष-अलग-अलग सूची को रोकने के लिए लिखना चाहिए, जो आपके सेल प्रजातियों के लिए एचपी, ऊर्जा और अम्लता का प्रतिनिधित्व करता है: जैसे 5 6 1,। संख्या 12 तक होनी चाहिए 0। यदि आप चाहें तो अम्लता हो सकती है । (अन्य विशेषताएं भी शून्य हो सकती हैं, लेकिन ऐसा करना कार्यात्मक रूप से खेल को रोक देता है!)

आप एक सेल से शुरू करते हैं, उत्तर-पश्चिम या दक्षिण-पूर्व कोने में, या तो किनारे से एक स्थान दूर। शुरुआत सेल में पूर्ण एचपी और ऊर्जा है।

हर कोशिका कार्य करती है

हर मोड़, आपके कार्यक्रम को आपकी टीम के प्रत्येक सेल के लिए एक बार आमंत्रित किया जाएगा (कोशिकाओं को छोड़कर सिर्फ इस मोड़ को बनाया गया है) ताकि सेल कार्य कर सके। आपका कार्यक्रम स्टड पर डेटा के साथ प्रदान किया जाता है जिसमें पेट्री डिश राज्य और इस विशेष सेल के बारे में जानकारी शामिल है:

10 4
..........
..xx.c....
...c...o..
......o...

6 3 5 7

पहले दो नंबर अखाड़ा की चौड़ाई और ऊँचाई को दर्शाते हैं: यहाँ, 10-बाय -4 अखाड़ा है।

  • oकोशिकाओं तुम्हारा कर रहे हैं; xकोशिकाओं अपने दुश्मन हैं। (यह हमेशा सच होता है; प्रत्येक खिलाड़ी हमेशा अपनी स्वयं की कोशिकाओं को देखता है o।)
  • .रिक्त स्थान खाली हैं।
  • cरिक्त स्थान खाद्य सेल लाशों प्रतिनिधित्व करते हैं।

खाली पंक्ति के बाद वाले नंबर इस सेल के बारे में जानकारी का प्रतिनिधित्व करते हैं:

  • पहले दो नंबर x,yनिर्देशांक हैं, 0,0शीर्ष बाईं ओर से अनुक्रमित (इसलिए 6 3यहां दक्षिण-सबसे oसेल को संदर्भित करता है )।
  • तीसरा नंबर सेल का एचपी है; चौथा नंबर कोशिका की ऊर्जा है।

आपके प्रोग्राम को एक कार्रवाई के लिए (स्टडआउट को) आउटपुट देना चाहिए। नीचे दिए गए उदाहरणों में, हम Nएक उदाहरण दिशा के रूप में उपयोग करेंगे, लेकिन यह उस कार्रवाई ( N/ S/ E/ W/ NE/ NW/ SE/ SW) के लिए कोई भी कानूनी दिशा निर्देश हो सकता है । सभी प्रोग्राम आउटपुट केस-असंवेदनशील है, लेकिन उदाहरण अपरकेस का उपयोग करेंगे। कोई भी आउटपुट एक्शन जो अमान्य है (या तो क्योंकि इसमें सिंटैक्स अमान्य है या एक गैरकानूनी कार्रवाई का प्रयास करता है) को नजरअंदाज किया जाता है और सेल RESTआईएनजी में परिणाम होता है (और इस प्रकार 2 ऊर्जा प्राप्त होती है)।

  • MOVE N
  • DIVIDE N
  • EAT N
  • ATTACK N 2 - संख्या हमले की ताकत का प्रतिनिधित्व करती है (1 - 3)
  • REST
  • EXPLODE

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

उदाहरण

यहां बताया गया है कि कोई प्रोग्राम कैसे व्यवहार कर सकता है। स्टड से इनपुट को यहां प्रमुख >तीर (एक स्पष्ट स्थान द्वारा वास्तविक इनपुट से अलग) के साथ चिह्नित किया गया है और स्टडआउट पर आउटपुट में <तीर हैं।

> BEGIN
< 5 6 1

फिर, कार्यक्रम फिर से शुरू किया गया है:

> 10 4
> ..........
> .o........
> ........x.
> ..........
>
> 1 1 5 6
< DIVIDE SE

आपके प्रतिद्वंद्वी की बारी के बाद (जिसने DIVIDE Wएकल शुरुआत सेल के साथ फैसला किया ), आपके कार्यक्रम को दो बार, प्रत्येक सेल के लिए एक बार आमंत्रित किया जाता है:

> 10 4
> ..........
> .o........
> ..o....xx.
> ..........
>
> 1 1 5 1
< MOVE E

अपनी बारी के दूसरे आह्वान के लिए:

> 10 4
> ..........
> ..o.......
> ..o....xx.
> ..........
>
> 2 2 5 1
< MOVE SE

ध्यान दें कि यह दूसरा सेल आपकी बारी से पहले दूसरे सेल के मूवमेंट के आधार पर अपडेटेड बोर्ड स्टेट को देखता है। यह भी ध्यान दें कि इस सेल को 1 ऊर्जा के साथ बनाया गया है, क्योंकि मूल कोशिका में 6 ऊर्जा होती है जब उसने विभाजन को अंतिम रूप दिया (इसलिए मूल 6, विभाजन की 5-ऊर्जा लागत घटाकर 1 ऊर्जा के साथ एक बाल कोशिका बनाई)।

अब आपकी बारी है और आपके प्रतिद्वंद्वी की बारी शुरू होती है। दो विरोधी कोशिकाओं को कार्य करने का मौका दिया जाएगा, और फिर आपकी अगली बारी शुरू होगी।

विजय

आप दोनों में से जीत सकते हैं:

  • सभी विरोधी कोशिकाओं को नष्ट करना, या
  • प्रत्येक खिलाड़ी द्वारा 150 टर्न पूरा करने के बाद अपने प्रतिद्वंद्वी से अधिक सेल होना

स्कोरिंग एक दूसरे को जमा करने के खिलाफ 100 खेलों में जीत की संख्या पर आधारित होगी। आधे सिमुलेशन में, आपके कार्यक्रम को पहले जाने की अनुमति होगी।

टाई गेम्स (यानी 150 बारी के बाद कोशिकाओं की समान संख्या, या केवल शेष कोशिकाओं को एक विस्फोट में एक साथ मार दिया जाता है) को किसी भी खिलाड़ी के जीत योगों में नहीं गिना जाता है।

अन्य सूचना

  • आपके कार्यक्रम को राज्य बनाए रखने का प्रयास नहीं करना चाहिए (पेट्री डिश की स्थिति का उपयोग करने से परे): एककोशिकीय जीवों में बहुत अच्छी स्मृति नहीं होती है और पल-पल पर दुनिया की प्रतिक्रिया होती है। विशेष रूप से, एक फ़ाइल (या अन्य डेटा स्टोर) पर लिखना, एक दूरस्थ सर्वर के साथ संचार करना, या पर्यावरण चर सेट करना स्पष्ट रूप से अस्वीकृत है।
  • प्रस्तुतियाँ Ubuntu 12.04.4 पर चलाई / संकलित की जाएंगी।
  • 100 स्कोरिंग खेलों की बारीकियों की अभी पुष्टि नहीं हुई है, लेकिन वे कई अखाड़ों के आकार (उदाहरण के लिए, एक छोटे अखाड़े पर 50 रन और एक बड़े क्षेत्र पर 50 रन) को शामिल करेंगे। एक बड़े क्षेत्र के लिए, मैं यह सुनिश्चित करने के लिए अधिकतम मोड़ संख्या बढ़ा सकता हूं कि एक उचित लड़ाई हो सकती है।

साधन

यहाँ ड्राइवर कोड है जो सिमुलेशन को चलाता है, जिसे Node.js के लिए लिखा जाता है, द्वारा बुलाया जाता है node petri.js 'first program' 'second program'। उदाहरण के लिए, एक जावा-लिखित सेल के खिलाफ पायथन-लिखित सेल की तरह लग सकता है node petri.js 'python some_cell.py' 'java SomeCellClass'

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

बेशक आप एक अलग भाषा में एक सेल लिखने के लिए स्वतंत्र हैं; ये केवल तीन भाषाएं हैं जिन्हें मैंने समय-बचत सहायता के लिए बॉयलरप्लेट कोड लिखने का निर्णय लिया था।

यदि आपको ड्राइवर को चलाने में कोई समस्या है, तो इस चुनौती के लिए मेरे द्वारा बनाए गए चैट रूम में मुझे पिंग करने के लिए स्वतंत्र महसूस करें । यदि आपके पास चैट के लिए पर्याप्त प्रतिष्ठा नहीं है, तो बस एक टिप्पणी छोड़ दें।


1
@Ryan आपको 'node c:/cell/cell_template.js'प्रत्येक तर्क के लिए पूरी तरह से रन करने योग्य कमांड निर्दिष्ट करने की आवश्यकता होगी , ठीक उसी तरह जैसे आपको 'java CellTemplate'जावा कोड के लिए निर्दिष्ट करने की आवश्यकता होगी । मैं चुनौती पाठ में वह स्पष्ट कर दूँगा। यदि आपको परेशानी हो रही है, तो हम (और तकनीकी मुद्दों के साथ कोई और) इस चर्चा को एक चैट रूम में जारी रख सकते हैं जिसे मैंने अभी बनाया है
अप्सिलर्स

1
@ खेल प्रति खेल केवल 2 विरोधियों।
अप्सिलर्स

3
यार, उदाहरण बहुत अच्छे हैं!
कॉमनग्यू

3
@apsillers हमने आपसे चैट में पूछा था लेकिन आप पिंग करना भूल गए थे, इसलिए शायद आपने इस पर ध्यान नहीं दिया होगा: हम सोच रहे थे कि आप गेम चलाने की योजना कब बना रहे हैं?
प्लेनैपस

2
@ मनु अंत में, हाँ! मैं बहुत लंबे समय के लिए माफी मांगता हूं। मेरे पास मैचमेकिंग / स्कोरकीपिंग कोड सेट है और मैं अब सबके कोड को चलाने के लिए अपने प्रयास में सबमिशन के साथ किसी भी समस्या को दूर कर रहा हूं। उसके बाद, मैं इसे एक या दो दिन के लिए अपने सर्वर पर चलाने दूंगा ताकि राउंड को पूरा कर सकूं।
अप्सिलर्स

जवाबों:


3

यहाँ मेरा अपेक्षाकृत सरल बॉट है, जिसे मैंने रूबी में क्रमादेशित किया है। मूल रूप से, यह पहले विभाजन को प्राथमिकता देता है, और क्षेत्र पर नियंत्रण हासिल करने के लिए दुश्मनों की ओर विभाजित करने का प्रयास करता है। इसकी दूसरी प्राथमिकता भोजन है, और तीसरा हमला है। यह आसानी से नमूना पायथन सेल को हरा देता है।

def surroundingCells(x, y)
  result = Hash.new
  if x >= 1
    if y >= 1
      # northwest
      result["NW"] = $petriDish[x - 1][y - 1]
    end
    if y < ($sizeY - 1) # $sizeY - 1 is the farthest south square
      # southwest
      result["SW"] = $petriDish[x - 1][y + 1]
    end
      # west
      result["W"] = $petriDish[x - 1][y]
  end
  if x < ($sizeX - 1)
    if y >= 1
      # northeast
      result["NE"] = $petriDish[x + 1][y - 1]
    end
    if y < ($sizeY - 1)
      # southeast
      result["SE"] = $petriDish[x + 1][y + 1]
    end
    # east
    result["E"] = $petriDish[x + 1][y]
  end
  # north
  result["N"] = $petriDish[x][y - 1] if y >= 1
  # south
  result["S"] = $petriDish[x][y + 1] if y < ($sizeY - 1)
  return result
end

def directionTowardsEnemies(locX, locY)
  totalXDirections = 0
  totalYDirections = 0
  totalTargetsFound = 0 # enemies or corpses
  optimalDirections = []
  for x in 0..($petriDish.length - 1)
    for y in 0..($petriDish[0].length - 1)
      if $petriDish[x][y] == 'c' or $petriDish[x][y] == 'x'
        totalXDirections += (x - locX)
        totalYDirections += (y - locY)
        totalTargetsFound += 1
      end
    end
  end
  if totalXDirections == 0
    if totalYDirections > 0
      optimalDirections << "S" << "SE" << "SW"
    else
      optimalDirections << "N" << "NE" << "NW"
    end
    return optimalDirections
  end
  if totalYDirections == 0
    if totalXDirections > 0
      optimalDirections << "E" << "NE" << "SE"
    else
      optimalDirections << "W" << "NW" << "SW"
    end
    return optimalDirections
  end
  if totalXDirections > 0
    if totalYDirections > 0
      optimalDirections << "SE"
      if totalYDirections > totalXDirections
        optimalDirections << "S" << "E"
      else
        optimalDirections << "E" << "S"
      end
    else
      optimalDirections << "NE"
      if -totalYDirections > totalXDirections
        optimalDirections << "N" << "E"
      else
        optimalDirections << "E" << "N"
      end
    end
    return optimalDirections
  end
  if totalXDirections < 0
    if totalYDirections > 0
      optimalDirections << "SW"
      if totalYDirections > -totalXDirections
        optimalDirections << "S" << "W"
      else
        optimalDirections << "W" << "S"
      end
    else
      optimalDirections << "NW"
      if -totalYDirections > -totalXDirections
        optimalDirections << "N" << "W"
      else
        optimalDirections << "W" << "N"
      end
    end
  end
  return optimalDirections
end

firstLine = gets
if firstLine == "BEGIN"
  puts "5 7 0"
  exit 0
end
$sizeX, $sizeY = firstLine.split(' ')[0].to_i, firstLine.split(' ')[1].to_i
$petriDish = Array.new($sizeX) { Array.new($sizeY) }
for y in 0..($sizeY - 1)
  line = gets
  chars = line.split('').reverse.drop(1).reverse # this gets every character but     the last
  for x in 0..(chars.length - 1)
    $petriDish[x][y] = chars[x]
  end
end
gets # blank line
info = gets
locX = info.split(' ')[0].to_i
locY = info.split(' ')[1].to_i
hp = info.split(' ')[2].to_i
energy = info.split(' ')[3].to_i

# dividing is our first priority
if(energy >= 5)
  # try to divide towards enemies
  dirs = directionTowardsEnemies(locX, locY)
  directions = { "N" => [0, -1], "NE" => [1, -1], "E" => [1, 0],
    "SE" => [1, 1], "S" => [0, 1], "SW" => [-1, 1],
    "W" => [-1, 0], "NW" => [-1, -1] }
  for dir in dirs
    potentialNewX = locX + directions[dir][0]
    potentialNewY = locY + directions[dir][1]
    if $petriDish[potentialNewX][potentialNewY] == '.'
      puts "DIVIDE #{dir}"
      exit 0
    end
  end
  # otherwise, just divide somewhere.
  surroundingCells(locX, locY).each do |k, v|
    if v == '.'
      puts "DIVIDE #{k}"
      exit 0
    end
  end
end

# next, eating
surroundingCells(locX, locY).each do |k, v|
  if v == 'c'
    puts "EAT #{k}"
    exit 0
  end
end

# next, attacking
surroundingCells(locX, locY).each do |k, v|
  attackStrength = 0
  if (energy > 5) then # we want to save energy for dividing
    attackStrength = [(energy - 5), 3].min
  else
    attackStrength = [energy, 3].min
  end
  if v == 'x'
    puts "ATTACK #{k} #{attackStrength}"
    exit 0
  end
end

# otherwise, rest
puts "REST"

मैं कोई रूबी प्रोग्रामर नहीं हूं, इसलिए मुझे आश्चर्य है कि कुछ चर सामान्य क्यों हैं और कुछ एक के साथ शुरू होते हैं $
११

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

वैश्विक चर उत्पादन कोड में ही खराब हैं। इस तरह की स्क्रिप्ट में उन्हें कौन पसंद करता है?
देखिए

क्या मेरी कोशिका वास्तव में एकमात्र है जिसकी क्षमता प्रसार 4-8-0 नहीं है?
एलेक्स

यह मेरे समन्वित बैक्टीरिया के लिए अब तक का सबसे अच्छा दावेदार है! मैंने अपनी रणनीति का निर्माण आपके एकल-कोशिका-जीव पर परीक्षण के परिणाम के आधार पर किया। =)
जस्टफॉल

3

एक सलि का जन्तु

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

यदि कोई शत्रु आसन्न या एक स्थान दूर है, तो हमेशा हमला करेगा या उसकी ओर बढ़ेगा, जिससे किसी भी रिक्त स्थान को भरने के लिए कुछ भी नहीं करने के पीछे की पंक्ति को अनुमति मिलेगी।

मैंने किसी अन्य सबमिशन के खिलाफ यह परीक्षण नहीं किया है, इसलिए यह पता नहीं है कि यह कितना अच्छा होगा।

var MAX_HP = 2;
var MAX_ENERGY = 10;
var ACIDITY = 0;

function PathfindingNode(_x, _y, _prevNode, _distance, _adjacentEnemies) {
    this.x = _x;
    this.y = _y;
    this.prevNode = _prevNode;
    this.distance = _distance;
    this.adjacentEnemies = _adjacentEnemies;
}

PathfindingNode.prototype.GetDistance = function()
{
    return this.distance;
}

var evaluatedNodes = {};
var initialNode = {};
var firstEval = true;

function evaluateNode(x, y, arena)
{
    //get surrounding reachable nodes that havent already been checked
    var adjacentEmpties = arena.getAdjacentMatches(arena.get(x, y), [".", "c"]);

    //if this node is adjacent to the start node - special case because the start node isnt an empty
    if (firstEval)
        adjacentEmpties.push({ 'x': initialNode.x, 'y': initialNode.y });

    //find the optimal node to reach this one
    var prevNode = null;
    for (var i in adjacentEmpties)
    {
        if(evaluatedNodes[adjacentEmpties[i].x + "," + adjacentEmpties[i].y])
        {
            var currentNode = evaluatedNodes[adjacentEmpties[i].x + "," + adjacentEmpties[i].y];

            if (!prevNode) {
                prevNode = currentNode;
            }
            else {
                if(currentNode.GetDistance() < prevNode.GetDistance())
                {
                    prevNode = currentNode;
                }
            }
        }
    }

    var adjacentEnemies = arena.getAdjacentMatches(arena.get(x, y), ["x"]);
    var newNode = new PathfindingNode(x, y, prevNode, prevNode.GetDistance() + 1, adjacentEnemies.length);
    evaluatedNodes[x + "," + y] = newNode;
}

function evaluateNeighbours(arena) {
    //breadth first search all reachable cells
    var nodesToEvaluate = [];
    for (var i in evaluatedNodes) {
        var emptyNodes = arena.getAdjacentMatches(arena.get(evaluatedNodes[i].x, evaluatedNodes[i].y), [".", "c"]);
        //only ones that havent already been eval'd
        for (var j in emptyNodes)
            if (!evaluatedNodes[emptyNodes[j].x + "," + emptyNodes[j].y])
                nodesToEvaluate.push(emptyNodes[j])
    }

    //have all available nodes been evaluated
    if (nodesToEvaluate.length === 0)
        return false;

    for (var i in nodesToEvaluate)
    {
        evaluateNode(parseInt(nodesToEvaluate[i].x), parseInt(nodesToEvaluate[i].y), arena)
    }

    firstEval = false;
    return true;
}

function getAllReachableNodes(arena, cell) {
    //return a list of all reachable cells, with distance and optimal path
    evaluatedNodes = {};

    //add the first node to get started
    var adjacentEnemies = arena.getAdjacentMatches(arena.get(cell.x, cell.y), ["x"]);
    var newNode = new PathfindingNode(parseInt(cell.x), parseInt(cell.y), null, 0, adjacentEnemies.length);
    evaluatedNodes[cell.x + "," + cell.y] = newNode;
    initialNode.x = parseInt(cell.x);
    initialNode.y = parseInt(cell.y);
    firstEval = true;

    while (evaluateNeighbours(arena))
        ;

    return evaluatedNodes;
}

function passedMiddleGround(arena)
{
    for (var i = (parseInt(arena.width) / 2) - 1; i < parseInt(arena.width); i++)
    {
        for(var j = 0; j < parseInt(arena.height); j++)
        {
            if (arena.get(i, j).symbol == "o")
                return true;
        }
    }
    return false;
}

function decide(arena, cell, outputCallback) {

    var nearbyEmpties = arena.getAdjacentMatches(cell.point, [".", "c"]);
    var nearbyEnemies = arena.getAdjacentMatches(cell.point, ["x"]);
    var nearbyCorpses = arena.getAdjacentMatches(cell.point, ["c"]);

    if (nearbyEnemies.length > 4 && cell.energy >= cell.hp && cell.hp <= 3) {
        outputCallback("EXPLODE");
        return;
    }

    //attack whenever we get the chance. leave the replication to the cells doing nothing
    if (cell.energy > 0 && nearbyEnemies.length > 0){
        outputCallback("ATTACK " + arena.getDirection(cell, nearbyEnemies[(nearbyEnemies.length * Math.random()) | 0]) + " " + Math.min(cell.energy, 3));
        return;
    }

    //if we are close to an enemy, move towards it. let the back line fill the new space
    if (cell.energy > 2) {
        for (var i = 0; i < nearbyEmpties.length; ++i) {
            var space = nearbyEmpties[i];
            if (arena.getAdjacentMatches(space, ["x"]).length) {
                outputCallback("MOVE " + arena.getDirection(cell, space));
                return;
            }
        }
    }

    //yum
    if (nearbyCorpses.length > 0) {
        outputCallback("EAT " + arena.getDirection(cell, nearbyCorpses[(nearbyCorpses.length * Math.random()) | 0]));
        return;
    }

    //until we pass the middle ground, just keep moving into tactical position. afterwards we can start replication
    if (passedMiddleGround(arena) && cell.energy < 5 && nearbyEmpties.length > 0)
    {
        outputCallback("REST");
        return;
    }

    //try to block the opponent cells - interrupt their replication
    //if we have enough energy to move, choose the best spot
    if (nearbyEmpties.length > 0 && ((cell.energy >= 2 && nearbyEnemies.length == 0) || cell.energy >= 5)) {

        var nextMove = null;

        if (nearbyEmpties.length === 1) {
            nextMove = nearbyEmpties[0];
        }
        else {
            var reachableNodes = getAllReachableNodes(arena, cell);

            //select nodes that have an adjacent enemy
            var enemyAdjacentNodes = {};
            var enemyNodesReachable = false;
            for (var node in reachableNodes) {
                if (reachableNodes.hasOwnProperty(node) && reachableNodes[node].adjacentEnemies > 0) {
                    enemyAdjacentNodes[node] = reachableNodes[node];
                    enemyNodesReachable = true;
                }
            }

            if (enemyNodesReachable)
            {
                //if there are any then select the closest one
                var closest = null;
                for (var node in enemyAdjacentNodes) {
                    if(!closest)
                    {
                        closest = enemyAdjacentNodes[node];
                    }
                    else{
                        if(enemyAdjacentNodes[node].GetDistance() < closest.GetDistance())
                        {
                            closest = enemyAdjacentNodes[node];
                        }
                    }

                }

                //select the first move of the nodes path
                //trace the selected node back to the first node to select the first move towards the cell.
                while (closest.prevNode != null && closest.prevNode.prevNode != null)
                {
                    closest = closest.prevNode;
                }
                nextMove = arena.get(closest.x, closest.y);
            }
        }

        //a path to the enemy was found
        if(nextMove)
        {
            //do this until we get half way across the board, then we just replicate
            if (!passedMiddleGround(arena)) {
                if (cell.energy >= 5) {
                    outputCallback("DIVIDE " + arena.getDirection(cell, nextMove));
                    return;
                }

                outputCallback("MOVE " + arena.getDirection(cell, nextMove));
                return;
            }
            else {
                outputCallback("DIVIDE " + arena.getDirection(cell, nextMove));
                return;
            }

        }

    }

    //if theres no path to an enemy available, just divide anywhere
    if (cell.energy >= 5 && nearbyEmpties.length > 0) {
        outputCallback("DIVIDE " + arena.getDirection(cell, nearbyEmpties[(nearbyEmpties.length * Math.random()) | 0]));
        return;
    }

    outputCallback("REST");
    return;
}

var input = "";
// quiet stdin EPIPE errors
process.stdin.on("error", function(err) {
    log("slight error: " + err);
});
process.stdin.on("data", function(data) {
    input += data;
});
process.stdin.on("end", function() {
    if(input == "BEGIN") {
        // output space-separated attributes
        process.stdout.write([MAX_HP, MAX_ENERGY, ACIDITY].join(" "));
        clearLog();
    } else {
        // read in arena and decide on an action
        var arena = new Arena();
        var lines = input.split("\n");
        var dimensions = lines[0].split(" ").map(function(d) { return parseInt(d); });
        arena.width = dimensions[0];
        arena.height = dimensions[1];
        for(var y=1; y<=dimensions[1]; ++y) {
            for(var x=0; x<lines[y].length; ++x) {
                arena.set(x, y-1, lines[y][x]);
            }
        }

        var stats = lines[dimensions[1]+2].split(" ");
        var cell = { x: stats[0], y: stats[1], hp: stats[2], energy: stats[3], point: arena.get(stats[0], stats[1]) };

        // decide on an action and write the action to stdout
        decide(arena, cell, function(output) { process.stdout.write(output); })
    }
});

var Arena = function() {
    this.dict = {};
};
Arena.prototype = {
    // get Point object
    get: function(x,y) {
        if(!this.dict[x+","+y])
            return 'w';
        return this.dict[x+","+y];
    },

    // store Point object
    set: function(x,y,d) {
        this.dict[x+","+y] = new Point(x,y,d);
    },

    // get an array of all Points adjacent to this one whose symbol is contained in matchList
    // if matchList is omitted, return all Points
    getAdjacentMatches: function(point, matchList) {
        var result = [];
        for(var i=-1; i<=1; ++i) {
            for(var j=-1; j<=1; ++j) {
                var inspectedPoint = this.get(point.x+i, point.y+j);
                if(inspectedPoint && 
                   (i!=0 || j!=0) &&
                   (!matchList || matchList.indexOf(inspectedPoint.symbol) != -1)) {
                    result.push(inspectedPoint);
                }
            }
        }
        return result;
    },

    // return the direction from point1 to point2
    getDirection: function(point1, point2) {
        var dx = point2.x - point1.x;
        var dy = point2.y - point1.y;
        dx = Math.abs(dx) / (dx || 1);
        dy = Math.abs(dy) / (dy || 1);

        c2d = { "0,0":"-",
                "0,-1":"N", "0,1":"S", "1,0":"E", "-1,0":"W",
                "-1,-1":"NW", "1,-1":"NE", "1,1":"SE", "-1,1":"SW" };

        return c2d[dx + "," + dy];
    }
}

var Point = function(x,y,d) {
    this.x = x;
    this.y = y;
    this.symbol = d;
}
Point.prototype.toString = function() {
    return "(" + this.x + ", " + this.y + ")";
}

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

Btw, इस काम के लिए के रूप में इरादा नहीं लगता है अगर यह के खिलाड़ी 2.
justhalf

3

में सरल सेल किया node.js। यह फिर से उदाहरण नोड सेल का परीक्षण किया और Kostronor के खिलाफ यह उन्हें धड़कता है।

अद्यतन करें

अभी भी काफी सरल है, दुश्मन या विभाजन की ओर बढ़ने की कोशिश करें।

// used in defining cell spec
var MAX_HP = 4;
var MAX_ENERGY = 8;
var ACIDITY = 0;

function decide(arena, cell, outputCallback) {

    var nearbyEmpties = arena.getAdjacentMatches(cell.point, [".", "c"]);
    var nearbyEnemies = arena.getAdjacentMatches(cell.point, ["x"]);
    var nearbyCorpses = arena.getAdjacentMatches(cell.point, ["c"]);
    var nearbyFriends = arena.getAdjacentMatches(cell.point, ["o"]);

    if (nearbyFriends.length >= 8) {
        outputCallback("REST");
        return;
    }

    if (nearbyFriends.length >= 7 && nearbyEnemies.length < 0 && nearbyCorpses.length > 0 && energy < MAX_ENERGY) {
        outputCallback("EAT " + arena.getDirection(cell, nearbyCorpses[(nearbyCorpses.length*Math.random())|0]));
        return;
    }

    // if you have two or more nearby enemies, explode if possible
    if(nearbyEnemies.length >= 1
        && cell.energy >= cell.hp 
        && cell.hp <= 1 
        && nearbyEnemies.length > nearbyFriends.length) {
        outputCallback("EXPLODE");
        return;
    }

    // if you have two or more nearby enemies, explode if possible
    if(nearbyEnemies.length >= 3 && cell.energy >= cell.hp && nearbyEnemies.length > nearbyFriends.length) {
        outputCallback("EXPLODE");
        return;
    }

    // if you have the energy and space to divide, do it
    if(cell.energy >= 5 && nearbyEmpties.length > 0) {
        var ed = arena.getEnemyDirection(cell);
        if (nearbyEmpties.indexOf(ed) >= 0 && Math.random() < 0.5){
            outputCallback("DIVIDE " + ed);
        } else{
            outputCallback("DIVIDE " + arena.getDirection(cell, nearbyEmpties[(nearbyEmpties.length*Math.random())|0]));
        }
        return;
    }

    // if at least one adjacent enemy, attack if possible
    if(cell.energy > 0 && nearbyEnemies.length > 0) {
        outputCallback("ATTACK " + arena.getDirection(cell, nearbyEnemies[(nearbyEnemies.length*Math.random())|0]) + " " + Math.min(cell.energy, 3));
        return;
    }

    if (Math.random() < 0.5) {
        for(var i=0; i<nearbyEmpties.length; ++i) {
            outputCallback("MOVE " + arena.getEnemyDirection(cell));
            return;
        }
    } 

    if (nearbyEmpties.length > 0 && nearbyEnemies.length <= 6) {
        outputCallback("REST"); // because next turn is divide time
        return;
    }

    // if there's a nearby corpse, eat it if your energy is below max
    if(nearbyCorpses.length > 0) {
        outputCallback("EAT " + arena.getDirection(cell, nearbyCorpses[(nearbyCorpses.length*Math.random())|0]));
        return;
    }

    outputCallback("REST");
    return;
}

var input = "";
// quiet stdin EPIPE errors
process.stdin.on("error", function(err) {
    console.log("slight error: " + err);
});
process.stdin.on("data", function(data) {
    input += data;
});
process.stdin.on("end", function() {
    if(input == "BEGIN") {
        // output space-separated attributes
        process.stdout.write([MAX_HP, MAX_ENERGY, ACIDITY].join(" "));
    } else {
        // read in arena and decide on an action
        var arena = new Arena();
        var lines = input.split("\n");
        var dimensions = lines[0].split(" ").map(function(d) { return parseInt(d); });
        arena.width = dimensions[0];
        arena.height = dimensions[1];
        for(var y=1; y<=dimensions[1]; ++y) {
            for(var x=0; x<lines[y].length; ++x) {
                arena.set(x, y-1, lines[y][x]);
            }
        }

        var stats = lines[dimensions[1]+2].split(" ");
        var cell = { x: stats[0], y: stats[1], hp: stats[2], energy: stats[3], point: arena.get(stats[0], stats[1]) };

        // decide on an action and write the action to stdout
        decide(arena, cell, function(output) { process.stdout.write(output); })
    }
});

var Arena = function() {
    this.dict = {};
};
Arena.prototype = {
    // get Point object
    get: function(x,y) {
        return this.dict[x+","+y];
    },

    // store Point object
    set: function(x,y,d) {
        this.dict[x+","+y] = new Point(x,y,d);
    },

    // get an array of all Points adjacent to this one whose symbol is contained in matchList
    // if matchList is omitted, return all Points
    getAdjacentMatches: function(point, matchList) {
        var result = [];
        for(var i=-1; i<=1; ++i) {
            for(var j=-1; j<=1; ++j) {
                var inspectedPoint = this.get(point.x+i, point.y+j);
                if(inspectedPoint && 
                   (i!=0 || j!=0) &&
                   (!matchList || matchList.indexOf(inspectedPoint.symbol) != -1)) {
                    result.push(inspectedPoint);
                }
            }
        }
        return result;
    },

    // return the direction from point1 to point2
    getDirection: function(point1, point2) {
        var dx = point2.x - point1.x;
        var dy = point2.y - point1.y;
        dx = Math.abs(dx) / (dx || 1);
        dy = Math.abs(dy) / (dy || 1);

        c2d = { "0,0":"-",
                "0,-1":"N", "0,1":"S", "1,0":"E", "-1,0":"W",
                "-1,-1":"NW", "1,-1":"NE", "1,1":"SE", "-1,1":"SW" };

        return c2d[dx + "," + dy];
    },

    getEnemyDirection: function(p) {
        for (var i = 0; i < this.width; i++) {
            for (var j = 0; j < this.height; j++) {
                var found = this.get(i,j);
                if (found != null && found.symbol == "x") {
                    return this.getDirection(p, found);
                }
            }
        }
        return "N"; //should never happen
    }
}

var Point = function(x,y,d) {
    this.x = x;
    this.y = y;
    this.symbol = d;
}
Point.prototype.toString = function() {
    return "(" + this.x + ", " + this.y + ")";
}

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

2

क्रमागत उन्नति

यह सबमिशन विकसित हो गया है और अब एक साधारण सिंग-सेल जीव नहीं है! यह जब भी संभव हो हमला / विस्फोट करने की कोशिश करता है, अन्यथा यह दुश्मन की ओर विभाजित या स्थानांतरित होता है। मूविंग को अधिकतम ऊर्जा के साथ अनुकूल कोशिकाओं से घिरे सेल की समस्या को हल करना चाहिए, कुछ उपयोगी करने में असमर्थ।
आगे बढ़ने के बाद दुश्मन को हिट करने के लिए हमेशा 3 ऊर्जा बची रहती है जितना मुश्किल हो।

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;

public class Evolution {
    public static final int MAX_HP = 4;
    public static final int MAX_ENERGY = 8;
    public static final int ACIDITY = 0;

    // given arena state and cell stats, return an action string (e.g., "ATTACK NW 2", "DIVIDE S")
    public static String decide(Arena arena, Point cell, int hp, int energy) {
        ArrayList<Point> nearbyEmpty = arena.getAdjacentMatches(cell, ".");
        ArrayList<Point> nearbyEnemies = arena.getAdjacentMatches(cell, "x");
        ArrayList<Point> nearbyCorpses = arena.getAdjacentMatches(cell, "c");
        ArrayList<Point> nearbyFriends = arena.getAdjacentMatches(cell, "o");

        // more than 1 enemy around => explode if possible and worth it
        if(nearbyEnemies.size() > 1 && energy > hp && hp <= 3 && nearbyEnemies.size() > nearbyFriends.size()) {
            return "EXPLODE";
        }

        // enemies around => always attack with max strength
        if(energy > 0 && nearbyEnemies.size() > 0) {
            int attackStrength = Math.min(energy, 3);
            Point enemy = nearbyEnemies.get(0);
            return "ATTACK " + arena.getDirection(cell, enemy) + " " + attackStrength;
        }       

        // safe spot => divide if possible
        if(energy >= 5 && nearbyEmpty.size() > 0) {
            Point randomEmpty = nearbyEmpty.get((int)Math.floor(nearbyEmpty.size()*Math.random()));
            return "DIVIDE " + arena.getDirection(cell, randomEmpty);
        }

        // nearby corpse and missing energy => eat
        if(nearbyCorpses.size() > 0 && energy < MAX_ENERGY) {
            Point corpse = nearbyCorpses.get(0);
            return "EAT " + arena.getDirection(cell, corpse);
        }

        // move towards enemy => constant flow of attacks
        if(energy == 4) {
            return "MOVE " + arena.getEnemyDirection(cell);
        }

        return "REST";
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br =
            new BufferedReader(new InputStreamReader(System.in));

        String firstLine;

        firstLine = br.readLine();
        if(firstLine.equals("BEGIN")) {
            System.out.println(MAX_HP + " " + MAX_ENERGY + " " + ACIDITY);
        } else {
            String[] dimensions = firstLine.split(" ");
            int width = Integer.parseInt(dimensions[0]);
            int height = Integer.parseInt(dimensions[1]);
            Point[][] arena = new Point[height][];
            String input;
            int lineno = 0;

            while(!(input=br.readLine()).equals("")) {
                String[] charList = input.substring(1).split("");
                arena[lineno] = new Point[width];
                for(int i=0; i<charList.length; ++i) {
                    arena[lineno][i] = new Point(i, lineno, charList[i]);
                }
                lineno++;
            }

            String[] stats = br.readLine().split(" ");
            int x = Integer.parseInt(stats[0]);
            int y = Integer.parseInt(stats[1]);
            int hp = Integer.parseInt(stats[2]);
            int energy = Integer.parseInt(stats[3]);

            Arena arenaObj = new Arena(arena, width, height);
            System.out.print(decide(arenaObj, arenaObj.get(x,y), hp, energy));
        }
    }

    public static class Arena {
        public Point[][] array;
        public HashMap<String, String> c2d;
        public int height;
        public int width;

        public Arena(Point[][] array, int width, int height) {
            this.array = array;
            this.width = width;
            this.height = height;

            this.c2d = new HashMap<String, String>();
            this.c2d.put("0,0", "-");
            this.c2d.put("0,-1", "N");
            this.c2d.put("0,1", "S");
            this.c2d.put("1,0", "E");
            this.c2d.put("-1,0", "W");
            this.c2d.put("-1,-1", "NW");
            this.c2d.put("1,-1", "NE");
            this.c2d.put("-1,1", "SW");
            this.c2d.put("1,1", "SE");
        }

        // get the character at x,y
        // or return empty string if out of bounds
        public Point get(int x, int y) {
            if(y < 0 || y >= this.array.length){
                return null;
            }

            Point[] row = this.array[y];

            if(x < 0 || x >= row.length) {
                return null;
            }

            return row[x];
        }

        // get arraylist of Points for each adjacent space that matches the target string
        public ArrayList<Point> getAdjacentMatches(Point p, String match) {
            ArrayList<Point> result = new ArrayList<Point>();
            for(int i=-1; i<=1; ++i) {
                for(int j=-1; j<=1; ++j) {
                    Point found = this.get(p.x+i, p.y+j);
                    if((i!=0 || j!=0) && found != null && found.symbol.equals(match)) {
                        result.add(found);
                    }
                }
            }
            return result;
        }

        // get the direction string from point 1 to point 2
        public String getDirection(Point p1, Point p2) {
            int dx = p2.x - p1.x;
            int dy = p2.y - p1.y;
            dx = Math.abs(dx) / (dx==0?1:dx);
            dy = Math.abs(dy) / (dy==0?1:dy);

            return this.c2d.get(dx + "," + dy);
        }

        public String getEnemyDirection(Point p) {
            for (int x = 0; x < width; x++) {
                for (int y = 0; y < height; y++) {
                    Point found = this.get(x,y);
                    if (found != null && found.symbol.equals("x")) {
                        return getDirection(p, found);
                    }
                }
            }
            return "N"; //should never happen
        }
    }

    public static class Point {
        int x, y;
        String symbol;

        public Point(int x, int y, String sym) {
            this.x=x;
            this.y=y;
            this.symbol=sym;
        }
    }
}

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

2

निडर

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

जब भी संभव हो (यह इस प्रकार अम्लता होने का) विस्फोट करने की प्रकृति से कोशिका का नाम है और विभाजन के तुरंत बाद हमला करने को प्राथमिकता देकर।

मैंने अपने ड्रॉपबॉक्स पर जनरेट की गई जार-फाइल अपलोड की । साथ दौड़ोjava -jar petridish-clojure.jar

केवल स्पष्ट करने हेतु:

> BEGIN
< 4 6 2 LOOP
> 10 4
> ..........
> ..xx.c....
> ...c...O..
> ......o...
> 
> 3 4 6
< DIVIDE NW
> 10 4
> ..........
> ..xx.c....
> ...c.o.o..
> ......o...
>
> 5 2 4 1
< EAT N
> END
(ns petridish.core
  (:require [clojure.string :as s])
  (:gen-class))

(def ^:const maxhp     4)
(def ^:const maxenergy 6)
(def ^:const acidity   2)

(defn str->int
  [x]
  (if (empty? x)
    0
    (Integer. (re-find #"\d+" x))))

(defn sum-vectors [vec1 vec2]
  (vec (map #(vec (map + % vec2)) vec1)))

(defn find-adjacent [[width height] board pos target]
  (let [cells (sum-vectors [[-1 -1] [0 -1] [1 -1]
                            [-1  0]        [1  0]
                            [-1  1] [0  1] [1  1]]
                           pos)
        directions ["NW" "N" "NE"
                    "W"      "E"
                    "SW" "S" "SE"]]
    (for [cell cells
          :when (and (> width  (cell 0) -1)
                     (> height (cell 1) -1)
                     (= target (get-in board (reverse cell))))]
      (directions (.indexOf cells cell)))))

(defn decide [size board [x y hp energy]]
  (let [friends (find-adjacent size board [x y] \o)
        enemies (find-adjacent size board [x y] \x)
        corpses (find-adjacent size board [x y] \c)
        empty   (find-adjacent size board [x y] \.)]
    (cond
      (and (<= hp 3) (> energy hp) (seq enemies))
        "EXPLODE"
      (and (>= energy 5) (seq empty))
        (str "DIVIDE " (first empty))
      (and (>= energy 3) (seq enemies))
        (str "ATTACK " (first enemies) " " (min 3 energy))
      (and (< energy maxenergy) (seq corpses))
        (str "EAT " (first corpses))
      (or (and (<= 5 energy maxenergy) (not (seq empty))) (< energy 5))
        "REST"
      (seq empty)
        (str "MOVE " (rand-nth empty)))))

(defn read-board [[width height]]
  (let [result (vec (for [i (range height)]
                        (read-line)))]
    (read-line) ; Skip the empty line
    result))

(defn reader []
  (loop []
    (let [firstline (read-line)]
      (when (not= firstline "END")
        (println
          (if (= firstline "BEGIN")
            (str maxhp " " maxenergy " " acidity " LOOP")
            (let [size   (map str->int (s/split firstline #"\s+"))
                  board  (read-board size)
                  status (map str->int (s/split (read-line) #"\s+"))]
              (decide size board status))))
        (recur)))))

(defn -main []
  (reader))

अद्यतन लॉग

1. Fixed the logic a little and removed redundancies.

एसिडिटी का अच्छा उपयोग- वास्तव में, मुझे लगता है कि यह एकमात्र बॉट है जो एसिडिटी का उपयोग करता है।
एलेक्स

@ एलेक्स हम देखेंगे कि यह कैसे काम करता है, लेकिन मुझे लगता है कि यह अमीबा को साफ करने में सक्षम होना चाहिए। आप कोड के बारे में क्या सोचते हैं? मैं क्लोजर के लिए बहुत नया हूं।
देखिए

आपके उदाहरण में, नव स्पंदित कोशिका कैसे चल सकती है? मैंने सोचा कि आपको एक और मोड़ की प्रतीक्षा करने की आवश्यकता है?
०14:१३ पर ५14

@ अन्याय ई, कोशिकाओं को नहीं पता कि वे कितने पुराने हैं।
देखिए

हाँ, लेकिन नियंत्रक जानता है, है ना? यह नवगठित सेल को टर्न देने वाला नहीं है।
at

2

भूखा, भूखा बॉट

यहां आर में एक प्रविष्टि है। मुझे आशा है कि मुझे सही ढंग से समझ में आया कि आपके कार्यक्रम के साथ संवाद करने के लिए तकनीकी चश्मा क्या थे। के साथ ट्रिगर किया जाना चाहिए Rscript Hungryhungrybot.R
यदि इसमें कम से कम 6 ऊर्जा होती है तो यह दुश्मन की दिशा में अधिमानतः विभाजित होती है। अन्यथा यह जो कुछ भी है उसके बगल में या जो कुछ भी पहुंचता है उसे खाता है। यदि कोई भोजन उपलब्ध नहीं है, तो यह या तो तब फट जाएगा जब बहन कोशिकाओं की तुलना में आसपास अधिक दुश्मन हों, या आस-पास के दुश्मनों से लड़ें। यदि ऊर्जा 0 है और केवल खाने के लिए कुछ नहीं है तो आराम करता है।

infile <- file("stdin")
open(infile)
input1 <- readLines(infile,1)
if(input1=="BEGIN"){
    out <- "4 7 1"
    }else{
        nr <- as.integer(strsplit(input1," ")[[1]][2])
        nc <- as.integer(strsplit(input1," ")[[1]][1])
        input2 <- readLines(infile, 2+as.integer(nr))
        arena <- do.call(rbind,strsplit(input2[1:nr],""))
        stats <- strsplit(input2[nr+2]," ")[[1]]
        coords <- as.integer(stats[2:1])+1
        hp <- as.integer(stats[3])
        nrj <- as.integer(stats[4])
        closest <- function(coords,arena,object){
            a <- which(arena==object,arr.ind=TRUE)
            if(length(a)){
                d <- apply(a,1,function(x)max(abs(x-coords)))
                b <- which.min(d)
                f <- a[b,]
                dir <- f-coords
                where <- ""
                if(dir[1]<0)where <- paste(where,"N",sep="")
                if(dir[1]>0)where <- paste(where,"S",sep="")
                if(dir[2]<0)where <- paste(where,"W",sep="")
                if(dir[2]>0)where <- paste(where,"E",sep="")
                dist <- d[b]
                }else{dist <- NA; where <- ""}
            list(dist,where)
            }
        near <- expand.grid((coords[1]-1):(coords[1]+1),(coords[2]-1):(coords[2]+1))
        near <- near[near[,1]<=nr&near[,2]<=nc,]
        adjacent <- t(matrix(apply(near,1,function(x)arena[x[1],x[2]]),nr=3,byrow=TRUE))
        w <- matrix(c('NW','N','NE','W','','E','SW','S','SE'),nr=3,byrow=TRUE)
        if(coords[1]==1) w <- w[-1,]
        if(coords[1]==nr) w <- w[-3,]
        if(coords[2]==1) w <- w[,-1]
        if(coords[2]==nc) w <- w[,-3]
        if(any(arena=="c")){food <- closest(coords,arena,"c")}else{food <- list(nrj+2,"")}
        enemies <- closest(coords,arena,"x")
        if(nrj>=6){
            empties <- w[adjacent=="."]
            if(!length(empties)){
                if(sum(adjacent=="x")>sum(adjacent=="o") & hp<=3 & nrj>=hp){
                    out <- "EXPLODE"
                    }else{out <- "REST"}
                }else if(enemies[[2]]%in%empties & enemies[[1]]!=1){
                out <- paste("DIVIDE", enemies[[2]])
                }else{
                out <- paste("DIVIDE", empties[1])
                }
            }else{
                if(nrj==0 & !any(adjacent=="c")){
                    out <- "REST"
                    }else{
                        if(any(adjacent=="c")){
                            out <- paste("EAT",w[adjacent=="c"][1])
                            }else if(any(arena=="c") & food[[1]]<=(nrj+1)){
                                    out <- paste("MOVE",food[[2]])
                            }else if(sum(adjacent=="x")>sum(adjacent=="o") & hp<=3 & nrj>=hp){
                                out <- "EXPLODE"
                            }else if(any(adjacent=="x")){
                                out <- paste("ATTACK",w[adjacent=="x"][1],max(nrj,3))
                            }else{
                                out <- paste("MOVE", enemies[[2]])
                            }
                    }
            }
        }
cat(out)
flush(stdout())

मैं (अंततः) चुनौती को चलाने की कोशिश कर रहा हूं, और मैं Error: unexpected 'else' in "else"आपके कोड में रहता हूं । मुझे डर है कि मैं आर को बिल्कुल नहीं जानता, इसलिए मैं इस त्रुटि को हल करना शुरू नहीं कर सकता। संदर्भ के लिए, मुझे यह त्रुटि तब मिलती है जब मैं इसे ड्राइवर में चलाता हूं और जब मैं बस प्रोग्राम चलाता हूं और मैन्युअल रूप से टाइप करता हूं BEGIN
अप्सिलर्स

@apsillers arf मैंने एक नई पंक्ति जोड़ी है जहाँ मुझे नहीं करना चाहिए: यह अब काम करना चाहिए।
प्लेनैपस

उस त्रुटि को ठीक किया ताकि हम सेल इनिट के माध्यम से प्राप्त कर सकें; अब मैं एक और एक हो रहा हूं जब खेल वास्तव में शुरू होता है:Error in if (dir[1] < 0) where <- paste(where, "N", sep = "") : missing value where TRUE/FALSE needed
अप्सिलर्स

अब पहली बारी ठीक चलती है, लेकिन बाद में बारी आती है Error: object 'food' not found(जब एलेक्स के रूबी को प्रस्तुत करने के खिलाफ सामना करना पड़ता है, संभवतः अन्य)
अप्सिलर्स

आप सेल अब ठीक चलता है, धन्यवाद! :) हालाँकि, ड्राइवर प्रोग्राम में जस्टफॉल ने कुछ गंभीर बगों की पहचान की है (MOVE लागत-मुक्त था और EXPLODE ने इसकी वैधता का हिसाब नहीं दिया था)। यदि आप अपडेट किए गए ड्राइवर कोड के खिलाफ रिटायर होने और अपनी सबमिशन अपडेट करने में रुचि रखते हैं, तो कृपया मुझे बताएं। यदि नहीं, तो यह पूरी तरह से ठीक है।
अप्सिलर्स

2

समन्वित जीवाणु

आशा करता हूं कि मैं लेट नहीं हूं।

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

जब आप एकल-कक्षीय होते हैं, तो आप पिछली स्थिति को याद कर सकते हैं, लेकिन आप अपनी स्थिति का शोषण अलग तरह से कर सकते हैं! =)

यह बैक्टीरिया को विभक्त और प्रस्तावक में विभाजित करेगा, और ऐसा करने पर रक्षा पंक्ति को बनाए रखते हुए, केवल आगे की पंक्ति के बजाय अधिक बैक्टीरिया को उपयोगी बनाएगा।

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

मध्य-खेल में, जो बोर्ड पर कोशिकाओं की संख्या से पता लगाया जाता है, वे दुश्मन के इलाके में उन्हें बाहर निकालने की कोशिश करेंगे। यह प्रमुख जीत की रणनीति है।

वर्तमान में अन्य सभी विरोधियों की तुलना में इसकी वृद्धि दर सबसे अधिक है, लेकिन इसकी धीमी शुरुआत है, इसलिए यह बड़े क्षेत्र में बेहतर काम करता है।

इसे लेकर चलें java CoordinatedBacteria

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;

public class CoordinatedBacteria {
    public static final int MAX_HP = 6;
    public static final int MAX_ENERGY = 6;
    public static final int ACIDITY = 0;

    // given arena state and cell stats, return an action string (e.g., "ATTACK NW 2", "DIVIDE S")
    public static String decide(final Arena arena, Point cell, int hp, int energy) {
        // empty and corpses are free for movement and division
        final Point2D enemyCenter = arena.getCenterOf("x");
        final Point2D ourCenter = arena.getCenterOf("o");
        final int moverPos = (enemyCenter.x <= ourCenter.x || enemyCenter.y <= ourCenter.y) ? (arena.width+arena.height+1)%2 : 1;
        final int attackPos = (enemyCenter.x <= ourCenter.x || enemyCenter.y <= ourCenter.y) ? (arena.width+arena.height)%2 : 1;

        int selfCount = arena.count("o");
        boolean isMidWay = selfCount > (arena.width*arena.height/2-1);

        if(!isMidWay){
            if(enemyCenter.x < ourCenter.x){
                enemyCenter.x = 0;
                enemyCenter.y = 0;
                ourCenter.x = arena.width;
                ourCenter.y = arena.height;
            } else {
                enemyCenter.x = arena.width;
                enemyCenter.y = arena.height;
                ourCenter.x = 0;
                ourCenter.y = 0;
            }
        }
        ArrayList<Point> nearbyEmpty = arena.getAdjacentMatches(cell, ".");
        Collections.sort(nearbyEmpty, new Comparator<Point>(){
            @Override
            public int compare(Point o1, Point o2) {
                Double score1 = arena.getAdjacentMatches(o1, ".").size()
                        + arena.getAdjacentMatches(o1, "c").size()
                        + arena.getAdjacentMatches(o1, "x").size()
                        - arena.getAdjacentMatches(o1, "o").size()
                        + distance(o1.x, o1.y, enemyCenter.x, enemyCenter.y)*100;
                Double score2 = arena.getAdjacentMatches(o2, ".").size()
                        + arena.getAdjacentMatches(o2, "c").size()
                        + arena.getAdjacentMatches(o2, "x").size()
                        - arena.getAdjacentMatches(o2, "o").size()
                        + distance(o1.x, o1.y, enemyCenter.x, enemyCenter.y)*100;
                return Double.compare(score2, score1);
            }
        });
        ArrayList<Point> nearbyEnemies = arena.getAdjacentMatches(cell, "x");
        Collections.sort(nearbyEnemies, new Comparator<Point>(){
            @Override
            public int compare(Point o1, Point o2) {
                Integer score1 = (arena.getAdjacentMatches(o1, ".").size()
                        + arena.getAdjacentMatches(o1, "c").size()
                        - arena.getAdjacentMatches(o1, "x").size()
                        + arena.getAdjacentMatches(o1, "o").size())
                        *10
                        + (isAtBoundary(o1, arena)?1000:0)
                        + (o1.x + o1.y + attackPos + 1)%2;
                Integer score2 = (arena.getAdjacentMatches(o2, ".").size()
                        + arena.getAdjacentMatches(o2, "c").size()
                        - arena.getAdjacentMatches(o2, "x").size()
                        + arena.getAdjacentMatches(o2, "o").size())
                        *10
                        + (isAtBoundary(o2, arena)?1000:0)
                        + (o2.x + o2.y + attackPos + 1)%2;
                return Integer.compare(score2, score1);
            }
        });
        ArrayList<Point> nearbyCorpses = arena.getAdjacentMatches(cell, "c");
        Collections.sort(nearbyCorpses, new Comparator<Point>(){
            @Override
            public int compare(Point o1, Point o2) {
                Integer score1 = arena.getAdjacentMatches(o1, "x").size()
                        - arena.getAdjacentMatches(o1, "o").size();
                Integer score2 = arena.getAdjacentMatches(o2, "x").size()
                        - arena.getAdjacentMatches(o2, "o").size();
                return Integer.compare(score1, score2);
            }
        });
        ArrayList<Point> nearbyFriends = arena.getAdjacentMatches(cell, "o");

        for(Point empty: nearbyEmpty){
            if(nearbyFriends.size()>=2 && energy >= 1 && arena.getAdjacentMatches(empty, "x").size()==3 && isAtBoundary(empty, arena)){
                return "MOVE "+arena.getDirection(cell, empty);
            }
        }

        for(Point empty: nearbyCorpses){
            if(nearbyFriends.size()>=2 && energy >= 1 && arena.getAdjacentMatches(empty, "x").size()==3 && isAtBoundary(empty, arena)){
                return "MOVE "+arena.getDirection(cell, empty);
            }
        }

        if ((cell.x+cell.y)%2 == moverPos && energy >= 1 && energy <= 5){
            if(nearbyEmpty.size()>0){
                Point foremost = nearbyEmpty.get(0);
                if(nearbyFriends.size() >= 4){
                    return "MOVE "+arena.getDirection(cell, foremost);
                }
            }
            if(nearbyCorpses.size() > 0) {
                Point corpse = nearbyCorpses.get(0);
                return "EAT " + arena.getDirection(cell, corpse);
            }

            if(energy > 0 && nearbyEnemies.size() > 0) {
                int attackStrength = Math.min(energy, 3);
                Point enemy = nearbyEnemies.get(0);
                return "ATTACK " + arena.getDirection(cell, enemy) + " " + attackStrength;
            }

            if(nearbyFriends.size() >= 4 && nearbyEmpty.size() > 0){
                Point movePoint = getBestPointToDivide(arena, nearbyEmpty);
                return "MOVE " + arena.getDirection(cell, movePoint);
            }
        }

        if(energy >= 5 && nearbyEmpty.size() > 0) {
            Point divisionPoint = getBestPointToDivide(arena, nearbyEmpty);
            if(energy == MAX_ENERGY && nearbyFriends.size() >= 5
                    && distance(enemyCenter.x, enemyCenter.y, cell.x, cell.y) > distance(enemyCenter.x, enemyCenter.y, divisionPoint.x, divisionPoint.y)){
                return "MOVE " + arena.getDirection(cell, divisionPoint);
            }
            return "DIVIDE " + arena.getDirection(cell, divisionPoint);
        }

        if(nearbyCorpses.size() > 0) {
            Point corpse = nearbyCorpses.get(0);
            if (energy < MAX_ENERGY){
                return "EAT " + arena.getDirection(cell, corpse);
            } else {
                return "DIVIDE " + arena.getDirection(cell, corpse);
            }
        }

        if(energy >= 5 && nearbyCorpses.size() > 0) {
            Point divisionPoint = getBestPointToDivide(arena, nearbyCorpses);
            if(energy == MAX_ENERGY && nearbyFriends.size() >= 5
                    && distance(enemyCenter.x, enemyCenter.y, cell.x, cell.y) < distance(enemyCenter.x, enemyCenter.y, divisionPoint.x, divisionPoint.y)){
                return "MOVE " + arena.getDirection(cell, divisionPoint);
            }
            return "DIVIDE " + arena.getDirection(cell, divisionPoint);
        }

        // if at least one adjacent enemy, attack if possible
        if(energy > 0 && nearbyEnemies.size() > 0) {
            int attackStrength = Math.min(energy, 3);
            Point enemy = nearbyEnemies.get(0);
            return "ATTACK " + arena.getDirection(cell, enemy) + " " + attackStrength;
        }

        return "REST";

    }

    public static boolean isAtBoundary(Point point, Arena arena){
        return point.x==0 || point.x==arena.width-1 || point.y==0 || point.y==arena.height-1;
    }

    public static double distance(double x1, double y1, double x2, double y2){
        return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
    }

    public static Point getBestPointToDivide(Arena arena, List<Point> nearbyEmpty){
        Point result = null;
        double minDist = 100000;
        List<Point> mostEmpty = new ArrayList<Point>();
        int max = -1000;
        List<Point> neighbor = nearbyEmpty;
        for(Point point: neighbor){
            int emptyNeighborScore = arena.getAdjacentMatches(point, ".").size()
                    + arena.getAdjacentMatches(point, "c").size()
                    + arena.getAdjacentMatches(point, "x").size()
                    - arena.getAdjacentMatches(point, "o").size();
            if(emptyNeighborScore > max){
                mostEmpty = new ArrayList<Point>();
                mostEmpty.add(point);
                max = emptyNeighborScore;
            } else if(emptyNeighborScore == max){
                mostEmpty.add(point);
            }
        }
        for(Point point: mostEmpty){
            Point2D enemyCenter = arena.getCenterOf("x");
            double dist = Math.pow(point.x-enemyCenter.x, 2) + Math.pow(point.y-enemyCenter.y, 2);
            if(dist < minDist){
                minDist = dist;
                result = point;
            }
        }
        return result;
    }

    public static void main(String[] args) throws IOException {
        BufferedReader br =
                new BufferedReader(new InputStreamReader(System.in));

        String firstLine;

        firstLine = br.readLine();
        if(firstLine.equals("BEGIN")) {
            System.out.println(MAX_HP + " " + MAX_ENERGY + " " + ACIDITY);
        } else {
            String[] dimensions = firstLine.split(" ");
            int width = Integer.parseInt(dimensions[0]);
            int height = Integer.parseInt(dimensions[1]);
            Point[][] arena = new Point[height][];
            String input;
            int lineno = 0;

            while(!(input=br.readLine()).equals("")) {
                char[] charList = input.toCharArray();
                arena[lineno] = new Point[width];
                for(int i=0; i<charList.length; ++i) {
                    arena[lineno][i] = new Point(i, lineno, charList[i]);
                }
                lineno++;
            }

            String[] stats = br.readLine().split(" ");
            int x = Integer.parseInt(stats[0]);
            int y = Integer.parseInt(stats[1]);
            int hp = Integer.parseInt(stats[2]);
            int energy = Integer.parseInt(stats[3]);

            Arena arenaObj = new Arena(arena, width, height);
            System.out.print(decide(arenaObj, arenaObj.get(x,y), hp, energy));
        }
    }

    public static class Arena {
        public Point[][] array;
        public HashMap<String, String> c2d;
        public int height;
        public int width;

        public Arena(Point[][] array, int width, int height) {
            this.array = array;
            this.width = width;
            this.height = height;


            this.c2d = new HashMap<String, String>();
            this.c2d.put("0,0", "-");
            this.c2d.put("0,-1", "N");
            this.c2d.put("0,1", "S");
            this.c2d.put("1,0", "E");
            this.c2d.put("-1,0", "W");
            this.c2d.put("-1,-1", "NW");
            this.c2d.put("1,-1", "NE");
            this.c2d.put("-1,1", "SW");
            this.c2d.put("1,1", "SE");
        }

        // get the character at x,y
        // or return empty string if out of bounds
        public Point get(int x, int y) {
            if(y < 0 || y >= this.array.length){
                return null;
            }

            Point[] row = this.array[y];

            if(x < 0 || x >= row.length) {
                return null;
            }

            return row[x];
        }

        // get arraylist of Points for each adjacent space that matches the target string
        public ArrayList<Point> getAdjacentMatches(Point p, String match) {
            ArrayList<Point> result = new ArrayList<Point>();
            for(int i=-1; i<=1; ++i) {
                for(int j=-1; j<=1; ++j) {
                    Point found = this.get(p.x+i, p.y+j);
                    if((i!=0 || j!=0) && found != null && found.symbol.equals(match)) {
                        result.add(found);
                    }
                }
            }
            return result;
        }

        public ArrayList<Point> getAdjacents(Point p){
            ArrayList<Point> result = new ArrayList<Point>();
            for(int i=-1; i<=1; ++i) {
                for(int j=-1; j<=1; ++j) {
                    Point found = this.get(p.x+i, p.y+j);
                    if((i!=0 || j!=0) && found != null) {
                        result.add(found);
                    }
                }
            }
            return result;
        }

        public int count(String sym){
            int result = 0;
            for(int y=0; y<array.length; y++){
                for(int x=0; x<array[y].length; x++){
                    Point cur = this.get(x, y);
                    if(cur!=null && cur.symbol.equals(sym)){
                        result++;
                    }
                }
            }
            return result;
        }

        // get the direction string from point 1 to point 2
        public String getDirection(Point p1, Point p2) {
            int dx = p2.x - p1.x;
            int dy = p2.y - p1.y;
            dx = Math.abs(dx) / (dx==0?1:dx);
            dy = Math.abs(dy) / (dy==0?1:dy);

            return this.c2d.get(dx + "," + dy);
        }

        public Point2D getCenterOf(String sym){
            Point2D result = new Point2D(0,0);
            int count = 0;
            for(int y=0; y<array.length; y++){
                for(int x=0; x<array[y].length; x++){
                    if(this.get(x,y).symbol.equals(sym)){
                        result.x += x;
                        result.y += y;
                        count++;
                    }
                }
            }
            result.x /= count;
            result.y /= count;
            return result;
        }

    }

    public static class Point {
        int x, y;
        String symbol;

        public Point(int x, int y, String sym) {
            this.x=x;
            this.y=y;
            this.symbol=sym;
        }

        public Point(int x, int y, char sym){
            this(x, y, ""+sym);
        }
    }

    public static class Point2D{
        double x,y;
        public Point2D(double x, double y){
            this.x = x;
            this.y = y;
        }
    }
}

1

मुझे लगता है कि मैं अपनी सबमिशन पोस्ट करूंगा, क्योंकि आप बॉयलरप्लेट लॉजिक को जोड़ने के लिए बहुत उदार हैं ...

आपके तर्क में एक समस्या थी, जहां खाने की कार्रवाई एक ईएटी के बजाय एक एटीटीएके जारी करेगी और लाश को बर्बाद कर देगी।

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

एसिड मेरे लिए अंक की बर्बादी लगता है इसलिए मैंने इसे बाहर रखा ...

मैंने सबमिशन का परीक्षण नहीं किया, क्योंकि यह 2 मिनट की बात थी;)

यहाँ मेरा कोड है:

/*
 Sample code for a "Battle for the Petri Dish" cell

 Released under the terms of the WTF Public License
 No warranty express or implied is granted, etc, etc.

 I just hacked this together very quickly; improvements are welcome, so please fork the Gist if you like.

 used this code for a submission @kostronor

 */

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;

public class SlimeCell {
    public static final int MAX_HP = 4;
    public static final int MAX_ENERGY = 8;
    public static final int ACIDITY = 0;

    // given arena state and cell stats, return an action string (e.g., "ATTACK NW 2", "DIVIDE S")
    public static String decide(final Arena arena, final Point cell, final int hp, final int energy) {
        // empty and corpses are free for movement and division
        ArrayList<Point> nearbyEmpty = arena.getAdjacentMatches(cell, ".");
        nearbyEmpty.addAll(arena.getAdjacentMatches(cell, "c"));

        ArrayList<Point> nearbyEnemies = arena.getAdjacentMatches(cell, "x");
        ArrayList<Point> nearbyCorpses = arena.getAdjacentMatches(cell, "c");
        ArrayList<Point> nearbyFriends = arena.getAdjacentMatches(cell, "o");

        // if you have energy and space to divide, divide into a random space
        if((energy >= 5) && (nearbyEmpty.size() > 0)) {
            Point randomEmpty = nearbyEmpty.get((int)Math.floor(nearbyEmpty.size()*Math.random()));
            return "DIVIDE " + arena.getDirection(cell, randomEmpty);
        }

        // if at least one adjacent enemy, attack if possible
        if((energy > 0) && (nearbyEnemies.size() > 1)) {
            int attackStrength = Math.min(energy, 3);
            Point enemy = nearbyEnemies.get((int)Math.floor(nearbyEnemies.size()*Math.random()));
            return "ATTACK " + arena.getDirection(cell, enemy) + " " + attackStrength;
        }

        // if there's a nearby corpse, eat it if your energy is below max
        if(nearbyCorpses.size() > 0) {
            Point corpse = nearbyCorpses.get((int)Math.floor(nearbyCorpses.size()*Math.random()));
            return "EAT " + arena.getDirection(cell, corpse);
        }

        return "REST";

    }

    public static void main(final String[] args) throws IOException {
        BufferedReader br =
                new BufferedReader(new InputStreamReader(System.in));

        String firstLine;

        firstLine = br.readLine();
        if(firstLine.equals("BEGIN")) {
            System.out.println(MAX_HP + " " + MAX_ENERGY + " " + ACIDITY);
        } else {
            String[] dimensions = firstLine.split(" ");
            int width = Integer.parseInt(dimensions[0]);
            int height = Integer.parseInt(dimensions[1]);
            Point[][] arena = new Point[height][];
            String input;
            int lineno = 0;

            while(!(input=br.readLine()).equals("")) {
                String[] charList = input.substring(1).split("");
                arena[lineno] = new Point[width];
                for(int i=0; i<charList.length; ++i) {
                    arena[lineno][i] = new Point(i, lineno, charList[i]);
                }
                lineno++;
            }

            String[] stats = br.readLine().split(" ");
            int x = Integer.parseInt(stats[0]);
            int y = Integer.parseInt(stats[1]);
            int hp = Integer.parseInt(stats[2]);
            int energy = Integer.parseInt(stats[3]);

            Arena arenaObj = new Arena(arena, width, height);
            System.out.print(decide(arenaObj, arenaObj.get(x,y), hp, energy));
        }
    }

    public static class Arena {
        public Point[][] array;
        public HashMap<String, String> c2d;
        public int height;
        public int width;

        public Arena(final Point[][] array, final int width, final int height) {
            this.array = array;
            this.width = width;
            this.height = height;

            this.c2d = new HashMap<String, String>();
            this.c2d.put("0,0", "-");
            this.c2d.put("0,-1", "N");
            this.c2d.put("0,1", "S");
            this.c2d.put("1,0", "E");
            this.c2d.put("-1,0", "W");
            this.c2d.put("-1,-1", "NW");
            this.c2d.put("1,-1", "NE");
            this.c2d.put("-1,1", "SW");
            this.c2d.put("1,1", "SE");
        }

        // get the character at x,y
        // or return empty string if out of bounds
        public Point get(final int x, final int y) {
            if((y < 0) || (y >= this.array.length)){
                return null;
            }

            Point[] row = this.array[y];

            if((x < 0) || (x >= row.length)) {
                return null;
            }

            return row[x];
        }

        // get arraylist of Points for each adjacent space that matches the target string
        public ArrayList<Point> getAdjacentMatches(final Point p, final String match) {
            ArrayList<Point> result = new ArrayList<Point>();
            for(int i=-1; i<=1; ++i) {
                for(int j=-1; j<=1; ++j) {
                    Point found = this.get(p.x+i, p.y+j);
                    if(((i!=0) || (j!=0)) && (found != null) && found.symbol.equals(match)) {
                        result.add(found);
                    }
                }
            }
            return result;
        }

        // get the direction string from point 1 to point 2
        public String getDirection(final Point p1, final Point p2) {
            int dx = p2.x - p1.x;
            int dy = p2.y - p1.y;
            dx = Math.abs(dx) / (dx==0?1:dx);
            dy = Math.abs(dy) / (dy==0?1:dy);

            return this.c2d.get(dx + "," + dy);
        }

    }

    public static class Point {
        int x, y;
        String symbol;

        public Point(final int x, final int y, final String sym) {
            this.x=x;
            this.y=y;
            this.symbol=sym;
        }
    }
}

1

बारी-बारी से बम फैलाया

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

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

/*
 Sample code for a "Battle for the Petri Dish" cell

 Released under the terms of the WTF Public License,
 No warranty express or implied is granted, etc, etc.

 I just hacked this together very quickly; improvements are welcome, so please fork the Gist if you like.
*/

// used in defining cell spec
var MAX_HP = 1;
var MAX_ENERGY = 7;
var ACIDITY = 4;

/*
   The decide function takes an Arena object (see below for prototype methods), a cell object,
   and an outputCallback, which accepts a command string to output
*/
function decide(arena, cell, outputCallback) {
    var nearbyEmpties = arena.getAdjacentMatches(cell.point, [".", "c"]);
    var nearbyEnemies = arena.getAdjacentMatches(cell.point, ["x"]);
    var nearbyCorpses = arena.getAdjacentMatches(cell.point, ["c"]);
    var nearbyFriendlies = arena.getAdjacentMatches(cell.point, ["o"]);

    //attempt to move away from friendlies if possible
    if(nearbyFriendlies.length>1 && cell.energy>0)
    {
        for(var i=0; i<nearbyEmpties.length; ++i)
        {
            var space = nearbyEmpties[i];
            if(arena.getAdjacentMatches(space, ["o"]).length == 1)
            {
                outputCallback("MOVE " + arena.getDirection(cell,space));
                return;
            }
        }
    }

    // Explode if there are two more adjacent enemies than friendlies or enemies and no friendlies.
    if((nearbyEnemies.length - nearbyFriendlies.length > 1 || (nearbyEnemies.length>0 && nearbyFriendlies.length == 0)) 
        && cell.energy >= cell.hp && cell.hp <= 3)
    {
        outputCallback("EXPLODE");
        return;
    }

    // if you have the energy and space to divide, and there's a way for the child to get away from friendlies, do it.
    if(cell.energy >= 5 && nearbyEmpties.length > 0)
    {
        for(var i=0; i<nearbyEmpties.length; ++i)
        {
            var space = nearbyEmpties[i];
            var possiblePositions = arena.getAdjacentMatches(space, ["o"]);
            for(var i=0; i<possiblePositions.length; ++i)
            {
                if(arena.getAdjacentMatches(possiblePositions[i], ["o"]).length == 0)
                {
                    outputCallback("DIVIDE " + arena.getDirection(cell,space));
                    return;
                }
            }
        }
    }

    // if at least one adjacent enemy, attack if possible
    if(cell.energy > 0 && nearbyEnemies.length > 0)
    {
        outputCallback("ATTACK " + arena.getDirection(cell, nearbyEnemies[(nearbyEnemies.length*Math.random())|0]) + " " + Math.min(cell.energy, 3));
        return;
    }

    // if there's a nearby corpse, eat it if your energy is below max
    if(nearbyCorpses.length > 0)
    {
        outputCallback("EAT " + arena.getDirection(cell, nearbyCorpses[(nearbyCorpses.length*Math.random())|0]));
        return;
    }

    outputCallback("REST");
    return;
}

var input = "";
// quiet stdin EPIPE errors
process.stdin.on("error", function(err) {
    //console.log("slight error: " + err);
});
process.stdin.on("data", function(data) {
    input += data;
});
process.stdin.on("end", function() {
    if(input == "BEGIN") {
        // output space-separated attributes
        process.stdout.write([MAX_HP, MAX_ENERGY, ACIDITY].join(" "));
    } else {
        // read in arena and decide on an action
        var arena = new Arena();
        var lines = input.split("\n");
        var dimensions = lines[0].split(" ").map(function(d) { return parseInt(d); });
        arena.width = dimensions[0];
        arena.height = dimensions[1];
        for(var y=1; y<=dimensions[1]; ++y) {
            for(var x=0; x<lines[y].length; ++x) {
                arena.set(x, y-1, lines[y][x]);
            }
        }

        var stats = lines[dimensions[1]+2].split(" ");
        var cell = { x: stats[0], y: stats[1], hp: stats[2], energy: stats[3], point: arena.get(stats[0], stats[1]) };

        // decide on an action and write the action to stdout
        decide(arena, cell, function(output) { process.stdout.write(output); })
    }
});

var Arena = function() {
    this.dict = {};
};
Arena.prototype = {
    // get Point object
    get: function(x,y) {
        return this.dict[x+","+y];
    },

    // store Point object
    set: function(x,y,d) {
        this.dict[x+","+y] = new Point(x,y,d);
    },

    // get an array of all Points adjacent to this one whose symbol is contained in matchList
    // if matchList is omitted, return all Points
    getAdjacentMatches: function(point, matchList) {
        var result = [];
        for(var i=-1; i<=1; ++i) {
            for(var j=-1; j<=1; ++j) {
                var inspectedPoint = this.get(point.x+i, point.y+j);
                if(inspectedPoint && 
                   (i!=0 || j!=0) &&
                   (!matchList || matchList.indexOf(inspectedPoint.symbol) != -1)) {
                    result.push(inspectedPoint);
                }
            }
        }
        return result;
    },

    // return the direction from point1 to point2
    getDirection: function(point1, point2) {
        var dx = point2.x - point1.x;
        var dy = point2.y - point1.y;
        dx = Math.abs(dx) / (dx || 1);
        dy = Math.abs(dy) / (dy || 1);

        c2d = { "0,0":"-",
                "0,-1":"N", "0,1":"S", "1,0":"E", "-1,0":"W",
                "-1,-1":"NW", "1,-1":"NE", "1,1":"SE", "-1,1":"SW" };

        return c2d[dx + "," + dy];
    }
}

var Point = function(x,y,d) {
    this.x = x;
    this.y = y;
    this.symbol = d;
}
Point.prototype.toString = function() {
    return "(" + this.x + ", " + this.y + ")";
}

मैं इसका परीक्षण करने की कोशिश कर रहा हूं लेकिन मुझे इसे चलाने के लिए नहीं मिल रहा है। मैंने नोड स्थापित किया है ।js कमांड लाइन की कोशिश की node c:/cells/petri.js 'node c:/cells/bomber.js' 'node c:/cells/sample.js। जब मैं इसे नोड एप्लिकेशन कंसोल में टाइप करता हूं, तो मुझे बस तीन डॉट्स मिलते हैं, जब मैं कोशिश करता हूं और इसे विंडोज़ सीएमडी में चलाता हूं, तो मुझे मिलता है: 'नोड' को आंतरिक या बाहरी कमांड, ऑपरेबल प्रोग्राम या बैच फ़ाइल के रूप में मान्यता नहीं दी जाती है। मैंने सही फ़ोल्डर में .js फ़ाइलों के रूप में सभी फ़ाइलों को सहेजा था। एक noob के लिए कोई मदद? मैं चैट पर जाऊंगा या कहीं और टिप्पणी करूंगा, लेकिन मेरा प्रतिनिधि बहुत कम है।
ओवरएक्टर

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

आपको लगता है कि लाइन पर एक प्रकार है if((nearbyEnemies.length - nearbyFriendlies.length > 1 ¦¦ - वे ¦¦एक वैध ऑपरेटर नहीं लगते हैं और आपके पास कोष्ठक बेमेल हैं। मुझे लगता है कि जब आप इसे पोस्ट करते हैं तो कोड स्वरूपण गड़बड़ हो जाता है?
अप्सिलर्स

यह मेरे परीक्षणों के अनुसार काफी खराब है। आपके पास बहुत सारे असाइनमेंट हैं ( =) जब आप चाहते हैं तो समानता तुलना ( ==) है।
6

ओह नहीं। मैं ज्यादातर उस भाषा में प्रोग्रामिंग कर रहा था, जहां (=) असाइनमेंट वापस किया जाता है जब मैंने यह लिखा था, क्या यह अब बेहतर तरीके से चलता है? मैंने हालांकि यह कभी भी बढ़िया करने की उम्मीद नहीं की थी।
ओवरएक्टर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.