Алгоритм решения лабиринта Хаскелла
Я пытаюсь реализовать решатель лабиринта, основанный на алгоритме, описанном в приведенной ниже ссылке в Haskell.
Http://www.cs.bu.edu/teaching/alg/maze/
Я довольно новичок в Хаскелле и функциональном программировании, и я в основном пытаюсь кодировать алгоритм, как описано в ссылке, я пытался пройти через многие другие ресурсы в интернете, но я застрял в той части, где ходьба останавливается, когда цель (она не останавливается, она возвращается к началу) достигнута, и я не могу найти ее. чтобы снять отметку с плохих позиций в лабиринте.
Лабиринт выглядит как
.########
.......#.
#.####..#
#.#######
...#.G...
##...####
#..######
Мой код выглядит следующим образом
findPath :: Int->Int->Maze->(Bool,Maze)
findPath x y maze
| not (isSafe maze x y) = (False,maze)
| isChar maze x y 'G' = trace ("Solution: "++ show maze)(True,maze)
| isChar maze x y '#' = (False,maze)
| isChar maze x y '!' = (False,maze)
| fst walkNorth = (True,markedList)
| fst walkEast = (True,markedList)
| fst walkSouth = (True,markedList)
| fst walkWest = (True,markedList)
| otherwise = (False,unMarkedList)
where markedList = replaceCharInMaze maze x y '+'
unMarkedList = replaceCharInMaze maze x y '!'
walkNorth = findPath x (y-1) markedList
walkEast = findPath (x+1) y markedList
walkSouth = findPath x (y+1) markedList
walkWest = findPath (x-1) y markedList
Функция isSafe просто проверяет границы, isChar-это просто совпадение символов в заданной позиции x, y,а функция replaceCharInMaze заменяет символ в позиции x,y на заданный символ.
isSafe :: [String]->Int->Int->Bool
isSafe list x y
| y >= 0 && y < length (head list) && x >= 0 && x < length list && (isChar list xy '.' || isChar list x y 'G') = True
| otherwise = False
Итак, у меня есть две проблемы
-
Я не могу настаивать на том, чтобы не-маркировка делалась в противном случае до следующего случая вызов рекурсии, как мне сохранить состояние лабиринта, чтобы даже незамеченное состояние было частью решения?
-
Затем, по мере продвижения алгоритма, он идет до цели и возвращается к началу, как остановить это?
Поскольку я новичок в Haskell и алгоритмах, я заглянул в такие темы, как монады состояний has, которые, казалось бы, были похожи на решение, но я не совсем уверен, что продолжу его, я также попытался заглянуть в другой стек переполнение сообщений, но не смог найти ничего, что помогло бы мне.
Выходные данные для лабиринта, полученные в ходе трассировки, выглядят следующим образом
+++#..###..#.
.#+++#+++.##.
####+#+#+#-##
...#+++#+#...
.#.####++.##.
.#G+++++#....
.############
....####.....
Но он не останавливается на этом, он возвращается к началу координат и выводит результат в виде
+..#..###..#.
.#...#....##.
####.#.#.#.##
...#...#.#...
.#.####...##.
.#G.....#....
.############
....####.....
1 ответ:
Вот что происходит, когда вы запускаете программу с вашим примером. Первые четыре охранника явно фальшивые, так что до этого момента мало что происходит. Он вычисляет
walkNorth, рекурсируя один раз, чтобы найти, чтоfst walkNorthтакже ложно. Затем он оцениваетwalkEast, что занимает некоторое время, так как в конечном итоге это приводит к цели. Он находит, чтоfst walkEastистинно, поэтому он возвращает(True,markedList). Важно понимать, чтоmarkedListв возвращаемой паре был "помечен" только один раз (следовательно, в вашем списке есть один"+"). выход). На пути к цели происходит много "отметок", но они не видны оттуда, откуда программа возвращает свой вывод. Каждый раз, когда вы передаетеmarkedListв одну из функцийwalkXXX, вы, по сути, создаете новый список с дополнительной маркировкой, которую можно увидеть только в вызове функции, в которую вы его передаете. На самом деле вам нужен лабиринт с отметками в том месте, где он был решен. В конце дня функцииwalkXXXлибо возвращают(False,maze), когда хождение в направлении XXX не приводит к цели (потому что 1-й или 3-й охранник оценивает как True), или(True,maze), Если это действительно приводит к цели (2-й охранник оценивает как True), в этом случаеmazeв этой точке будет иметь все правильные отметки. Поэтому вместо возвратаmarkedListдля случаевfst walkXXXвозвращайтеsnd walkXXX. то естьВаш первый вопрос немного запутан. Я думаю, что вы хотите изменить свои определения| fst walkNorth = (True,snd walkNorth) | walkEast = (True,snd walkEast) | walkSouth = (True,snd walkSouth) | walkWest = (True,snd walkWest)walkXXXна что-то очень грубо похожее это:И я позволю тебе заполнить последнюю. Если вы идете на восток, вы знаете, что вы пробовали идти на север и не нашли цель, поэтому вы можете снять ее и так далее. (Это не совсем сработает, по крайней мере, потому что он, вероятно, попытается заменить стены и персонажей за пределами лабиринта, но идея есть.) Вы, кажется, еще не привыкли к отсутствию у Хаскелла изменчивого состояния и частой рекурсии. Некоторые другие вещи (я не уверен в этом они): я не думаю, что ваш случайwalkNorth = findPath x (y-1) markedList walkEast = findPath (x+1) y (replaceCharInMaze markedList x (y-1)) walkSouth = findPath x (y+1) (replaceCharInMaze (replaceCharInMaze markedList x (y-1)) (x+1) y)otherwiseкогда-либо работает, и он действительно ничего не делает-попробуйте вынуть его и посмотреть, что произойдет; я также не думаю, чтоTrues в ваших парах(True,markedList)когда-либо имеют какой-либо эффект-попробуйте изменить их на False.