Просмотр исходного кода

Merge pull request #7 from NielsOverkamp/backend-2

Rework backend 2
NielsOverkamp 5 лет назад
Родитель
Сommit
e2c85fc22a
4 измененных файлов с 292 добавлено и 198 удалено
  1. 193 123
      game.py
  2. 2 1
      option.py
  3. 62 20
      player.py
  4. 35 54
      webserver.py

+ 193 - 123
game.py

@@ -6,40 +6,77 @@ from cards import Card, shuffle
 from option import OptionCode, Option
 from player import Player, StateCode, ErrorCode
 
+all_colors = [Color.RED, Color.BLUE, Color.YELLOW, Color.GREEN]
 
 class Game(object):
     """description of class"""
 
-    players: Dict[Color, Player]
+    players: List[Player]
     current_player: Player
     current_dealer: Player
     stock: List[str]
     number_of_cards: int
 
-    def __init__(self, players=None):
-        if players is None:
-            players = [
-                Player(Color.RED, "Rood"),
-                Player(Color.BLUE, "Blauw"),
-                Player(Color.YELLOW, "Geel"),
-                Player(Color.GREEN, "Groen")]
-
+    def __init__(self):
         self.stock = []
-        random.seed()
         self.number_of_cards = 0
+        self.players = []
+        self.current_player = None
+        self.current_dealer = None
+
+    def join_player(self, name):
+        player = Player(name=name)
+        self.players.append(player)
+        player.state = StateCode.PICK_COLOR
+        self.set_pick_color_state()
+        return player
+
+    def unjoin_player(self, player):
+        if player.color is None:
+            self.players.remove(player)
+        else:
+            player.name = None
+
+        self.set_pick_color_state()
+
+    def pick_color(self, player, color):
+        color_player = next((p for p in self.players if p.color == color), None)
+        if color_player is not None:
+            if color_player.name is None:
+                # reconnect, merge
+                player.merge_from(color_player)
+                self.players.remove(color_player)
+            else:
+                # error
+                player.message = f"Kleur {color} is al gekozen door een andere speler. " + player.message
+                player.set_error(ErrorCode.COLOR_ALREADY_CHOSEN, color=color) 
+                return
+
+        player.color = color
+        self.set_pick_color_state()
 
-        self.players = dict((player.color, player) for player in players)
 
-        for player in self.players.values():
-            player.options = [Option(OptionCode.DEAL, "Delen")]
-            player.message = "Wie begint er met delen?"
-            player.set_state(StateCode.FIRST_DEAL)
+    def set_pick_color_state(self):
+        used_colors = [player.color for player in self.players if player.color is not None and player.name is not None]
+        available_colors = [color for color in all_colors if color not in used_colors]
 
-    def deal(self, player_color):
-        player = self.players[player_color]
+        for player in self.players:
+            if player.state == StateCode.PICK_COLOR:
+                player.options = [Option(OptionCode.PICK_COLOR, str(color), color=color) for color in available_colors]
+                if len(used_colors) == 4 and player.color is not None:
+                    player.options.append(Option(OptionCode.DEAL, "Delen"))
 
-        self.current_player = player
-        self.current_dealer = player
+                if player.color is None:
+                    player.message = "Kies een kleur om mee te spelen"
+                else:
+                    player.message = "Wie begint er met delen?"
+
+            player.set_others(self.players)
+
+
+    def deal(self, dealer):
+        self.current_player = dealer
+        self.current_dealer = dealer
 
         if self.number_of_cards <= 2:
             self.stock = shuffle(2)
@@ -47,193 +84,226 @@ class Game(object):
         else:
             self.number_of_cards -= 1
 
-        for player in self.players.values():
-            player.hand = self.stock[:self.number_of_cards]
-            self.stock = self.stock[self.number_of_cards:]
-            player.options = [Option(OptionCode.SWAP_CARD, card.denom, card=card) for card in player.hand]
-            player.message = "Kies een kaart om te wisselen"
-            player.set_state(StateCode.SWAP_CARD)
-            player.selected_card = None
-            player.card_is_changed = False
-            player.passed = False
-
-        return self.players
-
-    def change_card(self, player_color, card):
-        player = self.players[player_color]
-
+        for player in self.players:
+            if player.color is not None:
+                player.hand = self.stock[:self.number_of_cards]
+                self.stock = self.stock[self.number_of_cards:]
+                player.options = [Option(OptionCode.SWAP_CARD, card.denom, card=card) for card in player.hand]
+                player.message = "Kies een kaart om te wisselen"
+                player.state = StateCode.SWAP_CARD
+                player.swap_card = None
+                player.card_is_swapped = False
+                player.passed = False
+                player.set_current(dealer)
+
+
+    def swap_card(self, player, card):
+        if player.swap_card is not None:
+            player.hand.append(player.swap_card)
+            player.swap_card = None
+        
         player.hand.remove(card)
         partner = self.partner(player)
 
