वेटोरी को! - वेक्टर रेसिंग ग्रां प्री


39

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

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

ट्रैक

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

स्टीयरिंग कार

आपकी कार एक दिए गए समन्वय पर और वेग वेक्टर के साथ शुरू होती है (0, 0)। प्रत्येक मोड़ में, आप वेग के प्रत्येक घटक को समायोजित कर सकते हैं ±1या इसे छोड़ सकते हैं। फिर, परिणामस्वरूप वेग वेक्टर को आपकी कार की स्थिति में जोड़ा जाता है।

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

                                    यहाँ छवि विवरण दर्ज करें

आप तो देश एक दीवार में, आप तुरंत खो देते हैं।

आपका कार्य

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

इनपुट

जब आपका कार्यक्रम लागू किया जाता है, तो स्टडिन से पढ़ें :

target
n m
[ASCII representation of an n x m racetrack]
time

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

न्यूलाइन-सीमांकित ट्रैक के लिए, निम्न वर्णों का उपयोग किया जाता है:

  • # - दीवार
  • S- शुरू
  • *- एक लक्ष्य
  • . - अन्य सभी ट्रैक सेल (यानी सड़क)

दी गई n x mग्रिड के बाहर की सभी कोशिकाओं को दीवारों के होने का अनुमान है।

समन्वित मूल शीर्ष बाएं कोने में है।

ये रहा एक सरल उदाहरण:

8
4.0
9 6
###...***
###...***
###...***
......###
S.....###
......###

0-आधारित अनुक्रमण का उपयोग करना, प्रारंभिक समन्वय होगा (0,4)

हर कदम के बाद आपको आगे इनपुट मिलेगा:

x y
u v
time

कहाँ x, y, u, vसभी 0-आधारित पूर्णांक हैं। (x,y)आपकी वर्तमान स्थिति है और (u,v)आपका वर्तमान वेग है। ध्यान दें कि x+uऔर / या y+vसीमा से बाहर हो सकता है।

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

जब खेल खत्म हो जाता है (क्योंकि आप एक दीवार में उतरे हैं, सीमा से बाहर चले गए, targetबदल गए, समय से बाहर भाग गए या लक्ष्य तक पहुंच गए), तो आपको एक खाली लाइन प्राप्त होगी।

उत्पादन

प्रत्येक मोड़ के लिए, stdout को लिखें :

Δu Δv

जहां Δuऔर Δvप्रत्येक में से एक हैं -1, 0, 1। यह (u,v)आपकी नई स्थिति निर्धारित करने के लिए जोड़ा जाएगा । बस स्पष्ट करने के लिए, निर्देश निम्नानुसार हैं

(-1,-1) ( 0,-1) ( 1,-1)
(-1, 0) ( 0, 0) ( 1, 0)
(-1, 1) ( 0, 1) ( 1, 1)

उपरोक्त उदाहरण के लिए एक इष्टतम समाधान होगा

1 0
1 -1
1 0

ध्यान दें कि कंट्रोलर खुद को stderr के साथ संलग्न नहीं करता है , इसलिए आप किसी भी प्रकार के डिबग आउटपुट के लिए इसका उपयोग करने के लिए स्वतंत्र हैं, जबकि आपको अपना बॉट विकसित करने की आवश्यकता हो सकती है। कृपया अपने सबमिट किए गए कोड में ऐसे किसी भी आउटपुट को हटा दें / टिप्पणी करें।

आपका बॉट प्रत्येक एक बारी में जवाब देने के लिए आधा सेकंड ले सकता है। लंबे समय तक चलने वाले परिवर्तनों के लिए, आपके पास target/2सेकंड का समय बजट (प्रति ट्रैक) होगा । हर बार जब एक मोड़ आधे से अधिक समय लेता है, तो अतिरिक्त समय आपके समय के बजट से घटाया जाएगा। जब आपका समय बजट शून्य हो जाएगा तो वर्तमान दौड़ समाप्त हो जाएगी।

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

स्कोरिंग

20 पटरियों का एक बेंचमार्क है। प्रत्येक ट्रैक के लिए:

  • यदि आप ट्रैक पूरा करते हैं, तो आपका स्कोर उन चालों की संख्या है जिन्हें आपको विभाजित करकेtarget एक लक्ष्य सेल तक पहुंचने की आवश्यकता है
  • आप समय / स्मृति समाप्त हो जाता है या लक्ष्य तक पहुँचने नहीं है इससे पहले कि targetबारी-बारी से नहीं बीते हैं या आप किसी भी समय एक दीवार में देश / सीमा से बाहर, अपने स्कोर है 2
  • यदि आपका कार्यक्रम निर्धारक नहीं है, तो आपका स्कोर उस ट्रैक पर औसतन 10 से अधिक रन है (कृपया अपने उत्तर में यह बताएं)।

आपका समग्र स्कोर व्यक्तिगत ट्रैक स्कोर का योग है। सबसे कम स्कोर जीत!

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

बाँध तोड़ना

अब चूंकि पहले से ही एक इष्टतम समाधान है, यह संभवतः प्रतिभागियों के स्कोर के लिए मुख्य कारक होगा।

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

  • मैं पक्ष लंबाई में वृद्धि होगी nद्वारा 10इस तरह से उत्पन्न पिछले ट्रैक की तुलना में। (यदि वे टाई नहीं तोड़ते हैं तो मैं आकार छोड़ सकता हूं।)
  • आधार यह वेक्टर-ग्राफिक है
  • यह इस Mathematica स्निपेट का उपयोग करके वांछित रिज़ॉल्यूशन पर rasterised किया जाएगा ।
  • शुरुआत शीर्ष बाएं कोने में है। विशेष रूप से, यह ट्रैक के उस छोर की सबसे ऊपरी पंक्ति का सबसे बाएं सेल होगा।
  • लक्ष्य नीचे दायें कोने में है। विशेष रूप से, यह ट्रैक के उस छोर के सबसे नीचे पंक्ति का सबसे सही सेल होगा।
  • targetइच्छा 4*n

प्रारंभिक बेंचमार्क का अंतिम ट्रैक पहले से ही इस तरह तैयार किया गया था, जिसके साथ n = 50

नियंत्रक

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

आप अपनी पसंद की एक ट्रैक फाइल के खिलाफ अपना बॉट चला सकते हैं:

ruby controller.rb track_file_name command to run your racer

जैसे

ruby controller.rb benchmark.txt ruby randomracer.rb

रिपॉजिटरी में भी दो वर्ग होते हैं Point2Dऔर Track। यदि आपका सबमिशन रूबी में लिखा गया है, तो अपनी सुविधा के लिए उन का पुन: उपयोग करने के लिए स्वतंत्र महसूस करें।

कमांड-लाइन स्विच

आप कमांड लाइन स्विच जोड़ सकते हैं -v, -s, -tबेंचमार्क के फ़ाइल नाम से पहले। आप एक से अधिक स्विच का उपयोग करना चाहते हैं, तो आप भी, उदाहरण के लिए कर सकते हैं, -vs। यही है जो वे करते हैं:

-v (क्रिया): नियंत्रक से थोड़ा अधिक डीबग आउटपुट बनाने के लिए इसका उपयोग करें।

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

-t(ट्रैक्स): आपको टेस्ट किए जाने वाले व्यक्तिगत ट्रैक्स का चयन करने देता है। ईजी -t "1,2,5..8,15"1, 2, 5, 6, 7, 8 और 15 को ही ट्रैक करेगा। इस सुविधा और विकल्प पार्सर के लिए वेंटरो को बहुत धन्यवाद ।

आपका सबमिशन

सारांश में, कृपया अपने उत्तर में निम्नलिखित शामिल करें:

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

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

सबसे अच्छा चालक उभरेगा!

लेकिन मैं खेलना चाहता हूँ!

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

लीडरबोर्ड

अंतिम अद्यतन: 01/09/2014, 21:29 यूटीसी
ट्रैक्स इन बेंचमार्क: 25
टाई-ब्रेकर आकार: 290, 440

  1. 6.86688 - कुरोई नेको
  2. 8.73108 - user2357112 - दूसरा सबमिशन
  3. 9.86627 - nneonneo
  4. 10.66109 - user2357112 - पहला सबमिशन
  5. 12.49643 - रे
  6. 40.0759 - छद्म नाम 117 (संभाव्य)

विस्तृत परीक्षण के परिणाम । (संभाव्य प्रस्तुतियाँ के लिए स्कोर अलग-अलग निर्धारित किए गए हैं।)

जवाबों:


5

सी ++ 11 - 6.66109

अभी तक एक और चौड़ाई पहले खोज कार्यान्वयन, केवल अनुकूलित।

इसे -s विकल्प के साथ चलाया जाना चाहिए ।
इसका इनपुट बिल्कुल भी सैनिटाइज नहीं है, इसलिए गलत ट्रैक इसे कद्दू में बदल सकते हैं।

