2022-04-11 00:01:57 +02:00
|
|
|
from __future__ import annotations
|
|
|
|
from typing import List
|
|
|
|
|
|
|
|
from common.constants import ACTION, Direction, ROWS, COLUMNS
|
|
|
|
|
|
|
|
|
|
|
|
class State:
|
|
|
|
def __init__(self, row, column, direction):
|
|
|
|
self.row = row
|
|
|
|
self.column = column
|
|
|
|
self.direction = direction
|
|
|
|
|
|
|
|
|
|
|
|
class Node:
|
|
|
|
def __init__(self, state, parent=None, action=None):
|
|
|
|
self.state = state
|
|
|
|
self.parent = parent
|
|
|
|
self.action = action
|
|
|
|
|
|
|
|
|
2022-04-11 12:56:22 +02:00
|
|
|
def goal_test(goal_list, state: State):
|
|
|
|
if (state.row, state.column) in goal_list:
|
2022-04-11 00:01:57 +02:00
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
def get_successors(state: State, map):
|
|
|
|
successors = list()
|
|
|
|
|
2022-04-11 12:00:15 +02:00
|
|
|
state_left = State(state.row, state.column, state.direction.left())
|
2022-04-11 00:01:57 +02:00
|
|
|
successors.append((ACTION.get("rotate_left"), state_left))
|
|
|
|
|
2022-04-11 12:00:15 +02:00
|
|
|
state_right = State(state.row, state.column, state.direction.right())
|
2022-04-11 00:01:57 +02:00
|
|
|
successors.append((ACTION.get("rotate_right"), state_right))
|
|
|
|
|
|
|
|
target = go(state.row, state.column, state.direction)
|
|
|
|
|
|
|
|
if is_valid_move(map, target[0], target[1]):
|
|
|
|
state_go = State(target[0], target[1], state.direction)
|
|
|
|
successors.append((ACTION.get("go"), state_go))
|
|
|
|
|
|
|
|
return successors
|
|
|
|
|
|
|
|
|
2022-04-11 13:13:03 +02:00
|
|
|
def graphsearch(initial_state: State, map, goal_list, fringe: List[Node] = None, explored: List[Node] = None):
|
2022-04-11 00:01:57 +02:00
|
|
|
# fringe and explored initialization
|
|
|
|
if fringe is None:
|
|
|
|
fringe = list()
|
|
|
|
if explored is None:
|
|
|
|
explored = list()
|
|
|
|
explored_states = set()
|
|
|
|
fringe_states = set()
|
|
|
|
|
|
|
|
# root Node
|
|
|
|
fringe.append(Node(initial_state))
|
|
|
|
fringe_states.add((initial_state.row, initial_state.column, initial_state.direction))
|
|
|
|
|
|
|
|
while True:
|
|
|
|
# fringe empty -> solution not found
|
|
|
|
if not any(fringe):
|
|
|
|
print("Brak rozwiazania")
|
|
|
|
return []
|
|
|
|
|
|
|
|
# get first element from fringe
|
|
|
|
element = fringe.pop(0)
|
|
|
|
fringe_states.remove((element.state.row, element.state.column, element.state.direction))
|
|
|
|
|
|
|
|
# if solution was found, prepare and return actions sequence
|
2022-04-11 12:56:22 +02:00
|
|
|
if goal_test(goal_list, element.state):
|
2022-04-11 00:01:57 +02:00
|
|
|
actions_sequence = [element.action]
|
|
|
|
parent = element.parent
|
|
|
|
|
|
|
|
while parent is not None:
|
|
|
|
# root's action will be None, don't add it
|
|
|
|
if parent.action is not None:
|
|
|
|
actions_sequence.append(parent.action)
|
|
|
|
parent = parent.parent
|
|
|
|
|
|
|
|
actions_sequence.reverse()
|
|
|
|
return actions_sequence
|
|
|
|
|
|
|
|
# add current node to explored (prevents infinite cycles)
|
|
|
|
explored.append(element)
|
|
|
|
explored_states.add((element.state.row, element.state.column, element.state.direction))
|
|
|
|
|
|
|
|
# loop through every possible next action
|
|
|
|
for successor in get_successors(element.state, map):
|
|
|
|
|
|
|
|
# make sure not to fall into a cycle
|
|
|
|
successor_state = (successor[1].row, successor[1].column, successor[1].direction)
|
2022-04-11 12:00:15 +02:00
|
|
|
if successor_state not in fringe_states and successor_state not in explored_states:
|
2022-04-11 00:01:57 +02:00
|
|
|
# create new Node and add it at the end of fringe
|
|
|
|
new_node = Node(state=successor[1],
|
|
|
|
parent=element,
|
|
|
|
action=successor[0])
|
|
|
|
fringe.append(new_node)
|
|
|
|
fringe_states.add((new_node.state.row, new_node.state.column, new_node.state.direction))
|
|
|
|
|
|
|
|
|
|
|
|
# TEMPORARY METHOD
|
|
|
|
def go(row, column, direction):
|
|
|
|
target = tuple()
|
|
|
|
|
|
|
|
if direction == Direction.RIGHT:
|
|
|
|
target = row, column + 1
|
|
|
|
elif direction == Direction.LEFT:
|
|
|
|
target = row, column - 1
|
|
|
|
elif direction == Direction.UP:
|
|
|
|
target = row - 1, column
|
|
|
|
elif direction == Direction.DOWN:
|
|
|
|
target = row + 1, column
|
|
|
|
|
|
|
|
return target
|
|
|
|
|
|
|
|
|
|
|
|
def is_valid_move(map, target_row, target_column):
|
2022-04-11 12:08:03 +02:00
|
|
|
if 0 <= target_row < ROWS and 0 <= target_column < COLUMNS and map[target_row][target_column] == ' ':
|
2022-04-11 00:01:57 +02:00
|
|
|
return True
|
|
|
|
|
|
|
|
return False
|