예제 #1
0
파일: showdown.py 프로젝트: AM22/Pokemon-AI
 def __init__(self, team_text, agent, username, pokedata, password=None,
              monitor_url=None, proxy=False, browser='chrome', predictor_name='PokeFrequencyPredictor',
              verbose=False, kernel_dir="kernel", kernel=False, lib_dir="../Lib"):
     self.logger = logging.getLogger("showdown")
     self.logger.setLevel(level=logging.INFO)
     self.agent = agent
     self.username = username
     self.password = password
     self.team_text = team_text
     self.predictor_name = predictor_name
     self.monitor_url = monitor_url
     self.battle_url = None
     self.pokedata = pokedata
     self.smogon_data = pokedata.smogon_data
     self.smogon_bw_data = pokedata.smogon_bw_data
     self.graph_move = pokedata.graph_move
     self.graph_poke = pokedata.graph_poke
     self.poke_moves = pokedata.poke_moves
     self.my_team = Team.make_team(team_text, self.smogon_data)
     self.opp_team = None
     self.simulator = Simulator(pokedata)
     arch = platform.architecture()
     #print(arch[0])
     self.lib_dir = Path(lib_dir)
     self.selenium = Selenium(proxy=proxy, browser=browser, driver_path = r"C:\Users\AM22\AppData\Local\Programs\Python\Python36")
     self.verbose = verbose
     self.kernel_dir = Path(kernel_dir)
     self.kernel = kernel
     if self.kernel and not self.kernel_dir.exists():
         self.kernel_dir.mkdir()
     self.state = KernelState(self.kernel_dir / KERNEL_STATE, self.kernel)
     self.state.update_state("status", "idle")
     if self.verbose:
         self.logger.setLevel(level=logging.DEBUG)
예제 #2
0
 def __init__(self, team_text, agent, username, pokedata, password=None,
              monitor_url=None, proxy=False, browser='phantomjs', predictor_name='PokeFrequencyPredictor',
              verbose=False, kernel_dir="kernel", kernel=False, lib_dir="lib"):
     self.logger = logging.getLogger("showdown")
     self.logger.setLevel(level=logging.INFO)
     self.agent = agent
     self.username = username
     self.password = password
     self.team_text = team_text
     self.predictor_name = predictor_name
     self.monitor_url = monitor_url
     self.battle_url = None
     self.pokedata = pokedata
     self.smogon_data = pokedata.smogon_data
     self.smogon_bw_data = pokedata.smogon_bw_data
     self.graph_move = pokedata.graph_move
     self.graph_poke = pokedata.graph_poke
     self.poke_moves = pokedata.poke_moves
     self.my_team = Team.make_team(team_text, self.smogon_data)
     self.opp_team = None
     self.simulator = Simulator(pokedata)
     arch = platform.architecture()
     self.lib_dir = Path(lib_dir) / OS_MAP[arch[0]][arch[1]]
     self.selenium = Selenium(proxy=proxy, browser=browser, lib_dir=self.lib_dir)
     self.verbose = verbose
     self.kernel_dir = Path(kernel_dir)
     self.kernel = kernel
     if self.kernel and not self.kernel_dir.exists():
         self.kernel_dir.mkdir()
     self.state = KernelState(self.kernel_dir / KERNEL_STATE, self.kernel)
     self.state.update_state("status", "idle")
     if self.verbose:
         self.logger.setLevel(level=logging.DEBUG)
예제 #3
0
 def __init__(self,
              team_text,
              agent,
              username,
              pokedata,
              password=None,
              monitor_url=None,
              proxy=False,
              browser='phantomjs',
              predictor_name='PokeFrequencyPredictor',
              verbose=False,
              kernel_dir="kernel",
              kernel=False,
              lib_dir="lib"):
     self.logger = logging.getLogger("showdown")
     self.logger.setLevel(level=logging.INFO)
     self.agent = agent
     self.username = username
     self.password = password
     self.team_text = team_text
     self.predictor_name = predictor_name
     self.monitor_url = monitor_url
     self.battle_url = None
     self.pokedata = pokedata
     self.smogon_data = pokedata.smogon_data
     self.smogon_bw_data = pokedata.smogon_bw_data
     self.graph_move = pokedata.graph_move
     self.graph_poke = pokedata.graph_poke
     self.poke_moves = pokedata.poke_moves
     self.my_team = Team.make_team(team_text, self.smogon_data)
     self.opp_team = None
     self.simulator = Simulator(pokedata)
     self.lib_dir = Path(lib_dir)
     self.selenium = Selenium(proxy=proxy,
                              browser=browser,
                              lib_dir=self.lib_dir)
     self.verbose = verbose
     self.kernel_dir = Path(kernel_dir)
     self.kernel = kernel
     if self.kernel and not self.kernel_dir.exists():
         self.kernel_dir.mkdir()
     self.state = KernelState(self.kernel_dir / KERNEL_STATE, self.kernel)
     self.state.update_state("status", "idle")
     if self.verbose:
         self.logger.setLevel(level=logging.DEBUG)
