222 lines
8.7 KiB
Python
222 lines
8.7 KiB
Python
|
import solver.astar
|
||
|
import logic.searcher
|
||
|
import map.moveable
|
||
|
import map.box
|
||
|
|
||
|
|
||
|
class Solver:
|
||
|
def __init__(self, player):
|
||
|
self.player = player
|
||
|
self.astar = solver.astar.Astar(player.entity_mapper.mapper.grid_file)
|
||
|
self.boxs_to_place = set(logic.searcher.Searcher.get_coords_box_to_place_from_map(player.entity_mapper.grid_of_sprites))
|
||
|
self.dots = set(logic.searcher.Searcher.get_coords_dots_from_map(player.entity_mapper.grid_of_sprites))
|
||
|
|
||
|
def get_box_near_player(self):
|
||
|
player_node = self.astar.get_node(self.player.position[0], self.player.position[1])
|
||
|
near_box_data = [None, None]
|
||
|
|
||
|
for box in self.boxs_to_place:
|
||
|
node_box = self.astar.get_node(box[0], box[1])
|
||
|
heuristic = player_node.heuristic_calc(node_box)
|
||
|
|
||
|
if near_box_data[0] is None or heuristic <= near_box_data[1]:
|
||
|
near_box_data[0] = node_box
|
||
|
near_box_data[1] = heuristic
|
||
|
|
||
|
return near_box_data[0], player_node
|
||
|
|
||
|
def get_dot_near_box(self, box_node):
|
||
|
near_dot_data = [None, None]
|
||
|
for dot in self.dots:
|
||
|
node_dot = self.astar.get_node(dot[0], dot[1])
|
||
|
heuristic = box_node.heuristic_calc(node_dot)
|
||
|
|
||
|
if near_dot_data[0] is None or heuristic <= near_dot_data[1]:
|
||
|
near_dot_data[0] = node_dot
|
||
|
near_dot_data[1] = heuristic
|
||
|
|
||
|
return near_dot_data[0], box_node
|
||
|
|
||
|
def get_symetric_node(self, from_node, to_node):
|
||
|
relative_position = (to_node.x - from_node.x, to_node.y - from_node.y)
|
||
|
return self.astar.get_node(from_node.x - relative_position[0], from_node.y - relative_position[1])
|
||
|
|
||
|
def get_diagonal_node(self, from_node, relative_position):
|
||
|
next_target_pos = [from_node.x + relative_position[0], from_node.y + relative_position[1]]
|
||
|
next_target_pos_temoin = next_target_pos[:]
|
||
|
|
||
|
additive = [1, -1]
|
||
|
if relative_position[1]:
|
||
|
arg = 0
|
||
|
else:
|
||
|
arg = 1
|
||
|
|
||
|
next_target_pos[arg] += additive[0]
|
||
|
next_target = self.astar.get_node(*next_target_pos)
|
||
|
if self.astar.is_obstacle(next_target):
|
||
|
next_target_pos = next_target_pos_temoin
|
||
|
next_target_pos[arg] += additive[1]
|
||
|
next_target = self.astar.get_node(*next_target_pos)
|
||
|
if self.astar.is_obstacle(next_target):
|
||
|
raise Exception("No diagonal available found.", next_target.x, next_target.y)
|
||
|
|
||
|
return next_target
|
||
|
|
||
|
def analyse_path_from_box_to_dot(self, path):
|
||
|
box_node = path[0]
|
||
|
target_dot = path[-1]
|
||
|
path_predecalage = path[:-1]
|
||
|
path_postdecalage = path[1:]
|
||
|
steps = []
|
||
|
history = None
|
||
|
intermediate_target = None
|
||
|
|
||
|
for i in range(len(path_postdecalage)):
|
||
|
try:
|
||
|
previous = path_predecalage[i - 1]
|
||
|
except IndexError:
|
||
|
previous = None
|
||
|
current = path_predecalage[i]
|
||
|
post = path_postdecalage[i]
|
||
|
|
||
|
symetric_node = self.get_symetric_node(current, post)
|
||
|
if self.astar.is_obstacle(symetric_node):
|
||
|
steps = False
|
||
|
if current == box_node:
|
||
|
post.transform_to_obstacle = True
|
||
|
if post == target_dot:
|
||
|
relative_position = (post.x - current.x, post.y - current.y)
|
||
|
intermediate_target = self.get_diagonal_node(current, relative_position)
|
||
|
break
|
||
|
else:
|
||
|
current.transform_to_obstacle = True
|
||
|
elif steps is not False:
|
||
|
bifurcation = self.get_bifurcation_from_path(current, post)
|
||
|
if bifurcation != history:
|
||
|
if history is not None:
|
||
|
steps.extend([{previous: current}, {symetric_node: current}])
|
||
|
history = bifurcation
|
||
|
|
||
|
if i == len(path_postdecalage) - 1 and steps is not False:
|
||
|
steps.append({current: post})
|
||
|
|
||
|
return steps, self.get_symetric_node(path[0], path[1]), intermediate_target
|
||
|
|
||
|
def get_bifurcation_from_path(self, current, post):
|
||
|
relative_position = (post.x - current.x, post.y - current.y)
|
||
|
return self.astar.offsets[relative_position]
|
||
|
|
||
|
def generate_steps(self, box_node, dot_node):
|
||
|
box_node.exception = True
|
||
|
change_target = False
|
||
|
intermediate_target = None
|
||
|
default = True
|
||
|
path_from_box_to_dot_base = []
|
||
|
|
||
|
path_from_box_to_dot = self.astar.solve(box_node, dot_node)
|
||
|
analyse = self.analyse_path_from_box_to_dot(path_from_box_to_dot)
|
||
|
while analyse[0] is False:
|
||
|
if analyse[2]:
|
||
|
param = (box_node, analyse[2])
|
||
|
intermediate_target = analyse[2]
|
||
|
change_target = True
|
||
|
default = False
|
||
|
else:
|
||
|
if change_target:
|
||
|
dot_node.transform_to_obstacle = False
|
||
|
param = (intermediate_target, dot_node, False)
|
||
|
default = False
|
||
|
else:
|
||
|
param = (box_node, dot_node)
|
||
|
default = True
|
||
|
change_target = False
|
||
|
|
||
|
path_from_box_to_dot = self.astar.solve(*param)
|
||
|
self.astar.reset_grid_calcul_data()
|
||
|
|
||
|
if not default:
|
||
|
path_from_box_to_dot_base.extend(path_from_box_to_dot)
|
||
|
if change_target is False:
|
||
|
analyse = self.analyse_path_from_box_to_dot(path_from_box_to_dot_base)
|
||
|
else:
|
||
|
analyse = False, None, None
|
||
|
else:
|
||
|
path_from_box_to_dot_base = []
|
||
|
analyse = self.analyse_path_from_box_to_dot(path_from_box_to_dot)
|
||
|
|
||
|
self.astar.reset_grid_data()
|
||
|
return analyse
|
||
|
|
||
|
def path_for_player_to_join_adjacent_box(self, player_node, adjacent_box_node):
|
||
|
path = self.astar.solve(player_node, adjacent_box_node, include_coords_start=False)
|
||
|
self.astar.reset_grid_calcul_data()
|
||
|
return path
|
||
|
|
||
|
def get_path_from_steps(self, steps, box_node):
|
||
|
box_node.exception = True
|
||
|
path = []
|
||
|
|
||
|
for i, step_dict in enumerate(steps, start=1):
|
||
|
goal = tuple(step_dict.keys())[0]
|
||
|
box = step_dict[goal]
|
||
|
if i % 2 == 0:
|
||
|
box.transform_to_obstacle = True
|
||
|
player_node = self.astar.get_node(self.player.position[0], self.player.position[1])
|
||
|
path.extend(self.astar.solve(player_node, goal, include_coords_start=False))
|
||
|
|
||
|
if path:
|
||
|
self.player.position = path[-1].x, path[-1].y
|
||
|
|
||
|
self.astar.reset_grid_data()
|
||
|
box_node.exception = True
|
||
|
|
||
|
return path
|
||
|
|
||
|
def transform_path_to_direction(self, path):
|
||
|
path_predecalage = path[:-1]
|
||
|
path_postdecalage = path[1:]
|
||
|
path = []
|
||
|
|
||
|
for i in range(len(path_postdecalage)):
|
||
|
current = path_predecalage[i]
|
||
|
post = path_postdecalage[i]
|
||
|
relative_position = (post.x - current.x, post.y - current.y)
|
||
|
path.append(getattr(map.moveable.DIRECTION, self.astar.offsets[relative_position]))
|
||
|
|
||
|
return path
|
||
|
|
||
|
def get_full_path(self):
|
||
|
full_path = []
|
||
|
|
||
|
while self.dots and self.boxs_to_place:
|
||
|
near_box_from_player = self.get_box_near_player()
|
||
|
near_dot_from_box = self.get_dot_near_box(near_box_from_player[0])[0]
|
||
|
|
||
|
steps, adjacent_box_node, _ = self.generate_steps(near_box_from_player[0], near_dot_from_box)
|
||
|
|
||
|
path_to_join_adjacent_box = self.path_for_player_to_join_adjacent_box(near_box_from_player[1], adjacent_box_node)
|
||
|
|
||
|
full_path.extend(path_to_join_adjacent_box)
|
||
|
|
||
|
if full_path:
|
||
|
self.player.position = full_path[-1].x, full_path[-1].y
|
||
|
|
||
|
path_from_steps = self.get_path_from_steps(steps, near_box_from_player[0])
|
||
|
|
||
|
full_path.extend(path_from_steps)
|
||
|
|
||
|
self.boxs_to_place.remove((near_box_from_player[0].x, near_box_from_player[0].y))
|
||
|
self.dots.remove((near_dot_from_box.x, near_dot_from_box.y))
|
||
|
self.astar.reset_grid_data()
|
||
|
near_box_from_player[0].character = " "
|
||
|
near_dot_from_box.character = "#"
|
||
|
near_box_from_player[1].character = " "
|
||
|
self.astar.get_node(self.player.position[0], self.player.position[1]).character = "@"
|
||
|
|
||
|
self.player.position = self.player.position_start
|
||
|
full_path.insert(0, self.astar.get_node(self.player.position[0], self.player.position[1]))
|
||
|
self.player.full_path = self.transform_path_to_direction(full_path)
|
||
|
self.player.full_path_temoin = self.player.full_path[:]
|
||
|
|
||
|
return True
|