मैंने इसे Microsoft Visual C ++ 2013 के साथ रिलीज़ किया, डिफ़ॉल्ट / O2 ध्वज (गति के लिए अनुकूलन) के साथ रिलीज़ का निर्माण किया।
G ++ और Microsoft IDE के साथ OK बनाता है।
मेरी बेयरबोन मेमोरी एलोकेटर बकवास का एक टुकड़ा है, इसलिए इसे अन्य एसटीएल कार्यान्वयन के साथ काम करने की उम्मीद नहीं है unordered_set!

#include <cstdint>
#include <iostream>
#include <fstream>
#include <sstream>
#include <queue>
#include <unordered_set>

#define MAP_START 'S'
#define MAP_WALL  '#'
#define MAP_GOAL  '*'

#define NODE_CHUNK_SIZE   100 // increasing this will not improve performances
#define VISIT_CHUNK_SIZE 1024 // increasing this will slightly reduce mem consumption at the (slight) cost of speed

#define HASH_POS_BITS 8 // number of bits for one coordinate
#define HASH_SPD_BITS (sizeof(size_t)*8/2-HASH_POS_BITS)

typedef int32_t tCoord; // 32 bits required to overcome the 100.000 cells (insanely) long challenge

// basic vector arithmetics
struct tPoint {
    tCoord x, y;
    tPoint(tCoord x = 0, tCoord y = 0) : x(x), y(y) {}
    tPoint operator+ (const tPoint & p) { return tPoint(x + p.x, y + p.y); }
    tPoint operator- (const tPoint & p) { return tPoint(x - p.x, y - p.y); }
    bool operator== (const tPoint & p) const { return p.x == x && p.y == y;  }
};

// a barebone block allocator. Improves speed by about 30%
template <class T, size_t SIZE> class tAllocator
{
    T * chunk;
    size_t i_alloc;
    size_t m_alloc;
public:
    typedef T                 value_type;
    typedef value_type*       pointer;
    typedef const value_type* const_pointer;
    typedef std::size_t       size_type;
    typedef value_type&       reference;
    typedef const value_type& const_reference;
    tAllocator()                                              { m_alloc = i_alloc = SIZE; }
    template <class U> tAllocator(const tAllocator<U, SIZE>&) { m_alloc = i_alloc = SIZE; }
    template <class U> struct rebind { typedef tAllocator<U, SIZE> other; };
    pointer allocate(size_type n, const_pointer = 0)
    {
        if (n > m_alloc) { i_alloc = m_alloc = n; }      // grow max size if request exceeds capacity
        if ((i_alloc + n) > m_alloc) i_alloc = m_alloc;  // dump current chunk if not enough room available
        if (i_alloc == m_alloc) { chunk = new T[m_alloc]; i_alloc = 0; } // allocate new chunk when needed
        T * mem = &chunk[i_alloc];
        i_alloc += n;
        return mem;
    }
    void deallocate(pointer, size_type) { /* memory is NOT released until process exits */ }
    void construct(pointer p, const value_type& x) { new(p)value_type(x); }
    void destroy(pointer p) { p->~value_type(); }
};

// a node in our search graph
class tNode {
    static tAllocator<tNode, NODE_CHUNK_SIZE> mem; // about 10% speed gain over a basic allocation
    tNode * parent;
public:
    tPoint pos;
    tPoint speed;
    static tNode * alloc (tPoint pos, tPoint speed, tNode * parent) { return new (mem.allocate(1)) tNode(pos, speed, parent); }
    tNode (tPoint pos = tPoint(), tPoint speed = tPoint(), tNode * parent = nullptr) : parent(parent), pos(pos), speed(speed) {}
    bool operator== (const tNode& n) const { return n.pos == pos && n.speed == speed; }
    void output(void)
    {
        std::string output;
        tPoint v = this->speed;
        for (tNode * n = this->parent ; n != nullptr ; n = n->parent)
        {
            tPoint a = v - n->speed;
            v = n->speed;
            std::ostringstream ss;  // a bit of shitty c++ text I/O to print elements in reverse order
            ss << a.x << ' ' << a.y << '\n';
            output = ss.str() + output;
        }
        std::cout << output;
    }
};
tAllocator<tNode, NODE_CHUNK_SIZE> tNode::mem;

// node queueing and storing
static int num_nodes = 0;
class tNodeJanitor {
    // set of already visited nodes. Block allocator improves speed by about 20%
    struct Hasher { size_t operator() (tNode * const n) const 
    {
        int64_t hash = // efficient hashing is the key of performances
            ((int64_t)n->pos.x   << (0 * HASH_POS_BITS))
          ^ ((int64_t)n->pos.y   << (1 * HASH_POS_BITS))
          ^ ((int64_t)n->speed.x << (2 * HASH_POS_BITS + 0 * HASH_SPD_BITS))
          ^ ((int64_t)n->speed.y << (2 * HASH_POS_BITS + 1 * HASH_SPD_BITS));
        return (size_t)((hash >> 32) ^ hash);
        //return (size_t)(hash);
    }
    };
    struct Equalizer { bool operator() (tNode * const n1, tNode * const n2) const
        { return *n1 == *n2; }};
    std::unordered_set<tNode *, Hasher, Equalizer, tAllocator<tNode *, VISIT_CHUNK_SIZE>> visited;
    std::queue<tNode *> queue; // currently explored nodes queue
public:
    bool empty(void) { return queue.empty();  }
    tNode * dequeue() { tNode * n = queue.front(); queue.pop(); return n; }
    tNode * enqueue_if_new (tPoint pos, tPoint speed = tPoint(0,0), tNode * parent = nullptr)
    {
        tNode signature (pos, speed);
        tNode * n = nullptr;
        if (visited.find (&signature) == visited.end()) // the classy way to check if an element is in a set
        {
            n = tNode::alloc(pos, speed, parent);
            queue.push(n);
            visited.insert (n);
num_nodes++;
        }
        return n;
    }
};

// map representation
class tMap {
    std::vector<char> cell;
    tPoint dim; // dimensions
public:
    void set_size(tCoord x, tCoord y) { dim = tPoint(x, y); cell.resize(x*y); }
    void set(tCoord x, tCoord y, char c) { cell[y*dim.x + x] = c; }
    char get(tPoint pos)
    {
        if (pos.x < 0 || pos.x >= dim.x || pos.y < 0 || pos.y >= dim.y) return MAP_WALL;
        return cell[pos.y*dim.x + pos.x];
    }
    void dump(void)
    {
        for (int y = 0; y != dim.y; y++)
        {
            for (int x = 0; x != dim.x; x++) fprintf(stderr, "%c", cell[y*dim.x + x]);
            fprintf(stderr, "\n");
        }
    }
};

// race manager
class tRace {
    tPoint start;
    tNodeJanitor border;
    static tPoint acceleration[9];
public:
    tMap map;
    tRace ()
    {
        int target;
        tCoord sx, sy;
        std::cin >> target >> sx >> sy;
        std::cin.ignore();
        map.set_size (sx, sy);
        std::string row;
        for (int y = 0; y != sy; y++)
        {
            std::getline(std::cin, row);
            for (int x = 0; x != sx; x++)
            {
                char c = row[x];
                if (c == MAP_START) start = tPoint(x, y);
                map.set(x, y, c);
            }
        }
    }

    // all the C++ crap above makes for a nice and compact solver
    tNode * solve(void)
    {
        tNode * initial = border.enqueue_if_new (start);
        while (!border.empty())
        {
            tNode * node = border.dequeue();
            tPoint p = node->pos;
            tPoint v = node->speed;
            for (tPoint a : acceleration)
            {
                tPoint nv = v + a;
                tPoint np = p + nv;
                char c = map.get(np);
                if (c == MAP_WALL) continue;
                if (c == MAP_GOAL) return new tNode (np, nv, node);
                border.enqueue_if_new (np, nv, node);
            }
        }
        return initial; // no solution found, will output nothing
    }
};
tPoint tRace::acceleration[] = {
    tPoint(-1,-1), tPoint(-1, 0), tPoint(-1, 1),
    tPoint( 0,-1), tPoint( 0, 0), tPoint( 0, 1),
    tPoint( 1,-1), tPoint( 1, 0), tPoint( 1, 1)};

#include <ctime>
int main(void)
{
    tRace race;
    clock_t start = clock();
    tNode * solution = race.solve();
    std::cerr << "time: " << (clock()-start)/(CLOCKS_PER_SEC/1000) << "ms nodes: " << num_nodes << std::endl;
    solution->output();
    return 0;
}

परिणाम

 No.       Size     Target   Score     Details
