আমার অ্যালগরিদম যা সবচেয়ে বড় বাক্সকে ছোট ছোট বাক্স থেকে তৈরি করা যায়, তা খুব ধীর


9

কিউব ভিত্তিক বিশ্বের (যেমন মাইনক্রাফ্ট, ট্রভ বা কিউব ওয়ার্ল্ড) কল্পনা করুন যেখানে সবকিছু অভিন্ন আকারের কিউব এবং সমস্ত কিউব একই ধরণের হয়

লক্ষ্যটি কয়েকটি সংখ্যক আয়তক্ষেত্রাকার বাক্সের সাথে বিশ্বের প্রতিনিধিত্ব করা (কিউবগুলি মার্জ করে তবে উত্তল আকারটি ধরে রাখা (ওরফে, একটি আয়তক্ষেত্রাকার বাক্স আকার))। আমার অ্যালগরিদম এটিতে সাফল্য পায় তবে এটির উদ্দেশ্যটি এর জন্য কার্য সম্পাদন খুব ধীর। দ্রুত অ্যালগরিদম আছে?

আমার অ্যালগরিদমের সিউডো-সি # কোডটি মূলত:

struct Coordinate { int x,y,z; }; //<-- integer based grid
HashSet<Coordinate> world; // <-- contains all the cubes

//width, height, and length represent how many cubes it spans
struct RectangularBox { Coordinate coord; int width,height,length; }

void Begin()
{
    List<RectangularBox> fewestBoxes = new List<RectangularBox>();
    while(world.Count > 0)
    {
         RectangularBox currentLargest = ExtractLargest();
         fewestBoxes.Add(currentLargest);
         world.RemoveRange(currentLargest.ContainedCubes());
    }
    //done; `fewestBoxes` contains the fewest rectangular boxes needed.
}

private RectangularBox ExtractLargest()
{
    RectangularBox largestBox = new RectangularBox();
    foreach (Coordinate origin in world)
    {
        RectangularBox box = FindMaximumSpan(origin);
        if (box.CalculateVolume() >= largestBox.CalculateVolume())
            largestBox = box;
    }
    return largestBox;
}

private RectangularBox FindMaximumSpan(Coordinate origin)
{
    int maxX, maxY,maxZ;
    while (world.Contains(origin.Offset(maxX, 0, 0))) maxX++;
    while (world.Contains(origin.Offset(0, maxY, 0))) maxY++;
    while (world.Contains(origin.Offset(0, 0, maxZ))) maxZ++;

    RectangularBox largestBox;
    for (int extentX = 0; extentX <= maxX; extentX++)
        for (int extentY = 0; extentY <= maxY; extentY++)
            for (int extentZ = 0; extentZ <= maxZ; extentZ++)
            {
                int lengthX = extentX + 1;
                int lengthY = extentY + 1;
                int lengthZ = extentZ + 1;
                if (BoxIsFilledWithCubes(origin, lengthX, lengthY, lengthZ))
                {
                    int totalVolume = lengthX * lengthY * lengthZ;
                    if (totalVolume >= largestBox.ComputeVolume())
                        largestBox = new RectangularBox(origin, lengthX, lengthY, lengthZ);
                }
                else
                    break;
            }
    return largestBox;
}

private bool BoxIsFilledWithCubes(Coordinate coord, 
    int lengthX, int lengthY, int lengthZ)
{
    for (int gX = 0; gX < lengthX; gX++)
        for (int gY = 0; gY < lengthY; gY++)
            for (int gZ = 0; gZ < lengthZ; gZ++)
                if (!world.Contains(coord.Offset(gX, gY, gZ)))
                    return false;
    return true;
}

মূলত, বিশ্বের প্রতিটি ব্লকের জন্য, এটি প্রথমে তিনটি ইতিবাচক মাত্রার (+ এক্স, + ওয়াই, + জেড) এর মধ্যে কতগুলি কনফিগাসিয়াস ব্লক রয়েছে তা খুঁজে পায়। এবং তারপরে এটি বন্যা পূরণ করে যা পরিমাণ এবং চেকগুলি যা সবচেয়ে বড় ফিলিং যা কোনও ব্লক অনুপস্থিত।


আপডেট: যেহেতু আমার মনে হয়েছে এটি গেমের রেন্ডারিং ইঞ্জিনের জন্য, তাই আমি কেবল স্পষ্ট করে বলতে চাই, এটি কোনও গেমের রেন্ডারিং ইঞ্জিনের জন্য নয়; এটি একটি ফাইল রূপান্তরকারী জন্য; জিইউআই নেই


2
সম্ভবত কোডেরভিউ.স্ট্যাকেক্সেঞ্জের.কমের জন্য আরও উপযুক্ত
রোটেম

