def test_pos_within(self): test_layout = ( """ ################## #0#. . # . # #2##### #####1# # . # . .#3# ################## """) universe = CTFUniverse.create(test_layout, 4) al = AdjacencyList(universe.free_positions()) free = set(pos for pos, val in universe.maze.items() if not val) self.assertFalse((0, 0) in al) self.assertRaises(NoPathException, al.pos_within, (0, 0), 0) self.assertFalse((6, 2) in al) self.assertRaises(NoPathException, al.pos_within, (6, 2), 0) self.assertTrue((1, 1) in al) self.assertEqual(set([(1, 1)]), al.pos_within((1, 1), 0)) target = set([(1, 1), (1, 2), (1,3), (2, 3), (3, 3), (3, 3)]) self.assertEqual(target, al.pos_within((1, 1), 5)) # assuming a_star is working properly for pos in target: self.assertTrue(len(al.a_star((1, 1), pos)) < 5) for pos in free.difference(target): self.assertTrue(len(al.a_star((1, 1), pos)) >= 5)
def test_pos_within(self): test_layout = ( """ ################## #0#. . # . # #2##### #####1# # . # . .#3# ################## """) universe = CTFUniverse.create(test_layout, 4) al = AdjacencyList(universe.free_positions()) free = {pos for pos, val in universe.maze.items() if not val} assert not ((0, 0) in al) with pytest.raises(NoPathException): al.pos_within((0, 0), 0) assert not ((6, 2) in al) with pytest.raises(NoPathException): al.pos_within((6, 2), 0) assert (1, 1) in al unittest.TestCase().assertCountEqual([(1, 1)], al.pos_within((1, 1), 0)) target = [(1, 1), (1, 2), (1,3), (2, 3), (3, 3)] unittest.TestCase().assertCountEqual(target, al.pos_within((1, 1), 5)) # assuming a_star is working properly for pos in target: assert len(al.a_star((1, 1), pos)) < 5 for pos in free.difference(target): assert len(al.a_star((1, 1), pos)) >= 5
def test_pos_within(self): test_layout = (""" ################## #0#. . # . # #2##### #####1# # . # . .#3# ################## """) universe = CTFUniverse.create(test_layout, 4) al = AdjacencyList(universe.free_positions()) free = {pos for pos, val in universe.maze.items() if not val} assert not ((0, 0) in al) with pytest.raises(NoPathException): al.pos_within((0, 0), 0) assert not ((6, 2) in al) with pytest.raises(NoPathException): al.pos_within((6, 2), 0) assert (1, 1) in al unittest.TestCase().assertCountEqual([(1, 1)], al.pos_within((1, 1), 0)) target = [(1, 1), (1, 2), (1, 3), (2, 3), (3, 3)] unittest.TestCase().assertCountEqual(target, al.pos_within((1, 1), 5)) # assuming a_star is working properly for pos in target: assert len(al.a_star((1, 1), pos)) < 5 for pos in free.difference(target): assert len(al.a_star((1, 1), pos)) >= 5
def test_pos_within(self): test_layout = ( """ ################## #0#. . # . # #2##### #####1# # . # . .#3# ################## """) universe = CTFUniverse.create(test_layout, 4) al = AdjacencyList(universe.free_positions()) free = set(universe.maze.pos_of(Free)) self.assertFalse((0, 0) in al) self.assertRaises(NoPathException, al.pos_within, (0, 0), 0) self.assertFalse((6, 2) in al) self.assertRaises(NoPathException, al.pos_within, (6, 2), 0) self.assertTrue((1, 1) in al) self.assertEqual(set([(1, 1)]), al.pos_within((1, 1), 0)) target = set([(1, 1), (1, 2), (1,3), (2, 3), (3, 3), (3, 3)]) self.assertEqual(target, al.pos_within((1, 1), 5)) # assuming a_star is working properly for pos in target: self.assertTrue(len(al.a_star((1, 1), pos)) < 5) for pos in free.difference(target): self.assertTrue(len(al.a_star((1, 1), pos)) >= 5)
def test_a_star2(self): test_layout = ( """ ######## #1# # # # #0 # # # ######## """ ) universe = CTFUniverse.create(test_layout, 2) al = AdjacencyList(universe.free_positions()) #Test distance to middle from both sides print(al.a_star(universe.bots[0].current_pos, universe.bots[1].current_pos)) print(al.a_star(universe.bots[1].current_pos, universe.bots[0].current_pos)) assert 7 == len(al.a_star(universe.bots[0].current_pos, universe.bots[1].current_pos)) assert 7 == len(al.a_star(universe.bots[1].current_pos, universe.bots[0].current_pos))
def test_a_star(self): test_layout = ( """ ################## #02.# . # . # # # ### ####1 # # ### . # . ##3# # # ################## """) universe = CTFUniverse.create(test_layout, 4) al = AdjacencyList(universe.free_positions()) #Test distance to middle from both sides assert 11 == len(al.a_star((1, 1), (7, 2))) assert 12 == len(al.a_star((2, 1), (7, 2))) assert 14 == len(al.a_star((16, 1), (7, 2))) assert 15 == len(al.a_star((15, 1), (7, 2)))
class SmartEatingPlayer(AbstractPlayer): def set_initial(self): self.adjacency = AdjacencyList( self.current_uni.reachable([self.initial_pos])) self.next_food = None def goto_pos(self, pos): return self.adjacency.a_star(self.current_pos, pos)[-1] def get_move(self): # check, if food is still present if (self.next_food is None or self.next_food not in self.enemy_food): if not self.enemy_food: # all food has been eaten? ok. i’ll stop return datamodel.stop self.next_food = self.rnd.choice(self.enemy_food) try: dangerous_enemy_pos = [ bot.current_pos for bot in self.enemy_bots if bot.is_destroyer ] next_pos = self.goto_pos(self.next_food) # check, if the next_pos has an enemy on it if next_pos in dangerous_enemy_pos: # whoops, better wait this round and take another food next time self.next_food = None return datamodel.stop move = diff_pos(self.current_pos, next_pos) return move except NoPathException: return datamodel.stop
class SmartEatingPlayer(AbstractPlayer): def set_initial(self): self.adjacency = AdjacencyList(self.current_uni.reachable([self.initial_pos])) self.next_food = None def goto_pos(self, pos): return self.adjacency.a_star(self.current_pos, pos)[-1] def get_move(self): # check, if food is still present if (self.next_food is None or self.next_food not in self.enemy_food): if not self.enemy_food: # all food has been eaten? ok. i’ll stop return datamodel.stop self.next_food = self.rnd.choice(self.enemy_food) try: dangerous_enemy_pos = [bot.current_pos for bot in self.enemy_bots if bot.is_destroyer] next_pos = self.goto_pos(self.next_food) # check, if the next_pos has an enemy on it if next_pos in dangerous_enemy_pos: # whoops, better wait this round and take another food next time self.next_food = None return datamodel.stop move = diff_pos(self.current_pos, next_pos) return move except NoPathException: return datamodel.stop
def test_path_to_same_position(self): test_layout = (""" ################## #0#. . # . # #2##### #####1# # . # . .#3# ################## """) universe = CTFUniverse.create(test_layout, 4) al = AdjacencyList(universe.free_positions()) self.assertEqual([], al.a_star((1, 1), (1, 1))) self.assertEqual([], al.bfs((1, 1), [(1, 1)]))
def test_a_star(self): test_layout = (""" ################## #0#. . # . # #2##### #####1# # . # . .#3# ################## """) universe = CTFUniverse.create(test_layout, 4) al = AdjacencyList(universe.free_positions()) # just a simple smoke test self.assertEqual(14, len(al.a_star((1, 1), (3, 1))))
def test_a_star(self): test_layout = ( """ ################## #0#. . # . # #2##### #####1# # . # . .#3# ################## """) universe = CTFUniverse.create(test_layout, 4) al = AdjacencyList(universe.free_positions()) # just a simple smoke test self.assertEqual(14, len(al.a_star((1, 1), (3, 1))))
def test_path_to_same_position(self): test_layout = ( """ ################## #0#. . # . # #2##### #####1# # . # . .#3# ################## """) universe = CTFUniverse.create(test_layout, 4) al = AdjacencyList(universe.free_positions()) assert [] == al.a_star((1, 1), (1, 1)) assert [] == al.bfs((1, 1), [(1, 1)])
def test_a_star2(self): test_layout = (""" ######## #1# # # # #0 # # # ######## """) universe = CTFUniverse.create(test_layout, 2) al = AdjacencyList(universe.free_positions()) #Test distance to middle from both sides print( al.a_star(universe.bots[0].current_pos, universe.bots[1].current_pos)) print( al.a_star(universe.bots[1].current_pos, universe.bots[0].current_pos)) assert 7 == len( al.a_star(universe.bots[0].current_pos, universe.bots[1].current_pos)) assert 7 == len( al.a_star(universe.bots[1].current_pos, universe.bots[0].current_pos))
def test_a_star(self): test_layout = (""" ################## #02.# . # . # # # ### ####1 # # ### . # . ##3# # # ################## """) universe = CTFUniverse.create(test_layout, 4) al = AdjacencyList(universe.free_positions()) #Test distance to middle from both sides assert 11 == len(al.a_star((1, 1), (7, 2))) assert 12 == len(al.a_star((2, 1), (7, 2))) assert 14 == len(al.a_star((16, 1), (7, 2))) assert 15 == len(al.a_star((15, 1), (7, 2))) # Test basic assertions assert 0 == len(al.a_star((1, 1), (1, 1))) assert 1 == len(al.a_star((1, 1), (2, 1))) assert 1 == len(al.a_star((2, 1), (1, 1))) # Test distance to middle from both sides assert 11 == len(al.a_star((1, 1), (7, 2))) assert 12 == len(al.a_star((2, 1), (7, 2))) assert 14 == len(al.a_star((16, 1), (7, 2))) assert 15 == len(al.a_star((15, 1), (7, 2)))
def test_pos_within(self): test_layout = ( """ ################## #0#. . # . # #2##### #####1# # . # . .#3# ################## """) universe = create_CTFUniverse(test_layout, 4) al = AdjacencyList(universe) free = set(universe.maze.pos_of(Free)) self.assertRaises(NoPositionException, al.pos_within, (0, 0), 0) self.assertRaises(NoPositionException, al.pos_within, (6, 2), 0) self.assertEqual(set([(1, 1)]), al.pos_within((1, 1), 0)) target = set([(1, 1), (1, 2), (1,3), (2, 3), (3, 3), (3, 3)]) self.assertEqual(target, al.pos_within((1, 1), 5)) # assuming a_star is working properly for pos in target: self.assertTrue(len(al.a_star((1, 1), pos)) < 5) for pos in free.difference(target): self.assertTrue(len(al.a_star((1, 1), pos)) >= 5)
class OurPlayer(AbstractPlayer): def set_initial(self): self.adjacency = AdjacencyList(self.current_uni.reachable([self.initial_pos])) self.next_food = None def goto_pos(self, pos): return self.adjacency.a_star(self.current_pos, pos)[-1] def get_move(self): # from SmartRandom dangerous_enemy_pos = [bot.current_pos for bot in self.enemy_bots if bot.is_destroyer] killable_enemy_pos = [bot.current_pos for bot in self.enemy_bots if bot.is_harvester] # easy kill (please test) for killable in killable_enemy_pos: if killable in self.legal_moves.items(): move = diff_pos(self.current_pos, killable) self.say("Easy kill!") return move #pdb.set_trace() # panic # for dangerous in dangerous_enemy_pos: # if killable in self.legal_moves.items(): # move = diff_pos(self.current_pos, killable) # self.say("Easy kill!") # return move # check, if food is still present # if the nearest is not suitable, choose one at random! if (self.next_food is None or self.next_food not in self.enemy_food): if not self.enemy_food: # all food has been eaten? ok. i’ll stop return datamodel.stop # SUBOPTIMAL (chooses at random) self.next_food = self.rnd.choice(self.enemy_food) try: next_pos = self.goto_pos(self.next_food) move = diff_pos(self.current_pos, next_pos) return move except NoPathException: return datamodel.stop
def test_a_star_exceptions(self): test_layout = (""" ############ #0. #.1# ############ """) universe = CTFUniverse.create(test_layout, 2) al = AdjacencyList(universe.free_positions()) with pytest.raises(NoPathException): al.a_star((1, 1), (10, 1)) with pytest.raises(NoPathException): al.a_star((0, 1), (10, 1)) with pytest.raises(NoPathException): al.a_star((1, 1), (11, 1))
def test_a_star_exceptions(self): test_layout = ( """ ############ #0. #.1# ############ """) universe = CTFUniverse.create(test_layout, 2) al = AdjacencyList(universe.free_positions()) with pytest.raises(NoPathException): al.a_star((1, 1), (10, 1)) with pytest.raises(NoPathException): al.a_star((0, 1), (10, 1)) with pytest.raises(NoPathException): al.a_star((1, 1), (11, 1))
class FoodEatingPlayer(AbstractPlayer): def set_initial(self): self.adjacency = AdjacencyList(self.current_uni.reachable([self.initial_pos])) self.next_food = None def goto_pos(self, pos): return self.adjacency.a_star(self.current_pos, pos)[-1] def get_move(self): # check, if food is still present if self.next_food is None or self.next_food not in self.enemy_food: if not self.enemy_food: # all food has been eaten? ok. i’ll stop return datamodel.stop self.next_food = self.rnd.choice(self.enemy_food) try: next_pos = self.goto_pos(self.next_food) move = diff_pos(self.current_pos, next_pos) return move except NoPathException: return datamodel.stop
class FoodEatingPlayer(AbstractPlayer): def set_initial(self): self.adjacency = AdjacencyList( self.current_uni.reachable([self.initial_pos])) self.next_food = None def goto_pos(self, pos): return self.adjacency.a_star(self.current_pos, pos)[-1] def get_move(self): # check, if food is still present if (self.next_food is None or self.next_food not in self.enemy_food): if not self.enemy_food: # all food has been eaten? ok. i’ll stop return datamodel.stop self.next_food = self.rnd.choice(self.enemy_food) try: next_pos = self.goto_pos(self.next_food) move = diff_pos(self.current_pos, next_pos) return move except NoPathException: return datamodel.stop
class FranziPlayer(AbstractPlayer): """ Basically a really awesome player. """ def __init__(self, priority_dir='stop', w_pdir=1, w_mate=-3, w_danger=-20, w_eat=7, w_defend=10, save_dist=5.): """ Attributes: - priority_dir: which direction to favor ('up' or 'down') - w_pdir: how important it is to go into the favored direction - w_mate: how important it is to stay within reasonable distance from the teammate - w_danger: how important it is to avoid enemy destroyers - w_eat: how important it is to eat the enemy's food - w_defend: how important it is to kill enemy harvesters """ if priority_dir == 'up': self.priority_dir = north elif priority_dir == 'down': self.priority_dir = south else: raise RuntimeWarning("Invalid priority_dir, use either up or down!") self.priority_dir = None self.save_dist = float(save_dist) self.w_danger = w_danger self.w_eat = w_eat self.w_pdir = w_pdir self.w_mate = w_mate self.w_defend = w_defend self.adjacency = None # to store an adjacency list with all possible positions def set_initial(self): # Now ``self.current_uni`` and ``self.current_state`` are known. # ``set_initial`` is always called before ``get_move``, so we can do some # additional initialization here self.adjacency = AdjacencyList(self.current_uni.reachable([self.initial_pos])) # Just printing the universe to give you an idea, please remove all # print statements in the final player. print self.current_uni.pretty def shortest_path(self, pos1, pos2): """ In the current maze, get the shortest path (list of positions) from pos1 to pos2 The length of this list is the maze distance of both positions will raise according exceptions if the positions are not reachable, etc. """ # using the a* search, you get a list of positions [pos2, ..., next_to_pos1] # ideally this path should be further pruned by removing unnecessary # detours introduced by using the manhattan distance as a heuristic return self.adjacency.a_star(pos1, pos2) def compute_min_dist(self, pos, other_pos): """ Inputs: - pos: for which position the distances should be computed - other_pos: a list of other positions (if any) Returns: - min_dist: the maze distance to the closest other position in the given list to our pos the distance is 0 if there are no other positions given (or the distance is actually 0, i.e. the bot is on this spot) """ if other_pos: return min([len(self.shortest_path(pos, i_pos)) for i_pos in other_pos]) return 0 def get_move(self): # get to know something about our surroundings dangerous_enemy_pos = [bot.current_pos for bot in self.enemy_bots if bot.is_destroyer] killable_enemy_pos = [bot.current_pos for bot in self.enemy_bots if bot.is_harvester] teammate_pos = [bot.current_pos for bot in self.team_bots if not bot==self.me] # compute how good our current position is curr_min_dist_food = self.compute_min_dist(self.current_pos, self.enemy_food) curr_min_dist_kill = self.compute_min_dist(self.current_pos, killable_enemy_pos) scored_moves = {} for move, new_pos in list(self.legal_moves.items()): # filter out obviously stupid moves if (move == stop or new_pos in dangerous_enemy_pos): continue # killing someone is always the best move elif new_pos in killable_enemy_pos: self.say("MUHAHAHAHAHA!!!") return move # compute the goodness of the new position else: ## compute the score of the move # improvements should be a 1 field difference -- do negative values make sense? # improvement in terms of getting closer to food food_improve = curr_min_dist_food-self.compute_min_dist(new_pos, self.enemy_food) score = self.w_eat*max(0, food_improve) # improvement in terms of getting closer to killable enemies kill_improve = curr_min_dist_kill-self.compute_min_dist(new_pos, killable_enemy_pos) score += self.w_defend*max(0, kill_improve) # make sure to get away from immediate danger danger_dist = self.compute_min_dist(new_pos, dangerous_enemy_pos) if danger_dist < self.save_dist: # the closer, the more dangerous score += self.w_danger*(1 - danger_dist/self.save_dist) # to avoid redundant behavior, stay away from teammates team_dist = self.compute_min_dist(new_pos, teammate_pos) if team_dist < self.save_dist: # the closer, the more dangerous score += self.w_mate*(1 - team_dist/self.save_dist) # is this our preferred direction? if move == self.priority_dir: score += self.w_pdir scored_moves[move] = score if scored_moves: best_move = max(scored_moves.keys(), key=scored_moves.get) # is this move especially cool? if self.legal_moves[best_move] in self.enemy_food: self.say("OmNomNom") return best_move else: # we ran out of smart moves self.say(">.<") return stop
class OurPlayer(BasePlayer): def set_initial(self): self.adjacency = AdjacencyList(self.current_uni.reachable([self.initial_pos])) self.next_food = None def goto_pos(self, pos): return self.adjacency.a_star(self.current_pos, pos)[-1] def abs_pos(self, vector): return (self.current_pos[0]+vector[0], self.current_pos[1]+vector[1]) def get_move(self): # from SmartRandom dangerous_enemy_pos = [bot.current_pos for bot in self.enemy_bots if (bot.is_destroyer and not bot.noisy)] killable_enemy_pos = [bot.current_pos for bot in self.enemy_bots if (bot.is_harvester and not bot.noisy)] # easy kill (kind of tested) for killable in killable_enemy_pos: if killable in self.legal_moves.values(): self.say("Easy kill!") print("Easy kill!") move = diff_pos(self.current_pos, killable) return move # don't die forbidden_moves = [] for dangerous in dangerous_enemy_pos: relative_pos = diff_pos(self.current_pos, dangerous) # check if the destroyer is nearby if relative_pos in ( (0,1), (1,0), (-1,0), (0,-1)): self.say("Enemy nearby!") forbidden_moves.append(relative_pos) if relative_pos in ( (0,2), (2,0), (-2,0), (0,-2)): self.say("Enemy in sight!") rpx, rpy = relative_pos forbidden_moves.append( (rpx//2, rpy//2) ) if relative_pos in ( (1,1), (1,-1), (-1,1), (-1,-1)): self.say("Enemy on diagonal!") rpx, rpy = relative_pos forbidden_moves.append( (0, rpy) ) forbidden_moves.append( (rpx, 0) ) forbidden_absolute_positions = [self.abs_pos(fm) for fm in forbidden_moves] # forbidden_absolute_positions WAS tested (kind of) # it doesn't account for walls (relevant in the second case) # check, if food is still present # if the nearest is not suitable, choose one at random! if (self.next_food is None or self.next_food not in self.enemy_food): if not self.enemy_food: # all food has been eaten? ok. i’ll stop return datamodel.stop self.next_food = self.get_efficient_eater_move() try: move = self.get_efficient_eater_move() # if it's not allowed, take a random move if move in forbidden_moves: # but we are not checking if it's forbidden again! next_pos = self.rnd.choice(list(self.legal_moves.values())) move = diff_pos(self.current_pos, next_pos) return move except NoPathException: return datamodel.stop
class ItalianPossessivePlayer(AbstractPlayer): def set_initial(self): self.adjacency = AdjacencyList( self.current_uni.reachable([self.initial_pos])) self.next_food = None def goto_pos(self, pos): #print(len(self.adjacency.a_star(self.current_pos, pos))) if len(self.adjacency.a_star(self.current_pos, pos)) > 0: return self.adjacency.a_star(self.current_pos, pos)[-1] else: return self.current_pos # Determine the closest enemy def get_enemy_to_block(self): dist_enemy0 = len( self.adjacency.a_star(self.current_pos, self.enemy_bots[0].current_pos)) dist_enemy1 = len( self.adjacency.a_star(self.current_pos, self.enemy_bots[1].current_pos)) self.enemy_to_block = np.argmin([dist_enemy0, dist_enemy1]) # Determine closest food for that enemy def get_closest_food(self): self.enemy_next_food_distance_list = np.array( list( map( lambda x: len( self.adjacency.a_star( self.enemy_bots[self.enemy_to_block].current_pos, x )), self.team_food))) # Decide which food to protect def get_food_to_protect(self): self.minimum_index = np.argmin(self.enemy_next_food_distance_list) self.food_to_protect = self.team_food[self.minimum_index] # Enemy path def get_enemy_path(self): self.enemy_path = self.adjacency.a_star( self.enemy_bots[self.enemy_to_block].current_pos, self.food_to_protect) # Point to intercept def get_point_to_intercept(self): if len(self.enemy_path) > 0: index = np.round(len(self.enemy_path) / 2) self.p_intercept = self.enemy_path[index.astype(int)] else: while len(self.enemy_path) == 0: self.enemy_next_food_distance_list = np.delete( self.enemy_next_food_distance_list, self.minimum_index) self.get_food_to_protect() self.get_enemy_path() index = np.round(len(self.enemy_path) / 2) self.p_intercept = self.enemy_path[index.astype(int)] #def sit_on_food(self): def get_move(self): # check, if food is still present self.say("Go Away!!") if (self.next_food is None or self.next_food not in self.enemy_food): if not self.enemy_food: # all food has been eaten? ok. i’ll stop return datamodel.stop self.get_enemy_to_block() self.get_closest_food() self.get_food_to_protect() self.get_enemy_path() self.get_point_to_intercept() try: next_pos = self.goto_pos(self.p_intercept) move = diff_pos(self.current_pos, next_pos) return move except NoPathException: print("Help!") return datamodel.stop
def len_of_shortest_path(layout): uni = CTFUniverse.create(layout, 2) al = AdjacencyList(uni.free_positions()) path = al.a_star(uni.bots[0].current_pos, uni.bots[1].current_pos) return len(path)
class EatingPlayerLower(AbstractPlayer): def set_initial(self): self.adjacency = AdjacencyList( self.current_uni.reachable([self.initial_pos])) self.tolerance = 5 self.range = range(1, 9) def gotoPos(self, aim): return (self.adjacency.a_star(self.current_pos, aim))[-1] def choose_strategy(self): if self.me.is_harvester: minDist2Bot = self.chooseClosestEnemy() strategy = 'run' if minDist2Bot[0] <= self.tolerance else 'eat' else: strategy = 'eat' return (strategy) def chooseClosestEnemy(self): dist2bot = np.array([ len(self.adjacency.a_star(self.current_pos, j.current_pos)) if j.is_destroyer else 1000 for j in self.enemy_bots ]) minDist = dist2bot.min() minPos = [x.current_pos for x in self.enemy_bots][dist2bot.argmin()] return (minDist, minPos) def eatMaxSafety(self, enemy_pos): next_step = np.zeros(len(self.enemy_food)) for i, j in enumerate(self.enemy_food): next_step[i] = len( self.adjacency.a_star( self.adjacency.a_star(self.current_pos, j)[-1], enemy_pos)) max_safe = next_step.max() max_pos = self.enemy_food[next_step.argmax()] return (max_safe, max_pos) def get_move(self): strategy = self.choose_strategy() nextPos = self.chooseNextPos(strategy) move = diffPos(self.current_pos, nextPos) if not move in self.legal_moves.keys(): move = self.rnd.choice(list(self.legal_moves.keys())) return (move) def chooseClosestFood(self): dist2food = np.array([ len(self.adjacency.a_star(self.current_pos, (x, y))) if y in self.range else 1000 for x, y in self.enemy_food ]) minDist = dist2food.min() minPos = self.enemy_food[dist2food.argmin()] return (minDist, minPos) def chooseNextPos(self, strategy): if strategy == 'eat': minFoodDist, posMinFood = self.chooseClosestFood() aim = posMinFood nextPos = self.gotoPos(aim) elif strategy == 'run': dummy, aim = self.chooseClosestEnemy() dummy2, aim2 = self.eatMaxSafety(aim) nextPos = self.gotoPos(aim2) return (nextPos)
class BasicDefensePlayer(AbstractPlayer): """ A crude defensive player. Will move towards the border, and as soon as it notices enemies in its territory, it will start to track them. When it kills the enemy it returns to the border and waits there for more. """ def set_initial(self): self.adjacency = AdjacencyList(self.current_uni) self.path = self.path_to_border self.tracking = None @property def path_to_border(self): """ Path to the closest border position. """ return self.adjacency.bfs(self.current_pos, self.team_border) @property def path_to_target(self): """ Path to the target we are currently tracking. """ return self.adjacency.a_star(self.current_pos, self.tracking_target.current_pos) @property def tracking_target(self): """ Bot object we are currently tracking. """ return self.current_uni.bots[self.tracking] def get_move(self): # if we were killed, for whatever reason, reset the path if self.current_pos == self.initial_pos: self.current_path = self.path_to_border # if we are not currently tracking anything if not self.tracking: # check the enemy positions possible_targets = [enemy for enemy in self.enemy_bots if self.team.in_zone(enemy.current_pos)] if possible_targets: # get the path to the closest one closest_enemy = min([(len(self.adjacency.a_star(self.current_pos, enemy.current_pos)),enemy) for enemy in possible_targets]) # track that bot by using its index self.tracking = closest_enemy[1].index else: # otherwise keep going if we aren't already underway if not self.path: self.path = self.path_to_border elif self.tracking: # if the enemy is no longer in our zone if not self.team.in_zone(self.tracking_target.current_pos): self.tracking = None self.path = self.path_to_border # otherwise update the path to the target else: self.path = self.path_to_target # if something above went wrong, just stand still if not self.path: return stop else: return diff_pos(self.current_pos, self.path.pop())
def len_of_shortest_path(layout): uni = CTFUniverse.create(layout, 2) al = AdjacencyList(uni.free_positions()) path = al.a_star(uni.bots[0].current_pos, uni.bots[1].current_pos) return len(path)
class UniverseNoiser(object): """ Class to make bot positions noisy. Supports uniform noise in maze space. Can be extended to support other types of noise. Noise will only be applied if the enemy bot is with a certain threshold (`sight_distance`). Parameters ---------- universe : CTFUniverse the universe which will later be used noise_radius : int, optional, default: 5 the radius for the uniform noise sight_distance : int, optional, default: 5 the distance at which noise is no longer applied. Attributes ---------- adjacency : AdjacencyList adjacency list representation of the Maze """ def __init__(self, universe, noise_radius=5, sight_distance=5): self.adjacency = AdjacencyList(universe) self.noise_radius = noise_radius self.sight_distance = sight_distance def uniform_noise(self, universe, bot_index): """ Apply uniform noise to the enemies of a Bot. Given a `bot_index` the method looks up the enemies of this bot. It then adds uniform noise in maze space to the enemy positions. If a position is noisy or not is indicated by the `noisy` attribute in the Bot class. The method will modify the reference, therefore it is important to use a copy of the universe as an argument. Parameters ---------- universe : CTFUniverse the universe to add noise to bot_index : int the bot whose enemies should be noisy Returns ------- noisy_universe : CTFUniverse universe with noisy enemy positions """ bot = universe.bots[bot_index] bots_to_noise = universe.enemy_bots(bot.team_index) for b in bots_to_noise: # Check that the distance between this bot and the enemy is larger # than `sight_distance`. if len(self.adjacency.a_star(bot.current_pos, b.current_pos)) > self.sight_distance: # If so then alter the position of the enemy possible_positions = list(self.adjacency.pos_within(b.current_pos, self.noise_radius)) b.current_pos = random.choice(possible_positions) b.noisy = True return universe
class OurPlayer(AbstractPlayer): b = "Bonnie" c = "Clyde" message_list = [\ (c, "This here's Miss Bonnie Parker. I'm Clyde Barrow. We rob banks."), \ (b, "Whooee! A man with a record!"), \ (c, "Hell, you might just be the best damn girl in Texas."), \ (b, "Go for it Clyde"), \ (b, "You're good!"), \ (c, "I ain't good. I'm the best!"), \ (b, "And modest."), \ (b, "Hey, that ain't ours!"), \ (c, "Sure it is."), \ (b, "But we come in this one."), \ (c, "That don't mean we have to go home in it!"), \ (c, "Next time, I'll aim a little lower!"), \ (b, "Tell them I don't smoke cigars."), \ (c, "'Least I ain't a liar."), \ (c, "We got a dollar ninety-eight, and you're laughing!"), \ ] talkcounter = 0 def __init__(self, name): self.name = name self.mess = "" def set_initial(self): self.current_strategy = 0 self.round_index = None self.score_history = np.zeros([2, 300]) self.tracking_idx = None self.path = [] self.memory = deque([], maxlen = 5) self.chase_mode = False self.border_mode = True self.chase_count = 0 self.FOOD_MIN = len(self.enemy_food)/3 def find_path(self, thingslist): """ finds the path to the nearest object *thingslist* - list of tuples with objects positions """ self.adjacency = AdjacencyList(self.current_uni.free_positions()) try: pathd = self.adjacency.bfs(self.current_pos, thingslist) except NoPathException: return None return pathd def read_score(self): self.score_history[0, self.round_index] = self.current_uni.teams[0].score self.score_history[1, self.round_index] = self.current_uni.teams[1].score @property def tracking_target(self): """ Bot object we are currently tracking. """ return self.current_uni.bots[self.tracking_idx] @property def path_to_target(self): """ Path to the target we are currently tracking. """ self.adjacency = AdjacencyList(self.current_uni.free_positions()) try: return self.adjacency.a_star(self.current_pos, self.tracking_target.current_pos) except NoPathException: return None def talk(self): mess = OurPlayer.message_list[0] if mess[0] == self.name: OurPlayer.message_list = OurPlayer.message_list[1:] OurPlayer.message_list.append(mess) string = mess[0] + ": " + mess[1] self.mess = string def start_chase(self): #self.say("Chase him!") self.chase_mode = True self.chase_count += 1 if self.partner: self.partner.chase_mode = True self.partner.chase_count += 1 def stop_chase(self): #self.say("Stopit!") self.chase_mode = False if self.partner: self.partner.chase_mode = False def go_for_border(self): if (self.me.index==0 or self.me.index==1) and self.border_mode: bor_u = [x for x in self.team_border if x[1]>x[0]//2 ] border_path = self.find_path(bor_u) elif (self.me.index==2 or self.me.index==3) and self.border_mode: bor_d = [x for x in self.team_border if x[1]<=x[0]//2] border_path = self.find_path(bor_d) else: border_path = self.find_path(self.team_border) if len(border_path)==0: return stop if border_path==None: return stop return diff_pos(self.current_pos, border_path.pop()) def go_for_food(self): food_path = self.find_path(self.enemy_food) mandist = manhattan_dist(self.me.current_pos, self.partner.me.current_pos) if mandist <=3 and self.round_index<100: distlst = [x for x in self.enemy_food if manhattan_dist(x, self.partner.me.current_pos)>5] food_path = self.find_path(distlst) if food_path==None: return self.random_move() if len(food_path)==0: return self.random_move() return diff_pos(self.current_pos, food_path.pop()) def safe_move(self, next_move, dontwanna=None): #get all the enemy bots that are destroyers dangerous_enemies = [enemy for enemy in self.enemy_bots if enemy.is_destroyer] #get all the positions where you can move to valid_pos = self.legal_moves.values() #get all the positions where dangerous enemies can move to (a list of two sublists) enemy_valid_pos_values = [self.current_uni.legal_moves(enemy.current_pos).values() for enemy in dangerous_enemies] #flatten list enemy_valid_pos_values = [item for sublist in enemy_valid_pos_values for item in sublist] #convert your planned next move to a position next_pos = tuple([sum(x) for x in zip(next_move,self.current_pos)]) #if your next position intersects with the enemy position if next_pos in enemy_valid_pos_values: #get all positions you could move to that are not enemy legal moves and are not the current position valid_pos = [i for i in valid_pos if i not in enemy_valid_pos_values and i != self.current_pos] if dontwanna: valid_pos = [i for i in valid_pos if i not in dontwanna] #pick any such safe position if len(valid_pos) > 0: next_pos = self.rnd.choice(valid_pos) next_move = tuple([x[0] - x[1] for x in zip(next_pos,self.current_pos)]) return(next_move) #if there are no valid positions, pick a random legal move else: try: self.say("".join(["I love you, ", + str(self.partner.name)])) except: pass return(self.rnd.choice(list(self.legal_moves.keys()))) else: return(next_move) def random_move(self): #self.say("Let the fight begin!") legal_moves = self.legal_moves # Remove stop try: del legal_moves[stop] except KeyError: pass # now remove the move that would lead to the previous_position # unless there is no where else to go. if len(legal_moves) > 1: for (k,v) in legal_moves.items(): if v == self.previous_pos: break del legal_moves[k] # just in case, there is really no way to go to: if not legal_moves: return stop # and select a move at random return self.rnd.choice(list(legal_moves.keys())) def attack_move(self): self.adjacency = AdjacencyList(self.current_uni.free_positions()) attackpath = [] if self.tracking_idx is not None: # if the enemy is no longer in our zone if not self.team.in_zone(self.tracking_target.current_pos): self.tracking_idx = None return self.go_for_food() # otherwise update the path to the target else: attackpath = self.path_to_target if self.tracking_idx is None: # check the enemy positions possible_targets = [enemy for enemy in self.enemy_bots if self.team.in_zone(enemy.current_pos)] if possible_targets: # get the path to the closest one try: possible_paths = [(enemy, self.adjacency.a_star(self.current_pos, enemy.current_pos)) for enemy in possible_targets] except NoPathException: return None else: return None if possible_paths: closest_enemy, path = min(possible_paths, key=lambda enemy_path: len(enemy_path[1])) self.tracking_idx = closest_enemy.index if len(attackpath)==0: return self.random_move() if len(attackpath)>0 and self.round_index%20==0: return self.random_move() return diff_pos(self.current_pos, attackpath.pop()) def get_distance_to_me(self, pos): return manhattan_dist(self.current_pos, pos) def get_closest_eatable_enemy_pos(self): enemies = [(enemy.current_pos, self.get_distance_to_me(enemy.current_pos)) for enemy in self.enemy_bots if enemy.is_harvester] if len(enemies) != 0: enemies = sorted(enemies, key=lambda x: x[1]) return enemies[0] return None def get_move(self): if OurPlayer.talkcounter % 13 == 0: self.talk() if OurPlayer.talkcounter % 13 == 10: self.mess = "" self.partner.mess = "" OurPlayer.talkcounter += 1 self.say(self.mess) if self.round_index is None: self.round_index = 0 else: self.round_index += 1 self.read_score() #switch both players to chase mode, if both are close but on two sides en = self.get_closest_eatable_enemy_pos() en = False if en: other_bot = [x for x in self.team_bots if x != self.me][0] dist_enemy_to_other_bot = manhattan_dist(other_bot.current_pos, en[0]) if (en[1] <= 5) and (dist_enemy_to_other_bot <= 5) and (self.get_distance_to_me(other_bot.current_pos) > en[1]): self.start_chase() if self.chase_count > 5: self.stop_chase() else: self.stop_chase() if self.chase_mode: #self.say("Chasemode") return self.safe_move(self.attack_move()) if self.me.is_destroyer: if self.border_mode: m1 = self.go_for_border() if m1 != stop: next_move = m1 else: next_move = self.go_for_food() self.border_mode = False else: next_move = self.go_for_food() am = self.attack_move() if am and not self.border_mode and len(self.enemy_food) < self.FOOD_MIN: next_move = am self.say("".join(["I'm going for them, ", self.partner.name, '!!'])) else: next_move = self.go_for_food() final_move = self.safe_move(next_move) final_pos = tuple([sum(i) for i in zip(final_move,self.current_pos)]) self.memory.append(final_pos) st = list(set(self.memory)) if len(self.memory)>4 and len(st) <= 2: final_move = self.safe_move(next_move, st) self.memory[-1] = final_move return self.safe_move(next_move)
class HungryPlayer(AbstractPlayer): """ Basically a clone of the FoodEatingPlayer. """ def __init__(self): # Do some basic initialisation here. You may also accept additional # parameters which you can specify in your factory. # Note that any other game variables have not been set yet. So there is # no ``self.current_uni`` or ``self.current_state`` pass def set_initial(self): # Now ``self.current_uni`` and ``self.current_state`` are known. # ``set_initial`` is always called before ``get_move``, so we can do some # additional initialisation here # Initialize an AdjacencyList for all reachable positions # This will help us find shortest paths # see in graph.py for more details self.adjacency = AdjacencyList( self.current_uni.reachable([self.initial_pos])) # Once we have picked a food item to go to, we’ll note it here # Otherwise we risk flapping between two states self.next_food = None def path_to(self, pos): """ Given a position, this return a shortest path from the current position. """ return self.adjacency.a_star(self.current_pos, pos) def get_move(self): # check, if food is still present, otherwise go somewhere else if (self.next_food is None or self.next_food not in self.enemy_food): if not self.enemy_food: # all food has been eaten? ok. i’ll stop self.say("I am hungry.") return stop # all the food is in self.enemy_food # we just pick one to go to # (of course, there may be a smarter choice than just going random) self.next_food = self.rnd.choice(self.enemy_food) try: # figure out the path to take shortest_path = self.path_to(self.next_food) # our next position is the last element in the path next_pos = shortest_path[-1] # we are a little exited about eating # (this does not account for any food we additionally eat on our way # to the food we have picked.) if len(shortest_path) == 1: self.say("Yay. Food next.") else: self.say("Eating in {0} steps.".format(len(shortest_path))) # should we check for the enemy at this position? # self.enemy_bots ? # Naah – we risk it :) # the difference between here and there # is the direction we need to go to move = diff_pos(self.current_pos, next_pos) return move except NoPathException: # whoops, there is no path possible # we better wait return stop
class HungryPlayer(AbstractPlayer): """ Basically a clone of the FoodEatingPlayer. """ def __init__(self): # Do some basic initialisation here. You may also accept additional # parameters which you can specify in your factory. # Note that any other game variables have not been set yet. So there is # no ``self.current_uni`` or ``self.current_state`` pass def set_initial(self): # Now ``self.current_uni`` and ``self.current_state`` are known. # ``set_initial`` is always called before ``get_move``, so we can do some # additional initialisation here # Initialize an AdjacencyList for all reachable positions # This will help us find shortest paths # see in graph.py for more details self.adjacency = AdjacencyList(self.current_uni.reachable([self.initial_pos])) # Once we have picked a food item to go to, we’ll note it here # Otherwise we risk flapping between two states self.next_food = None def path_to(self, pos): """ Given a position, this return a shortest path from the current position. """ return self.adjacency.a_star(self.current_pos, pos) def get_move(self): # check, if food is still present, otherwise go somewhere else if (self.next_food is None or self.next_food not in self.enemy_food): if not self.enemy_food: # all food has been eaten? ok. i’ll stop self.say("I am hungry.") return stop # all the food is in self.enemy_food # we just pick one to go to # (of course, there may be a smarter choice than just going random) self.next_food = self.rnd.choice(self.enemy_food) try: # figure out the path to take shortest_path = self.path_to(self.next_food) # our next position is the last element in the path next_pos = shortest_path[-1] # we are a little exited about eating # (this does not account for any food we additionally eat on our way # to the food we have picked.) if len(shortest_path) == 1: self.say("Yay. Food next.") else: self.say("Eating in {0} steps.".format(len(shortest_path))) # should we check for the enemy at this position? # self.enemy_bots ? # Naah – we risk it :) # the difference between here and there # is the direction we need to go to move = diff_pos(self.current_pos, next_pos) return move except NoPathException: # whoops, there is no path possible # we better wait return stop
class ItalianPossessivePlayer(AbstractPlayer): def set_initial(self): self.adjacency = AdjacencyList(self.current_uni.reachable([self.initial_pos])) self.next_food = None def goto_pos(self, pos): #print(len(self.adjacency.a_star(self.current_pos, pos))) if len(self.adjacency.a_star(self.current_pos, pos)) > 0: return self.adjacency.a_star(self.current_pos, pos)[-1] else: return self.current_pos # Determine the closest enemy def get_enemy_to_block(self): dist_enemy0 = len(self.adjacency.a_star(self.current_pos, self.enemy_bots[0].current_pos)) dist_enemy1 = len(self.adjacency.a_star(self.current_pos, self.enemy_bots[1].current_pos)) self.enemy_to_block = np.argmin([dist_enemy0, dist_enemy1]) # Determine closest food for that enemy def get_closest_food(self): self.enemy_next_food_distance_list = np.array(list(map( lambda x: len(self.adjacency.a_star(self.enemy_bots[self.enemy_to_block].current_pos, x)), self.team_food))) # Decide which food to protect def get_food_to_protect(self): self.minimum_index = np.argmin(self.enemy_next_food_distance_list) self.food_to_protect = self.team_food[self.minimum_index] # Enemy path def get_enemy_path(self): self.enemy_path = self.adjacency.a_star(self.enemy_bots[self.enemy_to_block].current_pos, self.food_to_protect) # Point to intercept def get_point_to_intercept(self): if len(self.enemy_path) > 0: index = np.round(len(self.enemy_path)/2) self.p_intercept = self.enemy_path[index.astype(int)] else: while len(self.enemy_path) == 0: self.enemy_next_food_distance_list = np.delete(self.enemy_next_food_distance_list, self.minimum_index) self.get_food_to_protect() self.get_enemy_path() index = np.round(len(self.enemy_path)/2) self.p_intercept = self.enemy_path[index.astype(int)] #def sit_on_food(self): def get_move(self): # check, if food is still present self.say("Go Away!!") if (self.next_food is None or self.next_food not in self.enemy_food): if not self.enemy_food: # all food has been eaten? ok. i’ll stop return datamodel.stop self.get_enemy_to_block() self.get_closest_food() self.get_food_to_protect() self.get_enemy_path() self.get_point_to_intercept() try: next_pos = self.goto_pos(self.p_intercept) move = diff_pos(self.current_pos, next_pos) return move except NoPathException: print("Help!") return datamodel.stop
class DrunkPlayer(AbstractPlayer): """ Basically a clone of the RandomPlayer. """ def __init__(self): # Do some basic initialisation here. You may also accept additional # parameters which you can specify in your factory. # Note that any other game variables have not been set yet. So there is # no ``self.current_uni`` or ``self.current_state`` self.sleep_rounds = 0 def set_initial(self): # Now ``self.current_uni`` and ``self.current_state`` are known. # ``set_initial`` is always called before ``get_move``, so we can do some # additional initialisation here # Just printing the universe to give you an idea, please remove all # print statements in the final player. print self.current_uni.pretty def check_pause(self): # make a pause every fourth step because whatever :) if self.sleep_rounds <= 0: if self.rnd.random() > 0.75: self.sleep_rounds = 3 if self.sleep_rounds > 0: self.sleep_rounds -= 1 self.say("I am confused. Very confused.") return stop def get_move(self): utility_function() for i in range(10): print self.enemy_bots[0].current_pos print " " self.check_pause() # legal_moves returns a dict {move: position} # we always need to return a move possible_moves = self.legal_moves.keys() # selecting one of the moves return self.rnd.choice(possible_moves) def set_initial(self): self.adjacency = AdjacencyList(self.current_uni.reachable([self.initial_pos])) self.next_food = None def goto_pos(self, pos): return self.adjacency.a_star(self.current_pos, pos)[-1] def get_move(self): # check, if food is still present if (self.next_food is None or self.next_food not in self.enemy_food): if not self.enemy_food: # all food has been eaten? ok. i’ll stop return datamodel.stop self.next_food = self.rnd.choice(self.enemy_food) try: next_pos = self.goto_pos(self.next_food) move = diff_pos(self.current_pos, next_pos) return move except NoPathException: return datamodel.stop
class ExtremelyHungryPlayer(AbstractPlayer): def set_initial(self): self.adjacency = AdjacencyList(self.current_uni.reachable([self.initial_pos])) self.next_food = None def goto_pos(self, pos): return self.adjacency.a_star(self.current_pos, pos)[-1] def compute_food_score(self, distance_decay=2.5): """ Compute: distance to every pill, first step for every pill. Out: dict of step options weighed by distance """ #initialise a dict of step options: {next_cell: weight_count} # loop through the list of available pills for p in self.enemy_food: # compute the path to the next one path_to_pill = self.adjacency.a_star(self.current_pos, p) first_step = diff_pos(self.current_pos, path_to_pill[-1]) # compute the length for scaling weight = np.exp(-len(path_to_pill)/distance_decay) # populate the step options dict self.step_options[first_step]+=weight def compute_enemy_score(self, enemy_distance_decay=1.5): """Update step_options to avoid the enemy. Currently only resets a valus of the step_options to -1 if it means taking the shortest path to the enemy. """ decay_per_distance = lambda d: \ -2*np.exp(-d**2/enemy_distance_decay**2) self.repulse_bot(self.enemy_bots, decay_per_distance) def repulse_bot(self, bot_list, function): '''In: list of bots to repulse, repulsion function ''' # get the possible positions for lm in self.legal_moves: # The position we would be in in this case "possible_position" p_pos = add_pos(self.current_pos, lm) for e in bot_list: # compute the path to the next move try: if e.noisy: continue except AttributeError: pass try: path_to_bot = self.adjacency.a_star(p_pos, e.current_pos) except pelita.graph.NoPathException: path_to_bot = [] distance = len(path_to_bot) self.step_options[lm] += function(distance) def compute_friend_score(self): '''Based on the friend_bot, decay function ''' d_decay = 5 max_repulsion = 1.1*self.step_options[max(self.step_options)] decay_function= lambda d: -max_repulsion*np.exp(-d**2 / d_decay**2) self.repulse_bot(self.other_team_bots, decay_function) def compute_optimal_move(self): """ Compute the optimal move based on the coordinate with the highest score """ # recommend the step with the highest score recommended_step = max(self.step_options, key=self.step_options.get) self.move = recommended_step #self.move = diff_pos(self.current_pos, recommended_coordinate) def get_move(self): # check, if food is still present self.say("ID %d" % self.me.index) if (self.next_food is None or self.next_food not in self.enemy_food): if not self.enemy_food: # all food has been eaten? ok. i’ll stop return datamodel.stop self.next_food = self.rnd.choice(self.enemy_food) self.step_options = defaultdict(float) # initialize the step options to zero for all valid moves. # This is important, otherwise the bot will not consider all options for lm in self.legal_moves: self.step_options[lm] = 0 self.compute_food_score() self.compute_enemy_score() self.compute_friend_score() self.compute_optimal_move() if self.me.index == 0: self.print_scores() #import pdb; pdb.set_trace() try: return self.move except NoPathException: print("Help!") return datamodel.stop def print_scores(self): """ Print the energy landscape for the next part """ # compute the indices x,y = self.current_pos l_coor = self.step_options[(-1,0)] r_coor = self.step_options[(1,0)] u_coor = self.step_options[(0,-1)] d_coor = self.step_options[(0,1)] c_coor = self.step_options[(0,0)] # scores = map(self.step_options.get, (u_idx, l_idx, r_idx, d_idx)) print_str = """ %3.2f %3.2f %3.2f %3.2f %3.2f""" % (u_coor, l_coor, c_coor, r_coor, d_coor) print(print_str) print("Direction: ", self.move)
class ExtremelyHungryPlayer(AbstractPlayer): def set_initial(self): self.adjacency = AdjacencyList(self.current_uni.reachable([self.initial_pos])) self.next_food = None def goto_pos(self, pos): return self.adjacency.a_star(self.current_pos, pos)[-1] def compute_food_score(self, distance_decay=2.5): """ Compute: distance to every pill, first step for every pill. Out: dict of step options weighed by distance """ # initialise a dict of step options: {next_cell: weight_count} # loop through the list of available pills for p in self.enemy_food: # compute the path to the next one path_to_pill = self.adjacency.a_star(self.current_pos, p) first_step = diff_pos(self.current_pos, path_to_pill[-1]) # compute the length for scaling weight = np.exp(-len(path_to_pill) / distance_decay) # populate the step options dict self.step_options[first_step] += weight def compute_enemy_score(self, enemy_distance_decay=1.5): """Update step_options to avoid the enemy. Currently only resets a valus of the step_options to -1 if it means taking the shortest path to the enemy. """ decay_per_distance = lambda d: -2 * np.exp(-d ** 2 / enemy_distance_decay ** 2) self.repulse_bot(self.enemy_bots, decay_per_distance) def repulse_bot(self, bot_list, function): """In: list of bots to repulse, repulsion function """ # get the possible positions for lm in self.legal_moves: # The position we would be in in this case "possible_position" p_pos = add_pos(self.current_pos, lm) for e in bot_list: # compute the path to the next move try: if e.noisy: continue except AttributeError: pass try: path_to_bot = self.adjacency.a_star(p_pos, e.current_pos) except pelita.graph.NoPathException: path_to_bot = [] distance = len(path_to_bot) self.step_options[lm] += function(distance) def compute_friend_score(self): """Based on the friend_bot, decay function """ d_decay = 5 max_repulsion = 1.1 * self.step_options[max(self.step_options)] decay_function = lambda d: -max_repulsion * np.exp(-d ** 2 / d_decay ** 2) self.repulse_bot(self.other_team_bots, decay_function) def compute_optimal_move(self): """ Compute the optimal move based on the coordinate with the highest score """ # recommend the step with the highest score recommended_step = max(self.step_options, key=self.step_options.get) self.move = recommended_step # self.move = diff_pos(self.current_pos, recommended_coordinate) def get_move(self): # check, if food is still present self.say("ID %d" % self.me.index) if self.next_food is None or self.next_food not in self.enemy_food: if not self.enemy_food: # all food has been eaten? ok. i’ll stop return datamodel.stop self.next_food = self.rnd.choice(self.enemy_food) self.step_options = defaultdict(float) # initialize the step options to zero for all valid moves. # This is important, otherwise the bot will not consider all options for lm in self.legal_moves: self.step_options[lm] = 0 self.compute_food_score() self.compute_enemy_score() self.compute_friend_score() self.compute_optimal_move() if self.me.index == 0: self.print_scores() # import pdb; pdb.set_trace() try: return self.move except NoPathException: print("Help!") return datamodel.stop def print_scores(self): """ Print the energy landscape for the next part """ # compute the indices x, y = self.current_pos l_coor = self.step_options[(-1, 0)] r_coor = self.step_options[(1, 0)] u_coor = self.step_options[(0, -1)] d_coor = self.step_options[(0, 1)] c_coor = self.step_options[(0, 0)] # scores = map(self.step_options.get, (u_idx, l_idx, r_idx, d_idx)) print_str = """ %3.2f %3.2f %3.2f %3.2f %3.2f""" % ( u_coor, l_coor, c_coor, r_coor, d_coor, ) print(print_str) print("Direction: ", self.move)
class JakovPlayer(AbstractPlayer): def set_initial(self): self.adjacency = AdjacencyList(self.current_uni.reachable([self.initial_pos])) self.next_food = None def goto_pos(self, pos): return self.adjacency.a_star(self.current_pos, pos)[-1] def get_move(self): # check, if food is still present if (self.next_food is None or self.next_food not in self.enemy_food): if not self.enemy_food: # all food has been eaten? ok. i’ll stop return datamodel.stop self.next_food = self.rnd.choice(self.enemy_food) # !!! to improve: not random from all enemy_food by from closest food # determine enemy positions dangerous & killable dangerous_enemy_pos = [bot.current_pos for bot in self.enemy_bots if bot.is_destroyer] non_noisy_dangerous_enemy_pos = [bot.current_pos for bot in self.enemy_bots if (bot.is_destroyer and not bot.noisy)] # killable_enemy_pos = [bot.current_pos for bot in self.enemy_bots if bot.is_harvester] try: next_pos = self.goto_pos(self.next_food) # next_pos = self.rnd.choice([(0,1),(0,-1),(1,0),(-1,0)]) move = diff_pos(self.current_pos, next_pos) my_adjecent_pos = self.adjacency.pos_within(self.current_pos,5) legal_moves = self.legal_moves # check if the next position is dangerous # list of dangerous enemy adecent positions # dangerous_enemy_adj_pos = [] acceptable_adjecent_pos = list(my_adjecent_pos) # for position in dangerous_enemy_pos: for position in non_noisy_dangerous_enemy_pos: dangerous_enemy_adj_pos = self.adjacency.pos_within(position,3) for enemy_adj_pos in dangerous_enemy_adj_pos: if enemy_adj_pos in acceptable_adjecent_pos: acceptable_adjecent_pos.remove(enemy_adj_pos) # TODO: improve to -> escape to the direction oposite from the enemy if len(acceptable_adjecent_pos) == 0: return self.rnd.choice(list(legal_moves.keys())) if next_pos not in my_adjecent_pos: next_pos = self.rnd.choice(list(my_adjecent_pos)) move = diff_pos(self.current_pos, next_pos) # Remove stop # try: # del legal_moves[datamodel.stop] # except KeyError: # pass # # now remove the move that would lead to the enemy # # unless there is no where else to go. # if len(legal_moves) > 1: # for (k,v) in legal_moves.items(): # if v in dangerous_enemy_pos: # break # del legal_moves[k] # # just in case, there is really no way to go to: # if not legal_moves: # return datamodel.stop # # and select a move at random # return self.rnd.choice(list(legal_moves.keys())) # selecting one of the moves # while next_pos in dangerous_enemy_pos: # move = self.rnd.choice(possible_moves) # next_pos = (self.current_pos[0] + move[0],self.current_pos[1] + move[1]) self.say("bla bla!") return move except NoPathException: return datamodel.stop