Beispiel #1
0
class Game:

    def __init__(self, conn, addr, port, name):
        self.serv_conn = conn
        self.serv_addr = addr
        self.serv_port = port
        self.game_name = name
        self.ai = AI()
        self.ai.connection = self.serv_conn

    #Attempt to connect to the server
    def connect(self):
        while True:
            try:
                #Attempting to connect
                self.serv_conn.connect((self.serv_addr, self.serv_port))
            except socket.error:
                #Failed to connect
                time.sleep(1)
            else:
                #Client connected
                return True

    def receive(self):
        data = utility.receive_string(self.serv_conn)
        message = json.loads(data)

        if message['type'] == 'changes':
            self.update_game(message)
        elif message['type'] == 'player_id':
            self.ai.my_player_id = message['args']['id']
        elif message['type'] == 'game_over':
            raise GameOverException(message["args"]["winner"], message["args"]["reason"])
        return message

    def wait_for(self, *types):
        while True:
            message = self.receive()
            if message['type'] in types:
                return message

    #Attempt to login to the server
    def login(self):
        login_json = client_json.login.copy()
        login_json['args']['username'] = self.ai.username
        login_json['args']['password'] = self.ai.password

        utility.send_string(self.serv_conn, json.dumps(login_json))

        message = self.wait_for('success', 'failure')
        if message['type'] == 'success':
            #Login success
            return True
        else:
            #Login failed
            return False

    #Attempt to create a game on the server
    def create_game(self):
        create_game_json = client_json.create_game.copy()
        if self.game_name is not None:
            create_game_json['args']['game_name'] = self.game_name

        utility.send_string(self.serv_conn, json.dumps(create_game_json))

        message = self.wait_for('success', 'failure')
        if message['type'] == "success":
            self.game_name = message['args']['name']
            print("Game created: {}".format(self.game_name))
            return True
        else:
            #Game creation failed
            return False

    #Receive Player ID from server
    def recv_player_id(self):
        self.wait_for('player_id')
        return True

    #Runs before main_loop has began.
    def init_main(self):
        self.wait_for('start_game')

        self.ai.init()
        return True

    #Runs after main_loop has finished.
    def end_main(self):
        self.ai.end()
        return True

    #Main connection loop until end of game.
    def main_loop(self):
        while True:
            message = self.wait_for('start_turn', 'game_over')
            if message['type'] == 'game_over':
                return True

            if self.ai.my_player_id == self.ai.player_id:
                utility.v_print("Turn Number: {}".format(self.ai.turn_number))
                self.ai.run()
                utility.send_string(self.serv_conn, json.dumps(client_json.end_turn))

     
    def get_log(self):
        log_json = client_json.get_log.copy()
        utility.send_string(self.serv_conn, json.dumps(log_json))

        message = self.wait_for('success', 'failure')
        if message['type'] == "success":
            file = open(self.game_name + '.glog', 'wb')
            file.write(message['args']['log'].encode('utf-8'))
            file.close()

    #Update game from message
    def update_game(self, message):
        if message.get("type") != "changes":
            return False

        for change in message.get("args").get("changes"):
            if change.get("action") == "add":
                self.change_add(change)

            elif change.get("action") == "remove":
                self.change_remove(change)

            elif change.get("action") == "update":
                self.change_update(change)

            elif change.get("action") == "global_update":
                self.change_global_update(change)

        return True

    #Parse the add action
    def change_add(self, change):
        values = change.get("values")
        if change.get("type") == "Player":
            temp = game_objects.Player(connection=self.serv_conn, parent_game=self, id=values.get("id"), name=values.get("name"), byte_dollars=values.get("byte_dollars"), cycles=values.get("cycles"), time=values.get("time"))
            self.ai.players.append(temp)
        if change.get("type") == "Virus":
            temp = game_objects.Virus(connection=self.serv_conn, parent_game=self, id=values.get("id"), x=values.get("x"), y=values.get("y"), owner=values.get("owner"), level=values.get("level"), moves_left=values.get("moves_left"), living=values.get("living"))
            self.ai.viruses.append(temp)
        if change.get("type") == "Tile":
            temp = game_objects.Tile(connection=self.serv_conn, parent_game=self, id=values.get("id"), x=values.get("x"), y=values.get("y"), owner=values.get("owner"))
            self.ai.tiles.append(temp)
        if change.get("type") == "Base":
            temp = game_objects.Base(connection=self.serv_conn, parent_game=self, id=values.get("id"), x=values.get("x"), y=values.get("y"), owner=values.get("owner"), spawns_left=values.get("spawns_left"))
            self.ai.bases.append(temp)
        return True

    #Parse the remove action.
    def change_remove(self, change):
        remove_id = change.get("id")
        for player in self.ai.players:
            if player.id == remove_id:
                self.ai.players.remove(player)
                return True
        for virus in self.ai.viruses:
            if virus.id == remove_id:
                self.ai.viruses.remove(virus)
                return True
        for tile in self.ai.tiles:
            if tile.id == remove_id:
                self.ai.tiles.remove(tile)
                return True
        for base in self.ai.bases:
            if base.id == remove_id:
                self.ai.bases.remove(base)
                return True
        return False

    #Parse the update action.
    def change_update(self, change):
        change_id = change.get("id")
        values = change.get("values")
        for player in self.ai.players:
            if player.id == change_id:
                player.__dict__.update(values)
                return True
        for virus in self.ai.viruses:
            if virus.id == change_id:
                virus.__dict__.update(values)
                return True
        for tile in self.ai.tiles:
            if tile.id == change_id:
                tile.__dict__.update(values)
                return True
        for base in self.ai.bases:
            if base.id == change_id:
                base.__dict__.update(values)
                return True
        return False

    #Parse the global_update action
    def change_global_update(self, change):
        values = change.get("values")
        self.ai.__dict__.update(values)
        return True

    def run(self):
        if not self.connect(): return False
        if not self.login(): return False
        if not self.create_game(): return False
        if not self.recv_player_id(): return False

        if not self.init_main(): return False
        try:
            self.main_loop()
        except GameOverException as e:
            if e.winner == self.ai.my_player_id:
                game_over_message = "You Win! - {reason}".format(reason=e.reason)
            else:
                game_over_message = "You Lose! - {reason}".format(reason=e.reason)
        else:
            game_over_message = "Game over was never reached."

        if not self.end_main(): return False
        print(game_over_message)

        if not self.get_log(): return False
