1. Введение
Поиск может быть как сложным, так и простым. Когда не известна (или только частично известна) как сама цель, так и способ её достижения, случайность важна
Целью исследования статьи будет сравнение способов нахождения цели как подвижной (жёлтый объект), так и неподвижной.
Эти способы:
- Случайный поиск (красный объект)
- Случайный поиск с памятью (синий объект)
- Случайный поиск с памятью и иерархией (зелёный объект)
- Поиск первого маршрута (фиолетовый объект)
- Поиск короткого маршрута (коричневый объект)
На рис.1 эти объекты показаны. Полностью код программы выложен на github

2. Основная часть
2.1. Класс P – случайный поиск
Конструктор инициализирует атрибуты и переменные класса: главное окно, цвет, координату по y и x, счётчик, словарь посещённых, цель, словарь иерархии, словарь соседей. Метод init_3_dict заполняет три словаря. Метод show закрашивает клетку в нужный цвет. Метод update обновляет объект. Метод top_show создаёт окно верхнего уровня и показывает сколько шагов сделано до цели.
class P():
    def __init__(self, root, color, node, target, maps, ban):
        self.root = root
        self.color = color
        self.y = node[0]
        self.x = node[1]
        P.target = target
        self.count = 0
        
        self.visit = {}
        P.hierarchy = {}
        P.neighbor = {}
        
        self.init_3_dict(maps, ban)В методе init_3_dict объявляется функция is_en, которая проверяет, чтобы координата не была забанина и не выходила за рамки карты.
def init_3_dict(self, maps, ban):
        def is_en(yx):
            if yx[0] < 0 or yx[0] > len(maps)-1: return
            if yx[1] < 0 or yx[1] > len(maps[0])-1: return
            if yx in ban: return
            return True
В цикле в словарь посещённых с ключом координата записываем начальное значение ноль. В словарь иерархии с таким же ключом записываем иерархическое имя этой координаты. Потом заполняем словарь соседей, вызывая функцию is_en.
for y in range(len(maps)):
            for x in range(len(maps[0])):
                self.visit[(y,x)] = 0
                P.hierarchy[(y,x)] = maps[y][x]
                
                n = []
                if is_en((y-1,x)):
                    n.append((y-1,x))
                if is_en((y+1,x)):
                    n.append((y+1,x))
                if is_en((y,x-1)):
                    n.append((y,x-1))
                if is_en((y,x+1)):
                    n.append((y,x+1))
                    
                P.neighbor[(y,x)] = n
Метод show закрашивает клетку с координатами y,x в нужный цвет.
def show(self, y, x, color):
        lb = Label(text=" ", background = color)
        lb.configure(text=P.hierarchy[(y,x)] )
        lb.grid(row=self.y, column=self.x, ipadx=10, ipady=5, padx=1, pady=1)
Метод move передвигает объект. В переменные y, x записываем координату соседа, которая выбрана случайно из списка соседей. Потом перерисовываем с новыми координатами.
Увеличиваем счётчик. Проверяем достигнута ли цель. Если цель достигнута, то в переменную класса J.disable записываем верно. Вызываем метод top_show().
def move(self):
        v = []
        for i in P.neighbor[(self.y, self.x)]:
            v.append(i)    
        y,x = random.choice(v)
        
        self.show(self.y, self.x, 'white')    
        self.y = y
        self.x = x
        self.show(y, x, self.color)
        
        self.count +=1
        
        if P.target == P.hierarchy[(self.y, self.x)]:
            J.disable = True
            self.top_show()
Метод update вызывает move и обновляет через каждые пол секунды.
def update(self):
        self.move()   
        self.root.after(500, self.update)
Метод top_show выводит результаты.
def top_show(self):
        top = Toplevel()
        lbt = Label(top, text=self.color + " = " + str(self.count))
        lbt.pack()
        top.mainloop()
2.2. Класс М – случайный поиск с памятью
Конструктор вызывает конструктор класса родителя и увеличивает значение той клетки поля, куда идём. Метод move передвигает объект. Метод choice возвращает координату, которую выбрал алгоритм случайного поиска с памятью.
В методе move вызываем метод choice. В остальном его работа аналогична методу родителя.
def move(self):
        yx = self.choice((self.y, self.x))
Метод choice перебирает координаты соседей и добавляет в список v кортежи. Первым элементом кортежа будет координата соседа, вторым — сколько раз она была посещена. Потом сортируем от маленького до большого. Перебираем все кортежи и в списке v оставляем только те, которые встречались столько раз, сколько записано в первом кортеже. Случайно выбираем любой из них.
def choice(self, yx):
        v = []
        for i in P.neighbor[yx]:
            v.append((i, self.visit[i])) 
            
        v.sort(key = lambda x: x[1], reverse = False)
        v = [i for i in v if v[0][1] == i[1]]
        v = random.choice(v)
        self.visit[v[0]] += 1
        return v[0]
2.3. Класс N – случайный поиск с памятью и иерархией.
Метод choice отбирает те кортежи, которые больше всего совпадают с иерархическим именем цели. Если это совпадение одинаково, то отбираются те координаты, которые меньше всего были посещены.
Конструктор вызывает конструктор родителя и инициализирует атрибут coincidence количество посимвольных совпадений иерархического имени с целью.
def __init__(self, root, color, node, target, maps, ban):
        super().__init__(root, color, node, target, maps, ban)
        self.coincidence = 0
