def find_shortest_path(grid, start_node, end_node):
marked_grid = [[None for i in range(len(j))] for j in grid]
step = 0
current_wave = [start_node]
manhattan_distance = ((-1, 0), (1, 0), (0, -1), (0, 1))
def generate_new_wave(current, new_wave):
possible_steps = list(filter(lambda x: -1 not in x and len(marked_grid) not in x
and marked_grid[x[0]][x[1]] is None
and x not in new_wave,
[tuple(map(lambda x, y: x + y, current, n)) for n in manhattan_distance]))
for step in possible_steps:
yield step
def build_new_wave():
new_wave = []
for current in current_wave:
marked_grid[current[0]][current[1]] = step
for drop in generate_new_wave(current, new_wave):
new_wave.append(drop)
return new_wave
while marked_grid[end_node[0]][end_node[1]] is None:
if len(current_wave) == 0:
step += 1
return False
current_wave = build_new_wave()
step += 1
recovered_path = []
step -= 1
while step != 0:
recovered_path.append(end_node)
for n in manhattan_distance:
candidate = tuple(map(lambda x, y: x + y, end_node, n))
try:
if marked_grid[candidate[0]][candidate[1]] == step - 1:
end_node = candidate
step -= 1
break
except IndexError:
pass
return list(reversed(recovered_path + [start_node]))
grid = [[(0,0), (0,1), (0,2), (0,3), (0,4)],
[(1,0), (1,1), (1,2), (1,3), (1,4)],
[(2,0), (2,1), (2,2), (2,3), (2,4)],
[(3,0), (3,1), (3,2), (3,3), (3,4)],
[(4,0), (4,1), (4,2), (4,3), (4,4)]
]
start_node = (0, 0)
end_node = (4, 4)
print(find_shortest_path(grid, start_node, end_node))
ZGVmIGZpbmRfc2hvcnRlc3RfcGF0aChncmlkLCBzdGFydF9ub2RlLCBlbmRfbm9kZSk6CiAgICBtYXJrZWRfZ3JpZCA9IFtbTm9uZSBmb3IgaSBpbiByYW5nZShsZW4oaikpXSBmb3IgaiBpbiBncmlkXQogICAgc3RlcCA9IDAKICAgIGN1cnJlbnRfd2F2ZSA9IFtzdGFydF9ub2RlXQogICAgbWFuaGF0dGFuX2Rpc3RhbmNlID0gKCgtMSwgMCksICgxLCAwKSwgKDAsIC0xKSwgKDAsIDEpKQoKICAgIGRlZiBnZW5lcmF0ZV9uZXdfd2F2ZShjdXJyZW50LCBuZXdfd2F2ZSk6CiAgICAgICAgcG9zc2libGVfc3RlcHMgPSBsaXN0KGZpbHRlcihsYW1iZGEgeDogLTEgbm90IGluIHggYW5kIGxlbihtYXJrZWRfZ3JpZCkgbm90IGluIHgKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbmQgbWFya2VkX2dyaWRbeFswXV1beFsxXV0gaXMgTm9uZQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFuZCB4IG5vdCBpbiBuZXdfd2F2ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFt0dXBsZShtYXAobGFtYmRhIHgsIHk6IHggKyB5LCBjdXJyZW50LCBuKSkgZm9yIG4gaW4gbWFuaGF0dGFuX2Rpc3RhbmNlXSkpCiAgICAgICAgZm9yIHN0ZXAgaW4gcG9zc2libGVfc3RlcHM6CiAgICAgICAgICAgIHlpZWxkIHN0ZXAKCiAgICBkZWYgYnVpbGRfbmV3X3dhdmUoKToKICAgICAgICBuZXdfd2F2ZSA9IFtdCiAgICAgICAgZm9yIGN1cnJlbnQgaW4gY3VycmVudF93YXZlOgogICAgICAgICAgICBtYXJrZWRfZ3JpZFtjdXJyZW50WzBdXVtjdXJyZW50WzFdXSA9IHN0ZXAKCiAgICAgICAgICAgIGZvciBkcm9wIGluIGdlbmVyYXRlX25ld193YXZlKGN1cnJlbnQsIG5ld193YXZlKToKICAgICAgICAgICAgICAgIG5ld193YXZlLmFwcGVuZChkcm9wKQoKICAgICAgICByZXR1cm4gbmV3X3dhdmUKCiAgICB3aGlsZSBtYXJrZWRfZ3JpZFtlbmRfbm9kZVswXV1bZW5kX25vZGVbMV1dIGlzIE5vbmU6CiAgICAgICAgaWYgbGVuKGN1cnJlbnRfd2F2ZSkgPT0gMDoKICAgICAgICAgICAgc3RlcCArPSAxCiAgICAgICAgICAgIHJldHVybiBGYWxzZQoKICAgICAgICBjdXJyZW50X3dhdmUgPSBidWlsZF9uZXdfd2F2ZSgpCiAgICAgICAgc3RlcCArPSAxCgogICAgcmVjb3ZlcmVkX3BhdGggPSBbXQogICAgc3RlcCAtPSAxCgogICAgd2hpbGUgc3RlcCAhPSAwOgogICAgICAgIHJlY292ZXJlZF9wYXRoLmFwcGVuZChlbmRfbm9kZSkKICAgICAgICBmb3IgbiBpbiBtYW5oYXR0YW5fZGlzdGFuY2U6CiAgICAgICAgICAgIGNhbmRpZGF0ZSA9IHR1cGxlKG1hcChsYW1iZGEgeCwgeTogeCArIHksIGVuZF9ub2RlLCBuKSkKICAgICAgICAgICAgdHJ5OgogICAgICAgICAgICAgICAgaWYgbWFya2VkX2dyaWRbY2FuZGlkYXRlWzBdXVtjYW5kaWRhdGVbMV1dID09IHN0ZXAgLSAxOgogICAgICAgICAgICAgICAgICAgIGVuZF9ub2RlID0gY2FuZGlkYXRlCiAgICAgICAgICAgICAgICAgICAgc3RlcCAtPSAxCiAgICAgICAgICAgICAgICAgICAgYnJlYWsKICAgICAgICAgICAgZXhjZXB0IEluZGV4RXJyb3I6CiAgICAgICAgICAgICAgICBwYXNzCiAgICAgICAgICAgIAogICAgcmV0dXJuIGxpc3QocmV2ZXJzZWQocmVjb3ZlcmVkX3BhdGggKyBbc3RhcnRfbm9kZV0pKQoKCmdyaWQgPSBbWygwLDApLCAoMCwxKSwgKDAsMiksICgwLDMpLCAoMCw0KV0sCiAgICAgICAgWygxLDApLCAoMSwxKSwgKDEsMiksICgxLDMpLCAoMSw0KV0sCiAgICAgICAgWygyLDApLCAoMiwxKSwgKDIsMiksICgyLDMpLCAoMiw0KV0sCiAgICAgICAgWygzLDApLCAoMywxKSwgKDMsMiksICgzLDMpLCAoMyw0KV0sCiAgICAgICAgWyg0LDApLCAoNCwxKSwgKDQsMiksICg0LDMpLCAoNCw0KV0KICAgICAgICBdCgpzdGFydF9ub2RlID0gKDAsIDApCmVuZF9ub2RlID0gKDQsIDQpCgpwcmludChmaW5kX3Nob3J0ZXN0X3BhdGgoZ3JpZCwgc3RhcnRfbm9kZSwgZW5kX25vZGUpKQ==