2D মানচিত্রে "মূলভূমি" সনাক্ত করার জন্য কি কোনও অ্যালগরিদম আছে?


28

এই মানচিত্রে, "মূলভূমি" হ'ল সমস্ত ভূমি যা চারটি মূল দিক (উত্তর, দক্ষিণ, পূর্ব, পশ্চিম - তির্যক নয়) - এ মানচিত্রের কেন্দ্রের সাথে সংযুক্ত হতে পারে। এখানে চিত্র বর্ণনা লিখুন

আমি মূল ভূখণ্ডটি সনাক্ত করতে এবং এর মধ্যে গর্তগুলি পূরণ করতে চাই। আমি তিনটি বিষয় ভেবেছিলাম:

  1. অ্যালগরিদম সন্ধানের পথ ব্যবহার করে মানচিত্রের কেন্দ্রের সাথে সংযুক্ত হতে পারলে প্রতিটি নন-ওয়াটার (অন্ধকার কোষ) কক্ষে অনুসন্ধান করুন। অনেক দামি! তবে এটি দ্বীপপুঞ্জের জন্য কাজ করতে পারে।

  2. মূল ভূখণ্ডটি এক বালতি সবুজ রঙে পূর্ণ। প্রতিটি গর্ত পেইন্ট দ্বারা বেষ্টিত ... এখন কি? যদি আমি সংলগ্নতার জন্য মূল ভূখণ্ডের অভ্যন্তরের প্রতিটি জলের পয়েন্টটি পরীক্ষা করি তবে আমি উপকূলের উপর প্রদর্শিত কিছু উপদ্বীপ এবং অন্যান্য ভৌগলিক বৈশিষ্ট্যগুলি মুছব।

  3. মূলভূমিটি বের করার জন্য এক ধরণের প্রান্ত সনাক্তকরণ। ভিতরে যা আছে তা রাখুন, এটি যদি জল হয় তবে তা পূরণ করুন, বাইরে যা সরিয়ে দিন। কমপ্লেক্স?

সম্ভবত কিছু গেম অভিজ্ঞ বিকাশকারী আমাকে এটির সাহায্য করতে পারে, সম্ভবত আমাকে কিছু পরিচিত অ্যালগরিদম বা কৌশলটির নাম দিচ্ছেন?


4
আমি কেবল ভাবছি আপনি এই মানচিত্রটি তৈরি করতে কোনও ধরণের অ্যালগরিদম ব্যবহার করেছেন কিনা। এবং যদি তাই হয়, আপনি কি ব্যবহার করেছেন?
জাগল্যান্ট

টাইলবেসড পরিবেশে কাজ করার সময় মূল্যবান হ'ল মার্চিং স্কোয়ারস অ্যালগরিদম । এটির সাহায্যে আপনি ছোট ছোট দ্বীপগুলি সনাক্ত করতে এবং ধরে রাখতে পারেন এবং তারপরে একক সেল দ্বীপগুলি বা আপনার যে মানদণ্ড থাকতে পারে তা মাপ অনুসারে বাছাই করুন।
উইলিয়াম মারিয়েরার

@ হ্যাঁ! উচ্চতার মানচিত্র তৈরি করতে হীরা স্কোয়ার অ্যালগরিদম, তারপরে সমস্ত বেলন এক মান হ'ল জল, বাকী, জমি। আমি এটিকে মহাদেশীয় আকার হিসাবে ব্যবহার করার পরিকল্পনা করছি, তারপরে ভূখণ্ডের বিশদ যুক্ত করতে অন্য একটি পাস।
গ্যাব্রিয়েল এ। জরিলা

@ মাইন্ড মার্চিং স্কোয়ারস অ্যালগোরিদম মহাদেশের সীমানা আঁকার জন্য কাজে আসবে। ধন্যবাদ সুন্দর পরামর্শ!
গ্যাব্রিয়েল এ জোরিলা

উত্তর:


32

অপসারণ দ্বীপপুঞ্জ

আমি আমার গেমগুলির একটির আগে এই ধরণের কাজটি করেছি। বাইরের দ্বীপ থেকে মুক্তি পাওয়ার জন্য প্রক্রিয়াটি মূলত:

  1. প্রথমে অবশ্যই গ্যারান্টি থাকতে হবে মানচিত্রের কেন্দ্রটি সর্বদা মূল জমির অন্তর্গত থাকবে এবং প্রতিটি পিক্সেলটি "ল্যান্ড" বা "জল" (অর্থাত্ বিভিন্ন রঙ) হিসাবে শুরু হয়।
  2. তারপরে মানচিত্রের কেন্দ্র থেকে শুরু করে কোনও "ল্যান্ড" টাইল জুড়ে ছড়িয়ে একটি চার দিকের বন্যা পূর্ণ করুন । এই বন্যায় পরিদর্শন করা প্রতিটি পিক্সেল চিহ্নিত করুন "মাইনল্যান্ড" এর মতো আলাদা ধরণের হিসাবে।
  3. অবশেষে পুরো মানচিত্রের ওপরে যান এবং অন্যান্য দ্বীপ থেকে মুক্তি পেতে যে কোনও অবশিষ্ট "ল্যান্ড" পিক্সেলকে "জল" তে রূপান্তর করুন।

