mirror of
https://codeberg.org/andyscott/2D-Puzzle-Solver.git
synced 2024-12-21 11:33:10 -05:00
Added Puzzle.py
This commit is contained in:
parent
8dea1ccff0
commit
2671d317ff
1 changed files with 140 additions and 0 deletions
140
Puzzle.py
Normal file
140
Puzzle.py
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
from typing import Deque
|
||||||
|
|
||||||
|
|
||||||
|
def solve_puzzle(Board: list, Source: tuple, Destination: tuple):
|
||||||
|
"""Finds a solution to a 2-D puzzle using a breadth first search
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
Board : list
|
||||||
|
A graph represented as an adjacency matrix
|
||||||
|
Source : tuple
|
||||||
|
The starting point on the board
|
||||||
|
Destination : tuple
|
||||||
|
The goal position
|
||||||
|
"""
|
||||||
|
|
||||||
|
queue = Deque()
|
||||||
|
queue.append(Source)
|
||||||
|
visited = {}
|
||||||
|
|
||||||
|
if is_valid(Source[0], Source[1], Board, visited):
|
||||||
|
visited[Source] = 0
|
||||||
|
if Source == Destination:
|
||||||
|
return [Destination]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
while len(queue) > 0:
|
||||||
|
r, c = queue.popleft()
|
||||||
|
possible_moves = [(1, 0), (0, 1), (-1, 0), (0, -1)]
|
||||||
|
for move_row, move_col in possible_moves:
|
||||||
|
row, col = r + move_row, c + move_col
|
||||||
|
if is_valid(row, col, Board, visited):
|
||||||
|
queue.append((row, col))
|
||||||
|
visited[(row, col)] = visited[(r, c)] + 1
|
||||||
|
if (row, col) == Destination:
|
||||||
|
return get_path(row, col, visited)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def is_valid(x: int, y: int, Board: list, visited: dict) -> bool:
|
||||||
|
"""Helper for solve_puzzle() to determine if a move is valid
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
x : int
|
||||||
|
Row
|
||||||
|
y : int
|
||||||
|
Column
|
||||||
|
Board : list
|
||||||
|
A graph represented as an adjacency matrix
|
||||||
|
visited : dict
|
||||||
|
Coordinates that have been visited
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
bool
|
||||||
|
True if the move is valid, otherwise False
|
||||||
|
"""
|
||||||
|
|
||||||
|
exists = False
|
||||||
|
valid = False
|
||||||
|
|
||||||
|
if (x >= 0 and y >= 0) and (x < len(Board) and y < len(Board[0])):
|
||||||
|
exists = True
|
||||||
|
|
||||||
|
target = (x, y)
|
||||||
|
if exists:
|
||||||
|
if Board[x][y] != "#" and target not in visited:
|
||||||
|
valid = True
|
||||||
|
|
||||||
|
return valid and exists
|
||||||
|
|
||||||
|
|
||||||
|
def get_path(row: int, col: int, visited: dict) -> tuple:
|
||||||
|
"""Helper for solve_puzzle() to assemble the steps and moves into lists
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
row : int
|
||||||
|
Row on the board
|
||||||
|
col : int
|
||||||
|
Column on the board
|
||||||
|
visited : dict
|
||||||
|
Coordinates that have been visited
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
tuple
|
||||||
|
List of tuples containing coordinates traversed, and list of directions
|
||||||
|
"""
|
||||||
|
|
||||||
|
steps = visited[(row, col)]
|
||||||
|
steps -= 1
|
||||||
|
path = [(row, col)]
|
||||||
|
directions = []
|
||||||
|
|
||||||
|
while steps >= 0:
|
||||||
|
if (row - 1, col) in visited and visited[(row - 1, col)] == steps:
|
||||||
|
path.append((row - 1, col))
|
||||||
|
directions.append("D")
|
||||||
|
row -= 1
|
||||||
|
if (row + 1, col) in visited and visited[(row + 1, col)] == steps:
|
||||||
|
path.append((row + 1, col))
|
||||||
|
directions.append("U")
|
||||||
|
row += 1
|
||||||
|
if (row, col - 1) in visited and visited[(row, col - 1)] == steps:
|
||||||
|
path.append((row, col - 1))
|
||||||
|
directions.append("R")
|
||||||
|
col -= 1
|
||||||
|
if (row, col + 1) in visited and visited[(row, col + 1)] == steps:
|
||||||
|
path.append((row, col + 1))
|
||||||
|
directions.append("L")
|
||||||
|
col += 1
|
||||||
|
steps -= 1
|
||||||
|
|
||||||
|
path.reverse()
|
||||||
|
directions.reverse()
|
||||||
|
return (path, directions)
|
||||||
|
|
||||||
|
|
||||||
|
# ------------------------------ Basic Testing --------------------------------#
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
puzzle = [
|
||||||
|
["-", "-", "-", "-", "-"],
|
||||||
|
["-", "-", "#", "-", "-"],
|
||||||
|
["-", "-", "-", "-", "-"],
|
||||||
|
["#", "-", "#", "#", "-"],
|
||||||
|
["-", "#", "-", "-", "-"],
|
||||||
|
]
|
||||||
|
|
||||||
|
source = (0, 2)
|
||||||
|
destination = (2, 2)
|
||||||
|
# source = (0, 0)
|
||||||
|
# destination = (4, 4)
|
||||||
|
result = solve_puzzle(puzzle, source, destination)
|
||||||
|
print(result)
|
Loading…
Reference in a new issue