89 lines
2.6 KiB
Python
89 lines
2.6 KiB
Python
from enum import Enum
|
|
|
|
from survival import GameMap
|
|
from survival.components.position_component import PositionComponent
|
|
from survival.enums import Direction
|
|
|
|
|
|
class Action(Enum):
|
|
ROTATE_LEFT = 0
|
|
ROTATE_RIGHT = 1
|
|
MOVE = 2
|
|
|
|
|
|
class State:
|
|
def __init__(self, position, direction):
|
|
self.position = position
|
|
self.direction = direction
|
|
|
|
|
|
class Node:
|
|
def __init__(self, state: State, parent=None, action=None):
|
|
self.state = state
|
|
self.parent = parent
|
|
self.action = action
|
|
|
|
|
|
def get_moved_position(position, direction):
|
|
vector = Direction.get_vector(direction)
|
|
return position[0] + vector[0], position[1] + vector[1]
|
|
|
|
|
|
def get_states(state: State, game_map: GameMap):
|
|
states = list()
|
|
|
|
states.append((Action.ROTATE_LEFT, State(state.position, state.direction.rotate_left(state.direction))))
|
|
states.append((Action.ROTATE_RIGHT, State(state.position, state.direction.rotate_right(state.direction))))
|
|
|
|
target_state = get_moved_position(state.position, state.direction)
|
|
if not game_map.is_colliding(target_state):
|
|
states.append((Action.MOVE, State(target_state, state.direction)))
|
|
|
|
return states
|
|
|
|
|
|
def graph_search(game_map: GameMap, start: PositionComponent, goal: tuple):
|
|
fringe = list()
|
|
explored = list()
|
|
|
|
explored_states = set()
|
|
fringe_states = set()
|
|
|
|
start = State(start.grid_position, start.direction)
|
|
fringe.append(Node(start))
|
|
fringe_states.add((tuple(start.position), start.direction))
|
|
|
|
while True:
|
|
# No solutions found
|
|
if not any(fringe):
|
|
return []
|
|
|
|
node = fringe.pop(0)
|
|
fringe_states.remove((tuple(node.state.position), node.state.direction))
|
|
|
|
# Check goal
|
|
if node.state.position == goal:
|
|
actions = [node.action]
|
|
parent = node.parent
|
|
|
|
while parent is not None:
|
|
if parent.action is not None:
|
|
actions.append(parent.action)
|
|
parent = parent.parent
|
|
|
|
actions.reverse()
|
|
return actions
|
|
|
|
explored.append(node)
|
|
explored_states.add((tuple(node.state.position), node.state.direction))
|
|
|
|
# Get all possible states
|
|
for state in get_states(node.state, game_map):
|
|
sub_state = (tuple(state[1].position), state[1].direction)
|
|
if sub_state not in fringe_states and sub_state not in explored_states:
|
|
new_node = Node(state=state[1],
|
|
parent=node,
|
|
action=state[0])
|
|
fringe.append(new_node)
|
|
fringe_states.add((tuple(new_node.state.position), new_node.state.direction))
|