Beispiel #2
0
class Quoridor(object):
    def __init__(self, pros):
        self.pros = pros
        self.size = 19
        self.ai_num = 5
        self.ai = ''

    def step_ai(self):
        if self.ai_id == 0:
            dis, path = self.findPath(1)
            x, y = path
            return self.step(x, y, 1)
        else:
            suc = self.ai.run(self.nw, self.ins)
            if type(suc) != str:
                if suc:
                    return self.finish(1 - self.nw.result() if self.
                                       should_reverse else self.nw.result())
                else:
                    return self.finish(0)
            else:
                self.ins = suc
            self.steps += 1
        return 2

    def reset(self):
        with open('record.txt', 'w') as f:
            f.write("Init\n")
        if self.ai != '' and type(self.ai.ai) is not dict:
            self.ai.ai.exit()
        self.ai_id = random.randint(1, self.ai_num)
        self.err = ['', '']
        self.record_json = {}
        self.running = True
        self.steps = 0
        self.nw = Board(self.record_json)
        self.json_out = open('result' + str(self.pros) + '.json', 'w')
        self.should_reverse = turn = random.randint(0, 1)
        # self.should_reverse = turn = 0
        self.record_json['id'] = [turn, 1 - turn]
        self.record_json['step'] = []
        self.ins = ""
        opp_state = self.state(1)
        if self.ai_id == 0:
            self.record_json['user'] = ["training", "short_path"]
        else:
            self.ai = AI(exec_file + str(self.ai_id), 1, self.pros)
            suc = self.ai.load()
            if not suc:
                print("fail")
                return copy.deepcopy(self.state(0)), copy.deepcopy(
                    self.finish(0)), copy.deepcopy(opp_state), copy.deepcopy(
                        -1), copy.deepcopy(self.ai_id)
            suc = self.ai.init(1 - turn)
            if not suc:
                print("fail2")
                return copy.deepcopy(self.state(0)), copy.deepcopy(
                    self.finish(0)), copy.deepcopy(opp_state), copy.deepcopy(
                        -1), copy.deepcopy(self.ai_id)
            self.record_json['user'] = ["training", self.ai.name]
        if turn == 1:
            result = self.step_ai()
            if result != 2:
                k = -1
            else:
                xx, yy = map(int, self.ins.split())
                k = self.change_from_loc(xx, yy) if result == 2 else -1
        else:
            result = self.nw.result()
            k = -1

        return copy.deepcopy(self.state(0)), copy.deepcopy(
            result), copy.deepcopy(opp_state), copy.deepcopy(k), copy.deepcopy(
                self.ai_id)

    def state(self, id):
        length = 20
        state = []
        side = id ^ self.should_reverse
        if side == 0:
            for i in range(1, length):
                state.append([])
                for j in range(1, length):
                    state[i -
                          1].append(1 if self.nw.board[i][j] == True else 0)
            state[self.nw.loc[side][0] - 1][self.nw.loc[side][1] - 1] = 2
            state[self.nw.loc[side ^ 1][0] - 1][self.nw.loc[side ^ 1][1] -
                                                1] = -2
        else:
            for i in range(1, length):
                state.append([])
                for j in range(1, length):
                    state[i -
                          1].append(1 if self.nw.board[length -
                                                       i][j] == True else 0)
            state[length - self.nw.loc[side][0] - 1][self.nw.loc[side][1] -
                                                     1] = 2
            state[length - self.nw.loc[side ^ 1][0] -
                  1][self.nw.loc[side ^ 1][1] - 1] = -2
        return state

    def step(self, x, y, ai):
        side = ai ^ self.should_reverse
        if (side == 0):
            self.ins = str(x + 1) + ' ' + str(y + 1)
            res = self.nw.update([x + 1, y + 1])
        else:
            if x % 2 == 1 and y % 2 == 0:
                self.ins = str(17 - x) + ' ' + str(y + 1)
                res = self.nw.update([17 - x, y + 1])
            else:
                self.ins = str(19 - x) + ' ' + str(y + 1)
                res = self.nw.update([19 - x, y + 1])
        self.steps += 1
        if res != True:
            self.err[ai] = res
            return self.finish(ai ^ 1)
        if self.nw.result() < 2:
            ans = 1 - self.nw.result(
            ) if self.should_reverse else self.nw.result()
            return self.finish(ans)
        else:
            ans = 2
        return ans

    def finish(self, winner):
        self.record_json['total'] = self.steps
        self.record_json['result'] = winner
        self.record_json['err'] = [self.err, ' ']
        if self.ai != '' and type(self.ai.ai) is not dict:
            self.ai.ai.exit()

        json_out = open('result' + str(self.pros) + '.json', 'w')
        json.dump(self.record_json, json_out)
        json_out.close()
        self.running = False
        return winner

    def build_graph(self, ai):
        state = copy.deepcopy(self.state(ai))
        u = ((0, 1), (0, -1), (1, 0), (-1, 0))
        G = nx.DiGraph()
        _G = nx.DiGraph()
        for i in range(1, self.size, 2):
            for j in range(1, self.size, 2):
                if state[i][j] == 2:
                    pos = (i, j)
                if state[i][j] == -2:
                    _pos = (i, j)
                G.add_node((i, j))
                _G.add_node((i, j))
        for i in range(1, self.size, 2):
            for j in range(1, self.size, 2):
                for k in range(len(u)):
                    if (state[i + u[k][0]][j + u[k][1]]):
                        continue
                    x = i + u[k][0] * 2
                    y = j + u[k][1] * 2
                    _G.add_weighted_edges_from([((i, j), (x, y), 1)])
                    if (state[x][y] == 0 or state[x][y] == 2):
                        G.add_weighted_edges_from([((i, j), (x, y), 1)])
                    else:
                        if state[x + u[k][0]][y + u[k][1]]:
                            for kk in range((k < 2) * 2, (k < 2) * 2 + 2):
                                if (state[x + u[kk][0]][y + u[kk][1]]):
                                    continue
                                G.add_weighted_edges_from([
                                    ((i, j), (x + u[kk][0] * 2,
                                              y + u[kk][1] * 2), 1)
                                ])
                        else:
                            G.add_weighted_edges_from([
                                ((i, j), (x + u[k][0] * 2, y + u[k][1] * 2), 1)
                            ])
        return G, pos, _G, _pos

    def findPath(self, ai):
        G, pos, _G, _pos = self.build_graph(ai)
        path = nx.shortest_path(G, source=pos)
        dis = nx.shortest_path_length(G, source=pos)
        min_dis = 1000
        min_path = ()
        for i in range(1, self.size, 2):
            now_dis = dis.get((17, i), 1001)
            if now_dis < min_dis or (now_dis == min_dis
                                     and random.randint(0, 4) == 0):
                min_dis = now_dis
                min_path = path[(17, i)][1]

        if min_path == ():
            _path = nx.shortest_path(_G, source=pos)
            _dis = nx.shortest_path_length(_G, source=pos)
            for i in range(1, self.size, 2):
                now_dis = _dis.get((17, i), 1000)
                if now_dis < min_dis:
                    min_dis = now_dis
            if _dis[_pos] == 1:
                for i in range(1, self.size, 2):
                    for j in range(1, self.size, 2):
                        now_dis = dis.get((i, j), 1000)
                        if (now_dis == 1):
                            min_path = (i, j)
            else:
                min_path = _path[_pos][1]

        return copy.deepcopy(min_dis), copy.deepcopy(min_path)
        G, pos = self.build_graph(ai)
        path = nx.shortest_path(G, source=pos)
        dis = nx.shortest_path_length(G, source=pos)
        min_dis = 1000
        min_path = ()
        for i in range(1, self.size, 2):
            now_dis = dis.get((17, i), 1000)
            if now_dis < min_dis:
                min_dis = now_dis
                min_path = path[(17, i)][1]
        if min_path == ():
            print(self.record_json)
            min_path = pos
        return copy.deepcopy(min_dis), copy.deepcopy(min_path)

    def wall_pos(self, kind):
        row = kind // 8
        col = kind % 8
        if row % 2 == 0:
            return row + 1, col * 2 + 2
        else:
            return row + 1, col * 2 + 1

    def change_from_loc(self, x, y):
        if x % 2 == 0 and y % 2 == 0:
            return 128
        if (self.should_reverse ^ 1 == 0):
            return (x - 2) * 8 + (y // 2 - 1)
        else:
            if x % 2 == 0:
                return (16 - x) * 8 + (y // 2 - 1)
            else:
                return (18 - x) * 8 + (y // 2 - 1)

    def action(self, kind):
        if kind < 128:
            x, y = self.wall_pos(kind)
        else:
            dis, path = self.findPath(0)
            x, y = path
        result = self.step(x, y, 0)
        opp_state = self.state(1)
        if result != 2:
            return copy.deepcopy(self.state(0)), copy.deepcopy(
                result), copy.deepcopy(opp_state), copy.deepcopy(-1)
        result = self.step_ai()
        xx, yy = map(int, self.ins.split())
        k = self.change_from_loc(xx, yy) if result == 2 else -1
        return copy.deepcopy(self.state(0)), copy.deepcopy(
            result), copy.deepcopy(opp_state), copy.deepcopy(k)
Beispiel #3
0
class Game:
    def __init__(self, conn, addr, port, name):
        self.serv_conn = conn
        self.serv_addr = addr
        self.serv_port = port
        self.game_name = name
        self.ai = AI()
        self.ai.connection = self.serv_conn

    #Attempt to connect to the server
    def connect(self):
        while True:
            try:
                #Attempting to connect
                self.serv_conn.connect((self.serv_addr, self.serv_port))
            except socket.error:
                #Failed to connect
                time.sleep(1)
            else:
                #Client connected
                return True

    def receive(self):
        data = utility.receive_string(self.serv_conn)
        message = json.loads(data)

        if message['type'] == 'changes':
            self.update_game(message)
        elif message['type'] == 'player_id':
            self.ai.my_player_id = message['args']['id']
        elif message['type'] == 'game_over':
            raise GameOverException(message["args"]["winner"],
                                    message["args"]["reason"])
        return message

    def wait_for(self, *types):
        while True:
            message = self.receive()
            if message['type'] in types:
                return message

    #Attempt to login to the server
    def login(self):
        login_json = client_json.login.copy()
        login_json['args']['username'] = self.ai.username
        login_json['args']['password'] = self.ai.password

        utility.send_string(self.serv_conn, json.dumps(login_json))

        message = self.wait_for('success', 'failure')
        if message['type'] == 'success':
            #Login success
            return True
        else:
            #Login failed
            return False

    #Attempt to create a game on the server
    def create_game(self):
        create_game_json = client_json.create_game.copy()
        if self.game_name is not None:
            create_game_json['args']['game_name'] = self.game_name

        utility.send_string(self.serv_conn, json.dumps(create_game_json))

        message = self.wait_for('success', 'failure')
        if message['type'] == "success":
            self.game_name = message['args']['name']
            print("Game created: {}".format(self.game_name))
            return True
        else:
            #Game creation failed
            return False

    #Receive Player ID from server
    def recv_player_id(self):
        self.wait_for('player_id')
        return True

    #Runs before main_loop has began.
    def init_main(self):
        self.wait_for('start_game')

        self.ai.init()
        return True

    #Runs after main_loop has finished.
    def end_main(self):
        self.ai.end()
        return True

    #Main connection loop until end of game.
    def main_loop(self):
        while True:
            message = self.wait_for('start_turn', 'game_over')
            if message['type'] == 'game_over':
                return True

            if self.ai.my_player_id == self.ai.player_id:
                utility.v_print("Turn Number: {}".format(self.ai.turn_number))
                self.ai.run()
                utility.send_string(self.serv_conn,
                                    json.dumps(client_json.end_turn))

    def get_log(self):
        log_json = client_json.get_log.copy()
        utility.send_string(self.serv_conn, json.dumps(log_json))

        message = self.wait_for('success', 'failure')
        if message['type'] == "success":
            file = open(self.game_name + '.glog', 'wb')
            file.write(message['args']['log'].encode('utf-8'))
            file.close()

    #Update game from message
    def update_game(self, message):
        if message.get("type") != "changes":
            return False

        for change in message.get("args").get("changes"):
            if change.get("action") == "add":
                self.change_add(change)

            elif change.get("action") == "remove":
                self.change_remove(change)

            elif change.get("action") == "update":
                self.change_update(change)

            elif change.get("action") == "global_update":
                self.change_global_update(change)

        return True

    #Parse the add action
    def change_add(self, change):
        values = change.get("values")
        if change.get("type") == "Player":
            temp = game_objects.Player(connection=self.serv_conn,
                                       parent_game=self,
                                       id=values.get("id"),
                                       name=values.get("name"),
                                       time=values.get("time"),
                                       expensivium=values.get("expensivium"),
                                       money=values.get("money"))
            self.ai.players.append(temp)
        if change.get("type") == "RobotType":
            temp = game_objects.RobotType(connection=self.serv_conn,
                                          parent_game=self,
                                          id=values.get("id"),
                                          max_health=values.get("max_health"),
                                          range=values.get("range"),
                                          splash=values.get("splash"),
                                          damage=values.get("damage"),
                                          movement=values.get("movement"),
                                          attacks=values.get("attacks"))
            self.ai.robotTypes.append(temp)
        if change.get("type") == "Robot":
            temp = game_objects.Robot(connection=self.serv_conn,
                                      parent_game=self,
                                      id=values.get("id"),
                                      x=values.get("x"),
                                      y=values.get("y"),
                                      owner=values.get("owner"),
                                      type=values.get("type"),
                                      health=values.get("health"),
                                      moves_left=values.get("moves_left"),
                                      attack_left=values.get("attack_left"),
                                      max_health=values.get("max_health"),
                                      range=values.get("range"),
                                      splash=values.get("splash"),
                                      damage=values.get("damage"),
                                      movement=values.get("movement"),
                                      attacks=values.get("attacks"))
            self.ai.robots.append(temp)
        if change.get("type") == "Factory":
            temp = game_objects.Factory(connection=self.serv_conn,
                                        parent_game=self,
                                        id=values.get("id"),
                                        x=values.get("x"),
                                        y=values.get("y"),
                                        owner=values.get("owner"))
            self.ai.factorys.append(temp)
        if change.get("type") == "Mine":
            temp = game_objects.Mine(connection=self.serv_conn,
                                     parent_game=self,
                                     id=values.get("id"),
                                     x=values.get("x"),
                                     y=values.get("y"),
                                     owner=values.get("owner"))
            self.ai.mines.append(temp)
        if change.get("type") == "Tile":
            temp = game_objects.Tile(connection=self.serv_conn,
                                     parent_game=self,
                                     id=values.get("id"),
                                     x=values.get("x"),
                                     y=values.get("y"),
                                     wall=values.get("wall"))
            self.ai.tiles.append(temp)
        return True

    #Parse the remove action.
    def change_remove(self, change):
        remove_id = change.get("id")
        try:
            index = self.ai.players.find(remove_id,
                                         key=operator.attrgetter('id'))
        except:
            pass
        else:
            self.ai.players.remove(index)
            return True
        try:
            index = self.ai.robotTypes.find(remove_id,
                                            key=operator.attrgetter('id'))
        except:
            pass
        else:
            self.ai.robotTypes.remove(index)
            return True
        try:
            index = self.ai.robots.find(remove_id,
                                        key=operator.attrgetter('id'))
        except:
            pass
        else:
            self.ai.robots.remove(index)
            return True
        try:
            index = self.ai.factorys.find(remove_id,
                                          key=operator.attrgetter('id'))
        except:
            pass
        else:
            self.ai.factorys.remove(index)
            return True
        try:
            index = self.ai.mines.find(remove_id,
                                       key=operator.attrgetter('id'))
        except:
            pass
        else:
            self.ai.mines.remove(index)
            return True
        try:
            index = self.ai.tiles.find(remove_id,
                                       key=operator.attrgetter('id'))
        except:
            pass
        else:
            self.ai.tiles.remove(index)
            return True
        return False

    #Parse the update action.
    def change_update(self, change):
        change_id = change.get("id")
        values = change.get("values")
        try:
            index = self.ai.players.find(change_id,
                                         key=operator.attrgetter('id'))
        except:
            pass
        else:
            self.ai.players[index].__dict__.update(values)
            return True
        try:
            index = self.ai.robotTypes.find(change_id,
                                            key=operator.attrgetter('id'))
        except:
            pass
        else:
            self.ai.robotTypes[index].__dict__.update(values)
            return True
        try:
            index = self.ai.robots.find(change_id,
                                        key=operator.attrgetter('id'))
        except:
            pass
        else:
            self.ai.robots[index].__dict__.update(values)
            return True
        try:
            index = self.ai.factorys.find(change_id,
                                          key=operator.attrgetter('id'))
        except:
            pass
        else:
            self.ai.factorys[index].__dict__.update(values)
            return True
        try:
            index = self.ai.mines.find(change_id,
                                       key=operator.attrgetter('id'))
        except:
            pass
        else:
            self.ai.mines[index].__dict__.update(values)
            return True
        try:
            index = self.ai.tiles.find(change_id,
                                       key=operator.attrgetter('id'))
        except:
            pass
        else:
            self.ai.tiles[index].__dict__.update(values)
            return True
        return False

    #Parse the global_update action
    def change_global_update(self, change):
        values = change.get("values")
        self.ai.__dict__.update(values)
        return True

    def run(self):
        if not self.connect(): return False
        if not self.login(): return False
        if not self.create_game(): return False
        if not self.recv_player_id(): return False

        if not self.init_main(): return False
        try:
            self.main_loop()
        except GameOverException as e:
            if e.winner == self.ai.my_player_id:
                game_over_message = "You Win! - {reason}".format(
                    reason=e.reason)
            else:
                game_over_message = "You Lose! - {reason}".format(
                    reason=e.reason)
        else:
            game_over_message = "Game over was never reached."

        if not self.end_main(): return False
        print(game_over_message)

        if not self.get_log(): return False
Beispiel #4
0
class Game:

    def __init__(self, conn, addr, port, name):
        self.serv_conn = conn
        self.serv_addr = addr
        self.serv_port = port
        self.game_name = name
        self.ai = AI()
        self.ai.connection = self.serv_conn

    #Attempt to connect to the server
    def connect(self):
        while True:
            try:
                #Attempting to connect
                self.serv_conn.connect((self.serv_addr, self.serv_port))
            except socket.error:
                #Failed to connect
                time.sleep(1)
            else:
                #Client connected
                return True

    def receive(self):
        data = utility.receive_string(self.serv_conn)
        message = json.loads(data)

        if message['type'] == 'changes':
            self.update_game(message)
        elif message['type'] == 'player_id':
            self.ai.my_player_id = message['args']['id']
        elif message['type'] == 'game_over':
            raise GameOverException(message["args"]["winner"], message["args"]["reason"])
        return message

    def wait_for(self, *types):
        while True:
            message = self.receive()
            if message['type'] in types:
                return message

    #Attempt to login to the server
    def login(self):
        login_json = client_json.login.copy()
        login_json['args']['username'] = self.ai.username

        utility.send_string(self.serv_conn, json.dumps(login_json))

        message = self.wait_for('success', 'failure')
        if message['type'] == 'success':
            #Login success
            return True
        else:
            #Login failed
            return False

    #Attempt to create a game on the server
    def create_game(self):
        create_game_json = client_json.create_game.copy()
        if self.game_name is not None:
            create_game_json['args']['game_name'] = self.game_name

        utility.send_string(self.serv_conn, json.dumps(create_game_json))

        message = self.wait_for('success', 'failure')
        if message['type'] == "success":
            self.game_name = message['args']['name']
            print("Game created: {}".format(self.game_name))
            return True
        else:
            #Game creation failed
            return False

    #Receive Player ID from server
    def recv_player_id(self):
        self.wait_for('player_id')
        return True

    #Runs before main_loop has began.
    def init_main(self):
        self.wait_for('start_game')

        self.ai.init()
        return True

    #Runs after main_loop has finished.
    def end_main(self):
        self.ai.end()
        return True

    #Main connection loop until end of game.
    def main_loop(self):
        while True:
            message = self.wait_for('start_turn', 'game_over')
            if message['type'] == 'game_over':
                return True

            if self.ai.my_player_id == self.ai.player_id:
                utility.v_print("Turn Number: {}".format(self.ai.turn_number))
                self.ai.run()
                utility.send_string(self.serv_conn, json.dumps(client_json.end_turn))

     
    def get_log(self):
        log_json = client_json.get_log.copy()
        utility.send_string(self.serv_conn, json.dumps(log_json))

        message = self.wait_for('success', 'failure')
        if message['type'] == "success":
            file = open(self.game_name + '.glog', 'wb')
            file.write(message['args']['log'].encode('utf-8'))
            file.close()

    #Update game from message
    def update_game(self, message):
        if message.get("type") != "changes":
            return False

        for change in message.get("args").get("changes"):
            if change.get("action") == "add":
                self.change_add(change)

            elif change.get("action") == "remove":
                self.change_remove(change)

            elif change.get("action") == "update":
                self.change_update(change)

            elif change.get("action") == "global_update":
                self.change_global_update(change)

        return True

    #Parse the add action
    def change_add(self, change):
        values = change.get("values")