예제 #4
0
파일: showdown.py 프로젝트: AM22/Pokemon-AI
class Showdown():
    def __init__(self,
                 team_text,
                 agent,
                 username,
                 pokedata,
                 password=None,
                 monitor_url=None,
                 proxy=False,
                 browser='phantomjs',
                 predictor_name='PokeFrequencyPredictor',
                 verbose=False,
                 kernel_dir="kernel",
                 kernel=False,
                 lib_dir="lib"):
        self.logger = logging.getLogger("showdown")
        self.logger.setLevel(level=logging.INFO)
        self.agent = agent
        self.username = username
        self.password = password
        self.team_text = team_text
        self.predictor_name = predictor_name
        self.monitor_url = monitor_url
        self.battle_url = None
        self.pokedata = pokedata
        self.smogon_data = pokedata.smogon_data
        self.smogon_bw_data = pokedata.smogon_bw_data
        self.graph_move = pokedata.graph_move
        self.graph_poke = pokedata.graph_poke
        self.poke_moves = pokedata.poke_moves
        self.my_team = Team.make_team(team_text, self.smogon_data)
        self.opp_team = None
        self.simulator = Simulator(pokedata)
        arch = platform.architecture()
        self.lib_dir = Path(lib_dir) / OS_MAP[arch[0]][arch[1]]
        self.selenium = Selenium(proxy=proxy,
                                 browser=browser,
                                 lib_dir=self.lib_dir)
        self.verbose = verbose
        self.kernel_dir = Path(kernel_dir)
        self.kernel = kernel
        if self.kernel and not self.kernel_dir.exists():
            self.kernel_dir.mkdir()
        self.state = KernelState(self.kernel_dir / KERNEL_STATE, self.kernel)
        self.state.update_state("status", "idle")
        if self.verbose:
            self.logger.setLevel(level=logging.DEBUG)

    def reset(self):
        self.state.update_state("status", "idle")
        self.logger.info("Resetting...")
        self.simulator.score = 0
        self.simulator.total = 0
        self.selenium.reset()
        self.opp_team = None
        self.my_team = Team.make_team(self.team_text, self.smogon_data)

    def create_initial_gamestate(self):
        self.logger.info("Creating initial gamestate...")
        my_pokes = self.my_team.copy()
        for i, poke in enumerate(my_pokes.poke_list):
            poke_name = poke.name
            if poke_name in NAME_CORRECTIONS:
                poke_name = NAME_CORRECTIONS[poke_name]
            poke.health = poke.final_stats['hp']
            poke.alive = True
        opp_poke_list = []
        log = SimulatorLog.parse(self.selenium.get_log())
        for event in log.events:
            if event.type == "team" and event.details[
                    'username'] != self.username:
                opp_poke_names = event.details['team']
        for name in opp_poke_names:
            if not name:
                continue
            poke_name = correct_name(name)
            "Corrected to:", poke_name
            if poke_name in self.smogon_data:
                moveset = [
                    m for m in self.smogon_data[poke_name].movesets
                    if 'Overused' == m['tag'] or 'Underused' == m['tag']
                    or 'Rarelyused' == m['tag'] or 'Neverused' == m['tag']
                    or 'Unreleased' == m['tag'] or 'Ubers' == m['tag']
                    or 'PU' in m['tag']
                ]
                if len(moveset) > 1:
                    moveset = SmogonMoveset.from_dict(moveset[1])
                elif len(moveset) == 1:
                    moveset = SmogonMoveset.from_dict(moveset[0])
                else:
                    moveset = [
                        m for m in self.smogon_bw_data[poke_name].movesets
                        if 'Overused' == m['tag'] or 'Underused' == m['tag']
                        or 'Rarelyused' == m['tag'] or 'Neverused' == m['tag']
                        or 'Unreleased' == m['tag'] or 'Ubers' == m['tag']
                        or 'PU' in m['tag']
                    ]
                    moveset = SmogonMoveset.from_dict(moveset[0])
            elif poke_name not in self.smogon_data and poke_name in self.smogon_bw_data:
                moveset = [
                    m for m in self.smogon_bw_data[poke_name].movesets
                    if 'Overused' == m['tag'] or 'Underused' == m['tag']
                    or 'Rarelyused' == m['tag'] or 'Neverused' == m['tag']
                    or 'Unreleased' == m['tag'] or 'Ubers' == m['tag']
                    or 'PU' in m['tag']
                ]
                moveset = SmogonMoveset.from_dict(moveset[0])
            else:
                moveset = SmogonMoveset(
                    None, None, None, {
                        'hp': 88,
                        'patk': 84,
                        'pdef': 84,
                        'spatk': 84,
                        'spdef': 84,
                        'spe': 84
                    }, {
                        'hp': 1.0,
                        'patk': 1.0,
                        'pdef': 1.0,
                        'spatk': 1.0,
                        'spdef': 1.0,
                        'spe': 1.0
                    }, None, 'ou')
            moveset.moves = None
            if poke_name in self.smogon_data:
                typing = self.smogon_data[poke_name].typing
                stats = self.smogon_data[poke_name].stats
            elif poke_name not in self.smogon_data and poke_name in self.smogon_bw_data:
                typing = self.smogon_bw_data[poke_name].typing
                stats = self.smogon_bw_data[poke_name].stats
            else:
                typing = ['Normal']
                stats = {
                    'hp': 80,
                    'patk': 80,
                    'pdef': 80,
                    'spatk': 80,
                    'spdef': 80,
                    'spe': 80
                }
            predictor = create_predictor(self.predictor_name, name,
                                         self.pokedata)
            poke = Pokemon(name,
                           typing,
                           stats,
                           moveset,
                           predictor,
                           calculate=True)
            moves = [x[0] for x in poke.predict_moves([])]
            poke.moveset.moves = moves[:4]
            poke.health = poke.final_stats['hp']
            poke.alive = True
            opp_poke_list.append(poke)
        my_primary = None
        for event in log.events:
            if event.type == "switch" and event.player == 0:
                for poke in my_pokes.poke_list:
                    if poke.name == event.poke:
                        my_primary = my_pokes.poke_list.index(poke)
            elif event.type == "switch" and event.player == 1:
                for poke in opp_poke_list:
                    if poke.name == event.poke:
                        opp_primary = opp_poke_list.index(poke)

        assert my_primary != None
        self.opp_team = Team(opp_poke_list)
        opp_pokes = self.opp_team.copy()
        my_pokes.primary_poke = my_primary
        opp_pokes.primary_poke = opp_primary

        gamestate = GameState([my_pokes, opp_pokes])
        return gamestate

    def correct_gamestate(self, gamestate):
        self.logger.info("Correcting Pokemon health...")
        gamestate = gamestate.deep_copy()
        my_poke_health = self.selenium.get_my_primary_health()
        opp_poke_health = self.selenium.get_opp_primary_health()
        my_team = gamestate.get_team(0)
        opp_team = gamestate.get_team(1)
        my_team.primary(
        ).health = my_poke_health / 100.0 * my_team.primary().final_stats['hp']
        opp_team.primary().health = opp_poke_health / 100.0 * opp_team.primary(
        ).final_stats['hp']
        return gamestate

    def update_latest_turn(self, gamestate):
        self.logger.info("Updating with latest information...")
        text_log = self.selenium.get_log()
        text_list = text_log.split("\n")
        buffer = []
        turns = []
        for line in text_list:
            line = line.strip()
            if re.match(r"Turn [0-9]+", line):
                turns.append(buffer)
                buffer = []
            else:
                buffer.append(line)
        my_poke_name = self.selenium.get_my_primary()
        opp_poke_name = self.selenium.get_opp_primary()

        old_gamestate = gamestate
        gamestate = gamestate.deep_copy()

        self.simulator.append_log(gamestate,
                                  turns[-1],
                                  my_poke=my_poke_name,
                                  opp_poke=opp_poke_name)
        move_events = []
        for event in self.simulator.latest_turn:
            if event.type == "move":
                move_events.append(event)
        if len(move_events) == 2 and move_events[0].player == 1:
            my_move = move_events[1].details['move']
            opp_move = move_events[0].details['move']
            if my_move == "Hidden Power":
                my_move = get_hidden_power(move_events[1].poke,
                                           self.smogon_data)
            if opp_move == "Hidden Power":
                opp_move = get_hidden_power(move_events[0].poke,
                                            self.smogon_data)
            if my_move in MOVE_CORRECTIONS:
                my_move = MOVE_CORRECTIONS[my_move]
            if opp_move in MOVE_CORRECTIONS:
                opp_move = MOVE_CORRECTIONS[opp_move]
            my_move = get_move(my_move)
            opp_move = get_move(opp_move)
            if move_events[0].player != self.simulator.get_first(
                    old_gamestate, [my_move, opp_move], 0):
                opp_poke = old_gamestate.get_team(1).primary()
                for poke in gamestate.get_team(1).poke_list:
                    if poke.name == opp_poke.name:
                        poke.item = "Choice Scarf"
        return gamestate

    def init(self):
        self.logger.info("Initializing showdown")
        self.selenium.start_driver()
        self.selenium.clear_cookies()
        self.selenium.screenshot('log.png')
        self.selenium.turn_off_sound()
        self.selenium.login(self.username, self.password)
        self.selenium.screenshot('log.png')
        self.selenium.make_team(self.team_text)
        self.selenium.screenshot('log.png')

    def update_monitor(self, done=False):
        if self.monitor_url is not None:
            self.logger.info("Updating online monitor at: %s",
                             self.monitor_url)
            if done:
                status = 'done'
            else:
                status = 'match'
            data = {
                'username': self.username,
                'status': status,
                'scores': self.scores,
                'url': self.battle_url
            }
            try:
                url = self.monitor_url + "/api/update"
                headers = {
                    'Content-type': 'application/json',
                    'Accept': 'text/plain'
                }
                requests.post(url, data=json.dumps(data), headers=headers)
            except:
                pass

    def play_game(self, challenge=None):
        self.state.update_state("status", "finding_game")
        self.logger.info("Finding a game...")
        self.selenium.screenshot('log.png')
        tier_click = False
        while not tier_click:
            try:
                self.selenium.choose_tier()
                self.selenium.screenshot('log.png')
                if challenge:
                    self.selenium.start_challenge_battle(challenge)
                else:
                    self.selenium.start_ladder_battle()
                self.selenium.screenshot('log.png')
                tier_click = True
            except TierException:
                self.logger.warning("Unable to click tier. Trying again...")
            self.selenium.screenshot('log.png')
            self.battle_url = self.selenium.driver.current_url
            self.selenium.screenshot('log.png')
            self.logger.info("Found game: %s", self.battle_url)
            self.state.update_state("status", "in_battle")
            self.state.update_state("battle_url", self.battle_url)
            self.update_monitor()
            self.selenium.wait_for_move()
            self.selenium.chat("gl hf!")
            self.selenium.switch_initial(0, 0)
            self.selenium.screenshot('log.png')
            gamestate = self.create_initial_gamestate()
            gamestate = self.update_latest_turn(gamestate)
            over = False
            while not over:
                print "=========================================================================================="
                print "My primary:", gamestate.get_team(0).primary()
                print "Their primary:", gamestate.get_team(1).primary()
                print "Their moves: ", gamestate.get_team(
                    1).primary().moveset.moves
                print "Their item: ", gamestate.get_team(1).primary().item
                print "Their ability: ", gamestate.get_team(
                    1).primary().ability
                print "My move:",
                move = self.agent.get_action(gamestate, 0)
                if move.is_switch():
                    self.selenium.switch(move.switch_index, move.backup_switch)
                else:
                    self.selenium.move(move.move_index,
                                       move.backup_switch,
                                       mega=move.mega,
                                       volt_turn=move.volt_turn)
                gamestate = self.update_latest_turn(gamestate)
                gamestate = self.correct_gamestate(gamestate)
                self.selenium.screenshot('log.png')
        self.state.delete_state("battle_url")

    def run(self, num_games=1, challenge=None):
        self.state.update_state("status", "initializing_battle")
        if challenge:
            self.logger.info("Set to challenge: %s", challenge)
        else:
            self.logger.info("Set to play %u games", num_games)
        self.init()
        self.scores = {'wins': 0, 'losses': 0, 'crashes': 0}

        def signal_handler(signal, frame):
            self.update_monitor(done=True)
            sys.exit(0)

        #signal.signal(signal.SIGINT, signal_handler)
        for i in range(num_games):
            self.simulator.log.reset()
            result, error = None, None
            try:
                self.play_game(challenge=challenge)
            except GameOverException:
                log = SimulatorLog.parse(self.selenium.get_log())
                disconnected = log.disconnected()
                if disconnected:
                    over, _ = log.is_over()
                    while not over:
                        time.sleep(5)
                        over, _ = log.is_over()
                _, over_event = log.is_over()
                result = over_event.details['username'] == self.username
            except UserNotOnlineException:
                self.logger.error("User not online: %s", challenge)
                self.logger.info("Exiting...")
                return
            except:
                error = traceback.format_exc()
                print "Error", error
                log = SimulatorLog.parse(self.selenium.get_log())
                _, over_event = log.is_over()
                if over_event is not None:
                    result = over_event.details['username'] == self.username
            log = self.selenium.get_log()
            id = self.selenium.get_battle_id()
            battle_url = "http://replay.pokemonshowdown.com/battle-%s" % id
            self.logger.info("Finished game! Replay can be found at: %s",
                             battle_url)
            user_folder = Path(".") / self.username
            if not user_folder.exists():
                user_folder.mkdir()
            if not (user_folder / "wins").exists():
                (user_folder / "wins").mkdir()
            if not (user_folder / "losses").exists():
                (user_folder / "losses").mkdir()
            if not (user_folder / "crashes").exists():
                (user_folder / "crashes").mkdir()
            if result == True:
                print "---------------"
                print "Won the battle! - %s" % battle_url
                print "---------------"
                self.scores['wins'] += 1
                with open(user_folder / "wins" / ("%s.log" % id), 'w') as fp:
                    fp.write(log)
                with open(user_folder / "wins" / ("%s.score" % id), 'w') as fp:
                    print >> fp, self.simulator.score
                    print >> fp, self.simulator.total
            elif result == False:
                print "---------------"
                print "Lost the battle! - %s" % battle_url
                print "---------------"
                self.scores['losses'] += 1
                with open(user_folder / "losses" / ("%s.log" % id), 'w') as fp:
                    fp.write(log)
                with open(user_folder / "losses" / ("%s.score" % id),
                          'w') as fp:
                    print >> fp, self.simulator.score
                    print >> fp, self.simulator.total
            else:
                print "---------------"
                print "Crashed! - %s" % id
                print "---------------"
                self.scores['crashes'] += 1
                with open(user_folder / "crashes" / ("%s.log" % id),
                          'w') as fp:
                    fp.write(log)
                with open(user_folder / "crashes" / ("%s.err" % id),
                          'w') as fp:
                    fp.write(error)
                with open(user_folder / "crashes" / ("%s.score" % id),
                          'w') as fp:
                    print >> fp, self.simulator.score
                    print >> fp, self.simulator.total
            events = SimulatorLog.parse(self.selenium.get_log())
            for event in events:
                if event.type == "ladder":
                    if event.details['username'] == self.username:
                        with open(user_folder / "ladder_ratings.txt",
                                  "a") as fp:
                            fp.write(event.details['ladder'] + "\n")
            self.reset()
        self.update_monitor(done=True)
        self.selenium.close()
        self.logger.info("Done!")
