Есть несколько решений для этого. Я бы предложил сначала преобразовать сетку в более объектно-ориентированную структуру, то есть ненаправленный граф с узлами, для которых на входе присутствуют единицы.
Тогда я бы выделил три вида ребер на этом графике:
- Те, где одна из конечных точек находится по диагонали («специальные» ребра)
- Те, где вышеприведенное неверно, но узлы находятся в одной строке
- Те, где вышеприведенное неверно, но узлы находятся в одном столбце
При повторении вы всегда должны учитывать специальные ребра, и в дополнение к этому ребра, которые находятся в одном из двух других наборов ребер (на основе предыдущего принятого направления).
Вот реализация:
class Node:
def __init__(self, y, x, size):
self.x = x
self.y = y
self.coord = (y, x)
self.diagonal = x == y or size - 1 - y
# Separate lists of neighbors: vertical, horizontal.
# Third list is for when this node or neighbor is on diagonal
self.neighbors = [[], [], []]
def addNeighbor(self, node, direction):
self.neighbors[direction].append(node)
class Maze:
def __init__(self, grid):
def addedge(a, b):
direction = 2 if a.diagonal or b.diagonal else int(a.x == b.x)
a.addNeighbor(b, direction)
b.addNeighbor(a, direction)
# alternative grid having Node references:
self.nodes = [[None] * len(grid) for _ in grid]
colNodes = [[] for _ in grid]
for y, row in enumerate(grid):
rowNodes = []
for x, cell in enumerate(row):
if cell: # only create nodes for when there is a 1 in the grid
node = Node(y, x, len(grid))
for neighbor in rowNodes + colNodes[x]:
addedge(node, neighbor)
rowNodes.append(node)
colNodes[x].append(node)
self.nodes[y][x] = node
def findpath(self, y, x):
def recur(node, neighbors):
visited.add(node)
longest = [node.coord]
# always visit "special" neighbors
# (i.e. those on diagonal or all vert/horiz when node is on diagonal)
for neighbor in node.neighbors[2] + neighbors:
if not neighbor in visited:
# toggle direction when going further
path = recur(neighbor, node.neighbors[1-int(node.x == neighbor.x)])
if len(path) >= len(longest):
longest = [node.coord] + path
visited.remove(node)
return longest
node = self.nodes[y][x]
if not node:
raise "Cannot start from that position"
visited = set()
# look in both directions of starting node
return recur(node, node.neighbors[0] + node.neighbors[1])
grid = [
[0, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[1, 1, 1, 0, 0],
[0, 0, 0, 0, 0],
[1, 0, 0, 1, 0]
]
maze = Maze(grid)
path = maze.findpath(2, 0)
print(path) # output: [(2, 0), (2, 2), (2, 1), (1, 1)]
path = maze.findpath(4, 3)
print(path) # output: [(4, 3), (4, 0), (2, 0), (2, 2), (2, 1), (1, 1)]
Обратите внимание, что координаты в этом решении начинаются с нуля, поэтому первая строка имеет номер 0 и т. Д.
Посмотреть, как он работает на repl.it