-        if partner.selected_card is None:
-            player.selected_card = card
+        if partner.swap_card is None:
+            player.swap_card = card
             player.message = "Wacht op je maat"
-            player.set_state(StateCode.SWAP_CARD_PARTNER)
-            player.options = [Option(OptionCode.UNDO_CARD, "Terug")]
-            return self.players
+            player.state = StateCode.SWAP_CARD
+            player.options = [Option(OptionCode.SWAP_CARD, card.denom, card=card) for card in player.hand]
+            player.options.append(Option(OptionCode.UNDO_CARD, "Terug"))
+            return
 
-        player.hand.append(partner.selected_card)
-        partner.selected_card = None
+        player.hand.append(partner.swap_card)
+        partner.swap_card = None
         partner.hand.append(card)
-        player.card_is_changed = True
-        partner.card_is_changed = True
+        player.card_is_swapped = True
+        partner.card_is_swapped = True
         partner.options.clear()
         player.options.clear()
         player.message = ""
 
-        if all(player.card_is_changed for player in self.players.values()):
+        if all(player.card_is_swapped for player in self.players if player.color is not None):
             self.next_turn()
         else:
             player.message = "Wacht op het andere team"
-            player.set_state(StateCode.SWAP_CARD_OTHERS)
+            player.state = StateCode.SWAP_CARD_OTHERS
             partner.message = "wacht op het andere team"
-            partner.set_state(StateCode.SWAP_CARD_OTHERS)
+            partner.state = StateCode.SWAP_CARD_OTHERS
 
-        return self.players
-
-    def play_card(self, player_color, card):
-        player = self.players[player_color]
 
+    def play_card(self, player, card):
+        if player.play_card is not None:
+            player.hand.append(player.play_card)
+            player.play_card = None
+        
         player.hand.remove(card)
-        player.selected_card = card
+        player.play_card = card
         player.options = [Option(OptionCode.UNDO_CARD, "Terug"), Option(OptionCode.READY, "Klaar")]
-        player.message = f"Je speelt {card}"
-        player.set_state(StateCode.PLAYING_CARD, card=card)
+        player.options.extend(Option(OptionCode.PLAY_CARD, card.denom, card=card) for card in self.current_player.hand)
+        player.message = f"Je speelt {card.denom}"
+        player.state = StateCode.PLAY_CARD
 
-        for other in self.players.values():
+        for other in self.players:
             if other.color != player.color:
-                other.message = f"{player.name} speelt {card}"
-                other.set_state(StateCode.PLAYING_CARD_OTHER, card=card, other_player_name=player.name)
+                other.message = f"{player.name} speelt een {card.denom}"
+                other.state = StateCode.PLAY_CARD_OTHER,
+                other.play_card = card
 
-        return self.players
-
-    def drop_cards(self, player_color):
-        player = self.players[player_color]
 
+    def drop_cards(self, player):
         player.hand = []
         player.options = []
         player.passed = True
+        player.play_card = None
         self.next_turn()
 
-    def ready(self, player_color):
-        player = self.players[player_color]
 
+    def ready(self, player):
         player.options.clear()
-        player.selected_card = None
+        player.play_card = None
         self.next_turn()
 
-        return self.players
-
-    def undo_card(self, player_color):
-        player = self.players[player_color]
 
-        player.hand.append(player.selected_card)
-        player.selected_card = None
-
-        if player.card_is_changed:
-            self.turn()
-        else:
+    def undo_card(self, player):
+        if player.swap_card is not None:
+            player.hand.append(player.swap_card)
+            player.swap_card = None
             player.options = [Option(OptionCode.SWAP_CARD, card.denom, card=card) for card in player.hand]
             player.message = "Kies een kaart om te wisselen"
-            player.set_state(StateCode.SWAP_CARD)
+            player.state = StateCode.SWAP_CARD
+        else:
+            player.hand.append(player.play_card)
+            player.play_card = None
+            self.turn()
 