-------------------------------------------------------------------------------------
  1       37 x 1        36   0.22222   Racer reached goal at ( 36, 0) in 8 turns.
  2       38 x 1        37   0.24324   Racer reached goal at ( 37, 0) in 9 turns.
  3       33 x 1        32   0.25000   Racer reached goal at ( 32, 0) in 8 turns.
  4       10 x 10       10   0.40000   Racer reached goal at ( 7, 7) in 4 turns.
  5        9 x 6         8   0.37500   Racer reached goal at ( 6, 0) in 3 turns.
  6       15 x 7        16   0.37500   Racer reached goal at ( 12, 4) in 6 turns.
  7       17 x 8        16   0.31250   Racer reached goal at ( 14, 0) in 5 turns.
  8       19 x 13       18   0.27778   Racer reached goal at ( 0, 11) in 5 turns.
  9       60 x 10      107   0.14953   Racer reached goal at ( 0, 6) in 16 turns.
 10       31 x 31      106   0.23585   Racer reached goal at ( 27, 0) in 25 turns.
 11       31 x 31      106   0.24528   Racer reached goal at ( 15, 15) in 26 turns.
 12       50 x 20       50   0.24000   Racer reached goal at ( 49, 10) in 12 turns.
 13      100 x 100    2600   0.01385   Racer reached goal at ( 50, 0) in 36 turns.
 14       79 x 63      242   0.24380   Racer reached goal at ( 3, 42) in 59 turns.
 15       26 x 1        25   0.32000   Racer reached goal at ( 25, 0) in 8 turns.
 16       17 x 1        19   0.52632   Racer reached goal at ( 16, 0) in 10 turns.
 17       50 x 1        55   0.34545   Racer reached goal at ( 23, 0) in 19 turns.
 18       10 x 7        23   0.34783   Racer reached goal at ( 1, 3) in 8 turns.
 19       55 x 55       45   0.17778   Racer reached goal at ( 50, 26) in 8 turns.
 20      101 x 100     100   0.14000   Racer reached goal at ( 99, 99) in 14 turns.
 21   100000 x 1         1   1.00000   Racer reached goal at ( 0, 0) in 1 turns.
 22       50 x 50      200   0.05500   Racer reached goal at ( 47, 46) in 11 turns.
 23      290 x 290    1160   0.16466   Racer reached goal at ( 269, 265) in 191 turns.
-------------------------------------------------------------------------------------
TOTAL SCORE:                 6.66109

प्रदर्शन

उस भद्दे C ++ भाषा में आपको एक माचिस हिलाने के लिए हुप्स के माध्यम से कूदने की आदत है। हालाँकि, आप इसे अपेक्षाकृत तेज़ और मेमोरी-कुशल कोड बनाने में सचेत कर सकते हैं।

हैशिंग

यहां कुंजी नोड्स के लिए एक अच्छी हैश तालिका प्रदान करना है। निष्पादन की गति के लिए यह प्रमुख कारक है। (GNU और Microsoft) के
दो कार्यान्वयन में unordered_set30% निष्पादन की गति का अंतर (GNU, yy) के पक्ष में था)।

अंतर वास्तव में आश्चर्यजनक नहीं है, कोड के ट्रक लोड के साथ क्या छिपा हुआ है unordered_set

जिज्ञासा से बाहर, मैंने हैश तालिका की अंतिम स्थिति पर कुछ आंकड़े दिए।
दोनों एल्गोरिदम लगभग एक ही बाल्टी / तत्वों के अनुपात के साथ समाप्त होते हैं, लेकिन
पुनरावृत्ति भिन्न होती है: 290x290 टाई ब्रेकर के लिए, जीएनयू को गैर-खाली बाल्टी प्रति 1.5 तत्वों का औसत मिलता है, जबकि Microsoft 5.8 (!) पर है।

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

निश्चित रूप से, मेरा हैशिंग फ़ंक्शन इष्टतम के पास कहीं नहीं है। मैं कई बदलाव / muls के आधार पर सामान्य पूर्णांक मिश्रण का उपयोग कर सकता था लेकिन एक हैश-कुशल फ़ंक्शन को गणना करने में समय लगता है।

यह प्रतीत होता है कि सम्मिलन की संख्या की तुलना में हैश तालिका प्रश्नों की संख्या बहुत अधिक है। उदाहरण के लिए, 290x290 टाई ब्रेकर में, आपके पास 22.7 मिलियन प्रश्नों के लिए लगभग 3.6 मिलियन सम्मिलन हैं।
इस संदर्भ में, एक उप-अपनाने वाला लेकिन तेजी से हैशिंग बेहतर प्रदर्शन करता है।

स्मृति आवंटन

एक कुशल मेमोरी एलोकेटर प्रदान करना दूसरा आता है। इसने लगभग 30% तक प्रदर्शन में सुधार किया। क्या यह जोड़ा गया बकवास कोड के लायक है बहस करने योग्य है :)।

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

और विजेता है...

Win7 के तहत मेरे पीसी पर, टाई ब्रेकर (23, 290x290) को लगभग 2.2 सेकंड में मेमोरी संस्करण के साथ लगभग 2.2 सेकंड में सबसे खराब संस्करण (यानी माइक्रोसॉफ्ट संकलित) द्वारा हल किया गया है।
तुलना के लिए, वर्तमान नेता (user2357112 द्वारा अजगर कोड) 30 सेकंड से थोड़ा अधिक लेता है और लगभग 880 एमबी की खपत करता है।

नियंत्रक मुद्दों

मुझे पूरा यकीन नहीं है कि मैं अपनी जान बचाने के लिए रूबी में कोड कर सकता हूं।
हालाँकि, मैंने कंट्रोलर कोड से दो समस्याओं को देखा और हैक किया:

1) मैप रीडिंग इन track.rb

माणिक 1.9.3 स्थापित होने के साथ, ट्रैक रीडर के shift.to_iलिए उपलब्ध नहीं होने के बारे में क्रॉक करेगा string.lines
लंबे समय तक ऑनलाइन रूबी प्रलेखन के माध्यम से लुढ़कने के बाद मैंने तारों को छोड़ दिया और इसके बजाय एक मध्यवर्ती सरणी का उपयोग किया, जैसे कि (फ़ाइल की शुरुआत में सही):

def initialize(string)
    @track = Array.new;
    string.lines.each do |line|
        @track.push (line.chomp)
    end

2) भूतों को मारना controller.rb

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

if silent
    begin # ;!;
        Process.kill('KILL', racer.pid)
    rescue Exception => e
    end

परीक्षण का मामला

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

इस उदाहरण में, ऊपरी बाएं कोने में लक्ष्य के साथ 100x400 का नक्शा और निचले दाएं में शुरुआत।

इस मानचित्र में 28 घुमावों में एक समाधान है, लेकिन एक बीएफएस सॉल्वर इसे खोजने के लिए लाखों राज्यों का पता लगाएगा (मेरा नाम 10.022.658 राज्यों का दौरा किया गया, लगभग 12 सेकंड का समय लगा और 600 एमबी पर पहुंच गया!)।

290x290 टाई ब्रेकर की आधी से कम सतह के साथ, इसे लगभग 3 गुना अधिक नोड विज़िट की आवश्यकता होती है। दूसरी ओर, एक हेयुरिस्टिक / ए * आधारित सॉल्वर को इसे आसानी से हारना चाहिए।

30
100 400
*...................................................................................................
....................................................................................................
                          < 400 lines in all >
....................................................................................................
....................................................................................................
...................................................................................................S

बोनस: एक समकक्ष (लेकिन कुछ हद तक कम कुशल) PHP संस्करण

यह वही है जो मैंने शुरू किया था, इससे पहले कि अंतर्निहित भाषा धीमेपन ने मुझे सी ++ का उपयोग करने के लिए मना लिया।
PHP आंतरिक हैश टेबल पाइथन के रूप में के रूप में कुशल नहीं लगते हैं, कम से कम इस विशेष मामले में :)।

<?php

class Trace {
    static $file;
    public static $state_member;
    public static $state_target;
    static function msg ($msg)
    {
        fputs (self::$file, "$msg\n");
    }

    static function dump ($var, $msg=null)
    {
        ob_start();
        if ($msg) echo "$msg ";
        var_dump($var);
        $dump=ob_get_contents();
        ob_end_clean();
        fputs (self::$file, "$dump\n");
    }

    function init ($fname)
    {
        self::$file = fopen ($fname, "w");
    }
}
Trace::init ("racer.txt");

class Point {
    public $x;
    public $y;

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

    function __toString ()
    {
        return "[$this->x $this->y]";
    }

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

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

class Node {
    public $posx  , $posy  ;
    public $speedx, $speedy;
    private $parent;

    public function __construct ($posx, $posy, $speedx, $speedy, $parent)
    {
        $this->posx = $posx;
        $this->posy = $posy;
        $this->speedx = $speedx;
        $this->speedy = $speedy;
        $this->parent = $parent;
    }

