একটি চিত্র প্রদত্ত কোনও গোলকধাঁধার প্রতিনিধিত্ব এবং সমাধান করা


271

কোনও চিত্র দেওয়া কোনও গোলকধাঁধার প্রতিনিধিত্ব ও সমাধানের সর্বোত্তম উপায় কী?

স্কোপ ইস্যু 134 এর কভার চিত্র

একটি জেপিজি চিত্র দেওয়া (উপরে যেমন দেখানো হয়েছে), এটি পড়ার সর্বোত্তম উপায় কোনটি, এটি কোনও ডেটা স্ট্রাকচারে পার্স করে এবং গোলকধাঁধাটি সমাধান করার উপায়? আমার প্রথম প্রবৃত্তিটি পিক্সেল দ্বারা চিত্রটিকে পিক্সেলে পড়া এবং এটি বুলিয়ান মানগুলির একটি তালিকায় (অ্যারে) সংরক্ষণ করা: Trueএকটি সাদা পিক্সেল এবং Falseএকটি অ-সাদা পিক্সেলের জন্য (রঙগুলি বাদ দেওয়া যেতে পারে)। এই পদ্ধতির সমস্যাটি হ'ল চিত্রটি "পিক্সেল নিখুঁত" নাও হতে পারে। এর মাধ্যমে আমি কেবল বোঝাতে চাইছি যে কোনও দেয়ালে কোথাও যদি সাদা পিক্সেল থাকে তবে এটি একটি অনিচ্ছাকৃত পথ তৈরি করতে পারে।

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

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

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

তারপরে গোলকধাঁধাটির সমাধান আসে। যদি আমি প্রথম দুটি পদ্ধতির কোনওটি ব্যবহার করি তবে আমি ম্যাট্রিক্সের সাথে মূলত শেষ করব। এই উত্তর অনুসারে , গোলকধাঁধার প্রতিনিধিত্ব করার একটি ভাল উপায় একটি গাছ ব্যবহার করছে এবং এটি সমাধানের একটি ভাল উপায় হ'ল এ * অ্যালগরিদম । চিত্র থেকে কেউ কীভাবে একটি গাছ তৈরি করবে? কোন ধারনা?

TL; DR
পার্স করার সর্বোত্তম উপায়? কোন তথ্য কাঠামোতে? কীভাবে কাঠামো সমাধান / বাধা সমাধানে সহায়তা করবে?

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

import png, numpy, Queue, operator, itertools

def is_white(coord, image):
  """ Returns whether (x, y) is approx. a white pixel."""
  a = True
  for i in xrange(3):
    if not a: break
    a = image[coord[1]][coord[0] * 3 + i] > 240
  return a

def bfs(s, e, i, visited):
  """ Perform a breadth-first search. """
  frontier = Queue.Queue()
  while s != e:
    for d in [(-1, 0), (0, -1), (1, 0), (0, 1)]:
      np = tuple(map(operator.add, s, d))
      if is_white(np, i) and np not in visited:
        frontier.put(np)
    visited.append(s)
    s = frontier.get()
  return visited

def main():
  r = png.Reader(filename = "thescope-134.png")
  rows, cols, pixels, meta = r.asDirect()
  assert meta['planes'] == 3 # ensure the file is RGB
  image2d = numpy.vstack(itertools.imap(numpy.uint8, pixels))
  start, end = (402, 985), (398, 27)
  print bfs(start, end, image2d, [])

12
আমি গোলকধাঁটিকে কালো এবং সাদা রূপান্তরিত করব এবং এটি সমাধান করার জন্য সেলুলার অটোমেটা পদ্ধতি সন্ধানের জন্য একটি পথ ব্যবহার করব।
ড্যান ডি

আপনার কি কেবল সেই চিত্রটি বা এই জাতীয় অনেকগুলি চিত্রের সাথে ডিল করতে হবে? অর্থাৎ এই নির্দিষ্ট চিত্রটির জন্য নির্দিষ্ট কিছু ম্যানুয়াল প্রসেসিংয়ের বিকল্প রয়েছে?
মিখাইল

1
@Whmarrh আমি পাইথন কোড করি না, তবে আমি নিশ্চিত যে আপনি একটি visited.append(s)অধীনে যান for.ifএবং এটি প্রতিস্থাপন করা উচিত visited.append(np)। এটি একটি সারিতে যুক্ত হয়ে গেলে একটি ভার্টেক্স পরিদর্শন করা হয়। আসলে, এই অ্যারেটির নাম "সারিবদ্ধ" করা উচিত। একবার আপনি সমাপ্তিতে পৌঁছে গেলে আপনি বিএফএসও বন্ধ করতে পারেন।
মিখাইল