4
@ রোটেম সম্ভবত, তবে আমি আসলে আমার কোডটি পর্যালোচনা না করে বিকল্প অ্যালগরিদমের সন্ধান করছি। আমি আমার কোডটি কেবল অভ্যাসের বল হিসাবে সরবরাহ করেছি।
মিঃ স্মিথ

অবশ্যই, বোধগম্য।
রোটেম

কম্পিউটার বিজ্ঞানের মতো এসই সাইটগুলিতে অ্যালগরিদম প্রশ্নগুলি আরও বেশি উপযুক্ত ...
বাকুরিউ

আপনি পদ্ধতিটি কতবার কল করেন তার উপরও নির্ভর করে। আপনি যদি এটি প্রতিটি ফ্রেমে কল করেন বা কেবল যখন কোনও ব্লক পরিবর্তন হয়। এই গেমগুলির মধ্যে সাধারণত খণ্ডগুলি থাকে (নির্দিষ্ট আকারের আয়তক্ষেত্র: উদাহরণস্বরূপ: 64x64x32 ব্লক), যতটা সম্ভব ক্যাশে মানগুলি থাকে এবং কেবল প্রতি অংশ গণনা করে। এবং কেবলমাত্র দৃশ্যমান ব্লকগুলিতে এই মানগুলি গণনা করুন।
the_lotus

উত্তর:


6

আপনি যখন সত্যটি ব্যবহার করতে পারেন

 BoxIsFilledWithCubes(c,x,y,z)

সত্যটি ফিরে আসে, তারপরে BoxIsFilledWithCubes(c,x+1,y,z)স্থানাঙ্ক পরিসীমা "(সি, এক্স, ওয়াই, জেড)" এ আবার সমস্ত কিউবগুলি পরীক্ষা করা প্রয়োজন হবে না । আপনার সাথে নতুন যারা কিউব চেক করতে শুধুমাত্র প্রয়োজন এক্স-তুল্য c.x + (x+1)। (একই ক্ষেত্রে সত্য y+1, বা z+1)। আরও সাধারণভাবে, একটি বাক্সকে দুটি ছোট বাক্সে বিভক্ত করে (যার জন্য আপনি ইতিমধ্যে বুঝতে পারেন যে তারা উভয় কিউব দ্বারা ভরাট, না উভয় ভরাট নয়), আপনি এখানে একটি বিভাজন এবং বিজয়ী কৌশল প্রয়োগ করতে পারেন, যা আপনার চেয়ে দ্রুত হয়ে ওঠে আপনি মধ্যবর্তী ফলাফল ক্যাশে যখন মূল পদ্ধতির।

এটি সম্পাদন করার জন্য, আপনি BoxIsFilledWithCubes(c,x,y,z)পুনরাবৃত্তির সাথে প্রয়োগ শুরু করেন , উদাহরণস্বরূপ:

 bool BoxIsFilledWithCubes(coord,lx,ly,lz)
 {
     if(lx==0|| ly==0 || lz==0)
        return true;
     if(lx==1 && ly==1 && lz==1)
          return world.Contains(coord);
     if(lx>=ly && lx>=lz)  // if lx is the maximum of lx,ly,lz ....
         return BoxIsFilledWithCubes(coord,lx/2,ly,lz) 
             && BoxIsFilledWithCubes(coord.Offset(lx/2,0,0), lx-lx/2, ly, lz);
     else if(ly>=lz && ly>=lx)  
         // ... analogously when ly or lz is the maximum

 }

এবং তারপরে একই পরামিতিগুলির সাথে কোনও পুনরাবৃত্তি কল এড়াতে স্মৃতিচারণ (যেমন এটি এখানে আলোচনা করা হয়েছে ) ব্যবহার করুন BoxIsFilledWithCubes। দ্রষ্টব্য, আপনি যখন নিজের worldপাত্রে কোনও পরিবর্তন প্রয়োগ করেন, তখন আপনাকে স্মৃতিচারণ ক্যাশে সাফ করতে হবে world.RemoveRange। তবুও আমার ধারণা এটি আপনার প্রোগ্রামটি আরও দ্রুত করে তুলবে।


5

একটি বিল্ড আপ octree আপনার বাক্সের আকারের একটি গাছের পাতা নোড aabb আকার সঙ্গে। অষ্টাটি অতিক্রম করার সময় আপনি সস্তায় নোডগুলি মার্জ করতে পারেন। সম্পূর্ণ ভরাট নোডগুলি মার্জ করার জন্য তুচ্ছ (নতুন বাক্স = প্যারেন্ট আবাব), যখন আংশিকভাবে পূর্ণ নোডের জন্য, আপনি মার্জ-সক্ষমতা যাচাই করতে আপনার বর্তমান অ্যালগরিদমের একটি বৈকল্পিক ব্যবহার করতে পারেন।