হ্রদ সরানো হচ্ছে

দ্বীপের অভ্যন্তরের গর্তগুলি (বা হ্রদ) থেকে মুক্তি পাওয়ার জন্য আপনি একই ধরণের প্রক্রিয়া করছেন তবে মানচিত্রের কোণ থেকে শুরু করে পরিবর্তে "জল" টাইলস দিয়ে ছড়িয়েছেন। এটি আপনাকে অন্যান্য জলের টাইলগুলির থেকে "সমুদ্র" পার্থক্য করতে দেয় এবং তারপরে আপনি পূর্ববর্তী দ্বীপগুলি থেকে যেমন মুক্তি পেয়েছিলেন তেমনই আপনি সেগুলি থেকে পরিত্রাণ পেতে পারেন।

উদাহরণ

আমাকে এখানে আমার কোথাও যে বন্যা ভরাট রয়েছে তার বাস্তবায়ন সন্ধান করতে দাও (অস্বীকৃতি, আমি দক্ষতার কোনও যত্ন নিই না, তাই আমি নিশ্চিত যে এটি বাস্তবায়নের আরও অনেক কার্যকর উপায় আছে):

private void GenerateSea()
{
    // Initialize visited tiles list
    visited.Clear();

    // Start generating sea from the four corners
    GenerateSeaRecursive(new Point(0, 0));
    GenerateSeaRecursive(new Point(size.Width - 1, 0));
    GenerateSeaRecursive(new Point(0, size.Height - 1));
    GenerateSeaRecursive(new Point(size.Width - 1, size.Height - 1));
}

private void GenerateSeaRecursive(Point point)
{
    // End recursion if point is outside bounds
    if (!WithinBounds(point)) return;

    // End recursion if the current spot is a land
    if (tiles[point.X, point.Y].Land) return;

    // End recursion if this spot has already been visited
    if (visited.Contains(point)) return;

    // Add point to visited points list
    visited.Add(point);

    // Calculate neighboring tiles coordinates
    Point right = new Point(point.X + 1, point.Y);
    Point left = new Point(point.X - 1, point.Y);
    Point up = new Point(point.X, point.Y - 1);
    Point down = new Point(point.X, point.Y + 1);

    // Mark neighbouring tiles as Sea if they're not Land
    if (WithinBounds(right) && tiles[right.X, right.Y].Empty)
        tiles[right.X, right.Y].Sea = true;
    if (WithinBounds(left) && tiles[left.X, left.Y].Empty)
        tiles[left.X, left.Y].Sea = true;
    if (WithinBounds(up) && tiles[up.X, up.Y].Empty)
        tiles[up.X, up.Y].Sea = true;
    if (WithinBounds(down) && tiles[down.X, down.Y].Empty)
        tiles[down.X, down.Y].Sea = true;

    // Call the function recursively for the neighboring tiles
    GenerateSeaRecursive(right);
    GenerateSeaRecursive(left);
    GenerateSeaRecursive(up);
    GenerateSeaRecursive(down);
}

আমি আমার গেমের লেকগুলি থেকে মুক্তি পেতে প্রথম পদক্ষেপ হিসাবে এটি ব্যবহার করেছি। এই কল করার পরে, আমাকে যা করতে হবে তা হ'ল:

private void RemoveLakes()
{
    // Now that sea is generated, any empty tile should be removed
    for (int j = 0; j != size.Height; j++)
        for (int i = 0; i != size.Width; i++)
            if (tiles[i, j].Empty) tiles[i, j].Land = true;
}

সম্পাদন করা

মন্তব্যের ভিত্তিতে কিছু অতিরিক্ত তথ্য যুক্ত করা হচ্ছে। যদি আপনার অনুসন্ধানের স্থানটি খুব বড় হয় তবে অ্যালগরিদমের পুনরাবৃত্ত সংস্করণ ব্যবহার করার সময় আপনি স্ট্যাকের ওভারফ্লো অনুভব করতে পারেন। এখানে স্ট্যাকওভারফ্লোতে একটি লিঙ্ক রয়েছে (শুল্কযুক্ত :-)) একটি অ্যালগরিদমের একটি পুনরাবৃত্ত সংস্করণে, Stack<T>পরিবর্তে (আমার উত্তরের সাথে মেলে সিতেও, তবে অন্যান্য ভাষাগুলির সাথে খাপ খাইয়ে নেওয়া সহজ হওয়া উচিত) এবং এর উপর অন্যান্য বাস্তবায়ন রয়েছে লিঙ্কটিও)।


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

জর্জডুকেট যা বলেছিলেন তার সাথে ইনলাইন করুন - আপনি গুগলিং ব্লব সনাক্তকরণ অ্যালগরিদমগুলি চেষ্টা করতে পারেন: এটি এফটিআইআর ব্যবহার করে মাল্টি টাচের ক্ষেত্রে একটি সাধারণ সমস্যা। আমার মনে আছে আমি একটি স্মার্ট অ্যালগরিদম নিয়ে এসেছি, তবে এটি কীভাবে কাজ করেছে তা আমার জীবনের জন্য মনে করতে পারি না।
জোনাথন ডিকিনসন