    public function path ()
    {
        $res = array();
        $v = new Point ($this->speedx, $this->speedy);
        for ($node = $this->parent ; $node != null ; $node = $node->parent)
        {
            $nv = new Point ($node->speedx, $node->speedy);
            $a = $nv->vector_to ($v);
            $v = new Point ($node->speedx, $node->speedy);
            array_unshift ($res, $a);
        }
        return $res;
    }
}

class Map {

    private static $target;       // maximal number of turns
    private static $time;         // time available to solve
    private static $sx, $sy;      // map dimensions
    private static $cell;         // cells of the map
    private static $start;        // starting point
    private static $acceleration; // possible acceleration values

    public static function init ()
    {
        // read map definition
        self::$target = trim(fgets(STDIN));
        list (self::$sx, self::$sy) = explode (" ", trim(fgets(STDIN)));
        self::$cell = array();
        for ($y = 0 ; $y != self::$sy ; $y++) self::$cell[] = str_split (trim(fgets(STDIN)));
        self::$time = trim(fgets(STDIN));

        // get starting point
        foreach (self::$cell as $y=>$row)
        {
            $x = array_search ("S", $row);
            if ($x !== false)
            {
                self::$start = new Point ($x, $y);
Trace::msg ("start ".self::$start);
                break;
            }
        }

        // compute possible acceleration values
        self::$acceleration = array();
        for ($x = -1 ; $x <= 1 ; $x++)
        for ($y = -1 ; $y <= 1 ; $y++)
        {
            self::$acceleration[] = new Point ($x, $y);
        }
    }

    public static function solve ()
    {
        $now = microtime(true);
        $res = array();
        $border = array (new Node (self::$start->x, self::$start->y, 0, 0, null));
        $present = array (self::$start->x." ".self::$start->y." 0 0" => 1);
        while (count ($border))
        {
if ((microtime(true) - $now) > 1)
{
Trace::msg (count($present)." nodes, ".round(memory_get_usage(true)/1024)."K");
$now = microtime(true);
}
            $node = array_shift ($border);
//Trace::msg ("node $node->pos $node->speed");
            $px = $node->posx;
            $py = $node->posy;
            $vx = $node->speedx;
            $vy = $node->speedy;
            foreach (self::$acceleration as $a)
            {
                $nvx = $vx + $a->x;
                $nvy = $vy + $a->y;
                $npx = $px + $nvx;
                $npy = $py + $nvy;
                if ($npx < 0 || $npx >= self::$sx || $npy < 0 || $npy >= self::$sy || self::$cell[$npy][$npx] == "#")
                {
//Trace::msg ("invalid position $px,$py $vx,$vy -> $npx,$npy");
                    continue;
                }
                if (self::$cell[$npy][$npx] == "*")
                {
Trace::msg ("winning position $px,$py $vx,$vy -> $npx,$npy");
                    $end = new Node ($npx, $npy, $nvx, $nvy, $node);
                    $res = $end->path ();
                    break 2;
                }
//Trace::msg ("checking $np $nv");
                $signature = "$npx $npy $nvx $nvy";
                if (isset ($present[$signature])) continue;
//Trace::msg ("*** adding $np $nv");
                $border[] = new Node ($npx, $npy, $nvx, $nvy, $node);
                $present[$signature] = 1;
            }
        }
        return $res;
    }
}

ini_set("memory_limit","1000M");
Map::init ();
$res = Map::solve();
//Trace::dump ($res);
foreach ($res as $a) echo "$a->x $a->y\n";
?>

erf ... मेरा नंगेबोन आवंटन केवल थोड़ा बहुत नंगेबोन है। मैं g ++ के साथ काम करने के लिए आवश्यक बकवास जोड़ूंगा, फिर। उसके लिए माफ़ करना।

ठीक है, यह तय है। जी ++ संस्करण वास्तव में लगभग 30% तेजी से काम करता है। यह अब stderr पर कुछ आँकड़े आउटपुट करता है। इसे बेझिझक टिप्पणी करें (स्रोत की अंतिम पंक्तियों से)। गड़गड़ाहट के लिए फिर से क्षमा करें।

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

परिणाम अपडेट किया गया। टाई ब्रेकर की कोई आवश्यकता नहीं थी, क्योंकि अन्य सभी प्रस्तुतियाँ आपके परीक्षण ट्रैक पर मेमोरी सीमा से अधिक हैं। उस पर बधाई! :)
मार्टिन एंडर

धन्यवाद। वास्तव में इस चुनौती ने मुझे इन एसटीएल हैश टेबल में खुदाई करने का अवसर दिया। हालांकि मुझे C ++ हिम्मत से नफरत है, लेकिन मैं अपनी जिज्ञासा से मारे जाने में मदद नहीं कर सकता। मियांउ! :)।

10

सी ++, 5.4 (निर्धारक, इष्टतम)

गतिशील प्रोग्रामिंग समाधान। बिल्कुल इष्टतम। बहुत तेज: 0.2 में सभी 20 टेस्टकेस को हल करता है। 64-बिट मशीनों पर विशेष रूप से तेज़ होना चाहिए। बोर्ड मानता है कि प्रत्येक दिशा में 32,000 से कम स्थान हैं (जो उम्मीद की जानी चाहिए कि यह सच है)।

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

के साथ संकलित करें g++ -O3। C ++ 11 (के लिए <unordered_map>) की आवश्यकता हो सकती है । चलाने के लिए, बस संकलित निष्पादन योग्य चलाएं (कोई झंडे या विकल्प समर्थित नहीं हैं; सभी इनपुट स्टड पर लिया गया है)।

#include <unordered_map>
#include <iostream>
#include <string>
#include <vector>
#include <sstream>

#include <cstdint>

#define MOVES_INF (1<<30)

union state {
    struct {
        short px, py, vx, vy;
    };
    uint64_t val;
};

struct result {
    int nmoves;
    short dvx, dvy;
};

typedef std::unordered_map<uint64_t, result> cache_t;
int target, n, m;
std::vector<std::string> track;
cache_t cache;

static int solve(uint64_t val) {
    cache_t::iterator it = cache.find(val);
    if(it != cache.end())
        return it->second.nmoves;

    // prevent recursion
    result res;
    res.nmoves = MOVES_INF;
    cache[val] = res;

    state cur;
    cur.val = val;
    for(int dvx = -1; dvx <= 1; dvx++) for(int dvy = -1; dvy <= 1; dvy++) {
        state next;
        next.vx = cur.vx + dvx;
        next.vy = cur.vy + dvy;
        next.px = cur.px + next.vx;
        next.py = cur.py + next.vy;
        if(next.px < 0 || next.px >= n || next.py < 0 || next.py >= m)
            continue;
        char c = track[next.py][next.px];
        if(c == '*') {
            res.nmoves = 1;
            res.dvx = dvx;
            res.dvy = dvy;
            break;
        } else if(c == '#') {
            continue;
        } else {
            int score = solve(next.val) + 1;
            if(score < res.nmoves) {
                res.nmoves = score;
                res.dvx = dvx;
                res.dvy = dvy;
            }
        }
    }

    cache[val] = res;
    return res.nmoves;
}

bool solve_one() {
    std::string line;
    float time;

    std::cin >> target;
    // std::cin >> time; // uncomment to use "time" control
    std::cin >> n >> m;
    if(!std::cin)
        return false;
    std::cin.ignore(); // skip newline at end of "n m" line

    track.clear();
    track.reserve(m);

    for(int i=0; i<m; i++) {
        std::getline(std::cin, line);
        track.push_back(line);
    }

    cache.clear();

    state cur;
    cur.vx = cur.vy = 0;
    for(int y=0; y<m; y++) for(int x=0; x<n; x++) {
        if(track[y][x] == 'S') {
            cur.px = x;
            cur.py = y;
            break;
        }
    }

    solve(cur.val);

    int sol_len = 0;
    while(track[cur.py][cur.px] != '*') {
        cache_t::iterator it = cache.find(cur.val);
        if(it == cache.end() || it->second.nmoves >= MOVES_INF) {
            std::cerr << "Failed to solve at p=" << cur.px << "," << cur.py << " v=" << cur.vx << "," << cur.vy << std::endl;
            return true;
        }

        int dvx = it->second.dvx;
        int dvy = it->second.dvy;
        cur.vx += dvx;
        cur.vy += dvy;
        cur.px += cur.vx;
        cur.py += cur.vy;
        std::cout << dvx << " " << dvy << std::endl;
        sol_len++;
    }

    //std::cerr << "Score: " << ((float)sol_len) / target << std::endl;

    return true;
}

int main() {
    /* benchmarking: */
    //while(solve_one())
    //    ;

    /* regular running */
    solve_one();
    std::string line;
    while(std::cin) std::getline(std::cin, line);

    return 0;
}

परिणाम

 No.    Size     Target   Score     Details