2
@ হোয়ামারহ এবং আপনিও মনে করেন যে পথটি নিষ্কাশনকারী ব্লকটি কার্যকর করা যায় না। এটি ব্যতীত, আপনি কেবল ফিনিসটি পৌঁছনীয় কিনা তা আবিষ্কার করতে পারেন তবে কীভাবে তা নয়।
মিখাইল

1
খুঁজে বের করতে যদি হয় একটি সমাধান, একটি UnionFind এবং লিনিয়ার স্ক্যান দ্রুততম অ্যালগরিদম হয়। এটি আপনাকে পথ দেয় না, তবে আপনাকে এমন একটি টাইলস দেয় যা একটি উপসেট হিসাবে পাথ করবে।
st0le

উত্তর:


236

এখানে একটি সমাধান।

  1. চিত্রগুলি গ্রেস্কেলে রূপান্তর করুন (এখনও বাইনারি নয়), রঙগুলির জন্য ওজন সামঞ্জস্য করে যাতে চূড়ান্ত গ্রেস্কেল চিত্রটি প্রায় অভিন্ন হয়। আপনি ছবিতে ফটোশপে স্লাইডারগুলি নিয়ন্ত্রণ করে এটি করতে পারেন -> সামঞ্জস্য -> কালো এবং সাদা।
  2. চিত্র -> অ্যাডজাস্টমেন্টস -> থ্রেশহোল্ডে ফটোশপে উপযুক্ত থ্রোসোল্ড সেট করে চিত্রকে বাইনারি রূপান্তর করুন।
  3. থ্রেশহোল্ডটি সঠিকভাবে নির্বাচিত হয়েছে তা নিশ্চিত করুন। 0 সহনশীলতা, বিন্দুর নমুনা, সংমিশ্রিত, কোনও অ্যান্টি-এলিয়াসিং সহ ম্যাজিক ওয়ান্ড সরঞ্জামটি ব্যবহার করুন। যে প্রান্তটি নির্বাচন বিরতিতে ভুল থ্রোসোল্ড দ্বারা প্রবর্তিত মিথ্যা প্রান্ত নয় তা পরীক্ষা করে দেখুন। আসলে, এই গোলকধাঁধার সমস্ত অভ্যন্তরীণ পয়েন্ট শুরু থেকেই অ্যাক্সেসযোগ্য।
  4. ভার্চুয়াল ভ্রমণকারী তার আশেপাশে চলবে না তা নিশ্চিত করার জন্য গোলকধাঁটিতে কৃত্রিম সীমানাগুলি যুক্ত করুন :)
  5. আপনার পছন্দের ভাষায় প্রস্থের প্রথম সন্ধান (বিএফএস) প্রয়োগ করুন এবং এটি শুরু থেকেই চালান। আমি এই কাজের জন্য ম্যাটল্যাবকে পছন্দ করি । @ থমাস যেমন ইতিমধ্যে উল্লেখ করেছে, নিয়মিত গ্রাফের প্রতিনিধিত্ব নিয়ে গণ্ডগোল করার দরকার নেই। আপনি সরাসরি বাইনারিযুক্ত চিত্রের সাথে কাজ করতে পারেন।

বিএফএসের জন্য ম্যাটল্যাব কোডটি এখানে:

function path = solve_maze(img_file)
  %% Init data
  img = imread(img_file);
  img = rgb2gray(img);
  maze = img > 0;
  start = [985 398];
  finish = [26 399];

  %% Init BFS
  n = numel(maze);
  Q = zeros(n, 2);
  M = zeros([size(maze) 2]);
  front = 0;
  back = 1;

  function push(p, d)
    q = p + d;
    if maze(q(1), q(2)) && M(q(1), q(2), 1) == 0
      front = front + 1;
      Q(front, :) = q;
      M(q(1), q(2), :) = reshape(p, [1 1 2]);
    end
  end

  push(start, [0 0]);

  d = [0 1; 0 -1; 1 0; -1 0];

  %% Run BFS
  while back <= front
    p = Q(back, :);
    back = back + 1;
    for i = 1:4
      push(p, d(i, :));
    end
  end

  %% Extracting path
  path = finish;
  while true
    q = path(end, :);
    p = reshape(M(q(1), q(2), :), 1, 2);
    path(end + 1, :) = p;
    if isequal(p, start) 
      break;
    end
  end
end

এটি সত্যিই খুব সহজ এবং মানসম্পন্ন, পাইথন বা এটি যাই হোক না কেন এটি বাস্তবায়নে অসুবিধা হওয়া উচিত নয় ।

এবং এখানে উত্তর:

এখানে চিত্র বিবরণ লিখুন


