diff options
author | lonkaars <l.leblansch@gmail.com> | 2021-04-11 17:50:58 +0200 |
---|---|---|
committer | lonkaars <l.leblansch@gmail.com> | 2021-04-11 17:50:58 +0200 |
commit | 28f104de9ae9abe4b42abafbf3865ede5687996c (patch) | |
tree | 65e651f09d8fbf81380384692e45803cb4f9d61c /api/game | |
parent | 7b4859059b3bbabf4139ccdf3270a82c094f5d8e (diff) |
dprint yapf python formatting
Diffstat (limited to 'api/game')
-rw-r--r-- | api/game/accept.py | 17 | ||||
-rw-r--r-- | api/game/cleanup.py | 34 | ||||
-rw-r--r-- | api/game/info.py | 120 | ||||
-rw-r--r-- | api/game/new.py | 61 | ||||
-rw-r--r-- | api/game/random.py | 36 | ||||
-rw-r--r-- | api/game/socket.py | 170 | ||||
-rw-r--r-- | api/game/voerbak_connector.py | 137 |
7 files changed, 319 insertions, 256 deletions
diff --git a/api/game/accept.py b/api/game/accept.py index 073f422..a231d3a 100644 --- a/api/game/accept.py +++ b/api/game/accept.py @@ -12,19 +12,18 @@ from game.new import start_game join_game = Blueprint('game_accept', __name__) + # join a game by game_id (public or private) -@join_game.route('/accept', methods = ['POST']) +@join_game.route('/accept', methods=['POST']) @auth_required("user") def index(game_id): - if cursor.execute("select status from games where game_id = ?", [game_id]).fetchone()[0] != "wait_for_opponent": - return "", 403 + if cursor.execute("select status from games where game_id = ?", + [game_id]).fetchone()[0] != "wait_for_opponent": + return "", 403 + + start_game(game_id, user_id) - start_game(game_id, user_id) + return {"id": game_id, "player_1": False, "game_started": True}, 200 - return { - "id": game_id, - "player_1": False, - "game_started": True - }, 200 dynamic_route = ["/game", join_game] diff --git a/api/game/cleanup.py b/api/game/cleanup.py index 0a9aa46..5b705d2 100644 --- a/api/game/cleanup.py +++ b/api/game/cleanup.py @@ -2,22 +2,30 @@ from db import cursor, connection import threading import time + # cleanup function that's ran every five minutes def cleanup(): - now = int( time.time() * 1000 ) - old_games = cursor.execute("select game_id from games where (status = \"wait_for_opponent\" or status = \"in_progress\") and last_activity < ?", [now - 5 * 60 * 1e3]).fetchall() - for game_id in old_games: - cursor.execute("delete from games where game_id = ?", [game_id[0]]) - connection.commit() + now = int(time.time() * 1000) + old_games = cursor.execute( + "select game_id from games where (status = \"wait_for_opponent\" or status = \"in_progress\") and last_activity < ?", + [now - 5 * 60 * 1e3] + ).fetchall() + for game_id in old_games: + cursor.execute("delete from games where game_id = ?", [game_id[0]]) + connection.commit() + + +def set_interval( + func, sec +): # https://stackoverflow.com/questions/2697039/python-equivalent-of-setinterval + def func_wrapper(): + set_interval(func, sec) + func() + + t = threading.Timer(sec, func_wrapper) + t.start() + return t -def set_interval(func, sec): # https://stackoverflow.com/questions/2697039/python-equivalent-of-setinterval - def func_wrapper(): - set_interval(func, sec) - func() - t = threading.Timer(sec, func_wrapper) - t.start() - return t # run every five minutes set_interval(cleanup, 5 * 60) - diff --git a/api/game/info.py b/api/game/info.py index 76a3ef8..869a19c 100644 --- a/api/game/info.py +++ b/api/game/info.py @@ -5,69 +5,83 @@ from user.info import format_user from rating import outcome from ruleset import resolve_ruleset -def format_game(game_id, user_id = None): - game = cursor.execute("select " + ", ".join([ - "game_id", # 0 - "parent_game", # 1 - "moves", # 2 - "player_1_id", # 3 - "player_2_id", # 4 - "outcome", # 5 - "created", # 6 - "started", # 7 - "duration", # 8 - "rating_delta_player_1", # 9 - "rating_delta_player_2", # 10 - "ruleset", # 11 - "status", # 12 - "private", # 13 - ]) + " from games where game_id = ?", [game_id]).fetchone() - - is_player_1 = game[4] != user_id - - # get opponent from perspective of `user_id` - opponent = game[4] if is_player_1 else game[3] - - # parse moves into list and return empty list if moves string is empty - moves = [] if len(game[2]) == 0 else [int(move) for move in str(game[2] + "0").split(",")] - - return { - "id": game[0], - "parent": game[1], - "moves": moves, - "opponent": None if not opponent else format_user(opponent), - "outcome": None if not game[5] else outcome(game[5], is_player_1), - "created": game[6], - "started": game[7], - "duration": game[8], - "rating": game[9] if is_player_1 else game[10], - "rating_opponent": game[10] if is_player_1 else game[9], - "ruleset": resolve_ruleset(game[11]), - "status": game[12], - "private": bool(game[13]), - } + +def format_game(game_id, user_id=None): + game = cursor.execute( + "select " + ", ".join( + [ + "game_id", # 0 + "parent_game", # 1 + "moves", # 2 + "player_1_id", # 3 + "player_2_id", # 4 + "outcome", # 5 + "created", # 6 + "started", # 7 + "duration", # 8 + "rating_delta_player_1", # 9 + "rating_delta_player_2", # 10 + "ruleset", # 11 + "status", # 12 + "private", # 13 + ] + ) + " from games where game_id = ?", + [game_id] + ).fetchone() + + is_player_1 = game[4] != user_id + + # get opponent from perspective of `user_id` + opponent = game[4] if is_player_1 else game[3] + + # parse moves into list and return empty list if moves string is empty + moves = [] if len(game[2]) == 0 else [ + int(move) for move in str(game[2] + "0").split(",") + ] + + return { + "id": game[0], + "parent": game[1], + "moves": moves, + "opponent": None if not opponent else format_user(opponent), + "outcome": None if not game[5] else outcome(game[5], is_player_1), + "created": game[6], + "started": game[7], + "duration": game[8], + "rating": game[9] if is_player_1 else game[10], + "rating_opponent": game[10] if is_player_1 else game[9], + "ruleset": resolve_ruleset(game[11]), + "status": game[12], + "private": bool(game[13]), + } + # check if game_id exists in database def valid_game_id(game_id): - query = cursor.execute("select game_id from games where game_id = ?", [game_id]).fetchone() - return bool(query) + query = cursor.execute( + "select game_id from games where game_id = ?", [game_id] + ).fetchone() + return bool(query) + game_info = Blueprint('game_info', __name__) -@game_info.route('/info', methods = ['POST']) + +@game_info.route('/info', methods=['POST']) def index(): - data = request.get_json() - if not data: return "", 400 + data = request.get_json() + if not data: return "", 400 + + game_id = data.get("id") or "" + if not game_id: return "", 400 - game_id = data.get("id") or "" - if not game_id: return "", 400 + user_id = None + token = request.cookies.get("token") or "" + if token: user_id = token_login(token) - user_id = None - token = request.cookies.get("token") or "" - if token: user_id = token_login(token) + if not valid_game_id(game_id): return "", 403 - if not valid_game_id(game_id): return "", 403 + return format_game(game_id, user_id), 200 - return format_game(game_id, user_id), 200 dynamic_route = ["/game", game_info] diff --git a/api/game/new.py b/api/game/new.py index 9868099..7f0862b 100644 --- a/api/game/new.py +++ b/api/game/new.py @@ -6,39 +6,60 @@ from randid import new_uuid from game.socket import games, game from hierarchy import auth_required -def create_game(user_1_id, private = False, user_2_id = None): - timestamp = int( time.time() * 1000 ) - game_id = new_uuid("games") +def create_game(user_1_id, private=False, user_2_id=None): + timestamp = int(time.time() * 1000) - cursor.execute("insert into games values (?, NULL, \"\", ?, ?, NULL, ?, NULL, ?, NULL, NULL, NULL, \"wait_for_opponent\", \"default\", ?, FALSE) ", (game_id, user_1_id, user_2_id, timestamp, timestamp, private)) - connection.commit() + game_id = new_uuid("games") + + cursor.execute( + "insert into games values (?, NULL, \"\", ?, ?, NULL, ?, NULL, ?, NULL, NULL, NULL, \"wait_for_opponent\", \"default\", ?, FALSE) ", + (game_id, user_1_id, user_2_id, timestamp, timestamp, private) + ) + connection.commit() + + return game_id - return game_id def start_game(game_id, user_2_id): - timestamp = int( time.time() * 1000 ) + timestamp = int(time.time() * 1000) + + db_game = cursor.execute( + "select player_2_id, status, private from games where game_id = ?", + [game_id] + ).fetchone() + if db_game[1] != "wait_for_opponent": return False - db_game = cursor.execute("select player_2_id, status, private from games where game_id = ?", [game_id]).fetchone() - if db_game[1] != "wait_for_opponent": return False + if db_game[0] == None: + cursor.execute( + "update games set player_2_id = ? where game_id = ?", + (user_2_id, game_id) + ) + cursor.execute( + "update games set status = \"in_progress\", started = ?, last_activity = ? where game_id = ?", + (timestamp, timestamp, game_id) + ) + connection.commit() - if db_game[0] == None: cursor.execute("update games set player_2_id = ? where game_id = ?", (user_2_id, game_id)) - cursor.execute("update games set status = \"in_progress\", started = ?, last_activity = ? where game_id = ?", (timestamp, timestamp, game_id)) - connection.commit() + players = cursor.execute( + "select player_1_id, player_2_id from games where game_id = ?", + [game_id] + ).fetchone() + games[game_id] = game(game_id, io, players[0], players[1]) - players = cursor.execute("select player_1_id, player_2_id from games where game_id = ?", [game_id]).fetchone() - games[game_id] = game(game_id, io, players[0], players[1]) + io.emit("gameStart", room=games[game_id].room) - io.emit("gameStart", room=games[game_id].room) new_game = Blueprint('new_game', __name__) -@new_game.route('/new', methods = ["GET", "POST"]) + +@new_game.route('/new', methods=["GET", "POST"]) @auth_required("user") def index(user_id): - # create a new private game (join by link) - #TODO: friend invites + notifications - game_id = create_game(user_id, True) - return { "id": game_id }, 200 + # create a new private game (join by link) + #TODO: friend invites + notifications + game_id = create_game(user_id, True) + return {"id": game_id}, 200 + dynamic_route = ["/game", new_game] diff --git a/api/game/random.py b/api/game/random.py index 4d70b56..2dfbe0b 100644 --- a/api/game/random.py +++ b/api/game/random.py @@ -11,27 +11,35 @@ from socket_io import io random_game = Blueprint('random', __name__) + @random_game.route('/random') @auth_required("user") def index(user_id): - # get public_games (random opponent queue) - public_games = cursor.execute("select game_id from games where private = FALSE and status = \"wait_for_opponent\"").fetchall() + # get public_games (random opponent queue) + public_games = cursor.execute( + "select game_id from games where private = FALSE and status = \"wait_for_opponent\"" + ).fetchall() + + game_started = False - game_started = False + # create a new public game if the queue is empty + if len(public_games) == 0: + game_id = create_game(user_id) + player_1 = True + # otherwise join a random public game + else: + game_id = random.choice(public_games)[0] - # create a new public game if the queue is empty - if len(public_games) == 0: - game_id = create_game(user_id) - player_1 = True - # otherwise join a random public game - else: - game_id = random.choice(public_games)[0] + start_game(game_id, user_id) - start_game(game_id, user_id) + player_1 = False + game_started = True - player_1 = False - game_started = True + return { + "id": game_id, + "player_1": player_1, + "game_started": game_started + }, 200 - return { "id": game_id, "player_1": player_1, "game_started": game_started }, 200 dynamic_route = ["/game", random_game] diff --git a/api/game/socket.py b/api/game/socket.py index cf45eb6..63f680c 100644 --- a/api/game/socket.py +++ b/api/game/socket.py @@ -9,97 +9,109 @@ from socket_io import io games = {} + class game: - def __init__(self, game_id, io, player_1_id, player_2_id): - self.game_id = game_id - self.room = "game-" + game_id - self.board = bord(7, 6) - self.io = io - self.player_1_id = player_1_id - self.player_2_id = player_2_id - - # drop a disc in `column` - def move(self, user_id, column): - if user_id != self.player_1_id and user_id != self.player_2_id: return - move = self.player_1_id if self.board.player_1 else self.player_2_id - if user_id != move: return - - self.board.drop_fisje(column) - - io.emit("fieldUpdate", { "field": self.board.board }, room=self.room) - - now = int( time.time() * 1000 ) - cursor.execute("update games set last_activity = ?, moves = moves || ? || ',' where game_id = ?", [now, column, self.game_id]) - connection.commit() - - if len(self.board.win_positions) > 0 or self.board.board_full: - outcome = "d" - if not self.board.board_full: - winner = self.board.board[int(self.board.win_positions[0][0])] - outcome = "w" if winner == "2" else "l" - io.emit("finish", { - "winPositions": self.board.win_positions, - "boardFull": self.board.board_full - }, room=self.room) - self.close("finished", outcome) - return - - io.emit("turnUpdate", { "player1": self.board.player_1 }, room=self.room) - - def resign(self): - self.board.kill_voerbak() - io.emit("resign", room=self.room) - self.close("resign", "d") - - def close(self, new_status, outcome): - cursor.execute(" ".join([ - "update games set", - "moves = moves || '0',", - "duration = ?,", - "status = ?,", - "outcome = ?", - "where game_id = ?" - ]), [ - int( time.time() * 1000 ) - cursor.execute("select started from games where game_id = ?", [self.game_id]).fetchone()[0], - new_status, - outcome, - self.game_id - ]) - connection.commit() - - games.pop(self.game_id) + def __init__(self, game_id, io, player_1_id, player_2_id): + self.game_id = game_id + self.room = "game-" + game_id + self.board = bord(7, 6) + self.io = io + self.player_1_id = player_1_id + self.player_2_id = player_2_id + + # drop a disc in `column` + def move(self, user_id, column): + if user_id != self.player_1_id and user_id != self.player_2_id: return + move = self.player_1_id if self.board.player_1 else self.player_2_id + if user_id != move: return + + self.board.drop_fisje(column) + + io.emit("fieldUpdate", {"field": self.board.board}, room=self.room) + + now = int(time.time() * 1000) + cursor.execute( + "update games set last_activity = ?, moves = moves || ? || ',' where game_id = ?", + [now, column, self.game_id] + ) + connection.commit() + + if len(self.board.win_positions) > 0 or self.board.board_full: + outcome = "d" + if not self.board.board_full: + winner = self.board.board[int(self.board.win_positions[0][0])] + outcome = "w" if winner == "2" else "l" + io.emit( + "finish", { + "winPositions": self.board.win_positions, + "boardFull": self.board.board_full + }, + room=self.room + ) + self.close("finished", outcome) + return + + io.emit("turnUpdate", {"player1": self.board.player_1}, room=self.room) + + def resign(self): + self.board.kill_voerbak() + io.emit("resign", room=self.room) + self.close("resign", "d") + + def close(self, new_status, outcome): + cursor.execute( + " ".join( + [ + "update games set", "moves = moves || '0',", + "duration = ?,", "status = ?,", "outcome = ?", + "where game_id = ?" + ] + ), [ + int(time.time() * 1000) - cursor.execute( + "select started from games where game_id = ?", + [self.game_id] + ).fetchone()[0], new_status, outcome, self.game_id + ] + ) + connection.commit() + + games.pop(self.game_id) + @io.on("newMove") def new_move(data): - if not data["game_id"] or \ - not data["move"] or \ - not data["token"]: return - if not data["game_id"] in games: return + if not data["game_id"] or \ + not data["move"] or \ + not data["token"]: + return + if not data["game_id"] in games: return + + game = games[data["game_id"]] + if (len(game.board.win_positions) > 0 or game.board.board_full): return + user_id = token_login(data["token"]) + game.move(user_id, data["move"]) - game = games[data["game_id"]] - if(len(game.board.win_positions) > 0 or game.board.board_full): return - user_id = token_login(data["token"]) - game.move(user_id, data["move"]) @io.on("resign") def resign(data): - if not data["game_id"] or \ - not request.cookies.get("token"): return - if not data["game_id"] in games: return + if not data["game_id"] or \ + not request.cookies.get("token"): + return + if not data["game_id"] in games: return - user_id = token_login(request.cookies.get("token")) - if not user_id: return + user_id = token_login(request.cookies.get("token")) + if not user_id: return - if games[data["game_id"]].player_1_id != user_id and \ - games[data["game_id"]].player_2_id != user_id: - return + if games[data["game_id"]].player_1_id != user_id and \ + games[data["game_id"]].player_2_id != user_id: + return + + games[data["game_id"]].resign() - games[data["game_id"]].resign() @io.on("registerGameListener") def register_game_listener(data): - game_id = data.get("game_id") - if not game_id: return - - join_room("game-" + game_id) + game_id = data.get("game_id") + if not game_id: return + join_room("game-" + game_id) diff --git a/api/game/voerbak_connector.py b/api/game/voerbak_connector.py index 048a5d1..412a512 100644 --- a/api/game/voerbak_connector.py +++ b/api/game/voerbak_connector.py @@ -11,82 +11,83 @@ EMPTY = Fore.LIGHTBLACK_EX + "_" + Fore.RESET VOERBAK_LOCATION = os.path.join(os.getcwd(), "voerbak/", "voerbak") if os.name == "nt": VOERBAK_LOCATION += ".exe" + class bord: - def __init__(self, w, h): - self.width = w - self.height = h - self.player_1 = True - self.board = "0" * (w * h) - self.board_full = False - self.win_positions = [] - self.process = subprocess.Popen([VOERBAK_LOCATION, f"-w {w}", f"-h {h}"], - stdin=subprocess.PIPE, - stdout=subprocess.PIPE, - stderr=None) - self.process.stdin.flush() + def __init__(self, w, h): + self.width = w + self.height = h + self.player_1 = True + self.board = "0" * (w * h) + self.board_full = False + self.win_positions = [] + self.process = subprocess.Popen( + [VOERBAK_LOCATION, f"-w {w}", f"-h {h}"], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=None + ) + self.process.stdin.flush() + + # get output from voerbak without trailing newline character (this might break on windows because crlf) + def get_output(self): + return self.process.stdout.readline().decode()[:-1] - # get output from voerbak without trailing newline character (this might break on windows because crlf) - def get_output(self): - return self.process.stdout.readline().decode()[:-1] + def kill_voerbak(self): + self.process.stdin.write(bytearray("0", "utf-8")) + self.process.stdin.flush() - def kill_voerbak(self): - self.process.stdin.write(bytearray("0", "utf-8")) - self.process.stdin.flush() + # read messages from voerbak + def update_board(self): + buffer = self.get_output() + while not buffer.isdigit(): + # win message + if buffer.startswith("w:"): + self.win_positions.append(buffer[2:].split("-")) + log.info(f"won: {buffer[2:].split('-')}") + self.kill_voerbak() + # error message + elif buffer.startswith("e:"): + log.warning(buffer[2:]) + # turn update message + elif buffer.startswith("m:"): + substr = buffer[2:] + self.player_1 = True if substr == "true" else False + # draw game message + elif buffer.startswith("d:"): + self.board_full = True + self.kill_voerbak() + buffer = self.get_output() + self.board = buffer - # read messages from voerbak - def update_board(self): - buffer = self.get_output() - while not buffer.isdigit(): - # win message - if buffer.startswith("w:"): - self.win_positions.append(buffer[2:].split("-")) - log.info(f"won: {buffer[2:].split('-')}") - self.kill_voerbak() - # error message - elif buffer.startswith("e:"): - log.warning(buffer[2:]) - # turn update message - elif buffer.startswith("m:"): - substr = buffer[2:] - self.player_1 = True if substr == "true" else False - # draw game message - elif buffer.startswith("d:"): - self.board_full = True - self.kill_voerbak() - buffer = self.get_output() - self.board = buffer + # debug board print function + def print(self): + for y in range(self.height - 1, -1, -1): + for x in range(self.width): + state = self.board[x + y * self.width] + char = [EMPTY, DISC_A, DISC_B] + print(char[int(state)], end=" ") + print("\n", end="") - # debug board print function - def print(self): - for y in range(self.height -1, -1, -1): - for x in range(self.width): - state = self.board[x + y * self.width] - char = [EMPTY, - DISC_A, - DISC_B - ] - print(char[int(state)], end=" ") - print("\n", end="") + def drop_fisje(self, column): + self.process.stdin.write(bytearray(f"{column}\n", "utf-8")) + self.process.stdin.flush() + self.update_board() - def drop_fisje(self, column): - self.process.stdin.write(bytearray(f"{column}\n", "utf-8")) - self.process.stdin.flush() - self.update_board() # debug game def main(): - gert = bord(7, 6) - while True: - print(gert.player_1) - if len(gert.win_positions) > 0: - print(f"won: {gert.win_positions}") - exit(0) - gert.print() - column = int(input("column?: ")) - 1 - if column not in range(gert.width): - continue - gert.drop_fisje(column + 1) + gert = bord(7, 6) + while True: + print(gert.player_1) + if len(gert.win_positions) > 0: + print(f"won: {gert.win_positions}") + exit(0) + gert.print() + column = int(input("column?: ")) - 1 + if column not in range(gert.width): + continue + gert.drop_fisje(column + 1) -if __name__ == "__main__": - main() +if __name__ == "__main__": + main() |