-------------------------------------------------------------------------------------
  1    37 x 1        36   0.22222   Racer reached goal at ( 36, 0) in 8 turns.
  2    38 x 1        37   0.24324   Racer reached goal at ( 37, 0) in 9 turns.
  3    33 x 1        32   0.25000   Racer reached goal at ( 32, 0) in 8 turns.
  4    10 x 10       10   0.40000   Racer reached goal at ( 7, 7) in 4 turns.
  5     9 x 6         8   0.37500   Racer reached goal at ( 6, 0) in 3 turns.
  6    15 x 7        16   0.37500   Racer reached goal at ( 12, 4) in 6 turns.
  7    17 x 8        16   0.31250   Racer reached goal at ( 15, 0) in 5 turns.
  8    19 x 13       18   0.27778   Racer reached goal at ( 1, 11) in 5 turns.
  9    60 x 10      107   0.14953   Racer reached goal at ( 2, 6) in 16 turns.
 10    31 x 31      106   0.25472   Racer reached goal at ( 28, 0) in 27 turns.
 11    31 x 31      106   0.24528   Racer reached goal at ( 15, 15) in 26 turns.
 12    50 x 20       50   0.24000   Racer reached goal at ( 49, 10) in 12 turns.
 13   100 x 100    2600   0.01385   Racer reached goal at ( 50, 0) in 36 turns.
 14    79 x 63      242   0.26860   Racer reached goal at ( 3, 42) in 65 turns.
 15    26 x 1        25   0.32000   Racer reached goal at ( 25, 0) in 8 turns.
 16    17 x 1        19   0.52632   Racer reached goal at ( 16, 0) in 10 turns.
 17    50 x 1        55   0.34545   Racer reached goal at ( 23, 0) in 19 turns.
 18    10 x 7        23   0.34783   Racer reached goal at ( 1, 3) in 8 turns.
 19    55 x 55       45   0.17778   Racer reached goal at ( 52, 26) in 8 turns.
 20    50 x 50      200   0.05500   Racer reached goal at ( 47, 46) in 11 turns.
-------------------------------------------------------------------------------------
TOTAL SCORE:              5.40009

नया टेस्टकेस


1
खैर, ऐसा कुछ होने की बहुत उम्मीद थी। डायनेमिक प्रोग्रामिंग को रेंडर करने के लिए पहेली में बस पर्याप्त स्थिति नहीं है। यदि मैं प्रवेश करता हूं, तो मुझे एक नक्शा प्रस्तुत करने की आवश्यकता होती है जिसे हल करने के लिए अधिक परिष्कृत खोज रणनीतियों की आवश्यकता होती है।
user2357112

आपका रेसर आपके परीक्षण के मामले में कैसा प्रदर्शन करता है?
user2357112

0.14 (14 चाल)
nneonneo

क्या वह समय लिया गया है या चाल / लक्ष्य? यदि यह चाल / लक्ष्य है, तो यह समय के संदर्भ में कैसा प्रदर्शन करता है?
user2357112

1
मुझे लगता है कि मैंने साइकिल रोकथाम कोड में एक बग पाया है। यह मान लिया गया है कि यह लग सकता है प्रत्येक राज्य के लिए एक राज्य एस से खोज पहुँच, एक इष्टतम पथ एस पर लौटने के लिए नहीं किया जा सकता है कि अगर एक इष्टतम पथ है एस के लिए वापसी, तो राज्य नहीं एक इष्टतम रास्ते पर हो सकता है (हम कर सकते थे के बाद से बस उस लूप को हटा दें और एक छोटा रास्ता प्राप्त करें), और इसलिए हमें परवाह नहीं है कि क्या हम उस राज्य के लिए बहुत अधिक परिणाम प्राप्त करते हैं। हालाँकि, यदि कोई इष्टतम पथ उस क्रम में A और B राज्यों से होकर गुजरता है, लेकिन खोज पहली बार A को ढूंढती है जबकि B स्टैक पर है, तो A के परिणाम लूप की रोकथाम के द्वारा जहर होते हैं।
user2357112

6

पायथन 2 , निर्धारक, इष्टतम

यहाँ मेरा रेसर है। मैंने इसे बेंचमार्क पर परीक्षण नहीं किया है (फिर भी रूबी के किस संस्करण और इंस्टॉलर को स्थापित करने के बारे में वफ़ल किया गया है), लेकिन इसे हर चीज को बेहतर तरीके से और समय सीमा के तहत हल करना चाहिए। इसे चलाने की आज्ञा है python whateveryoucallthefile.py-sनियंत्रक ध्वज की आवश्यकता है ।

# Breadth-first search.
# Future directions: bidirectional search and/or A*.

import operator
import time

acceleration_options = [(dvx, dvy) for dvx in [-1, 0, 1] for dvy in [-1, 0, 1]]

class ImpossibleRaceError(Exception): pass

def read_input(line_source=raw_input):
    # We don't use the target.
    target = int(line_source())

    width, height = map(int, line_source().split())
    input_grid = [line_source() for _ in xrange(height)]

    start = None
    for i in xrange(height):
        for j in xrange(width):
            if input_grid[i][j] == 'S':
                start = i, j
                break
        if start is not None:
            break

    walls = [[cell == '#' for cell in row] for row in input_grid]
    goals = [[cell == '*' for cell in row] for row in input_grid]

    return start, walls, goals

def default_bfs_stop_threshold(walls, goals):
    num_not_wall = sum(sum(map(operator.not_, row)) for row in walls)
    num_goals = sum(sum(row) for row in goals)
    return num_goals * num_not_wall

def bfs(start, walls, goals, stop_threshold=None):
    if stop_threshold is None:
        stop_threshold = default_bfs_stop_threshold(walls, goals)

    # State representation is (x, y, vx, vy)
    x, y = start
    initial_state = (x, y, 0, 0)
    frontier = {initial_state}
    # Visited set is tracked by a map from each state to the last move taken
    # before reaching that state.
    visited = {initial_state: None}

    while len(frontier) < stop_threshold:
        if not frontier:
            raise ImpossibleRaceError

        new_frontier = set()
        for x, y, vx, vy in frontier:
            for dvx, dvy in acceleration_options:
                new_vx, new_vy = vx+dvx, vy+dvy
                new_x, new_y = x+new_vx, y+new_vy
                new_state = (new_x, new_y, new_vx, new_vy)

                if not (0 <= new_x < len(walls) and 0 <= new_y < len(walls[0])):
                    continue
                if walls[new_x][new_y]:
                    continue
                if new_state in visited:
                    continue

                new_frontier.add(new_state)
                visited[new_state] = dvx, dvy

                if goals[new_x][new_y]:
                    return construct_path_from_bfs(new_state, visited)
        frontier = new_frontier

def construct_path_from_bfs(goal_state, best_moves):
    reversed_path = []
    current_state = goal_state
    while best_moves[current_state] is not None:
        move = best_moves[current_state]
        reversed_path.append(move)

        x, y, vx, vy = current_state
        dvx, dvy = move
        old_x, old_y = x-vx, y-vy # not old_vx or old_vy
        old_vx, old_vy = vx-dvx, vy-dvy
        current_state = (old_x, old_y, old_vx, old_vy)
    return reversed_path[::-1]

def main():
    t = time.time()

    start, walls, goals = read_input()
    path = bfs(start, walls, goals, float('inf'))
    for dvx, dvy in path:
        # I wrote the whole program with x pointing down and y pointing right.
        # Whoops. Gotta flip things for the output.
        print dvy, dvx

if __name__ == '__main__':
    main()

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

नया टेस्टकेस

(गिटहब लंबी लाइन प्रदर्शित नहीं कर सकता। ट्रैक है *S.......[and so on].....)


अतिरिक्त जमा: पायथन 2, द्विदिश खोज

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

# Bidirectional search.
# Future directions: A*.

import operator
import time

acceleration_options = [(dvx, dvy) for dvx in [-1, 0, 1] for dvy in [-1, 0, 1]]

class ImpossibleRaceError(Exception): pass

def read_input(line_source=raw_input):
    # We don't use the target.
    target = int(line_source())

    width, height = map(int, line_source().split())
    input_grid = [line_source() for _ in xrange(height)]

    start = None
    for i in xrange(height):
        for j in xrange(width):
            if input_grid[i][j] == 'S':
                start = i, j
                break
        if start is not None:
            break

    walls = [[cell == '#' for cell in row] for row in input_grid]
    goals = [[cell == '*' for cell in row] for row in input_grid]

    return start, walls, goals

def bfs_to_bidi_threshold(walls, goals):
    num_not_wall = sum(sum(map(operator.not_, row)) for row in walls)
    num_goals = sum(sum(row) for row in goals)
    return num_goals * (num_not_wall - num_goals)