-        return self.players
 
     def play_option(self, player, option):
-        if option.code == OptionCode.DEAL:
-            return self.deal(player.color)
+        if option.code == OptionCode.PICK_COLOR:
+            return self.pick_color(player, option.color)
+        elif option.code == OptionCode.DEAL:
+            return self.deal(player)
         elif option.code == OptionCode.SWAP_CARD:
-            return self.change_card(player.color, option.card)
+            return self.swap_card(player, option.card)
         elif option.code == OptionCode.PLAY_CARD:
-            return self.play_card(player.color, option.card)
+            return self.play_card(player, option.card)
         elif option.code == OptionCode.READY:
-            return self.ready(player.color)
+            return self.ready(player)
         elif option.code == OptionCode.UNDO_CARD:
-            return self.undo_card(player.color)
+            return self.undo_card(player)
         elif option.code == OptionCode.PASS:
-            return self.drop_cards(player.color)
+            return self.drop_cards(player)
         else:
             raise Exception(f"Unknown option {option.code}")
 
     def next_player(self, player):
         if player.color == Color.RED:
-            return self.players[Color.BLUE]
+            color = Color.BLUE
         elif player.color == Color.BLUE:
-            return self.players[Color.YELLOW]
+            color = Color.YELLOW
         elif player.color == Color.YELLOW:
-            return self.players[Color.GREEN]
+            color = Color.GREEN
         elif player.color == Color.GREEN:
-            return self.players[Color.RED]
+            color =  Color.RED
         else:
             raise Exception(f"Unknown color {player.Color}")
 
+        return next(player for player in self.players if player.color == color)
+
     def next_turn(self):
-        if all(len(player.hand) == 0 for player in self.players.values()):
+        if all(len(player.hand) == 0 for player in self.players):
             self.next_deal()
         else:
             self.current_player = self.next_player(self.current_player)
+            self.current_player.play_card = None
             while len(self.current_player.hand) == 0:
                 self.current_player = self.next_player(self.current_player)
             self.turn()
 
     def next_deal(self):
-        self.current_player = self.next_player(self.current_dealer)
-        self.current_player.options = [Option(OptionCode.DEAL, "Delen")]
-        self.current_player.message = f"Jij bent aan de beurt om te delen."
-        self.current_player.set_state(StateCode.DEAL)
+        dealer = self.next_player(self.current_dealer)
+        self.current_player = dealer
+        dealer.options = [Option(OptionCode.DEAL, "Delen")]
+        dealer.message = f"Jij bent aan de beurt om te delen."
+        dealer.state = StateCode.DEAL
         
-        for player in self.players.values():
-            if player.color != self.current_player.color:
-                player.message = f"{self.current_player.name} is aan de beurt om te delen"
-                player.set_state(StateCode.DEAL_OTHER, other_player_name=self.current_player.name) 
+        for player in self.players:
+            player.set_current(dealer)
+            if player.color != dealer.color:
+                player.message = f"{dealer.name} is aan de beurt om te delen"
+                player.state= StateCode.DEAL_OTHER 
 
-    def turn(self):
-        self.current_player.options = [Option(OptionCode.PLAY_CARD, card.denom, card=card) for card in self.current_player.hand]
-        self.current_player.options.append(Option(OptionCode.PASS, "Pas"))
-        self.current_player.message = "Kies een kaart om te spelen"
-        self.current_player.set_state(StateCode.PLAY_CARD)
 
-        for player in self.players.values():
+    def turn(self):
+        player = self.current_player
+        player.options = [Option(OptionCode.PLAY_CARD, card.denom, card=card) for card in player.hand]
+        player.options.append(Option(OptionCode.PASS, "Pas"))
+        player.message = "Kies een kaart om te spelen"
+        player.state = StateCode.PLAY_CARD
+        player.play_card = None
+
+        for player in self.players:
+            player.set_current(self.current_player)
             if player.color != self.current_player.color:
                 player.message = f"{self.current_player.name} is aan de beurt"
-                player.set_state(StateCode.PLAY_CARD_OTHER, other_player_name=self.current_player.name) 
+                player.state = StateCode.PLAY_CARD_OTHER 
+
 
     def partner(self, player):
         if player.color == Color.RED:
-            return self.players[Color.YELLOW]
+            color = Color.YELLOW
         elif player.color == Color.BLUE:
-            return self.players[Color.GREEN]
+            color = Color.GREEN
         elif player.color == Color.YELLOW:
