def __init__(self, game_opts, enemies, reward_func, agent_names=None): self.game_opts = game_opts self.enemies = enemies self.reward_func = reward_func self.game = Ants(self.game_opts.as_dict()) if len(self.enemies) >= self.game.num_players: raise ValueError( 'The number of enemies should be strictly less than the number of players. Otherwise there will be no agent to play against.' ) self.num_agents = self.game.num_players - len(self.enemies) if not agent_names: self.agent_names = [f'Agent {i}' for i in range(self.num_agents)] elif len(agent_names) != self.num_agents: raise ValueError( f'len(agent_names) == {len(agent_names)} should be 0 or equal to the number of agents == {self.num_agents}.' ) else: self.agent_names = agent_names self.observation_space = gym.spaces.Box( low=0, high=1, shape=(self.num_agents, 5 + self.game.num_players, self.game.height, self.game.width), dtype=np.uint8) self.action_space = gym.spaces.Box(low=0, high=4, shape=(self.num_agents, self.game.height, self.game.width), dtype=np.uint8) self.reset(self.game)
def start(): try: os.remove(DEBUG_LOG) except OSError: pass storage = TrainingStorage(remove=False) Ants.run(MyBot(storage))
def start(): try: os.remove(DEBUG_LOG) except OSError: pass Ants.run(MyBot())
def create_ant(self): if len(self.ants) >= self.ants_max: return if randint(0, 100) < self.probability_new_ant: ant = Ants(self.graph.nest, self.graph.nest, self.graph.nest, 0, 0, self.ant_greediness, self.ant_greediness_food) self.ants.append(ant)
def game(self, task, report_status=False): self.post_id += 1 try: matchup_id = int(task["matchup_id"]) log.info("Running game %s..." % matchup_id) options = None if 'game_options' in task: options = task["game_options"] if options == None: options = copy(server_info["game_options"]) options["map"] = self.get_map(task['map_filename']) options["output_json"] = True game = Ants(options) bots = [] for submission_id in task["submissions"]: submission_id = int(submission_id) if self.compile(submission_id, run_test=False): submission_dir = self.submission_dir(submission_id) run_cmd = compiler.get_run_cmd(submission_dir) #run_dir = tempfile.mkdtemp(dir=server_info["compiled_path"]) bot_dir = os.path.join(submission_dir, 'bot') bots.append((bot_dir, run_cmd)) #shutil.copytree(submission_dir, run_dir) else: self.clean_download(submission_id) raise Exception('bot', 'Can not compile bot %s' % submission_id) options['game_id'] = matchup_id log.debug((game.__class__.__name__, task['submissions'], options, matchup_id)) # set worker debug logging if self.debug: options['verbose_log'] = sys.stdout replay_log = open('replay.json', 'w') options['replay_log'] = replay_log #options['stream_log'] = sys.stdout options['error_logs'] = [sys.stderr for _ in range(len(bots))] # options['output_logs'] = [sys.stdout, sys.stdout] # options['input_logs'] = [sys.stdout, sys.stdout] options['capture_errors'] = True result = run_game(game, bots, options) if self.debug: replay_log.close() log.debug(result) if 'game_id' in result: del result['game_id'] result['matchup_id'] = matchup_id result['post_id'] = self.post_id if report_status: return self.cloud.post_result('api_game_result', result) except Exception as ex: log.debug(traceback.format_exc()) result = {"post_id": self.post_id, "matchup_id": matchup_id, "error": str(ex) } success = self.cloud.post_result('api_game_result', result) # cleanup download dirs map(self.clean_download, map(int, task['submissions'])) return success
def __init__(self, id, opts, map_name, nplayers): threading.Thread.__init__(self) self.id = id self.opts = opts self.players = [] self.bot_status = [] self.map_name = map_name self.nplayers = nplayers self.bots = [] self.ants = Ants(opts)
def __init__( self, db, opts, map_name, nplayers ): self.db = db self.id = db.latest self.opts = opts self.players = [] self.bot_status = [] self.ants = Ants(opts) self.map_name = map_name self.timestep = 0 self.nplayers = nplayers
def reset(self, init_game=None): self.reward_func.reset() self.game = init_game or Ants(self.game_opts.as_dict()) self.is_done = False self.game.start_game() for i, enemy in enumerate(self.enemies): enemy.reset() enemy.setup(self.game.get_player_start(i + self.num_agents)) enemy.update_map(self.game.get_player_state(i + self.num_agents)) obs = self._get_observations(reset=True) return obs
def simulate_battle(map_segment, attackradius2, attack_method): # add buffer so that battles aren't affected by wrapping buffer = int(sqrt(attackradius2)) + 1 map_data = create_map_data(map_segment, buffer) game = Ants({ 'attackradius2': attackradius2, 'map': map_data, 'attack': attack_method, # the rest of these options don't matter 'loadtime': 0, 'turntime': 0, 'viewradius2': 100, 'spawnradius2': 2, 'turns': 1 }) game.do_attack() # remove buffer and return return create_map_output(game.map, buffer)
def simulate_battle(map_segment, attackradius2, attack_method): # add buffer so that battles aren't affected by wrapping #buffer = int(sqrt(attackradius2)) + 1 buffer = 0 map_data = create_map_data(map_segment, buffer) game = Ants({ 'attackradius2': attackradius2, 'map': map_data, 'attack': attack_method, # the rest of these options don't matter 'loadtime': 0, 'turntime': 0, 'viewradius2': 100, 'spawnradius2': 2, 'turns': 1 }) game.do_attack() # Figure out what number we labeled each character a = 0 b = 0 #print game.player_chars if 'a' in game.player_chars: a = len(game.player_ants(game.player_chars.index('a'))) if 'b' in game.player_chars: b = len(game.player_ants(game.player_chars.index('b'))) # remove buffer and return return (create_map_output(game.map, buffer), (a,b))
def functional_test(self, submission_id): self.post_id += 1 log.info("Running functional test for %s" % submission_id) options = copy(server_info["game_options"]) options['strict'] = True # kills bot on invalid inputs options['food'] = 'none' options['turns'] = 30 log.debug(options) options["map"] = self.get_test_map() options['capture_errors'] = True game = Ants(options) if submission_id in self.download_dirs: bot_dir = self.download_dirs[submission_id] else: bot_dir = self.submission_dir(submission_id) bots = [(os.path.join(bot_dir, 'bot'), compiler.get_run_cmd(bot_dir)), (os.path.join(server_info['repo_path'], "ants", "submission_test"), "python TestBot.py")] log.debug(bots) # set worker debug logging if self.debug: options['verbose_log'] = sys.stdout #options['stream_log'] = sys.stdout options['error_logs'] = [sys.stderr, sys.stderr] # options['output_logs'] = [sys.stdout, sys.stdout] # options['input_logs'] = [sys.stdout, sys.stdout] result = run_game(game, bots, options) if 'status' in result: if result['status'][1] in ('crashed', 'timeout', 'invalid'): if type(result['errors'][1]) == unicode: errors_str = uni_to_ascii(result['errors'][1]) else: errors_str = '["' + '","'.join( uni_to_ascii(e) for e in result['errors'][1]) + '"]' msg = 'TestBot is not operational\n' + errors_str log.error(msg) return msg log.info(result['status'][0]) # player 0 is the bot we are testing if result['status'][0] in ('crashed', 'timeout', 'invalid'): if type(result['errors'][1]) == unicode: errors_str = uni_to_ascii(result['errors'][0]) else: errors_str = '["' + '","'.join( uni_to_ascii(e) for e in result['errors'][0]) + '"]' log.info(errors_str) return result['errors'][0] elif 'error' in result: msg = 'Function Test failure: ' + result['error'] log.error(msg) return msg return None
def run_rounds(): # this split of options is not needed, but left for documentation turns = 10 rounds = 1 game_options = { "map": '../../maps/random4.txt', "attack": 'damage', "food": 'sections', "viewradius2": 96, "attackradius2": 5, "spawnradius2": 2, "loadtime": 3000, "turntime": 1000, "turns": rounds, "seed": 42, } engine_options = { "loadtime": 3000, "turntime": 1000, "map_file": '../../maps/random4.txt', "turns": turns, "output_dir": '../../viewer/bro_viewer', "output_json": False, "log_input": False, "log_output": False, "serial": None, "verbose": True, "visualizer": opts.visualizer, } bots_files = ("python ../../dist/sample_bots/python/HunterBot.py", "python ../../dist/sample_bots/python/keth.py", "python ../../bots/bro/bro.py", "python ../../dist/sample_bots/python/HunterBot.py") random.seed(game_options['seed']) for round in range(game_options['turns']): map_file = open(game_options['map'], 'r') game_options["map"] = map_file.read() map_file.close() game = Ants(game_options) bots = [('.', arg) for arg in bots_files] if game.num_players != len(bots): print("Incorrect number of bots for map. Need %s, got %s" % (game.num_players, len(bots))) for arg in args: print("Bot Cmd: %s" % arg) break print('playgame round %s' % round) result = run_game(game, bots, engine_options, round) if engine_options['output_json']: print result
def game(self, task, report_status=False): self.post_id += 1 try: matchup_id = int(task["matchup_id"]) log.info("Running game %s..." % matchup_id) if 'options' in task: options = task["options"] else: options = server_info["game_options"] options["map"] = self.get_map(task['map_filename']) options["output_json"] = True game = Ants(options) bots = [] for submission_id in task["players"]: if self.compile(submission_id): submission_dir = self.submission_dir(submission_id) run_cmd = compiler.get_run_cmd(submission_dir) #run_dir = tempfile.mkdtemp(dir=server_info["submissions_path"]) bots.append((submission_dir, run_cmd)) #shutil.copytree(submission_dir, run_dir) else: raise Exception('bot', 'Can not compile bot %s' % submission_id) output_dir = os.path.join(server_info["root_path"], "games", str(matchup_id)) if not os.path.exists(output_dir): try: os.makedirs(output_dir) except: pass options['output_dir'] = output_dir options['log_input'] = True options['log_output'] = True result = run_game(game, bots, options, matchup_id) result['matchup_id'] = task['matchup_id'] result['post_id'] = self.post_id if report_status: self.cloud.post_result('api_game_result', result) except Exception as ex: import traceback traceback.print_exc() result = { "post_id": self.post_id, "matchup_id": matchup_id, "error": str(ex) } self.cloud.post_result('api_game_result', result)
def functional_test(self, submission_id): self.post_id += 1 try: matchup_id = 0 log.info("Running functional test for %s" % submission_id) options = server_info["game_options"] options["map"] = self.get_test_map() options["output_json"] = True game = Ants(options) submission_dir = self.submission_dir(submission_id) bots = [("../ants/submission_test/", "python TestBot.py"), (submission_dir, compiler.get_run_cmd(submission_dir))] result = run_game(game, bots, options, matchup_id) log.info(result) return True except Exception as ex: log.error(traceback.format_exc()) return False
def run_rounds(opts, args): # this split of options is not needed, but left for documentation game_options = { "map": opts.map, "attack": opts.attack, "food": opts.food, "viewradius2": opts.viewradius2, "attackradius2": opts.attackradius2, "spawnradius2": opts.spawnradius2, "loadtime": opts.loadtime, "turntime": opts.turntime, "turns": opts.turns, "seed": opts.seed } engine_options = { "loadtime": opts.loadtime, "turntime": opts.turntime, "map_file": opts.map, "turns": opts.turns, "output_dir": opts.output_dir, "output_json": opts.output_json, "log_input": opts.log_input, "log_output": opts.log_output, "serial": opts.serial, "verbose": opts.verbose } random.seed(opts.seed) for round in range(opts.rounds): map_file = open(opts.map, 'r') game_options["map"] = map_file.read() map_file.close() game = Ants(game_options) bots = [('.', arg) for arg in args] if game.num_players != len(bots): print("Incorrect number of bots for map. Need %s, got %s" % (game.num_players, len(bots))) for arg in args: print("Bot Cmd: %s" % arg) break print('playgame round %s' % round) result = run_game(game, bots, engine_options, round) if opts.output_json: print result
def main(argv): usage = "Usage: %prog [options] map bot1 bot2\n\nYou must specify a map file." parser = OptionParser(usage=usage) # map to be played # number of players is determined by the map file parser.add_option("-m", "--map_file", dest="map", help="Name of the map file") # maximum number of turns that the game will be played parser.add_option("-t", "--turns", dest="turns", default=200, type="int", help="Number of turns in the game") # the output directory will contain the replay file used by the visualizer # it will also contain the bot input/output logs, if requested parser.add_option("-o", "--output_dir", dest="output_dir", help="Directory to dump replay files to.") parser.add_option("-j", "--output_json", dest="output_json", action="store_true", default=False, help="Return json result from engine.") parser.add_option("-I", "--log_input", dest="log_input", action="store_true", default=False, help="Log input streams sent to bots") parser.add_option("-O", "--log_output", dest="log_output", action="store_true", default=False, help="Log output streams from bots") parser.add_option("--serial", dest="serial", action="store_true", help="Run bots in serial, instead of parallel.") parser.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False, help="Print out status as game goes.") parser.add_option("--turntime", dest="turntime", default=1000, type="int", help="Amount of time to give each bot, in milliseconds") parser.add_option("--loadtime", dest="loadtime", default=3000, type="int", help="Amount of time to give for load, in milliseconds") parser.add_option("-r", "--rounds", dest="rounds", default=1, type="int", help="Number of rounds to play") parser.add_option("--seed", dest="seed", default=None, type="int", help="Seed for the random number generator") # ants specific game options parser.add_option( "--attack", dest="attack", default="damage", help= "Attack method to use for engine. (closest, power, support, damage)") parser.add_option( "--food", dest="food", default="sections", help="Food spawning method. (none, random, sections, symmetric)") parser.add_option("--viewradius2", dest="viewradius2", default=96, type="int", help="Vision radius of ants squared") parser.add_option("--spawnradius2", dest="spawnradius2", default=2, type="int", help="Spawn radius of ants squared") parser.add_option("--attackradius2", dest="attackradius2", default=5, type="int", help="Attack radius of ants squared") (opts, args) = parser.parse_args(argv) if opts.map is None or not os.path.exists(opts.map): parser.print_help() return -1 try: # this split of options is not needed, but left for documentation game_options = { "map": opts.map, "attack": opts.attack, "food": opts.food, "viewradius2": opts.viewradius2, "attackradius2": opts.attackradius2, "spawnradius2": opts.spawnradius2, "loadtime": opts.loadtime, "turntime": opts.turntime, "turns": opts.turns, "seed": opts.seed } engine_options = { "loadtime": opts.loadtime, "turntime": opts.turntime, "map_file": opts.map, "turns": opts.turns, "output_dir": opts.output_dir, "output_json": opts.output_json, "log_input": opts.log_input, "log_output": opts.log_output, "serial": opts.serial, "verbose": opts.verbose } random.seed(opts.seed) for round in range(opts.rounds): map_file = open(opts.map, 'r') game_options["map"] = map_file.read() map_file.close() game = Ants(game_options) bots = [('.', arg) for arg in args] if game.num_players != len(bots): print("Incorrect number of bots for map. Need %s, got %s" % (game.num_players, len(bots))) break print('playgame round %s' % round) result = run_game(game, bots, engine_options, round) if opts.output_json: print result except Exception: traceback.print_exc() finally: return 1
def __init__(self, argv): opts, args = main(argv) self.game = Ants(get_game_opts(opts,args)) self.agent_moves = {} self.game.start_game() # TODO: might move self.screen_shape = (self.game.height, self.game.width)
class Engine(): def __init__(self, argv): opts, args = main(argv) self.game = Ants(get_game_opts(opts,args)) self.agent_moves = {} self.game.start_game() # TODO: might move self.screen_shape = (self.game.height, self.game.width) def reset(self): self.game.restart() self.agent_moves = {} self.game.start_game() def do_move(self, loc, direction): """ Execute the agent's action. Since action is choice of ant and direction, here we insert the intermediery states. :param loc: (row, col) :param direction: n,e,s,w :return: reward """ if self.game.map[loc[0]][loc[1]] != RL_AGENT or loc in self.agent_moves: return -1 if len(self.agent_moves) == 0: self.game.start_turn() self.agent_moves[loc] = direction if len(self.agent_moves) == len(self.game.player_ants(RL_AGENT)): orders = [] for (row, col) in self.agent_moves: orders.append("o %s %s %s" % (row, col, self.agent_moves[(row,col)])) print self.game.do_moves(RL_AGENT, orders) self.do_bots_move() self.game.finish_turn() self.agent_moves = {} # TODO: use ignored for reward calculations? return 0 def do_bots_move(self): pass def game_over(self): """ Check if our agent is still in game :return: """ return not self.game.is_alive(RL_AGENT) or self.game.game_over() def get_observation(self): screen = np.array(self.game.get_perspective(RL_AGENT)) # TODO: add temp states for already moved ants return screen
class RandomBot: def do_turn(self, ants): destinations = [] for a_row, a_col in ants.my_ants(): # try all directions randomly until one is passable and not occupied directions = AIM.keys() shuffle(directions) for direction in directions: (n_row, n_col) = ants.destination(a_row, a_col, direction) if (not (n_row, n_col) in destinations and ants.passable(n_row, n_col)): ants.issue_order((a_row, a_col, direction)) destinations.append((n_row, n_col)) break else: destinations.append((a_row, a_col)) if __name__ == '__main__': try: import psyco psyco.full() except ImportError: pass try: Ants.run(RandomBot()) except KeyboardInterrupt: print('ctrl-c, leaving ...')
Util.set_parameters( sys.argv) # set all parameters and value from arguments command # get the instance for the run index_instance = sys.argv.index("-i") if "-i" in sys.argv else sys.argv.index( "--instance") path = sys.argv[index_instance + 1] filename = os.path.basename(path) qap = Reader(path) # construct the problem Util.get_configuration() # get the best configuration of the ant system runs = [sys.maxsize for i in range(Params.singleton.MAX_RUN)] for t in range(Params.singleton.MAX_TRY): colony = Ants(qap.matrix_A, qap.matrix_B, Params.singleton.nb_ants, qap.size) colony.init_pheromone(1 / (Params.singleton.RHO * qap.size)) run = 0 start = time.time() while not terminal_condition(run, start): construct_solutions(colony) # build the solution for each ant if Params.singleton.lcs_flag: colony.local_search() # apply the local search update_pheromone( colony) # update the pheromone depending on the ant system save_run(run, colony) # Save the current run
class AntsEnv(gym.Env): """ Open AI gym environment for the Ants game. Args: - game_opts (AntsEnvOptions): Options to customize the game. - enemies ([Bot]): A list of enemy bots. - reward_func (RewardFunc): A RewardFunc object to calculate the reward at each step. - agent_names ([str]): A list of names for each agent. Properties: - observation_space: Box of shape (n, 5 + num_players, game_hight, game_width) of type np.uint8 where n is the number of agents. Most cell values are 0, or 1 to represent True, or False respectively. There are (4 + num_player) channels for the following: - Channel 0: If the cell is visible to the agent. - Channel 1: If the cell is land (else water). - Channel 2: If the cell has food. - Channel 3: If the cell has the agent's ant. - Channel 4: If the cell has an ant hill, then the player num (starting from 1) of the hill owner. Else 0. - Channel 5: If the cell has an ant which died the previous turn, then the player num (starting from 1) of the dead ant. Else 0. - Channel 6 and greater: If the cell has an enemy ant (one channel per enemy player). - action_space: Box of shape (n, game_height, game_width) with 0 <= cell value <= 4. 'n' is the number of agents. The cell value represents the move to make with the ant at each cell position for each agent: - 0: If the cell position has no player ants then don't move. - 1: Move 1 step north. - 2: Move 1 step east. - 3: Move 1 step south. - 4: Move 1 step west. """ # Observation channels CHANNEL_IS_VISIBLE = 0 CHANNEL_IS_LAND = 1 CHANNEL_HAS_FOOD = 2 CHANNEL_ANT_HILL = 3 CHANNEL_AGENT_ANT = 4 CHANNEL_DEAD_ANTS = 5 CHANNEL_ENEMY_ANT_START = 6 # Action types NUM_ACTIONS = 5 ACTION_DONT_MOVE = 0 ACTION_MOVE_NORTH = 1 ACTION_MOVE_EAST = 2 ACTION_MOVE_SOUTH = 3 ACTION_MOVE_WEST = 4 def __init__(self, game_opts, enemies, reward_func, agent_names=None): self.game_opts = game_opts self.enemies = enemies self.reward_func = reward_func self.game = Ants(self.game_opts.as_dict()) if len(self.enemies) >= self.game.num_players: raise ValueError( 'The number of enemies should be strictly less than the number of players. Otherwise there will be no agent to play against.' ) self.num_agents = self.game.num_players - len(self.enemies) if not agent_names: self.agent_names = [f'Agent {i}' for i in range(self.num_agents)] elif len(agent_names) != self.num_agents: raise ValueError( f'len(agent_names) == {len(agent_names)} should be 0 or equal to the number of agents == {self.num_agents}.' ) else: self.agent_names = agent_names self.observation_space = gym.spaces.Box( low=0, high=1, shape=(self.num_agents, 5 + self.game.num_players, self.game.height, self.game.width), dtype=np.uint8) self.action_space = gym.spaces.Box(low=0, high=4, shape=(self.num_agents, self.game.height, self.game.width), dtype=np.uint8) self.reset(self.game) def step(self, action): """ Run one timestep of the environment's dynamics. Accepts an action and returns a tuple (observation, reward, done, info). Args: - action (object): An action provided by the environment. If one of the agents is no longer alive, but the game is still going on, then that player's action is ignored. Returns: observation (object): Agent's observation of the current environment. reward ([float]) : Amount of reward returned after previous action for each agent. done (boolean): Whether the episode has ended, in which case further step() calls will throw an exception. info ([object]): The metadata with wich the reward was calculated per agent. """ if action.shape != self.action_space.shape: raise Exception( f'Shape of action {action.shape} should be same as shape of action space {self.action_space.shape}' ) if self.is_done: raise Exception( "Can't make moves on a game that has finished. Reset board to continue." ) reward_inputs = RewardInputs(self.num_agents) \ .set_game(self.game) reward_inputs.set_old_state(np.copy(self._current_state)) # Play moves for each bot in a random order self.game.start_turn() player_order = list(range(self.game.num_players)) np.random.shuffle(player_order) for player_num in player_order: if not self.game.is_alive(player_num): continue if 0 <= player_num < self.num_agents: moves = self._action_to_moves(action[player_num]) else: enemy_ind = player_num - self.num_agents moves = self.enemies[enemy_ind].get_moves() valid, ignored, invalid = self.game.do_moves(player_num, moves) if 0 <= player_num < self.num_agents: reward_inputs.set_ignored_moves(player_num, self._parse_bad_moves(ignored)) reward_inputs.set_invalid_moves(player_num, self._parse_bad_moves(invalid)) self.game.finish_turn() if self.game.game_over() or self.game.turn > self.game.turns: self.is_done = True self.game.finish_game() for i, enemy in enumerate(self.enemies): player_num = i + self.num_agents if self.game.is_alive(player_num): enemy.update_map(self.game.get_player_state(player_num)) obs = self._get_observations() # Calculate reward reward_inputs.set_new_state(obs) reward, info = self.reward_func(reward_inputs) return obs, reward, self.is_done, info def reset(self, init_game=None): self.reward_func.reset() self.game = init_game or Ants(self.game_opts.as_dict()) self.is_done = False self.game.start_game() for i, enemy in enumerate(self.enemies): enemy.reset() enemy.setup(self.game.get_player_start(i + self.num_agents)) enemy.update_map(self.game.get_player_state(i + self.num_agents)) obs = self._get_observations(reset=True) return obs def visualize(self, game_result=None): """ Visualize a game till the current state. Opens the game in a new browser, and will start visualization from the start, so is not the same as render. Args: - game_result: The game result to visualize. Default: None. Uses current game_result if None. """ game_result = game_result or self.get_game_result() visualizer.launch( game_result_json=json.dumps(game_result, sort_keys=True)) def get_game_result(self): """ Get the result of the game. """ game_result = { 'challenge': self.game.__class__.__name__.lower(), 'score': self.game.get_scores(), 'replayformat': 'json', 'replaydata': self.game.get_replay(), 'playernames': [name for name in self.agent_names] + [enemy.name for enemy in self.enemies] } return game_result def _get_observations(self, reset=False): if reset: self._current_state = np.zeros(self.observation_space.shape, dtype=self.observation_space.dtype) # Set all cells to land. self._current_state[:, AntsEnv.CHANNEL_IS_LAND] = 1 for i in range(self.num_agents): if not self.game.is_alive(i): continue state = self.game.get_player_state(i) self._update_observation(i, state) return np.copy(self._current_state) def _update_observation(self, agent_num, player_state_str): obs = self._current_state[agent_num] # clear all transient entities. obs[AntsEnv.CHANNEL_IS_VISIBLE] = 0 obs[AntsEnv.CHANNEL_AGENT_ANT] = 0 obs[AntsEnv.CHANNEL_DEAD_ANTS] = 0 obs[AntsEnv.CHANNEL_ENEMY_ANT_START:] = 0 obs[AntsEnv.CHANNEL_ANT_HILL] = 0 obs[AntsEnv.CHANNEL_HAS_FOOD] = 0 # update map for line in player_state_str.strip().split('\n'): line = line.strip().lower() tokens = line.split() key, (row, col) = tokens[0], map(int, tokens[1:3]) owner = None if len(tokens) <= 3 else int(tokens[3]) obs[AntsEnv.CHANNEL_IS_VISIBLE, row, col] = 1 if key == 'w': obs[AntsEnv.CHANNEL_IS_LAND, row, col] = 0 elif key == 'f': obs[AntsEnv.CHANNEL_HAS_FOOD, row, col] = 1 elif 0 <= owner < self.num_agents: player_num = owner + 1 if key == 'h': obs[AntsEnv.CHANNEL_ANT_HILL, row, col] = player_num elif key == 'a': obs[AntsEnv.CHANNEL_AGENT_ANT, row, col] = 1 self._update_visibility(obs, row, col) elif key == 'd': obs[AntsEnv.CHANNEL_DEAD_ANTS, row, col] = player_num elif owner is not None: player_num = owner + 1 if key == 'h': obs[AntsEnv.CHANNEL_ANT_HILL, row, col] = owner elif key == 'a': channel = AntsEnv.CHANNEL_ENEMY_ANT_START + owner - self.num_agents obs[channel, row, col] = 1 elif key == 'd': obs[AntsEnv.CHANNEL_DEAD_ANTS, row, col] = player_num return obs def _action_to_moves(self, action): moves = [] for row in range(action.shape[0]): for col in range(action.shape[1]): if action[row, col] == AntsEnv.ACTION_DONT_MOVE: pass elif action[row, col] == AntsEnv.ACTION_MOVE_NORTH: moves.append(f'o {row} {col} n') elif action[row, col] == AntsEnv.ACTION_MOVE_EAST: moves.append(f'o {row} {col} e') elif action[row, col] == AntsEnv.ACTION_MOVE_SOUTH: moves.append(f'o {row} {col} s') elif action[row, col] == AntsEnv.ACTION_MOVE_WEST: moves.append(f'o {row} {col} w') else: raise ValueError( f'action[{row}, {col}] = {action[row, col]} is not a valid move.' ) return moves def _update_visibility(self, obs, row, col): """ Updates the IS_VISIBLE channel given the location of an ant. """ h, w = obs.shape[1:] view_radius_sq = self.game_opts.view_radius_sq view_radius = int(view_radius_sq**0.5) offsets = [] for off_row in range(-view_radius, view_radius + 1): for off_col in range(-view_radius, view_radius + 1): dist = off_row**2 + off_col**2 if dist <= view_radius_sq: obs[AntsEnv.CHANNEL_IS_VISIBLE, (row + off_row) % h, (col + off_col) % w] = 1 def _parse_bad_moves(self, lines): store = np.zeros(self.action_space.shape[1:], dtype=self.action_space.dtype) for line in lines: tokens = line.strip().split() row, col = int(tokens[1]), int(tokens[2]) d = tokens[3] if d == 'n': d = 1 elif d == 'e': d = 2 elif d == 's': d = 3 elif d == 'w': d = 4 else: raise ValueError(f'Unexpected entry {line} in moves.') store[row, col] = d return store
from ants import Ants from HunterBot import HunterBot from FerrariBot import FerrariBot if __name__ == '__main__': try: import psyco psyco.full() except ImportError: pass try: Ants.run(FerrariBot()) except KeyboardInterrupt: print('ctrl-c, leaving ...')
class TcpGame(object): def __init__( self, db, opts, map_name, nplayers ): self.db = db self.id = db.latest self.opts = opts self.players = [] self.bot_status = [] self.ants = Ants(opts) self.map_name = map_name self.timestep = 0 self.nplayers = nplayers #~ def __del__(self): #~ log.info( "rip, game " + str(self.id) ) def step( self ): t = time() timed_out = (t - self.timestep > self.opts['turntime']*0.001) inp_ok = 0 for i,p in enumerate(self.players): if not self.ants.is_alive(i): continue if not p.sock: continue if p.poll(): inp_ok += 1 if (inp_ok == len(self.players)) or timed_out: self.timestep = time() return self.do_turn() return True def turn(self): return "game " + str(self.id) + " turn " + str(self.ants.turn) + " : " def do_turn( self ): self.ants.start_turn() for i,p in enumerate(self.players): s = p.poll() #~ log.info( self.turn() + p.name + " : " + str(s) ) p.clear() if not self.ants.is_alive(i): if self.bot_status[i] != "eliminated": log.debug( self.turn() + p.name + " got eliminated !") p.write("INFO: "+p.name+" got eliminated !\n") self.bot_status[i] = "eliminated" continue if s == None: log.warning( self.turn() + p.name + " timed out !") if self.bot_status[i] != "timed out": log.debug( self.turn() + p.name + " timed out !") self.bot_status[i] = "timed out" p.write("INFO: "+p.name+" timed out !\n") continue self.bot_status[i] = "survived" try: valid, ignored, invalid = self.ants.do_moves(i, s.split('\r\n')) except: log.error("!!!!!!!! do_moves failed " + str(self.ants.turn) + " : " + str(p.name)) if ignored: txt = " ignored: " + str(ignored) p.write( "INFO: " + txt + '\n' ) #~ log.debug(self.turn() +p.name +txt) if invalid: txt = " invalid: " + str(invalid) p.write( "INFO: " + txt + '\n' ) #~ log.debug( self.turn() +p.name + txt) try: self.ants.finish_turn() except: log.error("!!!!!!!! finish_turn failed " + str(self.ants.turn) + " : " + str(self.id)) # finished ? if ( self.ants.turn >= self.ants.turns) or ( self.ants.game_over() ): try: self.ants.finish_game() self.save_game() except: log.error(" !!!!!!!!!! finish game failed " + str(self.ants.turn) + " : " + str(self.id) + " !!!!!!!!!!! ") return False # finished # alive else: for i,p in enumerate(self.players): if self.ants.is_alive(i) and p.sock: p.write( 'turn ' + str(self.ants.turn) + '\n' + self.ants.get_player_state(i) + "go\n" ) return True def save_game(self): log.info("saving game : " + str(self.id) ) scores = self.ants.get_scores() ranks = [sorted(set(scores), reverse=True).index(x) for x in scores] game_result = { 'challenge': 'ants', 'game_id': self.id, 'status': self.bot_status, 'score': scores, 'rank': ranks, 'replayformat': 'json', 'replaydata': self.ants.get_replay(), 'playernames': [], } for i,p in enumerate(self.players): game_result['playernames'].append(p.name) rep_name = "games/"+ str(self.id)+".replay" f = open( rep_name, 'w' ) json.dump(game_result,f) f.close() # add to game db data shared with the webserver g = GameData() g.id = self.id g.map = self.map_name g.date = asctime() plr = {} for i,p in enumerate(self.players): if p.name in self.db.players: player = self.db.players[p.name] else: player = PlayerData() player.name = p.name self.db.players[p.name] = player #~ player.games.append(g.id) player.ngames += 1 plr[p.name] = scores[i] g.players = plr self.db.games[g.id] = g # pop from list if there's too many games: if len(self.db.games) > int(self.opts['db_max_games']): k = self.db.games.keys().pop(0) del(self.db.games[k]) log.info("db : " + str(len(self.db.games)) + " games") log.info("db : " + str(len(self.db.players)) + " players") # send final game info to players: end_line = 'INFO: hope, you enjoyed game ' + str(self.id) + '.\n' end_line += 'INFO: players: ' for i,p in enumerate(self.players): end_line += ' ' + p.name end_line += '\nINFO: scores : %s\n' % ' '.join([str(s) for s in scores]) end_line += 'end\n' for i,p in enumerate(self.players): try: p.write( end_line ) except: continue self.calc_ranks( self.players, ranks ) def calc_ranks( self, players, ranks ): class TrueSkillPlayer(object): def __init__(self, name, skill, rank): self.name = name self.old_skill = skill self.skill = skill self.rank = rank ts_players = [] for i, p in enumerate(players): pdata = self.db.players[p.name] ts_players.append( TrueSkillPlayer(i, (pdata.mu,pdata.sigma), ranks[i] ) ) trueskill.AdjustPlayers(ts_players) for i, p in enumerate(players): pdata = self.db.players[p.name] pdata.mu = ts_players[i].skill[0] pdata.sigma = ts_players[i].skill[1] pdata.skill = pdata.mu - pdata.sigma * 3
def populate(self): for i in range(self.ants_init): ant = Ants(self.graph.nest, self.graph.nest, self.graph.nest, False, 0, self.ant_greediness, self.ant_greediness_food) ant.attr = i self.ants.append(ant)
elif Q[state + action] == bestQ: bestActions.append(a) myAction = random.choice(bestActions) enemyAction = random.choice(actions) # Simulate orders map_data = create_map_data(sp, 0) game = Ants({ 'attackradius2': attackradius2, 'map': map_data, 'attack': method, # the rest of these options don't matter 'loadtime': 0, 'turntime': 0, 'viewradius2': 100, 'spawnradius2': 2, 'turns': 1 }) a = game.player_chars.index('a') b = game.player_chars.index('b') """ Orders must be of the form: o row col direction row, col must be integers direction must be in (n,s,e,w) """ myOrders = []
def run_rounds(opts, args): def get_cmd_wd(cmd): ''' get the proper working directory from a command line ''' new_cmd = [] wd = None for i, part in enumerate(reversed(cmd.split())): if wd == None and os.path.exists(part): wd = os.path.split(os.path.realpath(part))[0] if i == 0: new_cmd.insert(0, os.path.join(".", os.path.basename(part))) else: new_cmd.insert(0, os.path.basename(part)) else: new_cmd.insert(0, part) return wd, ' '.join(new_cmd) def get_cmd_name(cmd): ''' get the name of a bot from the command line ''' for i, part in enumerate(reversed(cmd.split())): if os.path.exists(part): return os.path.basename(part) # this split of options is not needed, but left for documentation game_options = { "map": opts.map, "attack": opts.attack, "food": opts.food, "viewradius2": opts.viewradius2, "attackradius2": opts.attackradius2, "spawnradius2": opts.spawnradius2, "loadtime": opts.loadtime, "turntime": opts.turntime, "turns": opts.turns, "food_rate": opts.food_rate, "food_turn": opts.food_turn, "food_start": opts.food_start, "food_visible": opts.food_visible, "cutoff_turn": opts.cutoff_turn, "cutoff_percent": opts.cutoff_percent } if opts.player_seed != None: game_options['player_seed'] = opts.player_seed if opts.engine_seed != None: game_options['engine_seed'] = opts.engine_seed engine_options = { "loadtime": opts.loadtime, "turntime": opts.turntime, "map_file": opts.map, "turns": opts.turns, "log_replay": opts.log_replay, "log_stream": opts.log_stream, "log_input": opts.log_input, "log_output": opts.log_output, "log_error": opts.log_error, "serial": opts.serial, "strict": opts.strict, "capture_errors": opts.capture_errors, "secure_jail": opts.secure_jail, "end_wait": opts.end_wait } for round in range(opts.rounds): # initialize game game_id = round + opts.game_id with open(opts.map, 'r') as map_file: game_options['map'] = map_file.read() if opts.engine_seed: game_options['engine_seed'] = opts.engine_seed + round game = Ants(game_options) # initialize bots bots = [get_cmd_wd(arg) for arg in args] bot_count = len(bots) # insure correct number of bots, or fill in remaining positions if game.num_players != len(bots): if game.num_players > len(bots) and opts.fill: extra = game.num_players - len(bots) for _ in range(extra): bots.append(bots[-1]) else: print("Incorrect number of bots for map. Need {0}, got {1}". format(game.num_players, len(bots)), file=stderr) for arg in args: print("Bot Cmd: {0}".format(arg), file=stderr) break bot_count = len(bots) # move position of first bot specified if opts.position > 0 and opts.position <= len(bots): first_bot = bots[0] bots = bots[1:] bots.insert(opts.position, first_bot) # initialize file descriptors if opts.log_dir and not os.path.exists(opts.log_dir): os.mkdir(opts.log_dir) if not opts.log_replay and not opts.log_stream and (opts.log_dir or opts.log_stdout): opts.log_replay = True replay_path = None # used for visualizer launch if opts.log_replay: if opts.log_dir: replay_path = os.path.join(opts.log_dir, '{0}.replay'.format(game_id)) engine_options['replay_log'] = open(replay_path, 'w') if opts.log_stdout: if 'replay_log' in engine_options and engine_options[ 'replay_log']: engine_options['replay_log'] = Tee( sys.stdout, engine_options['replay_log']) else: engine_options['replay_log'] = sys.stdout else: engine_options['replay_log'] = None if opts.log_stream: if opts.log_dir: engine_options['stream_log'] = open( os.path.join(opts.log_dir, '{0}.stream'.format(game_id)), 'w') if opts.log_stdout: if engine_options['stream_log']: engine_options['stream_log'] = Tee( sys.stdout, engine_options['stream_log']) else: engine_options['stream_log'] = sys.stdout else: engine_options['stream_log'] = None if opts.log_input and opts.log_dir: engine_options['input_logs'] = [ open( os.path.join(opts.log_dir, '{0}.bot{1}.input'.format(game_id, i)), 'w') for i in range(bot_count) ] else: engine_options['input_logs'] = None if opts.log_output and opts.log_dir: engine_options['output_logs'] = [ open( os.path.join(opts.log_dir, '{0}.bot{1}.output'.format(game_id, i)), 'w') for i in range(bot_count) ] else: engine_options['output_logs'] = None if opts.log_error and opts.log_dir: if opts.log_stderr: if opts.log_stdout: engine_options['error_logs'] = [ Tee( Comment(stderr), open( os.path.join( opts.log_dir, '{0}.bot{1}.error'.format(game_id, i)), 'w')) for i in range(bot_count) ] else: engine_options['error_logs'] = [ Tee( stderr, open( os.path.join( opts.log_dir, '{0}.bot{1}.error'.format(game_id, i)), 'w')) for i in range(bot_count) ] else: engine_options['error_logs'] = [ open( os.path.join(opts.log_dir, '{0}.bot{1}.error'.format(game_id, i)), 'w') for i in range(bot_count) ] elif opts.log_stderr: if opts.log_stdout: engine_options['error_logs'] = [Comment(stderr)] * bot_count else: engine_options['error_logs'] = [stderr] * bot_count else: engine_options['error_logs'] = None if opts.verbose: if opts.log_stdout: engine_options['verbose_log'] = Comment(sys.stdout) else: engine_options['verbose_log'] = sys.stdout engine_options['game_id'] = game_id if opts.rounds > 1: print('# playgame round {0}, game id {1}'.format(round, game_id)) # intercept replay log so we can add player names if opts.log_replay: intcpt_replay_io = StringIO.StringIO() real_replay_io = engine_options['replay_log'] engine_options['replay_log'] = intcpt_replay_io result = run_game(game, bots, engine_options) # add player names, write to proper io, reset back to normal if opts.log_replay: replay_json = json.loads(intcpt_replay_io.getvalue()) replay_json['playernames'] = [get_cmd_name(arg) for arg in args] real_replay_io.write(json.dumps(replay_json)) intcpt_replay_io.close() engine_options['replay_log'] = real_replay_io # close file descriptors if engine_options['stream_log']: engine_options['stream_log'].close() if engine_options['replay_log']: engine_options['replay_log'].close() if engine_options['input_logs']: for input_log in engine_options['input_logs']: input_log.close() if engine_options['output_logs']: for output_log in engine_options['output_logs']: output_log.close() if engine_options['error_logs']: for error_log in engine_options['error_logs']: error_log.close() if replay_path: if opts.nolaunch: if opts.html_file: visualizer.visualize_locally.launch( replay_path, True, opts.html_file) else: if opts.html_file == None: visualizer.visualize_locally.launch( replay_path, generated_path="replay.{0}.html".format(game_id)) else: visualizer.visualize_locally.launch( replay_path, generated_path=opts.html_file)
i = 0 for filename in os.listdir(path): qap = Reader(path + "" + filename) # Loop over each configurations for s in range(len(seeds)): Params.singleton.set_nb_ant(seeds[s][0]) Params.singleton.set_alpha(seeds[s][1]) Params.singleton.set_beta(seeds[s][2]) Params.singleton.set_rho(seeds[s][3]) Params.singleton.set_omega(seeds[s][4]) # Try 3 times each configuration on each instance for t in range(Params.singleton.MAX_TRY): colony = Ants(qap.matrix_A, qap.matrix_B, Params.singleton.nb_ants, qap.size) colony.init_pheromone(1 / ((Params.singleton.RHO) * qap.size)) run = 0 while not terminal_condition(run, i): print("[DEBUG] Run n°" + str(run + 1) + " on configuration n°" + str(s + 1)) print("[DEBUG] Build solutions....") construct_solutions(colony) print("[DEBUG] Update pheromones") update_pheromone(colony) print("[DEBUG] Update statistics") add_run(colony, run) run += 1