1
@ হোয়ারমারহ ওয়েল, "কেবল এই চিত্র" এর জন্য আপনার কাছে এখন একটি উত্তর আছে। আপনার কোন নির্দিষ্ট প্রশ্ন আছে? আমার তালিকা থেকে আইটেম 1-4 হ'ল ম্যানুয়াল প্রক্রিয়াজাতকরণ সম্পর্কে আমি জিজ্ঞাসা করছি। আইটেম 5 হ'ল একটি বিএফএস - গ্রাফের জন্য খুব বেসিক অ্যালগরিদম তবে এটি পিক্সেলকে শীর্ষে এবং প্রতিবেশীদের প্রান্তে রূপান্তর না করে সরাসরি চিত্রটিতে প্রয়োগ করা যেতে পারে।
মিখাইল

আমি মনে করি আপনি সবকিছু আবৃত করেছেন। পাইথনে আপনি যা বলেছিলেন তা বাস্তবায়নে আমি আমার হাত চেষ্টা করছি (বিএফএসের জায়গায় ডিএফএস ব্যবহার করে, কেবলমাত্র আমি এটি আগে একবার কোড করেছিলাম বলে)। আমি প্রশ্নটি আপডেট করতে / কিছুক্ষণের মধ্যে উত্তর গ্রহণ করতে ফিরে আসব।
কেন

2
@Wwmarrh DFS আপনাকে সবচেয়ে সংক্ষিপ্ততম পথটি খুঁজে পাবে না, যখন বিএফএস করবে। তারা সহজাতভাবে একই, পার্থক্য কেবল অন্তর্নিহিত কাঠামো। ডিএফএসের জন্য স্ট্যাক (FILO) এবং বিএফএসের জন্য সারি (FIFO)।
মিখাইল

3
বিএফএস এখানে সঠিক পছন্দ, কারণ এটি একটি সংক্ষিপ্ততম পথ তৈরি করে, যা করিডোরগুলি 1 পিক্সেলের চেয়েও প্রশস্ত হলেও এমনকি "সংবেদনশীল" পথ দেয়। ওটিওএফ ডিএফএস "বন্যা ভরাট" প্যাটার্ন সহ করিডোর এবং অপ্রত্যাশিত গোলকধাঁধার অঞ্চলগুলি ঘুরে দেখার ঝোঁক রাখবে।
j_random_hacker

1
@ জোসেফকর্ন পাথ কোনও দেয়াল ওভারল্যাপ করে না। কেবলমাত্র সমস্ত লাল পিক্সেল সরান এবং আপনি এখানে যান।
মিখাইল

160

এই সমাধানটি পাইথনে লেখা আছে। ছবি প্রস্তুতির জন্য পয়েন্টারটির জন্য ধন্যবাদ মিখাইল।

একটি অ্যানিমেটেড চওড়া-প্রথম অনুসন্ধান:

বিএফএসের অ্যানিমেটেড সংস্করণ

সমাপ্ত ধাঁধা:

সম্পূর্ণ ধাঁধা

#!/usr/bin/env python

import sys

from Queue import Queue
from PIL import Image

start = (400,984)
end = (398,25)

def iswhite(value):
    if value == (255,255,255):
        return True

def getadjacent(n):
    x,y = n
    return [(x-1,y),(x,y-1),(x+1,y),(x,y+1)]

def BFS(start, end, pixels):

    queue = Queue()
    queue.put([start]) # Wrapping the start tuple in a list

    while not queue.empty():

        path = queue.get() 
        pixel = path[-1]

        if pixel == end:
            return path

        for adjacent in getadjacent(pixel):
            x,y = adjacent
            if iswhite(pixels[x,y]):
                pixels[x,y] = (127,127,127) # see note
                new_path = list(path)
                new_path.append(adjacent)
                queue.put(new_path)

    print "Queue has been exhausted. No answer was found."


if __name__ == '__main__':

    # invoke: python mazesolver.py <mazefile> <outputfile>[.jpg|.png|etc.]
    base_img = Image.open(sys.argv[1])
    base_pixels = base_img.load()

    path = BFS(start, end, base_pixels)

    path_img = Image.open(sys.argv[1])
    path_pixels = path_img.load()

    for position in path:
        x,y = position
        path_pixels[x,y] = (255,0,0) # red

    path_img.save(sys.argv[2])

দ্রষ্টব্য: একটি সাদা পরিদর্শন করা পিক্সেল ধূসর চিহ্নিত করে। এটি পরিদর্শন করা তালিকার প্রয়োজনীয়তা সরিয়ে দেয় তবে কোনও পথ আঁকার আগে ডিস্ক থেকে ইমেজ ফাইলটির দ্বিতীয় লোডের প্রয়োজন হয় (যদি আপনি চূড়ান্ত পাথের এবং সম্মিলিত সমস্ত পথের সম্মিলিত চিত্র না চান)।

আমি যে ধাঁধাঁ ব্যবহার করেছি তার একটি ফাঁকা সংস্করণ।


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