-            return self.players[Color.RED]
+            color = Color.RED
         elif player.color == Color.GREEN:
-            return self.players[Color.BLUE]
+            color = Color.BLUE
         else:
             raise Exception(f"Unknown color {player.Color}")
 
+        return next(player for player in self.players if player.color == color)
+
 
 if __name__ == "__main__":
     game = Game()
-
-    colors = [Color.BLUE, Color.YELLOW, Color.GREEN, Color.RED]
+    red = game.join_player("Rood")
+    blue = game.join_player("Blauw")
+    yellow = game.join_player("Geel")
+    green = game.join_player("Groen")
+    olive = game.join_player("Olijf")
+    players = [blue, yellow, green, red]
+    game.pick_color(red, Color.RED)
+    game.pick_color(blue, Color.BLUE)
+    game.pick_color(yellow, Color.YELLOW)
+    game.pick_color(green, Color.GREEN)
 
     for round in range(2):
         for deal in [6, 5, 4, 3, 2]:
-            color = colors[0]
-            print(color)
-            game.deal(color)
-            game.change_card(Color.YELLOW, game.players[Color.YELLOW].hand[deal - 1])
-            game.change_card(Color.RED, game.players[Color.RED].hand[1])
-            game.change_card(Color.GREEN, game.players[Color.GREEN].hand[0])
-            game.change_card(Color.BLUE, game.players[Color.BLUE].hand[-1])
+            player = players[0]
+            print(f"{player.name} deals {deal} cards")
+            game.deal(player)
 
-            colors = colors[1:] + [colors[0]]
+            for player in game.players:
+                print(player.get_json(), end="\n\n")
 
-            for turn in range(deal):
-                for color in colors:
-                    game.play_card(color, game.players[color].hand[0])
-                    game.ready(color)
+            game.swap_card(yellow, yellow.hand[deal - 1])
+            game.swap_card(red, red.hand[1])
+            if round == 0:
+                game.swap_card(green, green.hand[0])
+            else:
+                game.swap_card(olive, olive.hand[0])
+            game.swap_card(blue, blue.hand[-1])
 
-    for player in game.players.values():
-        print(player.__dict__, end="\n\n")
+            players = players[1:] + players[:1]
 
-    print([card.__dict__ for card in game.stock], end="\n\n")
+            for turn in range(deal):
+                for player in players:
+                    card = player.hand[0]
+                    game.play_card(player, card)
+                    print(f"{player.name} plays {card.denom} of {card.suit}")
+                    game.ready(player)
+
+        if round == 0:
+            print(green.get_json(), end="\n\n")
+            green.name = None
+            game.pick_color(olive, Color.GREEN)
+            players = [yellow, olive, red, blue]

+ 2 - 1
option.py

@@ -17,12 +17,13 @@ class OptionCode(str, Enum):
 
 
 class Option(object):
-    def __init__(self, code, text, game_code=None, color=None, card=None):
+    def __init__(self, code, text, game_code=None, color=None, card=None, user_name=None):
         self.code = OptionCode(code)
         self.text = text
         self.game_code = int(game_code) if game_code != None else None
         self.color = Color(color) if color != None else None
         self.card = card if isinstance(card, Card) else Card(card['suit'], card['denom']) if isinstance(card, dict) else None
+        self.user_name = user_name
 
     def isOption(self, other):
         # ignore text and game_code 

+ 62 - 20
player.py

@@ -1,24 +1,21 @@
 from enum import Enum
+from cards import Card
 from color import Color
 from option import Option, OptionCode
+from typing import List
+
 import json
 
 
 class StateCode(str, Enum):
     START = "start"
-    JOIN_OTHERS = "join_others"
     PICK_COLOR = "pick_color"
-    PICK_COLOR_OTHERS = "pick_color_others"
-    FIRST_DEAL = "first_deal"
     DEAL = "deal"
     DEAL_OTHER = "deal_other"
     SWAP_CARD = "swap_card"
-    SWAP_CARD_PARTNER = "swap_card_partner"
     SWAP_CARD_OTHERS = "swap_card_others"
     PLAY_CARD = "play_card"
     PLAY_CARD_OTHER = "play_card_other"
-    PLAYING_CARD = "playing_card"
-    PLAYING_CARD_OTHER = "playing_card_other"
 
 
 class ErrorCode(str, Enum):
@@ -38,18 +35,50 @@ class PlayerError(object):
         self.code = ErrorCode(code)
         self.args = kwargs
 
