Projekt_Sztuczna_Inteligencja/objects/agent.py

152 lines
5.6 KiB
Python
Raw Normal View History

2021-03-26 16:36:21 +01:00
import project_constants as const
from assets import asset_constants as asset
2021-03-26 16:36:21 +01:00
import json
from time import sleep
from pygame import transform
from algorithms.learn.decision_tree import DecisionTree
2021-03-26 16:36:21 +01:00
# 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));
2021-03-26 16:36:21 +01:00
class Agent:
last_action = None
new_action = None
2021-03-26 16:36:21 +01:00
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.joblib",
const.ROOT_DIR + "/algorithms/learn/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
2021-03-26 16:36:21 +01:00
def go_right(self):
return self.position[0], self.position[1] + 1
2021-03-26 16:36:21 +01:00
def go_left(self):
return self.position[0], self.position[1] - 1
2021-03-26 16:36:21 +01:00
def go_up(self):
return self.position[0] - 1, self.position[1]
2021-03-26 16:36:21 +01:00
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