import pygame from collections import deque from classes.cell import Cell import prefs import heapq class Agent: def __init__(self, x, y, cells, baseScore=0): self.sprite = pygame.image.load("sprites/BartenderNew64.png").convert_alpha() self.sprite = pygame.transform.scale(self.sprite, (prefs.CELL_SIZE, prefs.CELL_SIZE)) self.current_cell = cells[x][y] self.moved=False self.last_move_time = pygame.time.get_ticks() self.last_interact_time = pygame.time.get_ticks() self.last_update_time = pygame.time.get_ticks() self.cells = cells self.score = baseScore self.multiplier = 1 self.direction = 0 self.directionPOM = 0 self.xPOM = 5 self.yPOM = 5 self.g_scores = {} self.textures = [ pygame.image.load("sprites/BartenderNew64.png").convert_alpha(), pygame.image.load("sprites/AgentLewo.png").convert_alpha(), pygame.image.load("sprites/AgentTyl.png").convert_alpha(), pygame.image.load("sprites/AgentPrawo.png").convert_alpha() ] def move_up(self): if pygame.time.get_ticks()-self.last_move_time > 125 and self.current_cell.Y > 0 and not self.cells[self.current_cell.X][self.current_cell.Y-1].blocking_movement: self.current_cell = self.cells[self.current_cell.X][self.current_cell.Y-1] self.moved=True self.last_move_time=pygame.time.get_ticks() def move_down(self): if pygame.time.get_ticks()-self.last_move_time > 125 and self.current_cell.Y < prefs.GRID_SIZE-1 and not self.cells[self.current_cell.X][self.current_cell.Y+1].blocking_movement: self.current_cell = self.cells[self.current_cell.X][self.current_cell.Y+1] self.moved=True self.last_move_time=pygame.time.get_ticks() def move_left(self): if pygame.time.get_ticks()-self.last_move_time > 125 and self.current_cell.X > 0 and not self.cells[self.current_cell.X-1][self.current_cell.Y].blocking_movement: self.current_cell = self.cells[self.current_cell.X-1][self.current_cell.Y] self.moved=True self.last_move_time=pygame.time.get_ticks() def move_right(self): if pygame.time.get_ticks()-self.last_move_time > 125 and self.current_cell.X < prefs.GRID_SIZE-1 and not self.cells[self.current_cell.X+1][self.current_cell.Y].blocking_movement: self.current_cell = self.cells[self.current_cell.X+1][self.current_cell.Y] self.moved=True self.last_move_time=pygame.time.get_ticks() def update(self, surface): surface.blit(self.sprite, (self.current_cell.X * prefs.CELL_SIZE, self.current_cell.Y * prefs.CELL_SIZE)) current_update_time = pygame.time.get_ticks() # różnca czasu między wyoływaniami, używa do uniezależnienia od ilości wywołań funkcji delta_time = ((current_update_time - self.last_update_time)/1000) self.increase_multiplier(-(1 / 16) * delta_time) self.last_update_time = current_update_time def increase_score(self, amount): self.score += amount * round(self.multiplier,2) print("Agent score changed from {} to {} (multiplied by {}!)".format(self.score - amount, self.score, round(self.multiplier,2))) def increase_multiplier(self, amount): self.multiplier += amount if self.multiplier > 2: self.multiplier = 2 print("Agent score changed from {} to {}".format(self.multiplier , self.multiplier + amount if self.multiplier + amount <= 2 else 2)) return if self.multiplier < 1: self.multiplier = 1 def moveto(self,x,y): if not self.cells[x][y].blocking_movement: self.current_cell = self.cells[x][y] self.moved=True self.last_move_time=pygame.time.get_ticks() print("Agent moved to x,y: ",x,y) else: print("Agent cannot move to this direction") def bfs(self, start, target, cells): queue = deque([(start,[])]) visited = set() while queue: current, path = queue.popleft() if current==target: return path + [current] if current in visited: continue visited.add(current) for neighbor in self.get_neighbors(current, cells): queue.append((neighbor, path + [current])) return None def get_neighbors(self, cell, cells): neighbors = [] x, y = cell.X, cell.Y if x > 0 and not cells[x-1][y].blocking_movement: neighbors.append(cells[x-1][y]) if x < prefs.GRID_SIZE - 1 and not cells[x+1][y].blocking_movement: neighbors.append(cells[x+1][y]) if y > 0 and not cells[x][y-1].blocking_movement: neighbors.append(cells[x][y-1]) if y < prefs.GRID_SIZE - 1 and not cells[x][y+1].blocking_movement: neighbors.append(cells[x][y+1]) return neighbors #oddaje tablice punktow jako sciezke agenta def convert_to_coordinates(self, shortest_path): coordinates = [(cell.X, cell.Y) for cell in shortest_path] return coordinates #Wyjmuje pierwsze koordynaty do ruszenia agenta a potem usuwa go z listy def pop_first_coordinates(self, coordinates): if coordinates: x, y = coordinates.pop(0) return x, y else: print("Lista współrzędnych jest pusta.") return None, None #Funkcja pomocnicza dla watku bo chcemy zeby agent poruszal sie ale zeby to normalnie wygladalo def sciezkaAgenta(self, agent, path): x,y = self.pop_first_coordinates(path) if x is not None and y is not None: agent.moveto(x,y) def rotate_left(self): if pygame.time.get_ticks()-self.last_move_time > 125: self.direction +=1 if self.direction==4: self.direction=0 self.sprite = self.textures[self.direction] self.sprite = pygame.transform.scale(self.sprite, (prefs.CELL_SIZE, prefs.CELL_SIZE)) self.last_move_time=pygame.time.get_ticks() print(self.direction) def rotate_right(self): if pygame.time.get_ticks()-self.last_move_time > 125: self.direction-=1 if self.direction==-1: self.direction=3 self.sprite = self.textures[self.direction] self.sprite = pygame.transform.scale(self.sprite, (prefs.CELL_SIZE, prefs.CELL_SIZE)) self.last_move_time=pygame.time.get_ticks() print(self.direction) def move_direction(self): if self.direction == 0 and pygame.time.get_ticks()-self.last_move_time > 125 and self.current_cell.Y < prefs.GRID_SIZE-1 and not self.cells[self.current_cell.X][self.current_cell.Y+1].blocking_movement: self.current_cell = self.cells[self.current_cell.X][self.current_cell.Y+1] self.moved=True self.last_move_time=pygame.time.get_ticks() if self.direction == 1 and pygame.time.get_ticks()-self.last_move_time > 125 and self.current_cell.X > 0 and not self.cells[self.current_cell.X-1][self.current_cell.Y].blocking_movement: self.current_cell = self.cells[self.current_cell.X-1][self.current_cell.Y] self.moved=True self.last_move_time=pygame.time.get_ticks() if self.direction == 2 and pygame.time.get_ticks()-self.last_move_time > 125 and self.current_cell.Y > 0 and not self.cells[self.current_cell.X][self.current_cell.Y-1].blocking_movement: self.current_cell = self.cells[self.current_cell.X][self.current_cell.Y-1] self.moved=True self.last_move_time=pygame.time.get_ticks() if self.direction == 3 and pygame.time.get_ticks()-self.last_move_time > 125 and self.current_cell.X < prefs.GRID_SIZE-1 and not self.cells[self.current_cell.X+1][self.current_cell.Y].blocking_movement: self.current_cell = self.cells[self.current_cell.X+1][self.current_cell.Y] self.moved=True self.last_move_time=pygame.time.get_ticks() def get_possible_moves(self): possible_moves = [] if self.directionPOM == 0: # Patrzy w dół possible_moves.append((0, 'left')) possible_moves.append((0, 'right')) if self.yPOM < prefs.GRID_SIZE - 1 and not self.cells[self.xPOM][self.yPOM + 1].blocking_movement: possible_moves.append((self.directionPOM, 'forward')) elif self.directionPOM == 1: # Patrzy w lewo possible_moves.append((1, 'left')) possible_moves.append((1, 'right')) if self.xPOM > 0 and not self.cells[self.xPOM - 1][self.yPOM].blocking_movement: possible_moves.append((self.directionPOM, 'forward')) elif self.directionPOM == 2: # Patrzy w górę possible_moves.append((2, 'left')) possible_moves.append((2, 'right')) if self.yPOM > 0 and not self.cells[self.xPOM][self.yPOM - 1].blocking_movement: possible_moves.append((self.directionPOM, 'forward')) elif self.directionPOM == 3: # Patrzy w prawo possible_moves.append((3, 'left')) possible_moves.append((3, 'right')) if self.xPOM < prefs.GRID_SIZE - 1 and not self.cells[self.xPOM + 1][self.yPOM].blocking_movement: possible_moves.append((self.directionPOM, 'forward')) return possible_moves def bfs2(self, target_x, target_y): visited = set() self.directionPOM = self.direction start_state = (self.current_cell.X, self.current_cell.Y, self.directionPOM) #print(start_state) queue = [] heapq.heappush(queue, (0,(start_state, [], 0))) while queue: _, que = heapq.heappop(queue) state, actions, gscore = que self.xPOM, self.yPOM, self.directionPOM = state if self.xPOM == target_x and self.yPOM == target_y: return actions if (self.xPOM, self.yPOM, self.directionPOM) in visited: continue visited.add((self.xPOM, self.yPOM, self.directionPOM)) possible_moves = self.get_possible_moves() for new_direction, action in possible_moves: new_x, new_y = self.xPOM, self.yPOM new_actions = actions + [action] if action == 'left': new_direction = (self.directionPOM + 1) % 4 elif action == 'right': new_direction = (self.directionPOM - 1) % 4 else: # forward if self.directionPOM == 0: new_y += 1 elif self.directionPOM == 1: new_x -= 1 elif self.directionPOM == 2: new_y -= 1 else: # direction == 3 new_x += 1 if 0 <= new_x < prefs.GRID_SIZE and 0 <= new_y < prefs.GRID_SIZE \ and not self.cells[new_x][new_y].blocking_movement: new_state = (new_x, new_y, new_direction) f_score = gscore + self.heuristic((new_x,new_y), (target_x,target_y)) gscore = gscore + self.cells[new_x][new_y].waga heapq.heappush(queue, (f_score, (new_state, new_actions, gscore+1))) return [] #Algorytm astar def moveto(self,x,y): if pygame.time.get_ticks()-self.last_move_time > 125 and self.current_cell.X < prefs.GRID_SIZE-1 and not self.cells[x][y].blocking_movement: self.current_cell = self.cells[x][y] self.moved=True self.last_move_time=pygame.time.get_ticks() print("Agent moved to x,y: ",x,y) else: print("Agent cannot move to this direction") def get_cost(self, cell): x, y = cell[0], cell[1] if x == 0 or x == len(self.cells) - 1 or y == 0 or y == len(self.cells[0]) - 1: return 15 # Koszt dla pól na krawędziach elif x == 1 or x == len(self.cells) - 2 or y == 1 or y == len(self.cells[0]) - 2: return 10 # Koszt dla pól drugiego rzędu i przedostatniego oraz drugiej kolumny i przedostatniej elif x == 2 or x == len(self.cells) - 3 or y == 2 or y == len(self.cells[0]) - 3: return 5 # Koszt dla pól trzeciego rzędu i trzeciego od końca oraz trzeciej kolumny i trzeciej od końca else: return 1 def heuristic(self, current, target): # Manhattan distance heuristic dx = abs(current[0] - target[0]) dy = abs(current[1] - target[1]) return dx + dy def priority(self, state, target): # Oblicza priorytet dla danego stanu g_score = self.g_score[state] h_score = self.heuristic(state, target) return g_score + h_score def astar(self, target, start_cost=0): if not isinstance(target, tuple) or len(target) != 2: raise ValueError("Target must be a tuple of two elements (x, y).") open_list = [(start_cost, (self.current_cell.X, self.current_cell.Y, self.directionPOM))] came_from = {} g_score = {(self.current_cell.X, self.current_cell.Y, self.directionPOM): start_cost} while open_list: _, current = heapq.heappop(open_list) if isinstance(current, int): raise ValueError("Current must be a tuple of three elements (x, y, direction).") x, y, _ = current # Unpack the current tuple if (x, y) == target: # Check if the current cell's coordinates match the target path = [] while current in came_from: path.append((current[0], current[1])) # Append only coordinates (x, y) to the path current = came_from[current] path = path[::-1] # Reverse the path cost = g_score[(x, y, self.directionPOM)] # Retrieve the cost from the g_score dictionary return path, cost for neighbor in self.get_neighbors(self.cells[x][y], self.cells): neighbor_coords = (neighbor.X, neighbor.Y, self.directionPOM) # Convert neighbor cell to tuple tentative_g_score = g_score[current] + self.get_cost(neighbor_coords) if tentative_g_score < g_score.get(neighbor_coords, float('inf')): came_from[neighbor_coords] = current g_score[neighbor_coords] = tentative_g_score f_score = tentative_g_score + self.heuristic(neighbor_coords, target) heapq.heappush(open_list, (f_score, neighbor_coords)) return [], float('inf')