import project_constants as const from assets import asset_constants as asset import json from time import sleep from pygame import transform from algorithms.learn.decision_tree.decision_tree import DecisionTree # Class of our agent, initialization of it # movement functions (those defined by the 'go_' prefix are not meant to actually move our agent, they just return some # values that are later used by another function called 'is_valid_move' (which is defined in Minefield)); class Agent: last_action = None new_action = None def __init__(self, json_path): with open(json_path) as json_data: data = json.load(json_data) self.row, self.column = data["agents_initial_state"]["position"].split(",") self.row, self.column = int(self.row), int(self.column) self.position = [self.row, self.column] self.on_screen_coordinates = const.get_tile_coordinates(tuple(self.position)) self.decision_tree = DecisionTree(const.ROOT_DIR + "/algorithms/learn/decision_tree/decision_tree.joblib", const.ROOT_DIR + "/algorithms/learn/decision_tree/dict_vectorizer.joblib") self.direction = const.Direction(data["agents_initial_state"]["direction"]) self.rotation_angle = -const.Direction(self.direction).value * 90 self.going_forward = False self.rotating_left = False self.rotating_right = False def defuse_a_mine(self, mine): mine_params = mine.investigate() chosen_wire = self.decision_tree.get_answer(mine_params) # TODO temporarily printing chosen wire print("agent's chosen wire: " + str(chosen_wire[0])) sleep(3) return mine.disarm(chosen_wire) def update_and_draw(self, window, delta_time, minefield): self.update(delta_time, minefield) self.draw(window) def draw(self, window): coord_x, coord_y = self.on_screen_coordinates[0], self.on_screen_coordinates[1] tl_dimension = const.V_TILE_SIZE / 2 rotating_rect = transform.rotate(asset.ASSET_SAPPER, self.rotation_angle).get_rect() rotating_rect.center = (coord_x + tl_dimension, coord_y + tl_dimension) window.blit(transform.rotate(asset.ASSET_SAPPER, self.rotation_angle), rotating_rect) def update(self, delta_time, minefield): self.new_action = self.going_forward + self.rotating_left * 2 + self.rotating_right * 4 # counting next agents terrain tile # heading either up or down if const.Direction(self.direction).value % 2 == 0 and self.going_forward: next_row = min(9, self.row + const.Direction(self.direction).value - 1) next_column = self.column # heading either left or right else: next_row = self.row next_column = min(9, self.column - const.Direction(self.direction).value + 2) value_modifier = minefield.matrix[next_row][next_column].cost.value if self.going_forward: direction = const.Direction(self.direction).value x, y = self.on_screen_coordinates # heading either up or down if direction % 2 == 0: self.on_screen_coordinates = (x, y + (direction - 1) * const.V_TILE_SIZE * delta_time / value_modifier) # heading either left or right else: self.on_screen_coordinates = (x - (direction - 2) * const.V_TILE_SIZE * delta_time / value_modifier, y) elif self.rotating_right: self.rotation_angle -= delta_time * 90 % 360 elif self.rotating_left: self.rotation_angle += delta_time * 90 % 360 if self.last_action != self.new_action or \ not any((self.going_forward, self.rotating_right, self.rotating_left)): self.last_action = self.new_action self.rotation_angle = -const.Direction(self.direction).value * 90 self.on_screen_coordinates = const.get_tile_coordinates(tuple(self.position)) def animate(self, action): self.reset_actions() if action == const.Action.ROTATE_LEFT: self.rotating_left = True elif action == const.Action.ROTATE_RIGHT: self.rotating_right = True elif action == const.Action.GO: self.going_forward = True def take_action(self, action): if action == const.Action.ROTATE_LEFT: self.rotate_left() elif action == const.Action.ROTATE_RIGHT: self.rotate_right() elif action == const.Action.GO: self.go() def rotate_left(self): self.direction = self.direction.previous() def rotate_right(self): self.direction = self.direction.next() def go(self): if self.direction == const.Direction.RIGHT: temp = self.go_right() self.position[1] = temp[1] self.column += 1 elif self.direction == const.Direction.LEFT: temp = self.go_left() self.position[1] = temp[1] self.column -= 1 elif self.direction == const.Direction.UP: temp = self.go_up() self.position[0] = temp[0] self.row -= 1 elif self.direction == const.Direction.DOWN: temp = self.go_down() self.position[0] = temp[0] self.row += 1 def go_right(self): return self.position[0], self.position[1] + 1 def go_left(self): return self.position[0], self.position[1] - 1 def go_up(self): return self.position[0] - 1, self.position[1] def go_down(self): return self.position[0] + 1, self.position[1] def reset_actions(self): self.going_forward = self.rotating_right = self.rotating_left = False