1
একটি ভাল, ধন্যবাদ। অন্যেরা যারা এটিকে নিয়ে খেলা করতে চান, আমি যেমন করলাম, আমি আমার সমস্যার মুখোমুখি হয়ে আমার পরামর্শগুলি ভাগ করতে চাই। 1) হয় চিত্রটিকে খাঁটি কালো ও সাদা রূপান্তর করুন অথবা নিকটে-সাদা | কালোকে স্বীকার করতে আপনার 'isWhite ()' ফাংশনটি পরিবর্তন করুন। আমি একটি 'ক্লিন আইমেজ' পদ্ধতি লিখেছিলাম যা সমস্ত পিক্সেলকে খাঁটি সাদা বা কালোতে রূপান্তরিত করে প্রিপ্রোসেস করে, অন্যথায় অ্যালগরিদম কোনও পথ খুঁজে পেতে ব্যর্থ হয়। 2) চিত্রটি স্পষ্টভাবে আরজিবি হিসাবে পড়ুন [বেস_আইএমজি = ইমেজ.ওপেন (img_in); বেস_আইএমজি = বেস_আইএমজি.কেনভার্ট ('আরজিবি')]। একটি জিআইএফ পেতে বেশ কয়েকটি চিত্র আউটপুট করুন এবং তারপরে 'রূপান্তর -ডেলা 5 -লুপ 1 * .jpg বিএফএস.gif' চালান।
স্টেফানো

1
13 লাইনে ইন্ডেন্ট মিস করা
স্লোভেন

81

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

def AStar(start, goal, neighbor_nodes, distance, cost_estimate):
    def reconstruct_path(came_from, current_node):
        path = []
        while current_node is not None:
            path.append(current_node)
            current_node = came_from[current_node]
        return list(reversed(path))

    g_score = {start: 0}
    f_score = {start: g_score[start] + cost_estimate(start, goal)}
    openset = {start}
    closedset = set()
    came_from = {start: None}

    while openset:
        current = min(openset, key=lambda x: f_score[x])
        if current == goal:
            return reconstruct_path(came_from, goal)
        openset.remove(current)
        closedset.add(current)
        for neighbor in neighbor_nodes(current):
            if neighbor in closedset:
                continue
            if neighbor not in openset:
                openset.add(neighbor)
            tentative_g_score = g_score[current] + distance(current, neighbor)
            if tentative_g_score >= g_score.get(neighbor, float('inf')):
                continue
            came_from[neighbor] = current
            g_score[neighbor] = tentative_g_score
            f_score[neighbor] = tentative_g_score + cost_estimate(neighbor, goal)
    return []

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

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

কোডটি এখানে:

import sys
from PIL import Image

def is_blocked(p):
    x,y = p
    pixel = path_pixels[x,y]
    if any(c < 225 for c in pixel):
        return True
def von_neumann_neighbors(p):
    x, y = p
    neighbors = [(x-1, y), (x, y-1), (x+1, y), (x, y+1)]
    return [p for p in neighbors if not is_blocked(p)]
def manhattan(p1, p2):
    return abs(p1[0]-p2[0]) + abs(p1[1]-p2[1])
def squared_euclidean(p1, p2):
    return (p1[0]-p2[0])**2 + (p1[1]-p2[1])**2

start = (400, 984)
goal = (398, 25)

# invoke: python mazesolver.py <mazefile> <outputfile>[.jpg|.png|etc.]

path_img = Image.open(sys.argv[1])
path_pixels = path_img.load()

distance = manhattan
heuristic = manhattan

path = AStar(start, goal, von_neumann_neighbors, distance, heuristic)

for position in path:
    x,y = position
    path_pixels[x,y] = (255,0,0) # red

path_img.save(sys.argv[2])

ফলাফলগুলির দৃশ্যধারণের জন্য এখানে কিছু চিত্র দেওয়া হয়েছে ( জোসেফ কার্ন দ্বারা পোস্ট করা একটি দ্বারা অনুপ্রাণিত )। অ্যানিমেশনগুলি মূল ওয়ে-লুপের 10000 পুনরাবৃত্তির পরে একটি নতুন ফ্রেম দেখায়।

প্রস্থ-প্রথম অনুসন্ধান:

প্রস্থ-প্রথম অনুসন্ধান

এ-স্টার ম্যানহাটন দূরত্ব:

এ-স্টার ম্যানহাটান দূরত্ব

এ-স্টার স্কোয়ারড ইউক্লিডিয়ান দূরত্ব:

এ-স্টার স্কোয়ারড ইউক্লিডিয়ান দূরত্ব

এ-স্টার ম্যানহাটান দূরত্ব চারটি দ্বারা গুন:

এ-স্টার ম্যানহাটনের দূরত্ব চার দ্বারা গুণিত হয়েছে