class GridBasedGoalContainer(object):
    '''Supports testing whether a state is a goal state with `in`.

    Does not perform bounds checking.'''
    def __init__(self, goal_grid):
        self.goal_grid = goal_grid
    def __contains__(self, state):
        x, y, vx, vy = state
        return self.goal_grid[x][y]

def forward_step(state, acceleration):
    x, y, vx, vy = state
    dvx, dvy = acceleration

    new_vx, new_vy = vx+dvx, vy+dvy
    new_x, new_y = x+new_vx, y+new_vy

    return (new_x, new_y, new_vx, new_vy)

def backward_step(state, acceleration):
    x, y, vx, vy = state
    dvx, dvy = acceleration

    old_x, old_y = x-vx, y-vy
    old_vx, old_vy = vx-dvx, vy-dvy

    return (old_x, old_y, old_vx, old_vy)

def bfs(start, walls, goals):
    x, y = start
    initial_state = (x, y, 0, 0)
    initial_frontier = {initial_state}
    visited = {initial_state: None}

    goal_state, frontier, visited = general_bfs(
        frontier=initial_frontier,
        visited=visited,
        walls=walls,
        goalcontainer=GridBasedGoalContainer(goals),
        stop_threshold=float('inf'),
        step_function=forward_step
    )

    return construct_path_from_bfs(goal_state, visited)

def general_bfs(
        frontier,
        visited,
        walls,
        goalcontainer,
        stop_threshold,
        step_function):

    while len(frontier) <= stop_threshold:
        if not frontier:
            raise ImpossibleRaceError

        new_frontier = set()
        for state in frontier:
            for accel in acceleration_options:
                new_state = new_x, new_y, new_vx, new_vy = \
                        step_function(state, accel)

                if not (0 <= new_x < len(walls) and 0 <= new_y < len(walls[0])):
                    continue
                if walls[new_x][new_y]:
                    continue
                if new_state in visited:
                    continue

                new_frontier.add(new_state)
                visited[new_state] = accel

                if new_state in goalcontainer:
                    return new_state, frontier, visited
        frontier = new_frontier
    return None, frontier, visited

def max_velocity_component(n):
    # It takes a distance of at least 0.5*v*(v+1) to achieve a velocity of
    # v in the x or y direction. That means the map has to be at least
    # 1 + 0.5*v*(v+1) rows or columns long to accomodate such a velocity.
    # Solving for v, we get a velocity cap as follows.
    return int((2*n-1.75)**0.5 - 0.5)

def solver(
        start,
        walls,
        goals,
        mode='bidi'):

    x, y = start
    initial_state = (x, y, 0, 0)
    initial_frontier = {initial_state}
    visited = {initial_state: None}
    if mode == 'bidi':
        stop_threshold = bfs_to_bidi_threshold(walls, goals)
    elif mode == 'bfs':
        stop_threshold = float('inf')
    else:
        raise ValueError('Unsupported search mode: {}'.format(mode))

    goal_state, frontier, visited = general_bfs(
        frontier=initial_frontier,
        visited=visited,
        walls=walls,
        goalcontainer=GridBasedGoalContainer(goals),
        stop_threshold=stop_threshold,
        step_function=forward_step
    )

    if goal_state is not None:
        return construct_path_from_bfs(goal_state, visited)

    # Switching to bidirectional search.

    not_walls_or_goals = []
    goal_list = []
    for x in xrange(len(walls)):
        for y in xrange(len(walls[0])):
            if not walls[x][y] and not goals[x][y]:
                not_walls_or_goals.append((x, y))
            if goals[x][y]:
                goal_list.append((x, y))
    max_vx = max_velocity_component(len(walls))
    max_vy = max_velocity_component(len(walls[0]))
    reverse_visited = {(goal_x, goal_y, goal_x-prev_x, goal_y-prev_y): None
                        for goal_x, goal_y in goal_list
                        for prev_x, prev_y in not_walls_or_goals
                        if abs(goal_x-prev_x) <= max_vx
                        and abs(goal_y - prev_y) <= max_vy}
    reverse_frontier = set(reverse_visited)
    while goal_state is None:
        goal_state, reverse_frontier, reverse_visited = general_bfs(
            frontier=reverse_frontier,
            visited=reverse_visited,
            walls=walls,
            goalcontainer=frontier,
            stop_threshold=len(frontier),
            step_function=backward_step
        )
        if goal_state is not None:
            break
        goal_state, frontier, visited = general_bfs(
            frontier=frontier,
            visited=visited,
            walls=walls,
            goalcontainer=reverse_frontier,
            stop_threshold=len(reverse_frontier),
            step_function=forward_step
        )
    forward_path = construct_path_from_bfs(goal_state, visited)
    backward_path = construct_path_from_bfs(goal_state,
                                            reverse_visited,
                                            step_function=forward_step)
    return forward_path + backward_path[::-1]

def construct_path_from_bfs(goal_state,
                            best_moves,
                            step_function=backward_step):
    reversed_path = []
    current_state = goal_state
    while best_moves[current_state] is not None:
        move = best_moves[current_state]
        reversed_path.append(move)
        current_state = step_function(current_state, move)
    return reversed_path[::-1]

def main():
    start, walls, goals = read_input()
    t = time.time()
    path = solver(start, walls, goals)
    for dvx, dvy in path:
        # I wrote the whole program with x pointing down and y pointing right.
        # Whoops. Gotta flip things for the output.
        print dvy, dvx

if __name__ == '__main__':
    main()

यह कभी-कभी 12 और 13 के मामले में विफल हो जाता है। न जाने क्यों कि त्रुटि संदेश कुछ हद तक हैं ... अमित्र
रे

@ मुझे त्रुटि संदेश भी मिलते हैं, लेकिन मुझे हमेशा उन लोगों के लिए परिणाम मिलते हैं। मुझे लगता है कि यह मेरे नियंत्रक में कुछ हो सकता है, क्योंकि ऐसा लगता है कि नियंत्रक रेसर प्रक्रिया को मारने की कोशिश करता है, हालांकि यह पहले से ही समाप्त हो गया है।
मार्टिन एंडर

@ m.buettner मुझे कारण मिला, ऐड -s तब यह ठीक होगा।
रे

@ रे ओह, मैं कर रहा हूँ। मुझे अभी भी पटरियों 13 और 14 पर एक त्रुटि मिलती है जब नियंत्रक प्रक्रिया को मारने की कोशिश कर रहा है, हालांकि परिणाम पहले से ही है। मुझे लगता है कि मुझे उस पर गौर करना चाहिए, लेकिन स्कोरिंग को प्रभावित नहीं करता इसलिए मैंने अभी तक परेशान नहीं किया।
मार्टिन एंडर जूल

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

3

अजगर 3: 6.49643 (इष्टतम, बीएफएस)

पुराने 20 केस बेंचमार्क फ़ाइल के लिए, इसे 5.35643 का स्कोर मिला। 5.4 के बाद से @nneonneo द्वारा समाधान इष्टतम नहीं है। शायद कुछ कीड़े।

यह समाधान ग्राफ़ को खोजने के लिए BFS का उपयोग करता है, प्रत्येक खोज स्थिति (x, y, dx, dy) के रूप में होती है। फिर मैं राज्यों से दूरियों के लिए एक मानचित्र का उपयोग करता हूं। सबसे खराब स्थिति में, यह समय और स्थान की जटिलता हे (n ^ 2 m ^ 2)। यह शायद ही कभी होगा क्योंकि गति बहुत अधिक नहीं होगी या रेसर दुर्घटनाग्रस्त हो जाएगा। दरअसल, सभी 22 टेस्टकेस को पूरा करने के लिए मेरी मशीन पर 3 सेकंड का समय लगता है।

from collections import namedtuple, deque
import itertools

Field = namedtuple('Map', 'n m grids')

class Grid:
    WALL = '#'
    EMPTY = '.'
    START = 'S'
    END = '*'

def read_nums():
    return list(map(int, input().split()))

def read_field():
    m, n = read_nums()
    return Field(n, m, [input() for i in range(n)])

def find_start_pos(field):
    return next((i, j)
        for i in range(field.n) for j in range(field.m)
        if field.grids[i][j] == Grid.START)

def can_go(field, i, j):
    return 0 <= i < field.n and 0 <= j < field.m and field.grids[i][j] != Grid.WALL

def trace_path(start, end, prev):
    if end == start:
        return
    end, step = prev[end]
    yield from trace_path(start, end, prev)
    yield step

def solve(max_turns, field, time):
    i0, j0 = find_start_pos(field)
    p0 = i0, j0, 0, 0
    prev = {}
    que = deque([p0])
    directions = list(itertools.product((-1, 0, 1), (-1, 0, 1)))

    while que:
        p = i, j, vi, vj = que.popleft()
        for dvi, dvj in directions:
            vi1, vj1 = vi + dvi, vj + dvj
            i1, j1 = i + vi1, j + vj1
            if not can_go(field, i1, j1):
                continue
            p1 = i1, j1, vi1, vj1
            if p1 in prev:
                continue
            que.append(p1)
            prev[p1] = p, (dvi, dvj)
            if field.grids[i1][j1] == Grid.END:
                return trace_path(p0, p1, prev)
    return []

