Example #1
0
    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)
Example #2
0
 def start():
     try:
         os.remove(DEBUG_LOG)
     except OSError:
         pass
     storage = TrainingStorage(remove=False)
     Ants.run(MyBot(storage))
Example #3
0
    def start():
        try:
            os.remove(DEBUG_LOG)
        except OSError:
            pass

        Ants.run(MyBot())
Example #4
0
 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)
Example #5
0
 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
Example #6
0
 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
Example #8
0
 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
Example #9
0
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)
Example #10
0
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)
Example #11
0
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))
Example #12
0
 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
Example #13
0
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
Example #14
0
 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)
Example #15
0
 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
Example #16
0
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
Example #17
0
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
Example #18
0
 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)
Example #19
0
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
Example #20
0

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 ...')
Example #21
0
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
Example #22
0
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
Example #23
0
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
Example #25
0
 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)
Example #26
0
                    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 = []
Example #27
0
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)
Example #28
0
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