ফলাফলগুলি দেখায় যে গোলকধাঁধার অন্বেষিত অঞ্চলগুলি হিউরিস্টিকস ব্যবহারের জন্য যথেষ্ট পার্থক্য করে। যেমন, স্কোয়ারড ইউক্লিডিয়ান দূরত্ব এমনকি অন্যান্য মেট্রিকগুলির মতো একটি পৃথক (সাবপটিমাল) পাথ তৈরি করে।

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

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


1
"এ-স্টার ম্যানহাটন দূরত্ব চার দ্বারা গুণিত হয়েছে"? হিউরিস্টিক যদি দূরত্বকে আরও বাড়িয়ে তুলতে পারে তবে এ-স্টার এ-স্টার নয়। (এবং এভাবেই কোনও সংক্ষিপ্ততম পথটি খুঁজে পাওয়ার গ্যারান্টি নেই)
উদাহরণস্বরূপ

@ উদাহরণ অবশ্যই, যদি কেউ অ-গ্রহণযোগ্য হিউরিস্টিক ফাংশন প্রয়োগ করে তবে অ্যালগোরিদম অনুকূল সমাধানটি খুঁজে পেতে ব্যর্থ হতে পারে (যেমন আমি আমার উত্তরে দেখিয়েছি)। তবে আমি সেই কারণে বেসিক অ্যালগরিদমটির নতুন নামকরণ করতে এতদূর যেতে পারি না।
moooeeeep

38

গাছের সন্ধান অনেক বেশি। গোলকধাঁধাটি সমাধানের পথে (গুলি) সহ স্বভাবত পৃথক is

( রেডডিট থেকে রেইনম্যান ২০০2 কে আমার কাছে এটি দেখানোর জন্য ধন্যবাদ ।)

এর কারণে, আপনি ধাঁধা প্রাচীরের সংযুক্ত বিভাগগুলি সনাক্ত করতে দ্রুত সংযুক্ত উপাদানগুলি ব্যবহার করতে পারেন । এটি পিক্সেলের উপর দিয়ে দু'বার পুনরাবৃত্তি করে।

যদি আপনি এটিকে সমাধানের পাথের একটি সুন্দর চিত্রতে পরিণত করতে চান তবে আপনি প্রতিটি সংযুক্ত অঞ্চলের জন্য "মৃত প্রান্ত" পাথ পূরণ করতে কাঠামোগত উপাদানগুলির সাথে বাইনারি ক্রিয়াকলাপগুলি ব্যবহার করতে পারেন।

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

% read in and invert the image
im = 255 - imread('maze.jpg');

% sharpen it to address small fuzzy channels
% threshold to binary 15%
% run connected components
result = bwlabel(im2bw(imfilter(im,fspecial('unsharp')),0.15));

% purge small components (e.g. letters)
for i = 1:max(reshape(result,1,1002*800))
    [count,~] = size(find(result==i));
    if count < 500
        result(result==i) = 0;
    end
end

% close dead-end channels
closed = zeros(1002,800);
for i = 1:max(reshape(result,1,1002*800))
    k = zeros(1002,800);
    k(result==i) = 1; k = imclose(k,strel('square',8));
    closed(k==1) = i;
end

% do output
out = 255 - im;
for x = 1:1002
    for y = 1:800
        if closed(x,y) == 0
            out(x,y,:) = 0;
        end
    end
end
imshow(out);

বর্তমান কোডের ফলাফল


24

একটি চৌম্বক অবিচ্ছিন্ন পূরণের জন্য একটি সারি ব্যবহার করে। প্রবেশদ্বারের বাম পিক্সেলটি সারিটির দিকে ঠেলা দেয় এবং তারপরে লুপটি শুরু করে। যদি কোনও সারিবদ্ধ পিক্সেল যথেষ্ট গা dark় হয় তবে এটি হালকা ধূসর রঙের (প্রান্তিকের উপরে) রঙিন হয় এবং সমস্ত প্রতিবেশী সারিতে সজ্জিত হয়।

from PIL import Image
img = Image.open("/tmp/in.jpg")
(w,h) = img.size
scan = [(394,23)]
while(len(scan) > 0):
    (i,j) = scan.pop()
    (r,g,b) = img.getpixel((i,j))
    if(r*g*b < 9000000):
        img.putpixel((i,j),(210,210,210))
        for x in [i-1,i,i+1]:
            for y in [j-1,j,j+1]:
                scan.append((x,y))
img.save("/tmp/out.png")

সমাধান ধূসর প্রাচীর এবং রঙিন প্রাচীরের মধ্যে করিডোর। দ্রষ্টব্য এই গোলকধাঁটির একাধিক সমাধান রয়েছে। এছাড়াও, এটি নিছক কাজ করে বলে মনে হচ্ছে।

সমাধান


1
ওয়াল-ম্যানেজ পদ্ধতিটি ভিত্তিতে আকর্ষণীয় নিষ্পাপ রেজোলিউশন। আসলে, সেরাটি নয়, তবে আমি এটি পছন্দ করি।
zessx