def main():
    for dvy, dvx in solve(int(input()), read_field(), float(input())):
        print(dvx, dvy)

main()

# परिणाम

± % time ruby controller.rb benchmark.txt python ../mybfs.py                                                                                                                                                                             !9349
["benchmark.txt", "python", "../mybfs.py"]

Running 'python ../mybfs.py' against benchmark.txt

 No.       Size     Target   Score     Details
-------------------------------------------------------------------------------------
  1       37 x 1        36   0.22222   Racer reached goal at ( 36, 0) in 8 turns.
  2       38 x 1        37   0.24324   Racer reached goal at ( 37, 0) in 9 turns.
  3       33 x 1        32   0.25000   Racer reached goal at ( 32, 0) in 8 turns.
  4       10 x 10       10   0.40000   Racer reached goal at ( 7, 7) in 4 turns.
  5        9 x 6         8   0.37500   Racer reached goal at ( 6, 0) in 3 turns.
  6       15 x 7        16   0.37500   Racer reached goal at ( 12, 4) in 6 turns.
  7       17 x 8        16   0.31250   Racer reached goal at ( 14, 0) in 5 turns.
  8       19 x 13       18   0.27778   Racer reached goal at ( 0, 11) in 5 turns.
  9       60 x 10      107   0.14953   Racer reached goal at ( 0, 6) in 16 turns.
 10       31 x 31      106   0.23585   Racer reached goal at ( 27, 0) in 25 turns.
 11       31 x 31      106   0.24528   Racer reached goal at ( 15, 15) in 26 turns.
 12       50 x 20       50   0.24000   Racer reached goal at ( 49, 10) in 12 turns.
 13      100 x 100    2600   0.01385   Racer reached goal at ( 50, 0) in 36 turns.
 14       79 x 63      242   0.24380   Racer reached goal at ( 3, 42) in 59 turns.
 15       26 x 1        25   0.32000   Racer reached goal at ( 25, 0) in 8 turns.
 16       17 x 1        19   0.52632   Racer reached goal at ( 16, 0) in 10 turns.
 17       50 x 1        55   0.34545   Racer reached goal at ( 23, 0) in 19 turns.
 18       10 x 7        23   0.34783   Racer reached goal at ( 1, 3) in 8 turns.
 19       55 x 55       45   0.17778   Racer reached goal at ( 50, 26) in 8 turns.
 20      101 x 100     100   0.14000   Racer reached goal at ( 99, 99) in 14 turns.
 21   100000 x 1         1   1.00000   Racer reached goal at ( 0, 0) in 1 turns.
 22       50 x 50      200   0.05500   Racer reached goal at ( 47, 46) in 11 turns.
-------------------------------------------------------------------------------------
TOTAL SCORE:                 6.49643

ruby controller.rb benchmark.txt python ../mybfs.py  3.06s user 0.06s system 99% cpu 3.146 total

हां, उपयोगकर्ता 2357112 की टिप्पणी के अनुसार nneonneo के चक्र की रोकथाम में एक बग है। जहाँ तक मुझे पता है, गति सीमित है O(√n)जिसके द्वारा आप O(n³)वर्ग ग्रिडों पर अपना कार्यान्वयन करेंगे (दूसरों के समान, मुझे लगता है)। मैं आपके सबमिशन बनाम user2357112 का बाद में स्कोर करने के लिए एक टाई ब्रेकर जोड़ूंगा।
मार्टिन एंडर

Btw, क्या आप एक और टेस्ट केस जोड़ने की योजना बना रहे हैं?
मार्टिन एंडर जूल

@ m.buettner नहीं, मुझे इस खेल के लिए एक अच्छी पर्याप्त समझ नहीं है। तो मेरा टेस्टकेस एक दिलचस्प होगा।
रे

दुर्भाग्य से, मुझे एक और नियम जोड़ना पड़ा। इस चुनौती में समय की तुलना में मेमोरी अधिक सीमित लगती है, इसलिए मुझे मेमोरी की खपत को सीमित करने के लिए कड़ी मेहनत करनी पड़ी। कोई भी रन जिसमें आपका रेसर 1GB से अधिक मेमोरी का उपयोग करता है उसे समय सीमा से अधिक होने पर उसी प्रभाव में छोड़ दिया जाएगा। इस नियम के साथ, आपका सबमिशन आकार के एक टाई-ब्रेकर पर उस सीमा को पार करने वाला पहला है n=270, यही कारण है कि अब आप अन्य दो "इष्टतम" सबमिशन के पीछे हैं। कहा जा रहा है कि, आपका सबमिशन भी तीनों में सबसे धीमा है, इसलिए किसी बड़े टाई-ब्रेकर के साथ, वैसे भी तीसरा होगा।
मार्टिन एंडर जूल

कृपया मुझे बताएं कि क्या आप किसी भी अनुकूलन को लागू करते हैं, इसलिए मैं परीक्षणों का पुनर्मिलन कर सकता हूं।
मार्टिन एंडर जूल

1

RandomRacer, ~ 40.0 (10 रन से अधिक औसत)

ऐसा नहीं है कि यह बॉट कभी एक ट्रैक को खत्म नहीं करता है , लेकिन 10 प्रयासों में एक बार की तुलना में निश्चित रूप से बहुत कम है। (मैं हर 20 से 30 सिमुलेशन या तो एक गैर-सबसे खराब स्थिति स्कोर प्राप्त करता हूं।)

यह ज्यादातर बेसलाइन मामले के रूप में कार्य करता है और एक रेसर के लिए संभावित (रूबी) कार्यान्वयन का प्रदर्शन करने के लिए होता है:

# Parse initial input
target = gets.to_i
size = gets.split.map(&:to_i)
track = []
size[1].times do
    track.push gets
end
time_budget = gets.to_f

# Find start position
start_y = track.find_index { |row| row['S'] }
start_x = track[start_y].index 'S'

position = [start_x, start_y]
velocity = [0, 0]

while true
    x = rand(3) - 1
    y = rand(3) - 1
    puts [x,y].join ' '
    $stdout.flush

    first_line = gets
    break if !first_line || first_line.chomp.empty?

    position = first_line.split.map(&:to_i)
    velocity = gets.split.map(&:to_i)
    time_budget = gets.to_f
end

इसे लेकर चलें

ruby controller.rb benchmark.txt ruby randomracer.rb

1

रैंडम रेसर 2.0, ~ 31

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

जावा में कार्यान्वित, जावा 8 के साथ संकलित, लेकिन जावा 6 ठीक होना चाहिए। कोई कमांड लाइन पैरामीटर नहीं। वहाँ पदानुक्रम का एक बहुत अच्छा क्लस्टरफ़ॉक है, इसलिए मुझे लगता है कि मैं जावा सही कर रहा हूं।

import java.util.Scanner;
import java.util.Random;
import java.util.ArrayList;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;

public class VectorRacing   {
    private static Scanner in = new Scanner(System.in);
    private static Random rand = new Random();
    private static Track track;
    private static Racer racer;
    private static int target;
    private static double time;
    public static void main(String[] args)  {
        init();
        main_loop();
    }
    private static void main_loop() {
        Scanner linescan;
        String line;
        int count = 0,
            x, y, u, v;

        while(!racer.lost() && !racer.won() && count < target)  {
            Direction d = racer.think();
            racer.move(d);
            count++;
            System.out.println(d);

            line = in.nextLine();
            if(line.equals("")) {
                break;
            }
            linescan = new Scanner(line);
            x = linescan.nextInt();
            y = linescan.nextInt();
            linescan = new Scanner(in.nextLine());
            u = linescan.nextInt();
            v = linescan.nextInt();
            time = Double.parseDouble(in.nextLine());

            assert x == racer.location.x;
            assert y == racer.location.y;
            assert u == racer.direction.x;
            assert v == racer.direction.y;
        }
    }
    private static void init()  {
        target = Integer.parseInt(in.nextLine());
        int width = in.nextInt();
        int height = Integer.parseInt(in.nextLine().trim());
        String[] ascii = new String[height];
        for(int i = 0; i < height; i++) {
            ascii[i] = in.nextLine();
        }
        time = Double.parseDouble(in.nextLine());
        track = new Track(width, height, ascii);
        for(int y = 0; y < ascii.length; y++)   {
            int x = ascii[y].indexOf("S");
            if( x != -1)    {
                racer = new RandomRacer(track, new Location(x, y));
                break;
            }
        }
    }

