class Map: def __init__(self): self.map = [] self.finder = AStarFinder(diagonal_movement=DiagonalMovement.never) def load(self, path): im = Image.open(path) w, h = im.size v = list( map(lambda p: 1 if (p[0] + p[1] + p[2]) // 3 > 127 else 0, im.getdata())) self.grid = Grid(matrix=[v[i * w:(i + 1) * w] for i in range(h)]) def width(self): return len(self.map[0]) def height(self): return len(self.map) def find_path(self, a, b): start = self.grid.node(a[0], a[1]) end = self.grid.node(b[0], b[1]) path, runs = self.finder.find_path(start, end, self.grid) self.grid.cleanup() return path
def is_playable(start_end: List, room_matrix: List[List[int]], print_path: bool=False) -> bool: if len(start_end) < 2: playable = True return playable grid = Grid(matrix=room_matrix) comb = list(combinations(start_end, 2)) playable = True # random.shuffle(comb) for _start, _end in comb: # print(_start, _end) abs_dis = abs(_start[0] - _end[0]) + abs(_start[1] - _end[1]) if abs_dis < 2: continue start = grid.node(_start[1], _start[0]) end = grid.node(_end[1], _end[0]) finder = AStarFinder(diagonal_movement=DiagonalMovement.never) path, runs = finder.find_path(start, end, grid) if print_path: print('operations:', runs, 'path length:', len(path)) print(grid.grid_str(path=path, start=start, end=end)) grid.cleanup() if len(path) == 0: playable = False break return playable
def find_path(self, grid, final): x = self.location[0] y = self.location[1] start = grid.node(x, y) end = grid.node(final[0], final[1]) finder = AStarFinder() self.path, runs = finder.find_path(start, end, grid) Grid.cleanup(grid)
def get_good_place(self, places): grid = Grid(matrix=self._matrix) self._grid = grid path_list = [] for place in places: path = self.get_path(place, grid) grid.cleanup() if path: path_list.append(path) return path_list
def get_other_player_path(self, afk_players): grid = Grid(matrix=self._matrix) self._grid = grid pnt = grid.node(self._me.get_x(), self._me.get_y()) pnt.walkable = True if not afk_players: return None for bomber in afk_players: if self._victim and self._victim == bomber: continue path = self.get_path(bomber, grid) if path: #logger.debug(grid.grid_str(path=path,start=pnt)) return path grid.cleanup() return None
def find_path(self, player, show=False): """Return True if the player can finish""" x, y = self.pos_player_in_grid(player) grid = Grid(matrix=self.matrix) if player.orient == "north": x_end = self.side - 1 for y_end in range(0, self.side, 2): start = grid.node(y, x) end = grid.node(y_end, x_end) path, runs = self.finder.find_path(start, end, grid) if path != []: if show: print(grid.grid_str(path=path, start=start, end=end)) return True grid.cleanup() elif player.orient == "east": y_end = 0 for x_end in range(0, self.side, 2): start = grid.node(y, x) end = grid.node(y_end, x_end) path, runs = self.finder.find_path(start, end, grid) if path != []: if show: print(grid.grid_str(path=path, start=start, end=end)) return True grid.cleanup() elif player.orient == "south": x_end = 0 for y_end in range(0, self.side, 2): start = grid.node(y, x) end = grid.node(y_end, x_end) path, runs = self.finder.find_path(start, end, grid) if path != []: if show: print(grid.grid_str(path=path, start=start, end=end)) return True grid.cleanup() elif player.orient == "west": y_end = self.side - 1 for x_end in range(0, self.side, 2): start = grid.node(y, x) end = grid.node(y_end, x_end) path, runs = self.finder.find_path(start, end, grid) if path != []: if show: print(grid.grid_str(path=path, start=start, end=end)) return True grid.cleanup() return False
class Obstacle_Grid(): def __init__(self): # in the end, `self.terrain_grid` will be a 2D array of values where zeros are obstacles # and all values greater than zero are edge weights for all edges connected to that node self.terrain_grid = [] with open("./resources/terrain.txt") as input: rows = input.readlines() # loop through entire terrain file and convert all chars to integers for row in rows: terrain_grid_row = [] for col in row: if col.isdigit(): terrain_grid_row.append(int(col)) self.terrain_grid.append(terrain_grid_row) # instantiate the Grid object using the newly converted terrain_grid # The pathfinding library requires this special object to work self.grid = Grid(matrix=self.terrain_grid) # define the A* pathfinding algorithm as the one we use. Another option is Dijkstra's self.finder = AStarFinder(diagonal_movement=DiagonalMovement.always) def find_shortest_path(self, location, destination): """ Purpose: create a list of spots in a 2D grid that define the shortest path between two spots Input: Starting location (`location`) and Ending location (`destination`) Output: A list of spots/locations in the 2D grid """ self.grid.cleanup() self.start = self.grid.node(location[1], location[0]) self.end = self.grid.node(destination[1], destination[0]) path_list, _ = self.finder.find_path(self.start, self.end, self.grid) return path_list def print_path_to_file(self, path_list): """ Purpose: Test function that prints the terrain with the shortest path between two nodes to the console Input: List of spots in terrain grid that define the shortest path between two nodes. Output: None """ print( self.grid.grid_str(path=path_list, start=self.start, end=self.end))
def is_playable(start_end: Dict, room_matrix: List[List[int]], print_path: bool=False) -> bool: # TODO: invesgate # if len(start_end) < 2: # playable = True # return playable all_start_end = [] for k in start_end: all_start_end = all_start_end + start_end[k] grid = Grid(matrix=room_matrix) comb = list(combinations(all_start_end, 2)) playable = True # random.shuffle(comb) for _start, _end in comb: # print(_start, _end) # hardcode here # if (_start in start_end["D"] and _end in start_end["D"]) or (_start in start_end["S"] and _end in start_end["S"]): # abs_dis = abs(_start[0] - _end[0]) + abs(_start[1] - _end[1]) # if abs_dis < 4: # continue start = grid.node(_start[1], _start[0]) end = grid.node(_end[1], _end[0]) finder = AStarFinder(diagonal_movement=DiagonalMovement.never) path, runs = finder.find_path(start, end, grid) if print_path and len(path) > 0: print('operations:', runs, 'path length:', len(path)) print(grid.grid_str(path=path, start=start, end=end)) grid.cleanup() if len(path) == 0: playable = False break return playable
def move(self, caves, allies, enemies): possiblesquares = [] for enemy in enemies: if len(enemy.getadjacent(caves, allies, enemies)) > 0: possiblesquares.append( enemy.getadjacent(caves, allies, enemies)) if len(possiblesquares) > 0: grid = Grid(matrix=createGrid(caves, allies, enemies)) finder = BreadthFirstFinder( diagonal_movement=DiagonalMovement.never) start = grid.node(self.x, self.y) minimum = None for i, squares in enumerate(possiblesquares): for square in squares: end = grid.node(square[0], square[1]) path, runs = finder.find_path(start, end, grid) #if self.x == 3 and self.y == 1: #print(grid.grid_str(path=path, start=start, end=end)) if len(path) == 0: continue if minimum == None or len(path) < minimum[0] or ( len(path) == minimum[0] and square[2] < minimum[2]): minimum = [ len(path), path[1], square[2], square[0], square[1] ] grid.cleanup() grid.cleanup() if minimum != None: selected = None end = grid.node(minimum[3], minimum[4]) for mysquare in self.getadjacent(caves, allies, enemies): start = grid.node(mysquare[0], mysquare[1]) path, runs = finder.find_path(start, end, grid) #print(grid.grid_str(path=path, start=start, end=end)) if len(path) == 0: continue if selected == None or len(path) < selected[0] or ( len(path) == selected[0] and mysquare[2] < selected[2]): selected = [ len(path), path[0], mysquare[2], mysquare[0], mysquare[1] ] grid.cleanup() self.x = selected[3] self.y = selected[4] if any(self.y + 1 == e.y and self.x == e.x for e in enemies) or any( self.y - 1 == e.y and self.x == e.x for e in enemies) or any( self.y == e.y and self.x + 1 == e.x for e in enemies) or any( self.y == e.y and self.x - 1 == e.x for e in enemies): enemies = self.attack(caves, allies, enemies) return enemies
class Player(pygame.sprite.Sprite): def __init__(self, group, startPosition, tilemap, startSprite): self.sprite = stopSprites[startSprite] self.image = pygame.image.load(baseDir + self.sprite) self.rect = self.image.get_rect(center=-startPosition) self.cartesianPos = pygame.math.Vector2(startPosition.x, startPosition.y) self.isoMov = pygame.math.Vector2(startPosition.x, startPosition.y) self.isoReal = pygame.math.Vector2(startPosition.x, startPosition.y) self.destination = pygame.math.Vector2(startPosition.x, startPosition.y) self.canInteract = True self.useDepth = True self.mapData = tilemap.map self.grid = Grid(matrix=tilemap.map) self.finder = AStarFinder(diagonal_movement=DiagonalMovement.never) self.path = 0 self.actualPath = 0 self.moving = False self.dX = 0 self.dY = 0 ## ANIMATION self.lastDir = startSprite self.walkCount = 0 self.animationSpeed = 29 self.lastUpdate = 0 self.standUp = False self.tilemap = tilemap pygame.sprite.Sprite.__init__(self, group) def cartesianToIsometric(self, cartesian): self.isoMov = pygame.math.Vector2( (cartesian.x - cartesian.y) + self.tilemap.tileSize.x / 2 + 12, (cartesian.x + cartesian.y) / 2 + self.tilemap.tileSize.y * 4 + 200) self.isoReal = pygame.math.Vector2(cartesian.x / 128, -cartesian.y / 128) def getAnimation(self): ## UP if (self.dY == -1 and self.dX == 0): if (self.walkCount < len(runFront)): self.image = pygame.image.load(baseDir + "Running5/" + runFront[self.walkCount]) if pygame.time.get_ticks( ) - self.lastUpdate > self.animationSpeed: self.lastDir = 0 self.walkCount += 1 self.lastUpdate = pygame.time.get_ticks() else: self.elapsed = 0 self.walkCount = 2 ## DOWN elif (self.dY == 1 and self.dX == 0): if (self.walkCount < len(runBack)): self.image = pygame.image.load(baseDir + "Running1/" + runBack[self.walkCount]) if pygame.time.get_ticks( ) - self.lastUpdate > self.animationSpeed: self.lastDir = 1 self.walkCount += 1 self.lastUpdate = pygame.time.get_ticks() else: self.elapsed = 0 self.walkCount = 2 ## LEFT elif (self.dX == -1 and self.dY == 0): if (self.walkCount < len(runLeft)): self.image = pygame.image.load(baseDir + "Running7/" + runLeft[self.walkCount]) if pygame.time.get_ticks( ) - self.lastUpdate > self.animationSpeed: self.lastDir = 2 self.walkCount += 1 self.lastUpdate = pygame.time.get_ticks() else: self.elapsed = 0 self.walkCount = 2 ## RIGHT elif (self.dX == 1 and self.dY == 0): if (self.walkCount < len(runRight)): self.image = pygame.image.load(baseDir + "Running3/" + runRight[self.walkCount]) if pygame.time.get_ticks( ) - self.lastUpdate > self.animationSpeed: self.lastDir = 3 self.walkCount += 1 self.lastUpdate = pygame.time.get_ticks() else: self.elapsed = 0 self.walkCount = 2 ## RIGHT-DOWN elif (self.dX == 1 and self.dY == 1): if (self.walkCount < len(runRightBack)): self.image = pygame.image.load(baseDir + "Running2/" + runRightBack[self.walkCount]) if pygame.time.get_ticks( ) - self.lastUpdate > self.animationSpeed: self.lastDir = 6 self.walkCount += 1 self.lastUpdate = pygame.time.get_ticks() else: self.elapsed = 0 self.walkCount = 0 ## RIGHT-UP elif (self.dX == 1 and self.dY == -1): if (self.walkCount < len(runRightUp)): self.image = pygame.image.load(baseDir + "Running4/" + runRightUp[self.walkCount]) if pygame.time.get_ticks( ) - self.lastUpdate > self.animationSpeed: self.lastDir = 7 self.walkCount += 1 self.lastUpdate = pygame.time.get_ticks() else: self.elapsed = 0 self.walkCount = 0 ## LEFT-DOWN elif (self.dX == -1 and self.dY == 1): if (self.walkCount < len(runLeftBack)): self.image = pygame.image.load(baseDir + "Running8/" + runLeftBack[self.walkCount]) if pygame.time.get_ticks( ) - self.lastUpdate > self.animationSpeed: self.lastDir = 4 self.walkCount += 1 self.lastUpdate = pygame.time.get_ticks() else: self.elapsed = 0 self.walkCount = 2 ## LEFT-UP elif (self.dX == -1 and self.dY == -1): if (self.walkCount < len(runLeftUp)): self.image = pygame.image.load(baseDir + "Running6/" + runLeftUp[self.walkCount]) if pygame.time.get_ticks( ) - self.lastUpdate > self.animationSpeed: self.lastDir = 5 self.walkCount += 1 self.lastUpdate = pygame.time.get_ticks() else: self.elapsed = 0 self.walkCount = 2 elif (self.standUp == True): if (self.walkCount < 185): self.image = pygame.image.load(baseDir + "StandingUP/" + standingUP[self.walkCount]) #self.lastDir = 5 self.walkCount += 1 self.lastUpdate = pygame.time.get_ticks() else: self.standUp = False elif (self.dY == 0 and self.dX == 0): self.standUp = False self.image = pygame.image.load(baseDir + stopSprites[self.lastDir]) def checkPosition(self): if (self.moving == True): if (self.isoReal.x == self.destination.x and -self.isoReal.y == self.destination.y): self.dX = 0 self.dY = 0 self.actualPath += 1 self.moving = False self.goToPosition() elif (self.isoReal.x == self.destination.x): self.dX = 0 elif (-self.isoReal.y == self.destination.y): self.dY = 0 def goToPosition(self): if (self.actualPath < len(self.path)): if (self.moving == False): self.destination = pygame.math.Vector2( self.path[self.actualPath][0], -self.path[self.actualPath][1]) ## CHECK X if (self.isoReal.x > self.destination.x): self.dX = -1 elif (self.isoReal.x < self.destination.x): self.dX = 1 else: self.dX = 0 ## CHECK Y if (-self.isoReal.y > self.destination.y): self.dY = -1 elif (-self.isoReal.y < self.destination.y): self.dY = 1 else: self.dY = 0 self.moving = True else: self.path = 0 self.actualPath = 0 def ProcessInputs(self, isoClickPos): if (self.canInteract == True): if (isoClickPos.x >= 0 and isoClickPos.x <= 9 and isoClickPos.y >= 0 and isoClickPos.y <= 9): if (self.actualPath == 0): mouseClick = pygame.mouse.get_pressed() if mouseClick[0] == 1: start = self.grid.node(int(self.isoReal.x), int(self.isoReal.y)) end = self.grid.node(int(isoClickPos.x), int(isoClickPos.y)) self.path = self.finder.find_path( start, end, self.grid)[0] #print(self.grid.grid_str(path=self.path, start=start, end=end)) self.goToPosition() self.grid.cleanup() def Update(self, camera, surface): self.checkPosition() if (self.moving == True): walkingSound.play() else: walkingSound.stop() self.cartesianPos.x += self.dX * 4 self.cartesianPos.y += self.dY * 4 self.cartesianToIsometric(self.cartesianPos) self.getAnimation() self.rect.center = pygame.Vector2(self.isoMov.x, self.isoMov.y)
def MouvePlayer(event): global startr for i in range(0, len(mmatrix)): for j in range(0, len(mmatrix[i])): if mmatrix[i][j] == "P": mmatrix[i][j] = 1 startr = [j, i] grid = Grid(matrix=mmatrix) start = grid.node(startr[0], startr[1]) Targetx = event.x Targety = event.y #Arrondi le x du clic XChanged = str(Targetx) if Targetx >= 100: XChanged = XChanged[1] + XChanged[2] XChanged = int(XChanged) if XChanged >= 50: TargetxArrondi = Targetx + (50 - XChanged) else: TargetxArrondi = Targetx - XChanged #Arrondi le y du clic YChanged = str(Targety) if Targety >= 100: YChanged = YChanged[1] + YChanged[2] YChanged = int(YChanged) if YChanged >= 50: TargetyArrondi = Targety + (50 - YChanged) else: TargetyArrondi = Targety - YChanged #print(TargetyArrondi) : The coords of your click end = grid.node(int(TargetxArrondi / 50), int(TargetyArrondi / 50)) finder = AStarFinder(diagonal_movement=DiagonalMovement.never) path, runs = finder.find_path(start, end, grid) if len(path) == 0: print("C'est un cul de sac") #I tryed to play a song, but it doesn't work :/ os.system('start Nope.mp3') else: PlayerPosition = startr #print(path) : Write the path the algorithm gonna use ! Pretty cool right ? Speed = 50 for mouvement in range(0, len(path)): oldP = PlayerPosition thenext = path[mouvement] colorcase = FindWhatToSeen(mmatrix[thenext[1]][thenext[0]]) oldcasePriority = mmatrix[thenext[1]][thenext[0]] PlayerPosition = path[mouvement] mmatrix[PlayerPosition[1]][PlayerPosition[0]] = "P" mmatrix[oldP[1]][oldP[0]] = oldcasePriority c.coords(Player, PlayerPosition[0] * 50, PlayerPosition[1] * 50, PlayerPosition[0] * 50 + 50, PlayerPosition[1] * 50 + 50) c.update() c.tag_raise(Player) Factor = 1 if colorcase == "blue": Factor = oldcasePriority * 10 c.after(Speed * Factor) #Change the speed with the Factor : In progress Grid.cleanup(grid)
path_founds[a1] = [ path_founds[a1][0] + 1, max(path_founds[a1][1], step_level) ] if not a2 in path_founds: path_founds[a2] = [0, 0] path_founds[a2] = [ path_founds[a2][0] + 1, max(path_founds[a2][1], step_level) ] print('Current path founds for ' + str(a1) + ' = ' + str(path_founds[a1][0]) + ' with step_level ' + str(path_founds[a1][1])) print('Current path founds for ' + str(a2) + ' = ' + str(path_founds[a2][0]) + ' with step_level ' + str(path_founds[a2][1])) grid.cleanup() step_level += 1 with open(scen_file_path + '/Paths/' + str(kind) + '.json', mode='w', encoding='utf-8') as fout: fout.write( json.dumps(kind_paths, indent=0, separators=(',', ':'), ensure_ascii=False, sort_keys=True))
class MainAgent(Agent): """ Klasa główna z której dziedziczą potem poszczególne typy jednostek Arg: id (int): unikalny id agenta model : model w którym agent będzie działać """ def __init__(self, id, model): super().__init__(id, model) self.pos = None self.health = 100 self.attack = 10 self.defence = 0.25 self.cost = 0 self.model = model self.color = "red" self.type = 'I' self.timer = True self.help_grid = [] self.Grid = Grid(matrix=self.help_grid) def update_path(self, enemy): """ Aktualizuje plansze przeszkód widzianych przez agenta :param enemy: Agent który ma być widziany nie jako przeszkoda :return: """ self.help_grid.clear() temp = [] for i in range(self.model.height): temp.clear() for j in range(self.model.width): if self.model.grid.is_cell_empty( (j, i)) or self.pos == (j, i) or enemy.pos == (j, i): temp.append(1) else: temp.append(0) self.help_grid.append(temp[:]) self.Grid = Grid(matrix=self.help_grid) def get_pos(self): """ Getter pozycji :return: zwraca pozycję """ return self.pos def get_cost(self): """ Getter kosztu :return: zwraca koszt """ return self.cost def get_dmg(self): """ Getter obrażeń :return: zwraca atak jednostki """ return self.attack def get_hp(self): """ getter życia :return: zwraca aktualne życie agenta """ return self.health def get_color(self): """ getter koloru :return: zwraca kolor agenta """ return self.color def set_hp(self, hp): """ ustawia życie agenta :param hp: nowe życie agenta :return: """ self.health = hp def set_color(self, color): """ ustawia kolor agenta :param color: nowy kolor agenta :return: """ self.color = color def scout(self, n): """ Szuka w zasiegu (n) przeciwników :param n: zasięg :return: zwraca listę przeciwników """ field = self.model.grid.get_neighbors( self.pos, # Pozycja jednostki True, # True=Moore neighborhood False=Von Neumann neighborhood False, # Srodek n # Promien ) opponents = [] for a in field: if a.get_color() == self.get_color() or a.get_color() == '#000000': pass else: opponents.append(a) return opponents def nearest_fields(self, n): """ sprawdza pola na które agent może przejść w zasięgu :param n: zasięg :return: zwraca listę krotek """ fields_around = self.model.grid.get_neighborhood( self.pos, True, False, n) return fields_around # def advanced_scout(self,pos): def move(self): """ Metoda poruszająca agenta Kiedy nikogo nie widzi porusza się losowo Jak widzi to idzie w jego stronę najszybszą ścieżką :return: """ others = self.scout(18) if len(others) < 1: self.model.grid.move_agent( self, self.random.choice(self.nearest_fields(1))) else: nemesis = self.random.choice(others) self.update_path(nemesis) start = self.Grid.node(self.pos[0], self.pos[1]) end = self.Grid.node(nemesis.pos[0], nemesis.pos[1]) finder = AStarFinder(diagonal_movement=DiagonalMovement.always) path, runs = finder.find_path(start, end, self.Grid) if len(path) > 0: if self.model.grid.is_cell_empty((path[1][0], path[1][1])): self.model.grid.move_agent(self, (path[1][0], path[1][1])) else: print("im stuck") self.Grid.cleanup() def attack_opponent(self): """ Szuka w swojej okolicy przeciwników i atakuje ich :return: """ opponents = self.scout(1) if len(opponents) > 0: other = self.random.choice(opponents) other.hurt_me(self.get_dmg()) def hurt_me(self, dmg): """ Zadaje obrażenia agentowi :param dmg: ilośc obrażeń :return: """ hit = random.randint(1, 100) / 100 if hit > self.defence: hp = self.get_hp() hp -= dmg self.set_hp(hp) self.check_dead() def step(self): """ Co ma robić podczas wywołania przez scheduler modelu :return: """ neighbors = self.scout(1) if len(neighbors) < 1 & self.timer: self.move() self.timer = not self.timer else: self.attack_opponent() self.timer = not self.timer def check_dead(self): """ Sprawdza czy agent jest martwy, Jak jest to usuwa go z modelu :return: """ if self.get_hp() <= 0: self.model.grid.remove_agent(self) self.model.schedule.remove(self)
class CellularAutomata(): def __init__(self, player, manager_dict, debug=False, consecutive_moves_no_shot=1, risk_007=0.1, mode="kamikaze"): ################MODE #KAMIKAZE #Trova il path minimo e va dritto alla bandiera, #cambia il path solo se si trova bloccato #007 #Trova il path minimo controllando anche la posizione degli avversari #preferisce cammini più sicuri per raggiungere la bandiera #cambia sempre il path a seconda degli avversari #Ha una percentuale di rischio impostabile #TODO: gestire il caso di 007 come impostore ################ self.finished = False self.debug = debug self.already_shoot = [] self.last_shot = False self.grid_cellular_map = Grid() self.consecutive_moves_no_shot = consecutive_moves_no_shot self.path = [] self.mode = mode self.risk_007 = risk_007 self.manager_dict = manager_dict self.game_interface = player self.visual = VisualComponent(player) self.flag_symbol = self.visual.getFlag() self.loyality = self.visual.getLoyality() self.player_position = self.visual.getPlayerPosition() self.game_symbol = self.visual.getPlayerGameSymbol() self.enemies = self.visual.get_enemies() self.raw_map, _ = self.game_interface.process_map() self.flag = np.where(self.raw_map == self.flag_symbol) if (self.flag == []): res = self.game_interface.interact("leave", text="No Flag in Map") if (self.debug): print(res) print("Error Flag") self.flag = (self.flag[0][0], self.flag[1][0]) def update(self): self.raw_map, response = self.game_interface.process_map() if (self.debug): print(response) self.grid_cellular_map = Grid(width=len(self.raw_map), height=len(self.raw_map[0])) list_enemies_position = [] for row in range(len(self.raw_map)): for column in range(len(self.raw_map[0])): current_cell = self.raw_map[row][column] walkable = True if (current_cell == "#" or current_cell == "@" or current_cell == "!" or current_cell == "&" or current_cell == self.flag_symbol.swapcase()): result = -1 walkable = False elif (current_cell == "$"): result = 2 walkable = True elif (self.is_enemy(current_cell)): result = 5 walkable = True if (self.visual.game_symbol != current_cell and self.visual != self.flag_symbol): list_enemies_position.append((row, column)) else: result = 5 walkable = True self.grid_cellular_map.nodes[column][row] = Node( x=row, y=column, walkable=walkable, weight=result) if (self.mode == "007"): if (random.uniform(0, 1) >= self.risk_007): next_move = {} if (self.player_position[0] + 1 <= len(self.raw_map)): next_move["S"] = (self.player_position[0] + 1, self.player_position[1]) if (self.player_position[0] - 1 >= 0): next_move["N"] = (self.player_position[0] - 1, self.player_position[1]) if (self.player_position[1] - 1 <= 0): next_move["O"] = (self.player_position[0], self.player_position[1] - 1) if (self.player_position[1] + 1 <= len(self.raw_map)): next_move["E"] = (self.player_position[0], self.player_position[1] + 1) for key in next_move: old_node = self.grid_cellular_map.nodes[next_move[key][0]][ next_move[key][1]] for enemy_position in list_enemies_position: if (enemy_position[1] == next_move[key][1] ): # Se la colonna è la stessa self.grid_cellular_map.nodes[next_move[key][1]][ next_move[key][0]] = Node( x=next_move[key][0], y=next_move[key][1], walkable=old_node.walkable, weight=11) if (enemy_position[0] == next_move[key][0] ): # Se la riga è la stessa self.grid_cellular_map.nodes[next_move[key][1]][ next_move[key][0]] = Node( x=next_move[key][0], y=next_move[key][1], walkable=old_node.walkable, weight=11) def move(self): # Prima Mossa o errore precedente o mod 007 if (self.path == []): start = self.grid_cellular_map.node(self.player_position[0], self.player_position[1]) end = self.grid_cellular_map.node(self.flag[0], self.flag[1]) self.grid_cellular_map.cleanup() finder = AStarFinder(diagonal_movement=DiagonalMovement.never, time_limit=10000, max_runs=100000) self.path, _ = finder.find_path(start, end, self.grid_cellular_map) self.n_moves = 1 if (self.path == []): # Path non trovato res = self.game_interface.interact("leave", text="No path found") if (self.debug): print("No path") print(res) return 2 for i in range(0, self.consecutive_moves_no_shot): path_x, path_y = self.path[self.n_moves][0], self.path[ self.n_moves][1] direction = "" if (self.player_position[0] < path_x): direction = "S" elif (self.player_position[0] > path_x): direction = "N" elif (self.player_position[1] > path_y): direction = "W" else: direction = "E" command_mov = self.game_interface.interact("move", direction) self.n_moves += 1 if (self.debug): print(command_mov) if ("blocked" not in command_mov): self.player_position = (path_x, path_y) else: if (self.debug): print("I'm here with the player: " + self.game_interface.player_name) result = self.game_interface.status("status") index_game_active = result.find("GA: name=" + self.game_interface.game_name + " " + "state=") condition_game_active = result[index_game_active + 9 + len( str(self.game_interface.game_name)) + 7] check_player_active = [ True for elem in result.splitlines() if (self.game_interface.player_name in elem and "ACTIVE" in elem) ] # Vittoria if (self.raw_map[path_x][path_y] == self.flag_symbol and condition_game_active.lower() != "a"): return 1 # Se il gioco è finito if (condition_game_active.lower() != "a"): print("Game Finished, no win") return 2 else: # Se è ancora vivo if (check_player_active == [True]): self.path = [] else: pass if (self.mode == "007"): self.path = [] return 0 def attack(self): # print(self.game_interface.deduction_game(command="accuse",player="pl6")) # print(self.game_interface.deduction_game(command="judge",player="pl6",player_nature="AI")) dict_shoot_direction = { "N": np.flip(self.raw_map[:self.player_position[0], self.player_position[1]]), "W": np.flip(self.raw_map[ self.player_position[0], :self.player_position[1]]), "S": [], "E": [] } # Check bordi mappa if (self.player_position[0] == (len(self.raw_map[0]) - 1)): dict_shoot_direction["S"] = self.raw_map[self.player_position[0]:, self.player_position[1]] if (self.player_position[1] != (len(self.raw_map[0]) - 1)): dict_shoot_direction["E"] = self.raw_map[ self.player_position[0], self.player_position[1] + 1:] else: dict_shoot_direction["E"] = self.raw_map[ self.player_position[0], self.player_position[1]:] else: dict_shoot_direction["S"] = self.raw_map[self.player_position[0] + 1:, self.player_position[1]] if (self.player_position[1] == (len(self.raw_map[0]) - 1)): dict_shoot_direction["E"] = self.raw_map[ self.player_position[0], self.player_position[1]:] else: dict_shoot_direction["E"] = self.raw_map[ self.player_position[0], self.player_position[1] + 1:] self.last_shot = False for key in dict_shoot_direction: for elem in dict_shoot_direction[key]: if (self.is_unshottable(elem)): break elif (self.is_enemy(elem)): result = self.game_interface.interact("shoot", direction=key) self.already_shoot.append(elem) self.last_shot = True if (self.debug): self.game_interface.command_chat("post", text_chat="shooting") print("***SHOOT***") if (self.loyality): print("IMPOSTOR-> ", self.game_symbol, " SHOOT ", elem) print("Elem: ", elem) print("RESULT: ", result) if (result.lower().find("error") != -1): print('Cannot Shoot') else: print("ARRAY SHOOTED") print(self.already_shoot) print("Vettore controllato: ") print(key + ": " + str(dict_shoot_direction[key])) print("***ENDSHOOT***") break return self.last_shot def manage_end(self, result, start_match): print("--- %.2f seconds ---" % (time.time() - start_match)) if (result == 1): print( "|||||||||||||||||||||||||||WIN|||||||||||||||||||||||||||||||||" ) if (self.mode == "007"): file_object = open('sample.txt', 'a') file_object.write(self.visual.player.player_name + "\n") print("007 WIN " + self.visual.player.player_name) stat = self.game_interface.status("status") leave = self.game_interface.interact("leave", text="Win Game") if (self.debug): print(stat) print(leave) self.game_interface.finished = True return True if (result == 2): print( "|||||||||||||||||||||||||||ERROR|||||||||||||||||||||||||||||||" ) leave = self.game_interface.command_chat("leave") if (self.debug): print(leave) return False def check_impostors(self, most_probable_impostor): if ("impostors" in self.manager_dict): current_most_pobable_impostor = max( self.manager_dict["impostors"], key=self.manager_dict["impostors"].get) if (current_most_pobable_impostor != most_probable_impostor): self.game_interface.deduction_game( "accuse", current_most_pobable_impostor) most_pobable_impostor = current_most_pobable_impostor if (self.debug): print("Find Impostor: ", most_pobable_impostor) return most_probable_impostor def wait_lobby(self): while (True): result = self.game_interface.status("status") if (self.debug): print(result) index = result.find("GA: name=" + self.game_interface.game_name + " " + "state=") condition = result[index + 9 + len(str(self.game_interface.game_name)) + 7] if (condition.lower() == "a"): # Prende il nome degli alleati self.manager_dict["allies"] = self.visual.get_allies_name( result) break def is_enemy(self, elem): if (elem in ['@', '.', '~', '$', '!']): return False if (self.enemies == "upper" and elem.isupper()): return True elif (self.enemies == "lower" and elem.islower()): return True return False def is_unshottable(self, elem): if (elem in ['#', '&', 'X', 'x'] or elem in self.already_shoot): return True return False def play(self): ##### LOBBY ####################################################################### self.wait_lobby() ####MATCH############################################################################ start_match = time.time() most_probable_impostor = "" while (True): self.update() # GESTIONE ACCUSE most_probable_impostor = self.check_impostors( most_probable_impostor) # GESTIONE COOLDOWN if ((time.time() - start_match) < 45.0): print("waiting") while ((time.time() - start_match) < 45.0): # TODO pass # ATTACK AND MOVE if (not (self.attack())): result = self.move() if (result == 1 or result == 2): return self.manage_end(result, start_match)
class Explore(): def __init__(self, shrink_factor): self.points_of_interst = [(0, 0), (5, -11.5), (-8.65, -10.0), (8.0, 10.0), (-6.0, 12.0), (-2, -11), (1, 11)] self.start_time = None self.current_goal = None self.global_costmap_update = None self.global_costmap_update_width = None self.global_costmap_update_height = None self.shrink_factor = shrink_factor self.range_of_vision = 0.6 self.current_odometry = None self.map_set = False self.msg = "" #used to see which cells have been explored # 0=obstacle,outOfBounds 1=unexplored, 2=explored self.exploration_map = None self.grid = None self.finder = AStarFinder(diagonal_movement=DiagonalMovement.always) self.img = None self.previous_b_x = None self.previous_b_y = None self.previous_a_y = None self.previous_a_x = None #used for pathfinding and reseting exploration map #0=obstacle 1=free self.default_map = None #local costmap self.local_costmap = None self.local_costmap_origin = None self.local_costmap_width = None self.local_costmap_height = None self.local_costmap_setup = False self.global_costmap = None rospy.loginfo("Waiting for a map...") try: occ_map = rospy.wait_for_message("/map", OccupancyGrid, 20) except: rospy.logerr("Problem getting a map. Check that you have a map_server" " running: rosrun map_server map_server <mapname> " ) sys.exit(1) rospy.loginfo("Map received. %d X %d, %f px/m." % (occ_map.info.width, occ_map.info.height, occ_map.info.resolution)) self.map_width = occ_map.info.width self.map_height = occ_map.info.height self.map_resolution = occ_map.info.resolution self.map_data = occ_map.data self.map_real_origin_x = occ_map.info.origin.position.x self.map_real_origin_y = occ_map.info.origin.position.y self.map_origin_x = ( occ_map.info.origin.position.x + (self.map_width / 2.0) * self.map_resolution*self.shrink_factor ) self.map_origin_y = ( occ_map.info.origin.position.y + (self.map_height / 2.0) * self.map_resolution*self.shrink_factor ) self.set_map_and_reduce() self._odometry_sub = rospy.Subscriber("/odom", Odometry, self._odometry_callback, queue_size=1) self._exploring_sub = rospy.Subscriber("/exploring", String, self._exploring_callback, queue_size=1) self._pose_subscriber = rospy.Subscriber("/amcl_pose", PoseWithCovarianceStamped, self._pose_callback, queue_size=1) self._local_costmap_subscriber = rospy.Subscriber("/move_base/local_costmap/costmap", OccupancyGrid, self._local_costmap_callback, queue_size=1) self._local_costmap_update_subscriber = rospy.Subscriber("/move_base/local_costmap/costmap_updates", OccupancyGridUpdate, self._local_costmap_update_callback, queue_size=1) self._global_costmap_subscriber = rospy.Subscriber("/move_base/global_costmap/costmap", OccupancyGrid, self._global_costmap_callback , queue_size=1) self._global_costmap_update_subscriber = rospy.Subscriber("/move_base/global_costmap/costmap_updates", OccupancyGridUpdate, self._global_costmap_update_callback , queue_size=1) self.goal_publisher = rospy.Publisher("/where_to_go", PoseWithCovarianceStamped ,queue_size=1) def _local_costmap_callback(self, costmap): self.local_costmap = costmap.data self.local_costmap_origin_position = self.translate_coord(costmap.info.origin.position.x, costmap.info.origin.position.y) self.local_costmap_width = costmap.info.width self.local_costmap_height = costmap.info.height self.local_costmap_setup = True def _local_costmap_update_callback(self, costmap): #rospy.loginfo("local_costmap_update_callback") self.local_costmap = costmap.data #rospy.loginfo("lcmu, x, y: {}".format((costmap.x, costmap.y))) #rospy.loginfo("Lcmu, height, width: {}".format((costmap.height, costmap.width))) def _global_costmap_callback(self, costmap): self.global_costmap= list(costmap.data) def _global_costmap_update_callback(self, costmap): self.global_costmap_update = costmap.data self.global_costmap_update_height = costmap.height self.global_costmap_update_width = costmap.width for i in range(len(costmap.data)): y = i/costmap.width + costmap.y x= i%costmap.width + costmap.x #print("type of gcm: {}, type of gcmu: {}".format(len(self.global_costmap), len(costmap.data))) self.global_costmap[y*self.map_width + x] = costmap.data[i] #rospy.loginfo("gcmu, x, y: {}".format((costmap.x, costmap.y))) #rospy.loginfo("gcmu, height, width: {}".format((costmap.height, costmap.width))) def _exploring_callback(self, msg): self.msg = msg.data def _pose_callback(self, odometry): self.current_odometry = odometry if self.map_set: self.update_exploration_map([], self.current_odometry.pose.pose) def _odometry_callback(self, odo): if self.map_set and self.current_odometry is not None and self.msg == "explore": if self.start_time is None: print("started time") self.start_time = time.time() copy_odo = deepcopy(self.current_odometry) #goal_pose = self.calc_next_goal(copy_odo.pose.pose) goal_pose = self.simple_calc_next_goal(copy_odo.pose.pose) self.current_goal = (goal_pose[0]*3, goal_pose[1]*3) rospy.loginfo("current_goal: {}".format(self.current_goal)) rospy.loginfo("current_array_pose: {}, goal_array_pose: {}".format(self.translate_coord(copy_odo.pose.pose.position.x, copy_odo.pose.pose.position.y), goal_pose)) goal_pose = self.translate_coord_back(goal_pose[0], goal_pose[1]) rospy.loginfo("current_real_pose: {}, goal_real_pose: {}".format((round(copy_odo.pose.pose.position.x, 3), round(copy_odo.pose.pose.position.y, 3)), (round(goal_pose[0], 3), round(goal_pose[1], 3)))) new_odo = copy_odo new_odo.pose.pose.position.x = goal_pose[0] new_odo.pose.pose.position.y = goal_pose[1] self.goal_publisher.publish(new_odo) rospy.sleep(3) def restart_exploration(self): self.exploration_map = self.default_map self.img = Image.fromarray(self.exploration_map.T, 'L') self.map_set = True rospy.loginfo("setup finished") def set_map(self): self.map_set = false self.default_map = np.zeros((self.map_height, self.map_width), dtype = np.uint8) for i in range(self.map_height): for j in range(self.map_width): cell = self.map_data[i*self.map_width + j] if cell < 0.196 and cell >= 0: #not explored self.default_map[i][j] = 1 self.grid = Grid(matrix = self.default_map) self.restart_exploration() def set_map_and_reduce(self): #reduce the resolution as well self.map_set = False self.default_map = np.zeros((self.map_height/self.shrink_factor, self.map_width/self.shrink_factor), dtype = np.uint8) for i in range(0, len(self.default_map)): for j in range(0, len(self.default_map[0])): sum = 0 for k in range(i*self.shrink_factor, i*self.shrink_factor+self.shrink_factor): for l in range(j*self.shrink_factor, j*self.shrink_factor + self.shrink_factor): cell = self.map_data[k*self.map_width + l] if cell < 0.196 and cell >= 0: sum = sum + 1 if sum == math.pow(self.shrink_factor,2): self.default_map[i, j] = 1 self.inflate_obstacles() self.grid = Grid(matrix = self.default_map) self.restart_exploration() def inflate_obstacles(self): temp_img = Image.fromarray(self.default_map.T, 'L') dis= 4 for i in range(len(self.default_map)): for j in range(len(self.default_map[0])): if self.default_map[i][j] == 0: #if i > dis and j > dis and i < len(self.default_map)-dis and j < len(self.default_map) - dis: ImageDraw.Draw(temp_img).ellipse([(i-dis, j-dis), (i+dis, j+dis)],fill=0, outline=0) self.default_map = np.array(temp_img).T #return temp_img def update_exploration_map(self, scan_data, pose): # does not use the scan_data # assume that camera is not abstructed # can be improved by taking the scan_data angle_of_vision = (math.pi*3)/5 robot_orientation = self.getHeading(pose.orientation) robot_position = pose.position """ a b -------- \ / \ / \ / \/ c c = the position of robot triangle = what the robot can see with the camera """ if robot_orientation - angle_of_vision/2 < -math.pi: b_angle = math.pi + (math.pi + (robot_orientation - angle_of_vision/2)) else: b_angle = robot_orientation - angle_of_vision/2 b_x = self.range_of_vision*math.cos(b_angle) + robot_position.x b_y = self.range_of_vision*math.sin(b_angle) + robot_position.y if robot_orientation + angle_of_vision/2 > math.pi: a_angle = -(math.pi - ((robot_orientation + angle_of_vision/2) - math.pi)) else: a_angle = robot_orientation + angle_of_vision/2 a_x = self.range_of_vision*math.cos(a_angle) + robot_position.x a_y = self.range_of_vision*math.sin(a_angle) + robot_position.y #transform the cords to array space b_x, b_y = self.translate_coord(b_x, b_y) a_x, a_y = self.translate_coord(a_x, a_y) c_x, c_y = self.translate_coord(robot_position.x, robot_position.y) #set cells to 2 (explored) if self.previous_b_x is None: ImageDraw.Draw(self.img).polygon([(a_y, a_x), (b_y, b_x), (c_y, c_x)], outline=2, fill=2) else: ImageDraw.Draw(self.img).polygon([(a_y, a_x), (b_y, b_x), (c_y, c_x)], outline=2, fill=2) ImageDraw.Draw(self.img).polygon([(a_y, a_x), (b_y, b_x), (self.previous_b_y, self.previous_b_x), (self.previous_a_y, self.previous_a_x)], outline=2, fill=2) ImageDraw.Draw(self.img).polygon([(self.previous_a_y, self.previous_a_x), (a_y, a_x), (self.previous_b_y, self.previous_b_x), (b_y, b_x)], outline=2, fill=2) self.previous_b_x = b_x self.previous_b_y = b_y self.previous_a_y = a_y self.previous_a_x = a_x def calc_next_goal(self, pose): #where the search will start (the location of robot/pose) x, y = self.translate_coord(pose.position.x, pose.position.y) self.exploration_map = np.array(self.img).T level = 0 inside_the_wall = False go_to = 1 #go to unexplored point if self.default_map[y][x] == 0: rospy.loginfo("calc_next_goal: inside the wall") inside_the_wall = True go_to = 2 #go to explored point while True: x_start = np.max([x - level, 0]) x_end = np.min([x + level, self.map_width/self.shrink_factor - 1]) y_start = np.max([y - level, 0]) y_end = np.min([y + level, self.map_height/self.shrink_factor - 1]) #for each: if not explored and can be reached i = y_start j = x_start while j < x_end: if j < self.map_width/self.shrink_factor and self.exploration_map[i][j] == 1: if (inside_the_wall or self.is_reachable(x, y, j, i)) and self.far_enough(x, y, j, i) and not self.blocked_in_local_costmap(j, i) and not self.blocked_in_global_costmap(j,i): return (j, i) else: self.exploration_map[i][j] = 0 j = j + 1 i = y_end j = x_start while i < y_end: if i < self.map_height/self.shrink_factor and self.exploration_map[i][j] == 1: if (inside_the_wall or self.is_reachable(x, y, j, i)) and self.far_enough(x, y, j, i) and not self.blocked_in_local_costmap(j, i) and not self.blocked_in_global_costmap(j,i): return (j, i) else: self.exploration_map[i][j] = 0 i = i + 1 i = y_end j = x_end while j > x_start: if j >= 0 and self.exploration_map[i][j] == 1: if (inside_the_wall or self.is_reachable(x, y, j, i)) and self.far_enough(x, y, j, i) and not self.blocked_in_local_costmap(j, i) and not self.blocked_in_global_costmap(j,i): return (j, i) else: self.exploration_map[i][j] = 0 j = j - 1 i = y_start j = x_end while i > y_start: if i >= 0 and self.exploration_map[i][j] == 1: if (inside_the_wall or self.is_reachable(x, y, j, i)) and self.far_enough(x, y, j, i) and not self.blocked_in_local_costmap(j, i) and not self.blocked_in_global_costmap(j,i): return (j, i) else: self.exploration_map[i][j] = 0 i = i - 1 level = level +1 #worst case if level > self.map_width and level > self.map_height: rospy.logwarn("Goal not found, restarting on level: {}".format(level)) self.restart_exploration() level = 0 def simple_calc_next_goal(self, pose): self.exploration_map = np.array(self.img).T if len(self.points_of_interst) == 0: return (0, 0) shortest= [] i = 0 x, y = self.translate_coord(pose.position.x, pose.position.y) rospy.loginfo("simple_calc, x,y: {}".format((x,y))) while len(self.points_of_interst) > i: p1 = self.points_of_interst[i] x2, y2 = self.translate_coord(p1[0], p1[1]) dis = self.calc_dis(x, y, x2, y2) if dis < 1: del self.points_of_interst[i] else: shortest.append((dis, (x2, y2))) i+=1 shortest.sort() return shortest[0][1] def translate_coord(self, x, y): x = int((x - self.map_origin_x)/(self.map_resolution*self.shrink_factor) + 0.5 + self.map_width/2.0) y = int((y - self.map_origin_y)/(self.map_resolution*self.shrink_factor) + 0.5 + self.map_height/2.0) return (x, y) def translate_coord_back(self, x, y): real_x = (x - self.map_width/2.0)*self.map_resolution*self.shrink_factor + self.map_origin_x real_y = (y - self.map_height/2.0)*self.map_resolution*self.shrink_factor + self.map_origin_y return (real_x, real_y) def is_reachable(self, x, y, x2, y2): self.grid.cleanup() start = self.grid.node(x, y) end = self.grid.node(x2, y2) path, runs = self.finder.find_path(start, end, self.grid) return len(path) > 0 def get_goal(self, x, y, x2, y2): min_dis = 0.25 self.grid.cleanup() start = self.grid.node(x, y) end = self.grid.node(x2, y2) path, runs = self.finder.find_path(start, end, self.grid) if len(path) == 0: return None path = path point = None dis = 0 while True: if len(path) ==0: break point = path[0] r_dis = math.sqrt(math.pow((x2 - point[0])*self.map_resolution*self.shrink_factor, 2) + math.pow((y2 - point[1])*self.map_resolution*self.shrink_factor, 2)) if r_dis == 0: ang = 0 elif r_dis <= self.range_of_vision and r_dis >= min_dis: ang = math.acos(((x2 - point[0])*self.map_resolution*self.shrink_factor)/r_dis) if x2 - point[0] <= 0: ang = ang if y2 - point[1] <= 0: ang = ang - 3*math.pi/2 else: ang = -(ang-math.pi/2) else: if y2 - point[1] <= 0: ang = ang + math.copysign(1, x2 - point[0])*math.pi/2 else: ang = ang break elif r_dis >= min_dis: path = path[(len(path) - 1):] else: point = path[0] #ang = return (point[0], point[1], ang) def far_enough(self, x, y, x2, y2): r_dis = math.sqrt(math.pow((x2 - x)*self.map_resolution*self.shrink_factor, 2) + math.pow((y2 - y)*self.map_resolution*self.shrink_factor, 2)) return r_dis >= 0.5 def calc_dis(self, x, y, x2, y2): r_dis = math.sqrt(math.pow((x2 - x)*self.map_resolution*self.shrink_factor, 2) + math.pow((y2 - y)*self.map_resolution*self.shrink_factor, 2)) return r_dis def blocked_in_local_costmap(self, x, y): rospy.loginfo("local costmap initiated: {}".format(self.local_costmap is not None)) if not self.local_costmap_setup: return False rospy.loginfo("costmap, origin: {}, height/width: {}".format((self.local_costmap_origin_position[0], self.local_costmap_origin_position[1]), (self.local_costmap_height, self.local_costmap_width))) local_x = (x - self.local_costmap_origin_position[0])*self.shrink_factor local_y = (y - self.local_costmap_origin_position[1])*self.shrink_factor rospy.loginfo("costmap, x: {}, y: {}".format(local_x, local_y, )) if local_x >= 0 and local_x < self.local_costmap_width and local_y >= 0 and local_y < self.local_costmap_height: if self.local_costmap[local_y*self.local_costmap_width + local_x] == 0: return False else: return True else: return False def blocked_in_global_costmap(self, x, y): rospy.loginfo("global costmap initiated: {}".format(self.global_costmap is not None)) if self.global_costmap == None: return False if self.global_costmap[y*self.shrink_factor*self.map_width + x*self.shrink_factor] == 0: return False else: rospy.loginfo("Blocked in global costmap: True") return True def getHeading(self, q): """ from pf_localisation.util.py Get the robot heading in radians from a Quaternion representation. :Args: | q (geometry_msgs.msg.Quaternion): a orientation about the z-axis :Return: | (double): Equivalent orientation about the z-axis in radians """ yaw = math.atan2(2 * (q.x * q.y + q.w * q.z), q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z) return yaw
class Enemy(pygame.sprite.Sprite): # Define the constructor for invader def __init__(self, color, width, height, x_ref, y_ref): # Call the sprite constructor super().__init__() # pathfinding map generation matrix = [[0 for y in range(maxsizey)] for x in range(maxsizex)] # Create walls on the screen (each tile is 20 x 20 so alter cords) self.hack = pygame.Surface([maxsizex * 20, maxsizey * 20], pygame.SRCALPHA) for y in range(maxsizey): for x in range (maxsizex): if map[x][y] == " ": #matrix[x][y] = 1 #stlightly randomises map to make enemies move interestingly randint = random.randint(1,50) matrix[x][y] = randint elif map[x][y] == "#" or map[x][y] == "": matrix[x][y] = 0 elif map[x][y] == "|": matrix[x][y] = 0 elif map[x][y] == "_": matrix[x][y] = 0 elif map[x][y] == "o": matrix[x][y] = 1 elif map[x][y] == "e": matrix[x][y] = 1 self.grid = Grid(matrix=matrix) # Create a sprite and fill it with colour self.image = pygame.Surface([width,height]) #self.image.fill(color) self.rect = self.image.get_rect() pygame.draw.circle(self.image, color, (width//2, height//2), width//2) # Set the position of the player attributes self.rect.x = x_ref self.rect.y = y_ref self.speedx = 0 self.speedy = 0 self.width = width self.height = height self.targetx = self.rect.x + self.width // 2 self.targety = self.rect.y + self.height // 2 def update(self): # definitions for later calculations xgrid = (self.rect.x + self.width - 1)// 20 ygrid = (self.rect.y + self.height - 1) // 20 centrex = self.rect.x + self.width // 2 centrey = self.rect.y + self.height // 2 #pathfinding logic ## if the target square has been reached sets the next one if (self.targetx == centrex) and (self.targety == centrey): if ((pacman.rect.x // 20 > 0) and (pacman.rect.y // 20 > 0) and (pacman.rect.x // 20 + 1 <= maxsizex - 1 ) and (pacman.rect.y // 20 + 1 <= maxsizey -1 )): start = self.grid.node(ygrid, xgrid) end = self.grid.node((pacman.rect.y + pacman.rect.height // 2) // 20, (pacman.rect.x + pacman.rect.width // 2) // 20) finder = AStarFinder(diagonal_movement=DiagonalMovement.never) #self.grid.cleanup() path, runs = finder.find_path(start, end, self.grid) self.grid.cleanup() if len(path) <= 1: oneblock = True else: oneblock = False self.targetx = (int(path[1][1]) * 20 + 10) self.targety = (int(path[1][0]) * 20 + 10) #print(path) #print('operations:', runs, 'path length:', len(path)) #print(self.grid.grid_str(path=path, start=start, end=end)) ## moves the enemy to the target square else: speedmultiplyer = 0 xdir = 0 ydir = 0 if centrex < self.targetx: speedmultiplyer += 1 xdir = 1 elif centrex > self.targetx: speedmultiplyer += 1 xdir = -1 elif centrey < self.targety: speedmultiplyer += 1 ydir = 1 elif centrey > self.targety: speedmultiplyer += 1 ydir = -1 self.rect.x += xdir * enemymovespeed / speedmultiplyer self.rect.y += ydir * enemymovespeed / speedmultiplyer