23

আপনি এখানে যান: গোলকধাঁধা-সমাধানকারী-পাইথন (গিটহাব)

এখানে চিত্র বর্ণনা লিখুন

আমি এর সাথে চারপাশে খেলতে মজা পেয়েছি এবং জোসেফ কার্নের উত্তরটি প্রসারিত করেছি । এটি থেকে বিরত না; আমি অন্য যে কেউ এটির সাথে খেলতে আগ্রহী হতে পারে তার জন্য কিছুটা ছোটখাটো সংযোজন করেছি।

এটি একটি অজগর-ভিত্তিক দ্রাবক যা সংক্ষিপ্ততম পথ খুঁজে পেতে বিএফএস ব্যবহার করে। আমার মূল সংযোজনগুলি, এগুলি হ'ল:

  1. ছবিটি অনুসন্ধানের আগে পরিষ্কার করা হয়েছে (যেমন, খাঁটি কালো এবং সাদা রূপান্তর করুন)
  2. স্বয়ংক্রিয়ভাবে একটি জিআইএফ উত্পন্ন করুন।
  3. স্বয়ংক্রিয়ভাবে একটি এভিআই উত্পন্ন করুন।

এটি যেমন দাঁড়িয়েছে, সূচনা / শেষ-পয়েন্টগুলি এই নমুনা ধাঁধাটির জন্য কঠোর কোডড, তবে আমি এটির প্রসারকে আরও বাড়িয়ে দেওয়ার পরিকল্পনা করছি যাতে আপনি উপযুক্ত পিক্সেল বাছাই করতে পারেন।


1
দুর্দান্ত, ধন্যবাদ, এটি বিএসডি / ডারউইন / ম্যাকের উপর চালিত হয়নি, যারা ম্যাক চেষ্টা করতে চান তাদের জন্য কিছু নির্ভরতা এবং শেল স্ক্রিপ্টের সামান্য পরিবর্তন দরকার ছিল: [ ম্যাজ
হোলজিটি

@ হোলজিটি: আপনি খুশী হয়েছিলেন যে এটি কার্যকর হয়েছে। আমি এটির জন্য কোনও টান অনুরোধকে স্বাগত জানাই। :)
স্টিফানো

5

আমি ম্যাট্রিক্স-অফ-বুলস বিকল্পের জন্য যেতে চাই। যদি আপনি দেখতে পান যে স্ট্যান্ডার্ড পাইথন তালিকাগুলি এটির জন্য খুব অদক্ষ, তবে আপনি তার numpy.boolপরিবর্তে একটি অ্যারে ব্যবহার করতে পারেন । 1000x1000 পিক্সেল গোলকধাঁধার জন্য স্টোরেজটি কেবল 1 এমবি।

কোনও গাছ বা গ্রাফ ডেটা স্ট্রাকচার তৈরি করে বিরক্ত করবেন না। এটি কেবল এটি সম্পর্কে চিন্তাভাবনার একটি উপায়, তবে এটির স্মৃতিতে উপস্থাপনের জন্য ভাল উপায় নয়; একটি বুলিয়ান ম্যাট্রিক্স উভয় কোড করা সহজ এবং আরও দক্ষ।

তারপরে এটি সমাধানের জন্য এ * অ্যালগোরিদম ব্যবহার করুন। দূরত্বের বৈজ্ঞানিকতার জন্য ম্যানহাটনের দূরত্ব ( distance_x + distance_y) ব্যবহার করুন ।

(row, column)স্থানাঙ্কগুলির একটি দ্বিগুণ দ্বারা নোডগুলি উপস্থাপন করুন । যখনই অ্যালগরিদম ( উইকিপিডিয়া সিউডোকোড ) "প্রতিবেশী" ডাকে, এটি সম্ভাব্য চারটি প্রতিবেশী (চিত্রের প্রান্তগুলি মনে রাখুন!) ল্যাপিংয়ের একটি সাধারণ বিষয়।

যদি আপনি দেখতে পান যে এটি এখনও খুব ধীর গতির হয়, তবে চিত্রটি লোড করার আগে আপনি ডাউনস্কল করার চেষ্টা করতে পারেন। প্রক্রিয়াটির কোনও সংকীর্ণ পথটি না হারাতে সাবধান হন।

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


এই দুর্দান্ত ব্লগ পোস্টটি দেখায় যে কীভাবে গণিতে ম্যাজিক সমাধান করা যায়। অজগর পদ্ধতিটি অনুবাদ করা কোনও সমস্যা হওয়া উচিত নয়
বোরিস গোরালিক