যেহেতু আমি পিএইচপি-তে স্ট্যাক ইস্যু করে চলেছি আমি LIFO বন্যার ভরাট বাস্তবায়িত করেছি, দুর্দান্তভাবে কাজ করেছি।
গ্যাব্রিয়েল এ জোরিলা

যখন কোনও ডিএফএস অ্যালগরিদমকে কোনও বিএফএস অ্যালগরিদম থেকে ডাকা হয় তখনই কি এটি বন্যা পূর্ণ হয় না? দয়া করে কাউকে ব্যাখ্যা করুন।
jcora

@ বেন আপনার মানে কি? ডিএফএস বা বিএফএসের মধ্যে পার্থক্য হ'ল নোডগুলি পরিদর্শন করা হয় কেবল সেই ক্রম। আমার মনে হয় না যে বন্যা ভরাট অ্যালগরিদম ট্র্যাভারসাল ক্রমের সুনির্দিষ্ট করে - যতক্ষণ না এটি পুরো অঞ্চলটি পুরোপুরি পূরণ করে ততক্ষণ এটি পর্যালোচনা করে না। আদেশ বাস্তবায়নের উপর নির্ভর করে। একটি স্ট্যাক ব্যবহার করে একটি সারি ব্যবহার করে যখন ট্র্যাভারসাল ক্রমের তুলনা করে একটি চিত্রের জন্য উইকিপিডিয়া প্রবেশের নীচে দেখুন । পুনরাবৃত্তির বাস্তবায়নটিকে একটি স্ট্যাক হিসাবেও বিবেচনা করা যেতে পারে (যেহেতু এটি কল স্ট্যাক ব্যবহার করে)।
ডেভিড গওভিয়া


5

এটি চিত্র প্রক্রিয়াকরণে একটি মানক ক্রিয়াকলাপ। আপনি একটি দ্বি-ফেজ অপারেশন ব্যবহার করেন।

মানচিত্রের একটি অনুলিপি তৈরি করে শুরু করুন। এই মানচিত্র থেকে, সমুদ্রের সীমানাযুক্ত সমস্ত স্থল পিক্সেলগুলিকে সমুদ্রের পিক্সেলে পরিণত করুন। আপনি যদি একবার এটি করেন তবে এটি 2x2 দ্বীপপুঞ্জকে বাদ দেবে এবং আরও বড় দ্বীপ সঙ্কুচিত করবে। আপনি যদি এটি দু'বার করেন তবে এটি 4x4 দ্বীপপুঞ্জ, এসটেটেরাকে দূর করবে।

দ্বিতীয় ধাপে, আপনি প্রায় বিপরীতটি করেন: স্থল সীমান্তের সমস্ত সমুদ্রের পিক্সেলগুলিতে পরিণত করুন, তবে কেবলমাত্র তারা মূল মানচিত্রে ল্যান্ড পিক্সেল হলে (এই কারণেই আপনি প্রথম পর্বে একটি অনুলিপি তৈরি করেছেন)। এটি দ্বীপপুঞ্জকে তাদের মূল আকারে ফিরিয়ে দেয়, যদি না তাদের প্রথম পর্বের সম্পূর্ণরূপে নির্মূল করা হয়।


1

আমার একই রকম সমস্যা ছিল তবে গেমের বিকাশে নয়। আমাকে একটি চিত্রের মধ্যে পিক্সেলগুলি খুঁজতে হয়েছিল যা একে অপরের সাথে সংলগ্ন ছিল এবং একই মান ছিল (সংযুক্ত অঞ্চল)। আমি একটি পুনরাবৃত্ত বন্যারফিল ব্যবহার করার চেষ্টা করেছি কিন্তু স্ট্যাকের ওভারফ্লোগুলি সৃষ্টি করে চলেছি (আমি একজন নবাগত প্রোগ্রামার: পি)। তারপরে আমি এই পদ্ধতিটি http://en.wikedia.org/wiki/Connected-component_labeling চেষ্টা করেছিলাম , যাইহোক আমার সমস্যার জন্য এটি আসলে আরও কার্যকর।


আপনার প্লাবনের স্ট্যাক সংস্করণটি আবার চেষ্টা করা উচিত এবং স্ট্যাকের সমস্যাগুলি সংরক্ষণ করা উচিত। সিসিএল থেকে অনেক বেশি সহজ হয়ে উঠেছে (যা আমি গত 2 সপ্তাহ ধরে ভাগ্য
নির্বিঘ্নে কাজ করে যাচ্ছি

হ্যাঁ, আমি উভয়ই চেষ্টা করেছি, তবে সিসিএলকে প্রথমে কাজ করার জন্য পেয়েছি: পি এবং এটি একটি ঝরঝরে ধারণা বলে মনে হয়েছিল। খুশি
হলেন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.