+
+class OtherPlayer(object):
+    def __init__(self, color, name):
+        self.color = color
+        self.name = name
+
+
+class DictEncoder(json.JSONEncoder):
+    def default(self, obj):
+        if hasattr(obj, '__dict__'):
+            return obj.__dict__
+        return json.JSONEncoder.default(self, obj)
+
+
 class Player(object):
+
+    color: Color
+    name: str
+    hand: List[Card]
+    options: List[Option]
+    message: str
+    state: PlayerState
+    error: PlayerError
+    swap_card: Card
+    card_is_swapped: bool
+    passed: bool
+    others: List[OtherPlayer]
+    current_player: OtherPlayer
+    play_card: Card
+
     def __init__(self, color = None, name = None):
         self.color = color
         self.name = name
         self.hand = []
         self.options = []
         self.message = "Even wachten"
-        self.set_state(StateCode.START)
+        self.state = StateCode.START
         self.error = None
-        self.selected_card = None
-        self.card_is_changed = False
+        self.swap_card = None
+        self.card_is_swapped = False
         self.passed = False
+        self.others = []
+        self.current_player = None
+        self.play_card = None
 
     def check_option(self, option):
         found_option = any(o.isOption(option) for o in self.options)
@@ -60,27 +89,40 @@ class Player(object):
             
         return found_option
 
-    def set_state(self, state_code, **kwargs):
-        self.state = PlayerState(state_code, **kwargs)
-
     def set_error(self, error_code, **kwargs):
-        if error_code != None:
+        if error_code is not None:
             self.error = PlayerError(error_code, **kwargs)
         else:
             self.error = None
 
+    def set_others(self, all_players):
+        self.others = [OtherPlayer(p.color, p.name) for p in all_players if p.name != self.name or p.color != self.color]
 
-class DogEncoder(json.JSONEncoder):
-    def default(self, obj):
-        if hasattr(obj, '__dict__'):
-            return obj.__dict__
-        return json.JSONEncoder.default(self, obj)
+    def set_current(self, current_player):
+        self.current_player = OtherPlayer(current_player.color, current_player.name)
+        self.play_card = current_player.play_card
+
+    def merge_from(self, other):
+        self.color = other.color
+        self.hand = other.hand
+        self.options = other.options
+        self.message = other.message
+        self.state = other.state
+        self.error = other.error
+        self.swap_card = other.swap_card
+        self.card_is_swapped = other.card_is_swapped
+        self.passed = other.passed
+        self.current_player = other.current_player
+        self.play_card = other.play_card
+
+    def get_json(self):
+        return json.dumps(self.__dict__, cls=DictEncoder)
 
 
 if __name__ == "__main__":
     player = Player(Color.BLUE, "Groen")
     player.options = [Option(OptionCode.NEW_GAME, "Nieuw spel", color='green'), Option(OptionCode.JOIN_GAME, "doe mee met een spel")]
-    player.set_state(StateCode.PICK_COLOR, other_player_name="Rood")
+    player.state = StateCode.PICK_COLOR
     print(player.__dict__)
     print(player.options[0].__dict__)
-    print(json.dumps(player.__dict__, cls=DogEncoder))
+    print(player.get_json())

+ 35 - 54
webserver.py

@@ -7,7 +7,10 @@ import functools
 import json
 import logging
 import os
+import random
 import websockets
+from http import HTTPStatus
+
 
 from color import Color
 from option import OptionCode, Option
@@ -20,6 +23,8 @@ games = dict()   # code -> game
 
 sockets = dict()   # code -> [(player, websocket), ...]
 
+users = ["Anna", "Bob", "Cynthia", "Daan", "Esther", "Frank", "Gerben", "Hanna", "Ida", "Joost", "Karin", "Loes", "Max", "Nina"]
+
 
 class DogEncoder(json.JSONEncoder):
     def default(self, obj):
@@ -28,9 +33,6 @@ class DogEncoder(json.JSONEncoder):
         return json.JSONEncoder.default(self, obj)
 
 