আমি প্রশ্ন আপডেট করেছি। আমি যদি booleanমানগুলির পরিবর্তে আরজিবি ট্রিপল ব্যবহার করা চয়ন করি তবে কি স্টোরেজটির তুলনা করা যাবে? তারপরে ম্যাট্রিক্সটি 2400 * 1200 হয় B
হোয়াবার্মে

@ কেন, সামান্য গভীরতা ক্ষতিপূরণ সঙ্কুচিত করতে পারেন। প্রতি পিক্সেল 2 বিট যে কারও জন্য যথেষ্ট হতে হবে।
ব্রায়ান কেইন

5

এখানে কিছু ধারনা.

(১. চিত্র প্রক্রিয়াকরণ :)

1.1 চিত্রটি আরজিবি হিসাবে লোড করুন পিক্সেল মানচিত্র । ইন সি # এটি ব্যবহার তুচ্ছ হয় system.drawing.bitmap। ইমেজিংয়ের জন্য সহজ সমর্থন না থাকা ভাষায়, কেবল চিত্রটিকে পোর্টেবল পিক্স্যাম্যাপ ফর্ম্যাট (পিপিএম) এ রূপান্তর করুন (একটি ইউনিক্স পাঠ্য উপস্থাপনা, বড় ফাইল তৈরি করে) বা আপনি সহজেই পড়তে পারেন এমন কিছু সাধারণ বাইনারি ফাইল ফর্ম্যাট যেমন বিএমপি বা টিজিএImageMagick ইউনিক্স বা IrfanView উইন্ডোজে।

১.২ আপনি পূর্বে উল্লিখিত হিসাবে, ধূসর স্বরের একটি সূচক হিসাবে প্রতিটি পিক্সেলের জন্য (আর + জি + বি) / 3 গ্রহণ করে ডেটা সরল করতে পারেন এবং তারপরে একটি কালো এবং সাদা টেবিল তৈরির মান প্রান্তিক করতে পারেন। 0 = কালো এবং 255 = সাদা ধরে ধরে 200 এর কাছাকাছি কিছু জেপিইজি শিল্পকর্মগুলি গ্রহণ করবে।

(২. সমাধান)

২.১ গভীরতা-প্রথম অনুসন্ধান: শুরুর অবস্থানের সাথে একটি খালি স্ট্যাকের সূচনা করুন, উপলভ্য অনুসরণীয় পদক্ষেপগুলি সংগ্রহ করুন, এলোমেলোভাবে একটি বেছে নিন এবং স্ট্যাকের দিকে ধাক্কা দিন, শেষ না হওয়া বা শেষের আগ পর্যন্ত অগ্রসর হন। স্ট্যাকটি পপিং করে ডেডেন্ড ব্যাকট্র্যাকে, আপনাকে মানচিত্রে কোন অবস্থানগুলি পরিদর্শন করা হয়েছিল তা ট্র্যাক করে রাখতে হবে যাতে যখন আপনি উপলভ্য পদক্ষেপগুলি সংগ্রহ করেন তখন কখনই একই পথটি দু'বার নেবেন না। প্রাণবন্ত খুব আকর্ষণীয়।

২.২ প্রস্থ-প্রথম অনুসন্ধান: উপরে উল্লিখিত, উপরে যেমন একই তবে কেবল সারি ব্যবহার করে। প্রাণবন্ত করার জন্যও আকর্ষণীয়। এটি চিত্র সম্পাদনা সফ্টওয়্যার বন্যা-পূরণের মতো কাজ করে। আমি মনে করি আপনি এই কৌশলটি ব্যবহার করে ফটোশপের কোনও গোলকধাঁধা সমাধান করতে সক্ষম হতে পারেন।

২.৩ ওয়াল অনুগামী: জ্যামিতিকভাবে বলতে গেলে, একটি গোলকধাঁধা একটি ভাঁজযুক্ত / সংশ্লেষিত নল। আপনি যদি দেয়ালে হাত রাখেন তবে আপনি শেষ পর্যন্ত প্রস্থানটি দেখতে পাবেন;) এটি সর্বদা কার্যকর হয় না। কিছু অনুমানের পুনরাবৃত্তি রয়েছে: নিখুঁত ম্যাজস ইত্যাদি, উদাহরণস্বরূপ, নির্দিষ্ট ম্যাজগুলিতে দ্বীপ রয়েছে। এটি তাকান; এটি আকর্ষণীয়।

(৩. মন্তব্যসমূহ :)

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


2

আর ব্যবহার করে একটি সমাধান এখানে দেওয়া হয়েছে।

### download the image, read it into R, converting to something we can play with...
library(jpeg)
url <- "https://i.stack.imgur.com/TqKCM.jpg"
download.file(url, "./maze.jpg", mode = "wb")
jpg <- readJPEG("./maze.jpg")

### reshape array into data.frame
library(reshape2)
img3 <- melt(jpg, varnames = c("y","x","rgb"))
img3$rgb <- as.character(factor(img3$rgb, levels = c(1,2,3), labels=c("r","g","b")))