Метод choice в цикле записывает иерархическое имя текущей координаты соседа. Переменная r хранит количество совпадений этой переменной c целью. Если количество совпадений r больше, то coincidence перезаписывается. В этом случае в список d записывается кортеж (координаты, количество посещений) из списка v. Если же r равно coincidence, то в d добавляем кортеж из v.
def choice(self, yx):
        v = []
        for i in P.neighbor[yx]:
            v.append((i, self.visit[i]))
             
        d = []
        for l in v:
            c = P.hierarchy[l[0]]
            
            r = 0
            for i in range(len(P.target)):
                if c[i] == P.target[i]:
                    r +=1
                else: break 
                
            if r > self.coincidence:
                self.coincidence = r
                d = [l]
            if r == self.coincidence:
                d.append(l)
        
        if d: v = d 
           
        v.sort(key = lambda x: x[1], reverse = False)
        v = [i for i in v if v[0][1] == i[1]]
        v = random.choice(v)
        self.visit[v[0]] += 1
        return v[0]   
2.4. Класс К – поиск маршрута и поиск самого короткого маршрута.
Конструктор в переменную end записывает координаты цели. Если параметр short равен False, то вызываем поиск маршрута. Иначе находим самый короткий маршрут.
Метод find_path в маршрут добавляет текущую координату. Если цель достигнута, тогда возвращает маршрут. Перебираем всех соседей. Если соседа нет в path, тогда рекурсивно вызываем себя. И то, что метод возвращает, записываем в newpath. Первым найденным маршрутом будет newpath. Отличие метода find_short_path в том, что, если длина newpath больше или равна длине shortest, тогда shortest перезаписывается.
def find_path(self, node, end, path=[]):
        path = path + [node]
        if node == end:
            return path
            
        for v in P.neighbor[node]:
            if v not in path:
                newpath = self.find_path(v, end, path)
                if newpath: 
                    return newpath
2.5. Класс J – подвижная цель.
Объект класса J передвигается как класс P. Если переменная класса J.disable равна верно, то объект останавливается.
2.6. Функция main.
Создаём главное окно. В переменную target записываем иерархическое имя цели. В список ban записаны координаты запретных клеток. В списке maps – сама карта. В цикле рисуем карту. Создаём объекты класса. Потом вызываем функцию update, которая обновляет объекты.
3. Выводы
Были проведены пять экспериментов как для подвижной цели, так и для неподвижной.
Из таблицы 1 видно, что самый лучший алгоритм – самый короткий маршрут. Второй по эффективности — это случайный поиск с памятью и иерархией. Худший – случайный поиск.
Таблица 1. Неподвижная цель

В случае подвижной цели результаты иные. Худшими стали те алгоритмы, которые изначально рассчитывали маршрут до цели. В таблице 2 прочерк означает, что цель не достигнута. Brown оказался хуже, чем Violet. Хуже, поскольку у Violet траектория длиньше (шанс встретить подвижную цель больше). Самый лучший алгоритм при поиске подвижной цели — случайный поиск с памятью и иерархией. На втором месте — случайный поиск с памятью.
Таблица 2. Подвижная цель

Если неизвестно подвижна ли цель или нет, то лучше использовать алгоритм случайный поиск с памятью и иерархией либо просто случайный поиск с памятью.
4. Заключение
Случайность важна, если поиск цели происходит в условиях неизвестности. Поиск сокращается, если данные представлены иерархично. Память, разумеется, тоже ценна.
Комментарии (9)
 - Griboks09.12.2019 20:59- Это вам лень было лабу печатать для препода, и вы залили её часть с картинками на хабр? 
 1. Условие задачи неизвестно.
 2. Подвижная цель меняет свои координаты? Или в чём заключается её подвижность?
 3. Способы решения также неизвестны, есть только какой-то странный код с непонятными переменными.
 4. Критерия сравнения нет.
 5. Выводы бесполезны без конкретных допущений и ограничений.
 - akryukov10.12.2019 07:43+1- Какой-то преподаватель хочет завести личную армию ботов? 
 Кто вообще плюсует этот поток сознания? За что?
 - Nastya_07 Автор10.12.2019 12:44- Можно усложнить (на будущее): 
 1) задавать словарь соседей динамически (так реалистичней)
 2) Сами области (иерархические) могут передвигаться (а не только отдельный объект)
 
 P.S. В более широком смысле, под передвижением можно иметь ввиду смену состояний (а не только смену координат)
 
           
 
vilgeforce
Что и зачем ищется — не ясно
Nastya_07 Автор
В статье же говорится, что сравниваются способы достижения цели.
Целью служит иерархическое имя (target '122' — в тестовом варианте)
Насколько мне известно, такие способы (алгоритмы) не применяются.
Имеется ввиду (случайный поиск с памятью, случайный поиск с памятью и иерархией).
Остальные — приведены для сравнения.
P.S. Никакого отношения к институту не имею.
vilgeforce
У меня вот цель — найти эффективный алгоритм факторизации в целых числах. Судя по тому что вы сравниваете способы достижения цели — один из них определенно позволит ее достичь, да?
Nastya_07 Автор
Нет.
Неужели не замечали за собой как ищем, например, потерянную вещь дома, просматривая одни и те же места?
Или как собака, к примеру, находит кого-то, идя по следу?
vilgeforce
Неужели не замечали что «цели» бывают разными у разных людей? А если вам пишут разные люди «нифига не понятно» — наверное и в самом деле не понятно нифига?
Nastya_07 Автор
Ну, главное чтобы работало. А код работает.… Первое всегда трудно. Хотя, если вникнуть, всё очень просто (даже слишком).