-from http import HTTPStatus
-
-
 MIME_TYPES = {
     "html": "text/html",
     "js": "text/javascript",
@@ -76,15 +78,15 @@ async def notify(player_sockets):
     if player_sockets:
         await asyncio.wait([websocket.send(json.dumps(player, cls=DogEncoder)) for (player, websocket) in player_sockets])
 
-
 async def handler(websocket, path):
-    player = Player()
+    player = Player(name=users[0])
     player.options = [
         Option(OptionCode.NEW_GAME, "Nieuw spel"), 
         Option(OptionCode.JOIN_GAME, "Doe mee met een spel", game_code='3936')]
     player.message = "Wat wil je doen?"
-    player.set_state(StateCode.START)
+    player.state = StateCode.START
     game_code = 0
+    game = None
     try:
         await notify([(player, websocket)])
 
@@ -95,66 +97,38 @@ async def handler(websocket, path):
                 await notify([(player, websocket)])
                 continue
 
+            # Thisis a change
+
             player.set_error(None)
 
             if option.code == OptionCode.NEW_GAME:
                 game_code = 3936  # random.randint(1000, 9999);
+                game = Game()
+                games[game_code] = game
+                if option.user_name is None:
+                    option.user_name = users[0]
+                    users.append(users[0])
+                    users.remove(users[0])
+                player = game.join_player(option.user_name)
                 sockets[game_code] = [(player, websocket)]
-                player.message = f"De andere spelers kunnen meedoen door code {game_code} in te voeren"
-                player.set_state(StateCode.JOIN_OTHERS, game_code=game_code)
-                player.options = []
                 await notify(sockets[game_code])
 
             elif option.code == OptionCode.JOIN_GAME:
                 game_code = option.game_code
-                socketlist = sockets.get(game_code) if game_code > 0 else None
-                if socketlist is None:
+                game = games.get(game_code) if game_code > 0 else None
+
+                if game is None:
                     player.message = f"onbekande code {game_code}"
                     player.set_error(ErrorCode.UNKNOWN_CODE, game_code=game_code)
                     await notify([(player, websocket)])
                     continue
 
+                if option.user_name is None:
+                    option.user_name = users[0]
+                    users.append(users[0])
+                    users.remove(users[0])
+                player = game.join_player(option.user_name)
                 sockets[game_code].append((player, websocket))
-                if len(sockets[game_code]) < 4:
-                    player.message = "wacht op de andere spelers"
-                    player.set_state(StateCode.JOIN_OTHERS, game_code=game_code)
-                    player.options = []
-                    await notify([(player, websocket)])
-
-                else:
-                    for (player, _) in sockets[game_code]:
-                        player.message = "Kies een kleur om mee te spelen"
-                        player.set_state(StateCode.PICK_COLOR)
-                        player.options = [
-                            Option(OptionCode.PICK_COLOR, "Rood", color=Color.RED),
-                            Option(OptionCode.PICK_COLOR, "Blauw", color=Color.BLUE),
-                            Option(OptionCode.PICK_COLOR, "Geel", color=Color.YELLOW),
-                            Option(OptionCode.PICK_COLOR, "Groen", color=Color.GREEN)
-                            ]
-                   
-                    await notify(sockets[game_code])
-
-            elif option.code == OptionCode.PICK_COLOR:
-                color = option.color
-                if any(other.color == color for (other, _) in sockets[game_code]):
-                    player.message = f"Kleur {option.text} is al gekozen door een andere speler. " + player.message
-                    player.set_error(ErrorCode.COLOR_ALREADY_CHOSEN, color=color) 
-                    await notify([(player, websocket)])
-                    continue
-
-                player.color = color
-                player.name = option.text
-                player.message = "Wacht op de andere spelers"
-                player.set_state(StateCode.PICK_COLOR_OTHERS)
-                player.options = []
-
-                for (other, _) in sockets[game_code]:
-                    other.options = [option for option in other.options if option.color != color]
-
-                if all( not any(p.options) for (p, _) in sockets[game_code]):
-                    game = Game(p for (p, _) in sockets[game_code])
-                    games[game_code] = game
-
                 await notify(sockets[game_code])
 
             else:
@@ -162,12 +136,19 @@ async def handler(websocket, path):
                 game.play_option(player, option)
                 await notify(sockets[game_code])
     finally:
-        if player is not None and game_code > 0:
-            sockets[game_code].remove((player, websocket))
-        pass
+        if player is not None:
+            if game is not None:
+                game.unjoin_player(player)
+
+            if game_code > 0:
+                sockets[game_code].remove((player, websocket))
+                await notify(sockets[game_code])
+
 
 if __name__ == "__main__":
 
+    random.seed()
+
     static_handler = functools.partial(process_request, os.path.join(os.getcwd(), 'ui'))
 
     start_server = websockets.serve(handler, "localhost", 6789, process_request=static_handler)