দুটি নোড সম্পূর্ণরূপে পূর্ণ তা বোঝায় না যে সেগুলি একত্রিত করা উচিত; এটি বৃহত্তম বক্স সন্ধানের দিকে কোনও পদক্ষেপ নয়; আপনি যদি এগুলি মার্জ করেন, সম্ভবত বৃহত্তম বাক্সটি সন্ধানের পরে আপনাকে আবারো আবার বিভাজন করতে হবে। এই দৃশ্যটিতে অষ্টা কীভাবে সহায়তা করে তা আমি দেখতে পাই না।
মিঃ স্মিথ

পূর্ণ নোডগুলি এই অর্থে একত্রীকরণ করা যায় যে সমস্ত 8 শিশু একটি বড় বড় বাক্সের অংশ হতে পারে। এই বৃহত্তর বাক্সটি পরে ভাগ করতে হবে না, তবে এটি মার্জ হতে পারে। শ্রেণিবিন্যাস আপনাকে দ্রুত প্রচুর বাক্সগুলিকে মার্জ করার অনুমতি দেয়, সম্পূর্ণরূপে ভরা নোডগুলি আপনাকে আরও পরীক্ষা ছাড়াই একটি স্তর উপরে উঠতে দেয়।
উইলবার্ট

1

আপনার মনে হয় কমপক্ষে ও (এন ^ 2) ( বিগ ও টেনশন দেখুন ) আপনি বিশ্বের সমস্ত বাক্স "বিগিন ()" তে লুপ করেন, তারপরে প্রতিটি বাক্সের জন্য, আপনি এক্সট্রাক্টরেজেস্টের বিশ্বের সমস্ত বাক্সে লুপ করেন ( )। সুতরাং 10 সম্পর্কিত সম্পর্কযুক্ত বাক্স বিশিষ্ট একটি পৃথিবীতে 5 টি সম্পর্কিত সম্পর্কযুক্ত বাক্সের চেয়ে 4 গুণ বেশি সময় লাগবে।

সুতরাং আপনাকে এক্সট্রাকলার্জেস্ট () দেখতে থাকা বাক্সগুলির সংখ্যা সীমাবদ্ধ করতে হবে, এটি করতে আপনাকে কিছু ধরণের স্থানিক অনুসন্ধান ব্যবহার করতে হবে , যেমন আপনি 3 ডি-তে কাজ করছেন, আপনার জন্য একটি 3D স্থানিক অনুসন্ধানের প্রয়োজন হতে পারে। তবে প্রথমে 2d স্থানিক অনুসন্ধানটি বোঝার দ্বারা শুরু করুন।

তারপরে বিবেচনা করুন যে আপনার একে অপরের শীর্ষে অনেকগুলি বাক্স রয়েছে কিনা, যদি না হয় তবে 2 ডি স্পেসিয়াল অনুসন্ধান যা কেবল x, y কে আবৃত করে আপনার লুপিং কেটে দেওয়ার জন্য যথেষ্ট হতে পারে।

অক্ট্রি / কোয়াডট্রি এক বিকল্প, তবে স্থান বিভাজনের জন্য আরও অনেক বিকল্প রয়েছে ,

তবে আপনি কেবল মাত্র দুটি মাত্রিক তালিকা ( গ্রিড স্পেসিয়াল ইনডেক্স ) ব্যবহার করতে সক্ষম হতে পারেন , যেখানে বিন্দুটি (ক, খ) আবৃত সমস্ত বাক্স অ্যারে [এ, বি] তালিকাতে রয়েছে। তবে সর্বাধিক চটজলদি খুব বড় অ্যারে বাড়ে, তাই অ্যারে [মোড (এ, 100), মব (বি, 100)] তালিকা সম্পর্কে কী হবে? এই সমস্ত আপনার ডেটা কেমন তা নির্ভর করে

(আমি গ্রিড সলিউশনটি বাস্তব জীবনে খুব ভালভাবে কাজ করতে দেখেছি))

অথবা উইলবার্ট আপনার বাক্সের আকারের পাতার নোড আবাব আকারের সাথে অষ্ট্রি দিয়ে যা বলেছেন তা করুন, তবে পরে আপনাকে সম্ভবত সেই বাক্সটি খুঁজে পেতে পারেন যা ব্যবহারকারীর মাউস ইত্যাদির দিকে ইশারা করছে, আবার একবার স্থানিক অনুসন্ধানের ক্ষেত্রে।

( আপনি কেবল এই সফ্টওয়্যারটি কাজ করার চেষ্টা করছেন কিনা বা আপনি কীভাবে আরও উন্নত প্রোগ্রামার হতে পারেন তা বুঝতে চেষ্টা করছেন এবং অতএব শিখতে আরও আগ্রহী হন তবে একটি দ্রুত সমাধানের সিদ্ধান্ত নিতে হবে ))

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.