aboutsummaryrefslogtreecommitdiff
path: root/api/game/socket.py
blob: 09b2151ae32ceac25a9980773d354f863df55580 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
from flask import Blueprint, request, make_response
from flask_socketio import SocketIO, emit, Namespace, join_room
from game.voerbak_connector import bord
from db import cursor, connection
from socket_io import io
from hierarchy import io_auth_required
import time
import json

games = {}


def participants_only(func):
    '''
    listener should have two parameters:
    listener(data: socket.io.data, user_id: str, game: game)

    listener should only be executed if the request comes from one of
    the game participants (player_1_id | player_2_id)
    '''
    def wrapper(data, user_id):
        game_id = data["game_id"]

        if not game_id or \
           not game_id in games:
            return

        game = games[game_id]
        if game.player_1_id != user_id and \
           game.player_2_id != user_id:
            return

        return func(data, user_id, game)

    wrapper.__name__ = func.__name__
    return wrapper


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 len(self.board.win_positions) > 0: return
        if self.board.board_full: 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")
@io_auth_required("none")
@participants_only
def new_move(data, user_id, game):
    move = data.get("move")
    if not move: return

    game.move(user_id, move)


@io.on("resign")
@io_auth_required("none")
@participants_only
def resign(data, user_id, game):
    game.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)