예제 #5
0
class Showdown():
    def __init__(self, team_text, agent, username, pokedata, password=None,
                 monitor_url=None, proxy=False, browser='phantomjs', predictor_name='PokeFrequencyPredictor',
                 verbose=False, kernel_dir="kernel", kernel=False, lib_dir="lib"):
        self.logger = logging.getLogger("showdown")
        self.logger.setLevel(level=logging.INFO)
        self.agent = agent
        self.username = username
        self.password = password
        self.team_text = team_text
        self.predictor_name = predictor_name
        self.monitor_url = monitor_url
        self.battle_url = None
        self.pokedata = pokedata
        self.smogon_data = pokedata.smogon_data
        self.smogon_bw_data = pokedata.smogon_bw_data
        self.graph_move = pokedata.graph_move
        self.graph_poke = pokedata.graph_poke
        self.poke_moves = pokedata.poke_moves
        self.my_team = Team.make_team(team_text, self.smogon_data)
        self.opp_team = None
        self.simulator = Simulator(pokedata)
        arch = platform.architecture()
        self.lib_dir = Path(lib_dir) / OS_MAP[arch[0]][arch[1]]
        self.selenium = Selenium(proxy=proxy, browser=browser, lib_dir=self.lib_dir)
        self.verbose = verbose
        self.kernel_dir = Path(kernel_dir)
        self.kernel = kernel
        if self.kernel and not self.kernel_dir.exists():
            self.kernel_dir.mkdir()
        self.state = KernelState(self.kernel_dir / KERNEL_STATE, self.kernel)
        self.state.update_state("status", "idle")
        if self.verbose:
            self.logger.setLevel(level=logging.DEBUG)

    def reset(self):
        self.state.update_state("status", "idle")
        self.logger.info("Resetting...")
        self.simulator.score = 0
        self.simulator.total = 0
        self.selenium.reset()
        self.opp_team = None
        self.my_team = Team.make_team(self.team_text, self.smogon_data)

    def create_initial_gamestate(self):
        self.logger.info("Creating initial gamestate...")
        my_pokes = self.my_team.copy()
        for i, poke in enumerate(my_pokes.poke_list):
            poke_name = poke.name
            if poke_name in NAME_CORRECTIONS:
                poke_name = NAME_CORRECTIONS[poke_name]
            poke.health = poke.final_stats['hp']
            poke.alive = True
        opp_poke_list = []
        log = SimulatorLog.parse(self.selenium.get_log())
        for event in log.events:
            if event.type == "team" and event.details['username'] != self.username:
                opp_poke_names = event.details['team']
        for name in opp_poke_names:
            if not name:
                continue
            poke_name = correct_name(name)
            "Corrected to:", poke_name
            if poke_name in self.smogon_data:
                moveset = [m for m in self.smogon_data[poke_name].movesets if 'Overused' == m['tag'] or 'Underused' == m['tag'] or 'Rarelyused' == m['tag'] or 'Neverused' == m['tag'] or 'Unreleased' == m['tag'] or 'Ubers' == m['tag'] or 'PU' in m['tag']]
                if len(moveset) > 1:
                    moveset = SmogonMoveset.from_dict(moveset[1])
                elif len(moveset) == 1:
                    moveset = SmogonMoveset.from_dict(moveset[0])
                else:
                    moveset = [m for m in self.smogon_bw_data[poke_name].movesets if 'Overused' == m['tag'] or 'Underused' == m['tag'] or 'Rarelyused' == m['tag'] or 'Neverused' == m['tag'] or 'Unreleased' == m['tag'] or 'Ubers' == m['tag'] or 'PU' in m['tag']]
                    moveset = SmogonMoveset.from_dict(moveset[0])
            elif poke_name not in self.smogon_data and poke_name in self.smogon_bw_data:
                moveset = [m for m in self.smogon_bw_data[poke_name].movesets if 'Overused' == m['tag'] or 'Underused' == m['tag'] or 'Rarelyused' == m['tag'] or 'Neverused' == m['tag'] or 'Unreleased' == m['tag'] or 'Ubers' == m['tag'] or 'PU' in m['tag']]
                moveset = SmogonMoveset.from_dict(moveset[0])
            else:
                moveset = SmogonMoveset(None, None, None, {'hp': 88, 'patk': 84, 'pdef': 84, 'spatk': 84, 'spdef': 84, 'spe': 84}, {'hp': 1.0, 'patk': 1.0, 'pdef': 1.0, 'spatk': 1.0, 'spdef': 1.0, 'spe': 1.0}, None, 'ou')
            moveset.moves = None
            if poke_name in self.smogon_data:
                typing = self.smogon_data[poke_name].typing
                stats = self.smogon_data[poke_name].stats
            elif poke_name not in self.smogon_data and poke_name in self.smogon_bw_data:
                typing = self.smogon_bw_data[poke_name].typing
                stats = self.smogon_bw_data[poke_name].stats
            else:
                typing = ['Normal']
                stats = {'hp': 80, 'patk': 80, 'pdef': 80, 'spatk': 80, 'spdef': 80, 'spe': 80}
            predictor = create_predictor(self.predictor_name, name, self.pokedata)
            poke = Pokemon(name, typing, stats, moveset, predictor, calculate=True)
            moves = [x[0] for x in poke.predict_moves([])]
            poke.moveset.moves = moves[:4]
            poke.health = poke.final_stats['hp']
            poke.alive = True
            opp_poke_list.append(poke)
        my_primary = None
        for event in log.events:
            if event.type == "switch" and event.player == 0:
                for poke in my_pokes.poke_list:
                    if poke.name == event.poke:
                        my_primary = my_pokes.poke_list.index(poke)
            elif event.type == "switch" and event.player == 1:
                for poke in opp_poke_list:
                    if poke.name == event.poke:
                        opp_primary = opp_poke_list.index(poke)

        assert my_primary != None
        self.opp_team = Team(opp_poke_list)
        opp_pokes = self.opp_team.copy()
        my_pokes.primary_poke = my_primary
        opp_pokes.primary_poke = opp_primary

        gamestate = GameState([my_pokes, opp_pokes])
        return gamestate

    def correct_gamestate(self, gamestate):
        self.logger.info("Correcting Pokemon health...")
        gamestate = gamestate.deep_copy()
        my_poke_health = self.selenium.get_my_primary_health()
        opp_poke_health = self.selenium.get_opp_primary_health()
        my_team = gamestate.get_team(0)
        opp_team = gamestate.get_team(1)
        my_team.primary().health = my_poke_health / 100.0 * my_team.primary().final_stats['hp']
        opp_team.primary().health = opp_poke_health / 100.0 * opp_team.primary().final_stats['hp']
        return gamestate


    def update_latest_turn(self, gamestate):
        self.logger.info("Updating with latest information...")
        text_log = self.selenium.get_log()
        text_list = text_log.split("\n")
        buffer = []
        turns = []
        for line in text_list:
            line = line.strip()
            if re.match(r"Turn [0-9]+", line):
                turns.append(buffer)
                buffer = []
            else:
                buffer.append(line)
        my_poke_name = self.selenium.get_my_primary()
        opp_poke_name = self.selenium.get_opp_primary()

        old_gamestate = gamestate
        gamestate = gamestate.deep_copy()

        self.simulator.append_log(gamestate, turns[-1], my_poke=my_poke_name, opp_poke=opp_poke_name)
        move_events = []
        for event in self.simulator.latest_turn:
            if event.type == "move":
                move_events.append(event)
        if len(move_events) == 2 and move_events[0].player == 1:
            my_move = move_events[1].details['move']
            opp_move = move_events[0].details['move']
            if my_move == "Hidden Power":
                my_move = get_hidden_power(move_events[1].poke, self.smogon_data)
            if opp_move == "Hidden Power":
                opp_move = get_hidden_power(move_events[0].poke, self.smogon_data)
            if my_move in MOVE_CORRECTIONS:
                my_move = MOVE_CORRECTIONS[my_move]
            if opp_move in MOVE_CORRECTIONS:
                opp_move = MOVE_CORRECTIONS[opp_move]
            my_move = get_move(my_move)
            opp_move = get_move(opp_move)
            if move_events[0].player != self.simulator.get_first(old_gamestate, [my_move, opp_move], 0):
                opp_poke = old_gamestate.get_team(1).primary()
                for poke in gamestate.get_team(1).poke_list:
                    if poke.name == opp_poke.name:
                        poke.item = "Choice Scarf"
        return gamestate

    def init(self):
        self.logger.info("Initializing showdown")
        self.selenium.start_driver()
        self.selenium.clear_cookies()
        self.selenium.screenshot('log.png')
        self.selenium.turn_off_sound()
        self.selenium.login(self.username, self.password)
        self.selenium.screenshot('log.png')
        self.selenium.make_team(self.team_text)
        self.selenium.screenshot('log.png')

    def update_monitor(self, done=False):
        if self.monitor_url is not None:
            self.logger.info("Updating online monitor at: %s",
                             self.monitor_url)
            if done:
                status = 'done'
            else:
                status = 'match'
            data = {
                'username': self.username,
                'status': status,
                'scores': self.scores,
                'url': self.battle_url
            }
            try:
                url = self.monitor_url + "/api/update"
                headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
                requests.post(url, data=json.dumps(data), headers=headers)
            except:
                pass

    def play_game(self, challenge=None):
        self.state.update_state("status", "finding_game")
        self.logger.info("Finding a game...")
        self.selenium.screenshot('log.png')
        tier_click = False
        while not tier_click:
            try:
                self.selenium.choose_tier()
                self.selenium.screenshot('log.png')
                if challenge:
                    self.selenium.start_challenge_battle(challenge)
                else:
                    self.selenium.start_ladder_battle()
                self.selenium.screenshot('log.png')
                tier_click = True
            except TierException:
                self.logger.warning("Unable to click tier. Trying again...")
            self.selenium.screenshot('log.png')
            self.battle_url = self.selenium.driver.current_url
            self.selenium.screenshot('log.png')
            self.logger.info("Found game: %s", self.battle_url)
            self.state.update_state("status", "in_battle")
            self.state.update_state("battle_url", self.battle_url)
            self.update_monitor()
            self.selenium.wait_for_move()
            self.selenium.chat("gl hf!")
            self.selenium.switch_initial(0, 0)
            self.selenium.screenshot('log.png')
            gamestate = self.create_initial_gamestate()
            gamestate = self.update_latest_turn(gamestate)
            over = False
            while not over:
                print "=========================================================================================="
                print "My primary:", gamestate.get_team(0).primary()
                print "Their primary:", gamestate.get_team(1).primary()
                print "Their moves: ", gamestate.get_team(1).primary().moveset.moves
                print "Their item: ", gamestate.get_team(1).primary().item
                print "Their ability: ", gamestate.get_team(1).primary().ability
                print "My move:",
                move = self.agent.get_action(gamestate, 0)
                if move.is_switch():
                    self.selenium.switch(move.switch_index, move.backup_switch)
                else:
                    self.selenium.move(move.move_index, move.backup_switch, mega=move.mega, volt_turn=move.volt_turn)
                gamestate = self.update_latest_turn(gamestate)
                gamestate = self.correct_gamestate(gamestate)
                self.selenium.screenshot('log.png')
        self.state.delete_state("battle_url")

    def run(self, num_games=1, challenge=None):
        self.state.update_state("status", "initializing_battle")
        if challenge:
            self.logger.info("Set to challenge: %s", challenge)
        else:
            self.logger.info("Set to play %u games", num_games)
        self.init()
        self.scores = {
            'wins': 0,
            'losses': 0,
            'crashes': 0
        }
        def signal_handler(signal, frame):
            self.update_monitor(done=True)
            sys.exit(0)
        #signal.signal(signal.SIGINT, signal_handler)
        for i in range(num_games):
            self.simulator.log.reset()
            result, error = None, None
            try:
                self.play_game(challenge=challenge)
            except GameOverException:
                log = SimulatorLog.parse(self.selenium.get_log())
                disconnected = log.disconnected()
                if disconnected:
                    over,_ = log.is_over()
                    while not over:
                        time.sleep(5)
                        over,_ = log.is_over()
                _, over_event = log.is_over()
                result = over_event.details['username'] == self.username
            except UserNotOnlineException:
                self.logger.error("User not online: %s", challenge)
                self.logger.info("Exiting...")
                return
            except:
                error = traceback.format_exc()
                print "Error", error
                log = SimulatorLog.parse(self.selenium.get_log())
                _, over_event = log.is_over()
                if over_event is not None:
                    result = over_event.details['username'] == self.username
            log = self.selenium.get_log()
            id = self.selenium.get_battle_id()
            battle_url = "http://replay.pokemonshowdown.com/battle-%s" % id
            self.logger.info("Finished game! Replay can be found at: %s", battle_url)
            user_folder = Path(".") / self.username
            if not user_folder.exists():
                user_folder.mkdir()
            if not (user_folder / "wins").exists():
                (user_folder / "wins").mkdir()
            if not (user_folder / "losses").exists():
                (user_folder / "losses").mkdir()
            if not (user_folder / "crashes").exists():
                (user_folder / "crashes").mkdir()
            if result == True:
                print "---------------"
                print "Won the battle! - %s" % battle_url
                print "---------------"
                self.scores['wins'] += 1
                with open(user_folder / "wins" / ("%s.log" % id), 'w') as fp:
                    fp.write(log)
                with open(user_folder / "wins" / ("%s.score" % id), 'w') as fp:
                    print >>fp, self.simulator.score
                    print >>fp, self.simulator.total
            elif result == False:
                print "---------------"
                print "Lost the battle! - %s" % battle_url
                print "---------------"
                self.scores['losses'] += 1
                with open(user_folder / "losses" / ("%s.log" % id), 'w') as fp:
                    fp.write(log)
                with open(user_folder / "losses" / ("%s.score" % id), 'w') as fp:
                    print >>fp, self.simulator.score
                    print >>fp, self.simulator.total
            else:
                print "---------------"
                print "Crashed! - %s" % id
                print "---------------"
                self.scores['crashes'] += 1
                with open(user_folder / "crashes" / ("%s.log" % id), 'w') as fp:
                    fp.write(log)
                with open(user_folder / "crashes" / ("%s.err" % id), 'w') as fp:
                    fp.write(error)
                with open(user_folder / "crashes" / ("%s.score" % id), 'w') as fp:
                    print >>fp, self.simulator.score
                    print >>fp, self.simulator.total
            events = SimulatorLog.parse(self.selenium.get_log())
            for event in events:
                if event.type == "ladder":
                    if event.details['username'] == self.username:
                        with open(user_folder / "ladder_ratings.txt", "a") as fp:
                            fp.write(event.details['ladder'] + "\n")
            self.reset()
        self.update_monitor(done=True)
        self.selenium.close()
        self.logger.info("Done!")