def apply_moves(self, p1_actions, p2_actions): new_p1_guys = [[0] * self.height for x in range(self.width)] new_p2_guys = [[0] * self.height for x in range(self.width)] for (x, y), direction in p1_actions: quantity = int(p1_actions[((x, y), direction)]) if direction not in actions.ALL_ACTIONS: continue if self.p1_guys >= quantity: new_x, new_y = actions.next_pos((x, y), direction) if self.__is_on_board((new_x, new_y)): new_p1_guys[new_x][new_y] += quantity self.p1_guys[x][y] -= quantity for (x, y), direction in p2_actions: quantity = int(p2_actions[((x, y), direction)]) if direction not in actions.ALL_ACTIONS: continue if self.p2_guys >= quantity: new_x, new_y = actions.next_pos((x, y), direction) if self.__is_on_board((new_x, new_y)): new_p2_guys[new_x][new_y] += quantity self.p2_guys[x][y] -= quantity for x in range(self.width): for y in range(self.height): new_p1_guys[x][y] += self.p1_guys[x][y] new_p2_guys[x][y] += self.p2_guys[x][y] self.p1_guys = new_p1_guys self.p2_guys = new_p2_guys
def apply_moves(self, p1_actions, p2_actions): new_p1_guys = [[0] * self.height for x in range(self.width)] new_p2_guys = [[0] * self.height for x in range(self.width)] for (x, y), direction in p1_actions: quantity = int(p1_actions[((x, y), direction)]) if direction not in actions.ALL_ACTIONS: continue if len(self.p1_guys) >= quantity: new_x, new_y = actions.next_pos((x, y), direction) if self.__is_on_board((new_x, new_y)): new_p1_guys[new_x][new_y] += quantity self.p1_guys[x][y] -= quantity for (x, y), direction in p2_actions: quantity = int(p2_actions[((x, y), direction)]) if direction not in actions.ALL_ACTIONS: continue if len(self.p2_guys) >= quantity: new_x, new_y = actions.next_pos((x, y), direction) if self.__is_on_board((new_x, new_y)): new_p2_guys[new_x][new_y] += quantity self.p2_guys[x][y] -= quantity for x in range(self.width): for y in range(self.height): new_p1_guys[x][y] += self.p1_guys[x][y] new_p2_guys[x][y] += self.p2_guys[x][y] self.p1_guys = new_p1_guys self.p2_guys = new_p2_guys
def get_order(self, x, y, guys, dist_to_unowned, first): best_action = None best_dist = 999 best_food = 0.0 for action in self.MOVE_ACTIONS: x2, y2 = actions.next_pos( (x,y), action) if not self.in_bounds(x2, y2): continue dist = dist_to_unowned[x2][y2] # First ignores distance, only interested in food and unowned tiles if first: if self.is_mine(x2, y2, guys): dist = 999 else: dist = 0 food = self.get_food(x2, y2) if dist < best_dist or (dist == best_dist and food > best_food): best_action = action best_dist = dist best_food = food x2, y2 = actions.next_pos( (x,y), best_action) # New pos if first: # First guy can't move if it's to a worse food spot... # or my guys are there already # or we're near the end of the game if self.get_food(x2, y2) <= self.get_food(x, y) \ or self.is_mine(x2, y2, guys) \ or self.turn_no > 500: return ((x, y), actions.STAY) # Make pos less attractive so others spread out (occasionally) if random.random() > 0.9: dist_to_unowned[x2][y2] += 0.1 # Update guys self.update_guys(x, y, x2, y2, guys) # Give the order return ((x, y), best_action)
def get_order(self, x, y, guys, dist_to_unowned, first): best_action = None best_dist = 999 best_food = 0.0 for action in self.MOVE_ACTIONS: x2, y2 = actions.next_pos((x, y), action) if not self.in_bounds(x2, y2): continue dist = dist_to_unowned[x2][y2] # First ignores distance, only interested in food and unowned tiles if first: if self.is_mine(x2, y2, guys): dist = 999 else: dist = 0 food = self.get_food(x2, y2) if dist < best_dist or (dist == best_dist and food > best_food): best_action = action best_dist = dist best_food = food x2, y2 = actions.next_pos((x, y), best_action) # New pos if first: # First guy can't move if it's to a worse food spot... # or my guys are there already # or we're near the end of the game if self.get_food(x2, y2) <= self.get_food(x, y) \ or self.is_mine(x2, y2, guys) \ or self.turn_no > 500: return ((x, y), actions.STAY) # Make pos less attractive so others spread out (occasionally) if random.random() > 0.9: dist_to_unowned[x2][y2] += 0.1 # Update guys self.update_guys(x, y, x2, y2, guys) # Give the order return ((x, y), best_action)
def take_turn(self, guys, my_food, their_food, my_money, their_money): # Update turn number self.turn_no += 1 # Update unoccupied_time: bias movement toward open spaces for x in range(self.width): for y in range(self.height): if guys[x][y]: self.unoccupied_time[x][y] = 0 else: self.unoccupied_time[x][y] += 1 # Make a grid of distance to closest non-owned tile # This got twisted into becoming a general attractiveness measure dist_to_unowned = [ [999] * self.height for i in range(self.width) ] open = [] # open list of seeds to grow a distance/attractiveness grid for x in range(self.width): for y in range(self.height): # Longer unowned and higher food tiles are more attractive. # Magic numbers seemed to help so it wouldn't be overwhelmed by # attraction to unoccupied area attractiveness = self.unoccupied_time[x][y] * (1 + self.get_food(x,y)) * 0.1 # Only add non-owned tiles if not self.is_mine(x, y, guys): # Attraction is represented as negative distance open.append( (-attractiveness, x, y) ) for d, x, y in open: dist_to_unowned[x][y] = d # Djikstra's algorithm to fill out grid of shortest distances heapq.heapify(open) while len(open) > 0: d, x, y = heapq.heappop(open) if dist_to_unowned[x][y] < d: continue # Shorter dist found already for m in self.MOVE_ACTIONS: x2, y2 = actions.next_pos( (x,y), m) if not self.in_bounds(x2, y2): continue # Bias around enemy guys # and places there are lots of my guys already cost = 1 if guys[x2][y2]: num_guys, is_mine = guys[x2][y2] if is_mine: cost = 1 + 0.1*num_guys else: cost = num_guys if dist_to_unowned[x2][y2] > d + cost: dist_to_unowned[x2][y2] = d + cost heapq.heappush(open, (d + cost, x2, y2)) # Make a list of all my guys, sorted by most to least food # Sorting was originally to help guys move toward higher food but I # don't think it's actually necessary any more. all_guys = [] for x in range(self.width): for y in range(self.height): if not self.is_mine(x, y, guys): continue num_guys, is_mine = guys[x][y] all_guys.append( (self.get_food(x,y), x, y, num_guys) ) all_guys.sort(reverse=True) # Get the best order for each guy. Record where guys still can move # (max of 1 guy still can move in each square as only the first guy # might choose to STAY) orders = {} still_can_move = {} for unused, x, y, num_guys in all_guys: for i in range(num_guys): # Get the best order for this guy position, action = self.get_order(x, y, guys, dist_to_unowned, i == 0) if action == actions.STAY: still_can_move[position] = True else: order = (position, action) if order not in orders: orders[order] = 1 else: orders[order] += 1 # Try moving the guys that still_can_move if other guys have moved into their square # Iterate over orders looking to see if destination square still can move open = orders.keys() while len(open) > 0: # Order stores origin position, translate to destination position origin, action = open.pop() position = actions.next_pos(origin, action) if position in still_can_move: still_can_move.pop(position) x, y = position position, action = self.get_order(x, y, guys, dist_to_unowned, False) # Action can never be STAY because this is not being treated as the first guy # on the square any more (because someone else is taking its space as first) order = (position, action) if order not in orders: orders[order] = 1 else: orders[order] += 1 open.append(order) return orders
def take_turn(self, guys, my_food, their_food, my_money, their_money): width = len(guys) height = len(guys[0]) MOVE_ACTIONS = actions.ALL_ACTIONS[1:] ### update self.unoccupied_time: bias movement toward open spaces for x in range(width): for y in range(height): if guys[x][y]: self.unoccupied_time[x][y] = 0 else: self.unoccupied_time[x][y] += 1 ### Make a "map" of distance to closest non-owned square dist_to_unowned = [ [999] * height for i in range(width) ] open = [] # open list for x in range(width): for y in range(height): food = 1.0 - self.money_payout_rates[x][y] attractiveness = self.unoccupied_time[x][y] * (1 + food) if not guys[x][y]: open.append( (-attractiveness,x,y) ) else: num_guys, is_mine = guys[x][y] if not is_mine: open.append( (-attractiveness,x,y) ) for d, x, y in open: dist_to_unowned[x][y] = d # Djikstra to fill out map heapq.heapify(open) while len(open) > 0: d, x, y = heapq.heappop(open) if dist_to_unowned[x][y] < d: continue # Better dist found already for m in MOVE_ACTIONS: x2, y2 = actions.next_pos( (x,y), m) if not self.in_bounds(x2, y2): continue # Bias around enemy guys # and places there are lots of my guys already cost = 1 if guys[x2][y2]: num_guys, is_mine = guys[x2][y2] if is_mine: cost = 1 + 0.1*num_guys else: cost = num_guys if dist_to_unowned[x2][y2] > d + cost: dist_to_unowned[x2][y2] = d + cost heapq.heappush(open, (d + cost, x2, y2)) # for y in range(height): # for x in range(width): # print dist_to_unowned[x][y], # print '' orders = {} for x in range(width): for y in range(height): if not guys[x][y]: continue num_guys, is_mine = guys[x][y] if not is_mine: continue # Move all but 1 guys for i in range(num_guys-1): action = None best_dist = 999 best_food = 0.0 for m in MOVE_ACTIONS: x2, y2 = actions.next_pos( (x,y), m) if not self.in_bounds(x2, y2): continue dist = dist_to_unowned[x2][y2] food = 1.0 - self.money_payout_rates[x2][y2] if dist < best_dist or (dist == best_dist and food > best_food): action = m best_dist = dist best_food = food # Make pos less attractive so others spread out (occasionally) if random.random() > 0.9: x2, y2 = actions.next_pos( (x,y), action) dist_to_unowned[x2][y2] += 0.1 # Give the order key = ((x, y), action) if key not in orders: orders[key] = 1 else: orders[key] += 1 return orders
def take_turn(self, guys, my_food, their_food, my_money, their_money): self.turn_no += 1 width = len(guys) height = len(guys[0]) MOVE_ACTIONS = actions.ALL_ACTIONS[1:] ### update self.unoccupied_time: bias movement toward open spaces for x in range(width): for y in range(height): if guys[x][y]: self.unoccupied_time[x][y] = 0 else: self.unoccupied_time[x][y] += 1 ### Make a "map" of distance to closest non-owned square dist_to_unowned = [ [999] * height for i in range(width) ] open = [] # open list for x in range(width): for y in range(height): attractiveness = self.unoccupied_time[x][y] * (1 + self.get_food(x,y)) * 0.1 if not guys[x][y]: open.append( (-attractiveness,x,y) ) else: num_guys, is_mine = guys[x][y] if not is_mine: open.append( (-attractiveness,x,y) ) for d, x, y in open: dist_to_unowned[x][y] = d # Djikstra to fill out map heapq.heapify(open) while len(open) > 0: d, x, y = heapq.heappop(open) if dist_to_unowned[x][y] < d: continue # Better dist found already for m in MOVE_ACTIONS: x2, y2 = actions.next_pos( (x,y), m) if not self.in_bounds(x2, y2): continue # Bias around enemy guys # and places there are lots of my guys already cost = 1 if guys[x2][y2]: num_guys, is_mine = guys[x2][y2] if is_mine: cost = 1 + 0.1*num_guys else: cost = num_guys if dist_to_unowned[x2][y2] > d + cost: dist_to_unowned[x2][y2] = d + cost heapq.heappush(open, (d + cost, x2, y2)) # for y in range(height): # for x in range(width): # print dist_to_unowned[x][y], # print '' orders = {} all_guys = [] # in order of best food, most food at start for x in range(width): for y in range(height): if not guys[x][y]: continue num_guys, is_mine = guys[x][y] if not is_mine: continue all_guys.append( (self.get_food(x,y), x, y, num_guys) ) all_guys.sort(reverse=True) for food, x, y, num_guys in all_guys: # Move guys for i in range(num_guys): action = None best_dist = 999 best_food = 0.0 for m in MOVE_ACTIONS: x2, y2 = actions.next_pos( (x,y), m) if not self.in_bounds(x2, y2): continue dist = dist_to_unowned[x2][y2] if i == 0: # First guy ignores distance, only interested in food and unowned tiles if self.is_mine(x2, y2, guys): dist = 999 else: dist = 0 food = self.get_food(x2,y2) if dist < best_dist or (dist == best_dist and food > best_food): action = m best_dist = dist best_food = food x2, y2 = actions.next_pos( (x,y), action) # New pos if i == 0: # First guy can only move if it's to a better food spot... if self.get_food(x2,y2) <= self.get_food(x,y): continue # and my guys aren't there already if self.is_mine(x2,y2,guys): continue # and we're not near the end of the game if self.turn_no > 750: continue # Make pos less attractive so others spread out (occasionally) if random.random() > 0.9: dist_to_unowned[x2][y2] += 0.1 # Give the order key = ((x, y), action) if key not in orders: orders[key] = 1 else: orders[key] += 1 # Update guys self.update_guys(x,y,x2,y2,guys) return orders
def apply_actions(self, p1_actions, p2_actions, turn): new_p1_guys = [[0] * self.height for x in range(self.width)] new_p2_guys = [[0] * self.height for x in range(self.width)] # Resolve P1 actions orders, guys_to_hire = p1_actions for (x, y), action in orders: quantity = int(orders[((x, y), action)]) if action not in actions.ALL_ACTIONS: continue if self.p1_guys[x][y] >= quantity: if action in actions.MOVE_ACTIONS: # Resolve movement new_x, new_y = actions.next_pos((x, y), action) if self.__is_on_board((new_x, new_y)): new_p1_guys[new_x][new_y] += quantity self.p1_guys[x][y] -= quantity elif action == actions.PLANT: # Plant a plant if there's no plant already here and they # have enough seeds. if self.p1_plants[x][y] < 0 and self.p2_plants[x][ y] < 0 and self.p1_seeds > 0: self.p1_plants[x][y] = turn self.p1_seeds = self.p1_seeds - 1 elif action == actions.HARVEST: # Harvest a plant, but not one you planted this turn! if self.p1_plants[x][y] >= 0 and self.p1_plants[x][ y] != turn: gold, seeds = actions.get_plant_payout( turn - self.p1_plants[x][y], True) self.p1_gold = self.p1_gold + gold self.p1_seeds = self.p1_seeds + seeds self.p1_plants[x][y] = None elif self.p2_plants[x][y] >= 0 and self.p2_plants[x][ y] != turn: gold, seeds = actions.get_plant_payout( turn - self.p2_plants[x][y], False) self.p1_gold = self.p1_gold + gold self.p1_seeds = self.p1_seeds + seeds self.p2_plants[x][y] = None # Hire more guys for P1 if self.p1_gold >= (guys_to_hire * actions.GOLD_PER_GUY): self.p1_guys_to_spawn = guys_to_hire self.p1_gold = self.p1_gold - (guys_to_hire * actions.GOLD_PER_GUY) # Resolve P2 actions orders, guys_to_hire = p2_actions for (x, y), action in orders: quantity = int(orders[((x, y), action)]) if action not in actions.ALL_ACTIONS: continue if self.p2_guys[x][y] >= quantity: if action in actions.MOVE_ACTIONS: # Resolve movement new_x, new_y = actions.next_pos((x, y), action) if self.__is_on_board((new_x, new_y)): new_p2_guys[new_x][new_y] += quantity self.p2_guys[x][y] -= quantity elif action == actions.PLANT: # Plant a plant if there's no plant already here and they # have enough seeds. if self.p2_plants[x][y] < 0 and self.p1_plants[x][ y] < 0 and self.p2_seeds > 0: self.p2_plants[x][y] = turn self.p2_seeds = self.p2_seeds - 1 elif action == actions.HARVEST: # Harvest a plant if self.p2_plants[x][y] >= 0 and self.p2_plants[x][ y] != turn: gold, seeds = actions.get_plant_payout( turn - self.p2_plants[x][y], True) self.p2_gold = self.p2_gold + gold self.p2_seeds = self.p2_seeds + seeds self.p2_plants[x][y] = None elif self.p1_plants[x][y] >= 0 and self.p1_plants[x][ y] != turn: gold, seeds = actions.get_plant_payout( turn - self.p1_plants[x][y], False) self.p2_gold = self.p2_gold + gold self.p2_seeds = self.p2_seeds + seeds self.p1_plants[x][y] = None # Hire more guys for P2 if self.p2_gold >= (guys_to_hire * actions.GOLD_PER_GUY): self.p2_guys_to_spawn = guys_to_hire self.p2_gold = self.p2_gold - (guys_to_hire * actions.GOLD_PER_GUY) for x in range(self.width): for y in range(self.height): new_p1_guys[x][y] += self.p1_guys[x][y] new_p2_guys[x][y] += self.p2_guys[x][y] self.p1_guys = new_p1_guys self.p2_guys = new_p2_guys # Keep track of the max gold and max seeds seen so far. We'll # use this to normalize the values for the line graph in the # visualization. self.max_gold = max(self.max_gold, self.p1_gold, self.p2_gold) self.max_seeds = max(self.max_seeds, self.p1_seeds, self.p2_seeds)
def take_turn(self, guys, my_food, their_food, my_money, their_money): # Update turn number self.turn_no += 1 # Update unoccupied_time: bias movement toward open spaces for x in range(self.width): for y in range(self.height): if guys[x][y]: self.unoccupied_time[x][y] = 0 else: self.unoccupied_time[x][y] += 1 # Make a grid of distance to closest non-owned tile # This got twisted into becoming a general attractiveness measure dist_to_unowned = [[999] * self.height for i in range(self.width)] open = [] # open list of seeds to grow a distance/attractiveness grid for x in range(self.width): for y in range(self.height): # Longer unowned and higher food tiles are more attractive. # Magic numbers seemed to help so it wouldn't be overwhelmed by # attraction to unoccupied area attractiveness = self.unoccupied_time[x][y] * ( 1 + self.get_food(x, y)) * 0.1 # Only add non-owned tiles if not self.is_mine(x, y, guys): # Attraction is represented as negative distance open.append((-attractiveness, x, y)) for d, x, y in open: dist_to_unowned[x][y] = d # Djikstra's algorithm to fill out grid of shortest distances heapq.heapify(open) while len(open) > 0: d, x, y = heapq.heappop(open) if dist_to_unowned[x][y] < d: continue # Shorter dist found already for m in self.MOVE_ACTIONS: x2, y2 = actions.next_pos((x, y), m) if not self.in_bounds(x2, y2): continue # Bias around enemy guys # and places there are lots of my guys already cost = 1 if guys[x2][y2]: num_guys, is_mine = guys[x2][y2] if is_mine: cost = 1 + 0.1 * num_guys else: cost = num_guys if dist_to_unowned[x2][y2] > d + cost: dist_to_unowned[x2][y2] = d + cost heapq.heappush(open, (d + cost, x2, y2)) # Make a list of all my guys, sorted by most to least food # Sorting was originally to help guys move toward higher food but I # don't think it's actually necessary any more. all_guys = [] for x in range(self.width): for y in range(self.height): if not self.is_mine(x, y, guys): continue num_guys, is_mine = guys[x][y] all_guys.append((self.get_food(x, y), x, y, num_guys)) all_guys.sort(reverse=True) # Get the best order for each guy. Record where guys still can move # (max of 1 guy still can move in each square as only the first guy # might choose to STAY) orders = {} still_can_move = {} for unused, x, y, num_guys in all_guys: for i in range(num_guys): # Get the best order for this guy position, action = self.get_order(x, y, guys, dist_to_unowned, i == 0) if action == actions.STAY: still_can_move[position] = True else: order = (position, action) if order not in orders: orders[order] = 1 else: orders[order] += 1 # Try moving the guys that still_can_move if other guys have moved into their square # Iterate over orders looking to see if destination square still can move open = orders.keys() while len(open) > 0: # Order stores origin position, translate to destination position origin, action = open.pop() position = actions.next_pos(origin, action) if position in still_can_move: still_can_move.pop(position) x, y = position position, action = self.get_order(x, y, guys, dist_to_unowned, False) # Action can never be STAY because this is not being treated as the first guy # on the square any more (because someone else is taking its space as first) order = (position, action) if order not in orders: orders[order] = 1 else: orders[order] += 1 open.append(order) return orders
def apply_actions(self, p1_actions, p2_actions, turn): new_p1_guys = [[0] * self.height for x in range(self.width)] new_p2_guys = [[0] * self.height for x in range(self.width)] # Resolve P1 actions orders, guys_to_hire = p1_actions for (x, y), action in orders: quantity = int(orders[((x, y), action)]) if action not in actions.ALL_ACTIONS: continue if self.p1_guys[x][y] >= quantity: if action in actions.MOVE_ACTIONS: # Resolve movement new_x, new_y = actions.next_pos((x, y), action) if self.__is_on_board((new_x, new_y)): new_p1_guys[new_x][new_y] += quantity self.p1_guys[x][y] -= quantity elif action == actions.PLANT: # Plant a plant if there's no plant already here and they # have enough seeds. if self.p1_plants[x][y] < 0 and self.p2_plants[x][y] < 0 and self.p1_seeds > 0: self.p1_plants[x][y] = turn self.p1_seeds = self.p1_seeds - 1 elif action == actions.HARVEST: # Harvest a plant, but not one you planted this turn! if self.p1_plants[x][y] >= 0 and self.p1_plants[x][y] != turn: gold, seeds = actions.get_plant_payout(turn - self.p1_plants[x][y], True) self.p1_gold = self.p1_gold + gold self.p1_seeds = self.p1_seeds + seeds self.p1_plants[x][y] = None elif self.p2_plants[x][y] >= 0 and self.p2_plants[x][y] != turn: gold, seeds = actions.get_plant_payout(turn - self.p2_plants[x][y], False) self.p1_gold = self.p1_gold + gold self.p1_seeds = self.p1_seeds + seeds self.p2_plants[x][y] = None # Hire more guys for P1 if self.p1_gold >= (guys_to_hire * actions.GOLD_PER_GUY): self.p1_guys_to_spawn = guys_to_hire self.p1_gold = self.p1_gold - (guys_to_hire * actions.GOLD_PER_GUY) # Resolve P2 actions orders, guys_to_hire = p2_actions for (x, y), action in orders: quantity = int(orders[((x, y), action)]) if action not in actions.ALL_ACTIONS: continue if self.p2_guys[x][y] >= quantity: if action in actions.MOVE_ACTIONS: # Resolve movement new_x, new_y = actions.next_pos((x, y), action) if self.__is_on_board((new_x, new_y)): new_p2_guys[new_x][new_y] += quantity self.p2_guys[x][y] -= quantity elif action == actions.PLANT: # Plant a plant if there's no plant already here and they # have enough seeds. if self.p2_plants[x][y] < 0 and self.p1_plants[x][y] < 0 and self.p2_seeds > 0: self.p2_plants[x][y] = turn self.p2_seeds = self.p2_seeds - 1 elif action == actions.HARVEST: # Harvest a plant if self.p2_plants[x][y] >= 0 and self.p2_plants[x][y] != turn: gold, seeds = actions.get_plant_payout(turn - self.p2_plants[x][y], True) self.p2_gold = self.p2_gold + gold self.p2_seeds = self.p2_seeds + seeds self.p2_plants[x][y] = None elif self.p1_plants[x][y] >= 0 and self.p1_plants[x][y] != turn: gold, seeds = actions.get_plant_payout(turn - self.p1_plants[x][y], False) self.p2_gold = self.p2_gold + gold self.p2_seeds = self.p2_seeds + seeds self.p1_plants[x][y] = None # Hire more guys for P2 if self.p2_gold >= (guys_to_hire * actions.GOLD_PER_GUY): self.p2_guys_to_spawn = guys_to_hire self.p2_gold = self.p2_gold - (guys_to_hire * actions.GOLD_PER_GUY) for x in range(self.width): for y in range(self.height): new_p1_guys[x][y] += self.p1_guys[x][y] new_p2_guys[x][y] += self.p2_guys[x][y] self.p1_guys = new_p1_guys self.p2_guys = new_p2_guys # Keep track of the max gold and max seeds seen so far. We'll # use this to normalize the values for the line graph in the # visualization. self.max_gold = max(self.max_gold, self.p1_gold, self.p2_gold) self.max_seeds = max(self.max_seeds, self.p1_seeds, self.p2_seeds)
def take_turn(self, guys, my_food, their_food, my_money, their_money): width = len(guys) height = len(guys[0]) MOVE_ACTIONS = actions.ALL_ACTIONS[1:] ### update self.unoccupied_time: bias movement toward open spaces for x in range(width): for y in range(height): if guys[x][y]: self.unoccupied_time[x][y] = 0 else: self.unoccupied_time[x][y] += 1 ### Make a "map" of distance to closest non-owned square dist_to_unowned = [[999] * height for i in range(width)] open = [] # open list for x in range(width): for y in range(height): food = 1.0 - self.money_payout_rates[x][y] attractiveness = self.unoccupied_time[x][y] * (1 + food) if not guys[x][y]: open.append((-attractiveness, x, y)) else: num_guys, is_mine = guys[x][y] if not is_mine: open.append((-attractiveness, x, y)) for d, x, y in open: dist_to_unowned[x][y] = d # Djikstra to fill out map heapq.heapify(open) while len(open) > 0: d, x, y = heapq.heappop(open) if dist_to_unowned[x][y] < d: continue # Better dist found already for m in MOVE_ACTIONS: x2, y2 = actions.next_pos((x, y), m) if not self.in_bounds(x2, y2): continue # Bias around enemy guys # and places there are lots of my guys already cost = 1 if guys[x2][y2]: num_guys, is_mine = guys[x2][y2] if is_mine: cost = 1 + 0.1 * num_guys else: cost = num_guys if dist_to_unowned[x2][y2] > d + cost: dist_to_unowned[x2][y2] = d + cost heapq.heappush(open, (d + cost, x2, y2)) # for y in range(height): # for x in range(width): # print dist_to_unowned[x][y], # print '' orders = {} for x in range(width): for y in range(height): if not guys[x][y]: continue num_guys, is_mine = guys[x][y] if not is_mine: continue # Move all but 1 guys for i in range(num_guys - 1): action = None best_dist = 999 best_food = 0.0 for m in MOVE_ACTIONS: x2, y2 = actions.next_pos((x, y), m) if not self.in_bounds(x2, y2): continue dist = dist_to_unowned[x2][y2] food = 1.0 - self.money_payout_rates[x2][y2] if dist < best_dist or (dist == best_dist and food > best_food): action = m best_dist = dist best_food = food # Make pos less attractive so others spread out (occasionally) if random.random() > 0.9: x2, y2 = actions.next_pos((x, y), action) dist_to_unowned[x2][y2] += 0.1 # Give the order key = ((x, y), action) if key not in orders: orders[key] = 1 else: orders[key] += 1 return orders