    public static class RandomRacer extends Racer   {
        public RandomRacer(Track t, Location l) {
            super(t, l);
        }
        public Direction think()    {
            ArrayList<Pair<Location, Direction> > possible = this.getLocationsCanMoveTo();
            if(possible.size() == 0)    {
                return Direction.NONE;
            }
            Pair<Location, Direction> ret = null;
            do  {
                ret = possible.get(rand.nextInt(possible.size()));
            }   while(possible.size() != 1 && ret.a.equals(this.location));
            return ret.b;
        }
    }

    // Base things
    public enum Direction   {
        NORTH("0 -1"), SOUTH("0 1"), EAST("1 0"), WEST("-1 0"), NONE("0 0"),
        NORTH_EAST("1 -1"), NORTH_WEST("-1 -1"), SOUTH_EAST("1 1"), SOUTH_WEST("-1 1");

        private final String d;
        private Direction(String d) {this.d = d;}
        public String toString()    {return d;}
    }
    public enum Cell    {
        WALL('#'), GOAL('*'), ROAD('.'), OUT_OF_BOUNDS('?');

        private final char c;
        private Cell(char c)    {this.c = c;}
        public String toString()    {return "" + c;}
    }

    public static class Track   {
        private Cell[][] track;
        private int target;
        private double time;
        public Track(int width, int height, String[] ascii) {
            this.track = new Cell[width][height];
            for(int y = 0; y < height; y++) {
                for(int x = 0; x < width; x++)  {
                    switch(ascii[y].charAt(x))  {
                        case '#':   this.track[x][y] = Cell.WALL; break;
                        case '*':   this.track[x][y] = Cell.GOAL; break;
                        case '.':
                        case 'S':   this.track[x][y] = Cell.ROAD; break;
                        default:    System.exit(-1);
                    }
                }
            }
        }
        public Cell atLocation(Location loc)    {
            if(loc.x < 0 || loc.x >= track.length || loc.y < 0 || loc.y >= track[0].length) return Cell.OUT_OF_BOUNDS;
            return track[loc.x][loc.y];
        }

        public String toString()    {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            PrintStream ps = new PrintStream(bos);
            for(int y = 0; y < track[0].length; y++)    {
                for(int x = 0; x < track.length; x++)   {
                    ps.append(track[x][y].toString());
                }
                ps.append('\n');
            }
            String ret = bos.toString();
            ps.close();
            return ret;
        }
    }

    public static abstract class Racer  {
        protected Velocity tdir;
        protected Location tloc;
        protected Track track;
        public Velocity direction;
        public Location location;

        public Racer(Track track, Location start)   {
            this.track = track;
            direction = new Velocity(0, 0);
            location = start;
        }
        public boolean canMove() throws GoHereDammitException {return canMove(Direction.NONE);}
        public boolean canMove(Direction d) throws GoHereDammitException    {
            tdir = new Velocity(direction);
            tloc = new Location(location);
            tdir.add(d);
            tloc.move(tdir);
            Cell at = track.atLocation(tloc);
            if(at == Cell.GOAL) {
                throw new GoHereDammitException();
            }
            return at == Cell.ROAD;
        }
        public ArrayList<Pair<Location, Direction> > getLocationsCanMoveTo()    {
            ArrayList<Pair<Location, Direction> > ret = new ArrayList<Pair<Location, Direction> >(9);
            for(Direction d: Direction.values())    {
                try {
                    if(this.canMove(d)) {
                        ret.add(new Pair<Location, Direction>(tloc, d));
                    }
                }   catch(GoHereDammitException e)  {
                    ret.clear();
                    ret.add(new Pair<Location, Direction>(tloc, d));
                    return ret;
                }
            }
            return ret;
        }
        public void move()  {move(Direction.NONE);}
        public void move(Direction d)   {
            direction.add(d);
            location.move(direction);
        }
        public boolean won()    {
            return track.atLocation(location) == Cell.GOAL;
        }
        public boolean lost()   {
            return track.atLocation(location) == Cell.WALL || track.atLocation(location) == Cell.OUT_OF_BOUNDS;
        }
        public String toString()    {
            return location + ", " + direction;
        }
        public abstract Direction think();

        public class GoHereDammitException extends Exception    {
            public GoHereDammitException()  {}
        }
    }

    public static class Location extends Point  {
        public Location(int x, int y)   {
            super(x, y);
        }
        public Location(Location l) {
            super(l);
        }
        public void move(Velocity d)    {
            this.x += d.x;
            this.y += d.y;
        }
    }

    public static class Velocity extends Point  {
        public Velocity(int x, int y)   {
            super(x, y);
        }
        public Velocity(Velocity v) {
            super(v);
        }
        public void add(Direction d)    {
            if(d == Direction.NONE) return;
            if(d == Direction.NORTH || d == Direction.NORTH_EAST || d == Direction.NORTH_WEST)  this.y--;
            if(d == Direction.SOUTH || d == Direction.SOUTH_EAST || d == Direction.SOUTH_WEST)  this.y++;
            if(d == Direction.EAST || d == Direction.NORTH_EAST || d == Direction.SOUTH_EAST)   this.x++;
            if(d == Direction.WEST || d == Direction.NORTH_WEST || d == Direction.SOUTH_WEST)   this.x--;
        }
    }

    public static class Point   {
        protected int x, y;
        protected Point(int x, int y)   {
            this.x = x;
            this.y = y;
        }
        protected Point(Point c)    {
            this.x = c.x;
            this.y = c.y;
        }
        public int getX()   {return x;}
        public int getY()   {return y;}
        public String toString()    {return "(" + x + ", " + y + ")";}
        public boolean equals(Point p)  {
            return this.x == p.x && this.y == p.y;
        }
    }

    public static class Pair<T, U>  {
        public T a;
        public U b;
        public Pair(T t, U u)   {
            a=t;b=u;
        }
    }
}

परिणाम (मैंने देखा है सबसे अच्छा मामला)

Running 'java VectorRacing' against ruby-runner/benchmark.txt

 No.    Size     Target   Score     Details
-------------------------------------------------------------------------------------
  1    37 x 1        36   0.38889   Racer reached goal at ( 36, 0) in 14 turns.
  2    38 x 1        37   0.54054   Racer reached goal at ( 37, 0) in 20 turns.
  3    33 x 1        32   0.62500   Racer reached goal at ( 32, 0) in 20 turns.
  4    10 x 10       10   0.40000   Racer reached goal at ( 9, 8) in 4 turns.
  5     9 x 6         8   0.75000   Racer reached goal at ( 6, 2) in 6 turns.
  6    15 x 7        16   2.00000   Racer did not reach the goal within 16 turns.
  7    17 x 8        16   2.00000   Racer hit a wall at position ( 8, 2).
  8    19 x 13       18   0.44444   Racer reached goal at ( 16, 2) in 8 turns.
  9    60 x 10      107   0.65421   Racer reached goal at ( 0, 6) in 70 turns.
 10    31 x 31      106   2.00000   Racer hit a wall at position ( 25, 9).
 11    31 x 31      106   2.00000   Racer hit a wall at position ( 8, 1).
 12    50 x 20       50   2.00000   Racer hit a wall at position ( 27, 14).
 13   100 x 100    2600   2.00000   Racer went out of bounds at position ( 105, 99).
 14    79 x 63      242   2.00000   Racer went out of bounds at position (-2, 26).
 15    26 x 1        25   0.32000   Racer reached goal at ( 25, 0) in 8 turns.
 16    17 x 1        19   2.00000   Racer went out of bounds at position (-2, 0).
 17    50 x 1        55   2.00000   Racer went out of bounds at position ( 53, 0).
 18    10 x 7        23   2.00000   Racer went out of bounds at position ( 10, 2).
 19    55 x 55       45   0.33333   Racer reached goal at ( 4, 49) in 15 turns.
 20    50 x 50      200   2.00000   Racer hit a wall at position ( 14, 7).
-------------------------------------------------------------------------------------
TOTAL SCORE:             26.45641

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

आह यह अन्य निर्देशिका से भी चलाने के लिए मिला है। कमांड लाइन पर जावा से परिचित नहीं लोगों के लिए:java -cp path/to/class/file VectorRacing
मार्टिन एंडर

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

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

दुर्भाग्य से, मुझे एक और नियम जोड़ना पड़ा। इस चुनौती में समय की तुलना में मेमोरी अधिक सीमित लगती है, इसलिए मुझे मेमोरी की खपत को सीमित करने के लिए कड़ी मेहनत करनी पड़ी। कोई भी रन जिसमें आपका रेसर 1GB से अधिक मेमोरी का उपयोग करता है उसे समय सीमा से अधिक होने पर उसी प्रभाव में छोड़ दिया जाएगा। पटरियों के वर्तमान सेट के लिए, आपका स्कोर इस परिवर्तन से प्रभावित नहीं हुआ है (और संभवतः कभी नहीं होगा)।
मार्टिन एंडर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.