## split out rgb values into separate columns
img3 <- dcast(img3, x + y ~ rgb)

আরজিবি থেকে গ্রেস্কেল, দেখুন: https://stackoverflow.com/a/27491947/2371031

# convert rgb to greyscale (0, 1)
img3$v <- img3$r*.21 + img3$g*.72 + img3$b*.07
# v: values closer to 1 are white, closer to 0 are black

## strategically fill in some border pixels so the solver doesn't "go around":
img3$v2 <- img3$v
img3[(img3$x == 300 | img3$x == 500) & (img3$y %in% c(0:23,988:1002)),"v2"]  = 0

# define some start/end point coordinates
pts_df <- data.frame(x = c(398, 399),
                     y = c(985, 26))

# set a reference value as the mean of the start and end point greyscale "v"s
ref_val <- mean(c(subset(img3, x==pts_df[1,1] & y==pts_df[1,2])$v,
                  subset(img3, x==pts_df[2,1] & y==pts_df[2,2])$v))

library(sp)
library(gdistance)
spdf3 <- SpatialPixelsDataFrame(points = img3[c("x","y")], data = img3["v2"])
r3 <- rasterFromXYZ(spdf3)

# transition layer defines a "conductance" function between any two points, and the number of connections (4 = Manhatten distances)
# x in the function represents the greyscale values ("v2") of two adjacent points (pixels), i.e., = (x1$v2, x2$v2)
# make function(x) encourages transitions between cells with small changes in greyscale compared to the reference values, such that: 
# when v2 is closer to 0 (black) = poor conductance
# when v2 is closer to 1 (white) = good conductance
tl3 <- transition(r3, function(x) (1/max( abs( (x/ref_val)-1 ) )^2)-1, 4) 

## get the shortest path between start, end points
sPath3 <- shortestPath(tl3, as.numeric(pts_df[1,]), as.numeric(pts_df[2,]), output = "SpatialLines")

## fortify for ggplot
sldf3 <- fortify(SpatialLinesDataFrame(sPath3, data = data.frame(ID = 1)))

# plot the image greyscale with start/end points (red) and shortest path (green)
ggplot(img3) +
  geom_raster(aes(x, y, fill=v2)) +
  scale_fill_continuous(high="white", low="black") +
  scale_y_reverse() +
  geom_point(data=pts_df, aes(x, y), color="red") +
  geom_path(data=sldf3, aes(x=long, y=lat), color="green")

ভাল খবর!

সমাধান যা সঠিকভাবে সংক্ষিপ্ততম পথ খুঁজে পায়

আপনি কিছু সীমান্তের পিক্সেল (হা!) না পূরণ করলে এটিই ঘটে ...

সমাধান সংস্করণ যেখানে দ্রাবক গোলকধাঁধা কাছাকাছি যায়

সম্পূর্ণ প্রকাশ: আমি এটির সন্ধান করার আগে নিজেই একটি খুব অনুরূপ প্রশ্ন জিজ্ঞাসা করেছি এবং উত্তর দিয়েছি। তারপরে এসও এর যাদু দ্বারা এটি একটি শীর্ষ "সম্পর্কিত প্রশ্নাবলী" হিসাবে খুঁজে পেয়েছে। আমি ভেবেছিলাম আমি এই গোলকধাঁধাটিকে একটি অতিরিক্ত পরীক্ষার মামলা হিসাবে ব্যবহার করব ... আমি খুব খুশি হয়ে জানতে পেরেছিলাম যে আমার উত্তরটিও এই অ্যাপ্লিকেশনটির জন্য খুব অল্প সংশোধন করে কাজ করে।


0

ভাল সমাধানটি হ'ল পিক্সেল দ্বারা প্রতিবেশীদের সন্ধান করার পরিবর্তে এটি সেল দ্বারা সম্পন্ন হবে, কারণ কোনও করিডোরটিতে 15px থাকতে পারে তাই একই করিডোরে এটি বাম বা ডানের মতো পদক্ষেপ নিতে পারে, যখন এটি স্থানচ্যূতকরণের মতো করা হয়েছিল এটি কিউব ছিল এটি আপ, ডাউন, বাম বা ডানদিকে মত একটি সাধারণ ক্রিয়া হবে


আপনার পয়েন্টটি বৈধ করার জন্য আপনি কি উত্তরের মতো সমাধান গ্রাফ এবং অ্যালগরিদম যুক্ত করতে পারেন? এটি উত্তম হবে যদি আপনি সেগুলিকে আপনার উত্তরের সাথে আরও বেশি ওজন যোগ করতে পারেন যাতে অন্যরা আপনার উত্তরটির আরও বেশি বোঝার সুযোগ পায়।
হিমাংশু বানসাল
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.