diff options
-rw-r--r-- | swiftstory/board.py | 9 | ||||
-rw-r--r-- | swiftstory/cards.py | 4 | ||||
-rw-r--r-- | swiftstory/client.py | 11 | ||||
-rw-r--r-- | swiftstory/exception.py | 11 | ||||
-rw-r--r-- | swiftstory/game.py | 15 | ||||
-rw-r--r-- | swiftstory/game_manager.py | 9 | ||||
-rw-r--r-- | swiftstory/interface/ws.py | 5 | ||||
-rw-r--r-- | swiftstory/player.py | 7 | ||||
-rw-r--r-- | swiftstory/status.py | 4 |
9 files changed, 69 insertions, 6 deletions
diff --git a/swiftstory/board.py b/swiftstory/board.py index 31ddd11..01082e4 100644 --- a/swiftstory/board.py +++ b/swiftstory/board.py @@ -1,3 +1,5 @@ +""" This module defines the Board class. """ + import random from typing import List, Optional, Tuple @@ -9,6 +11,7 @@ class Board: of cards ''' def __init__(self) -> None: + """ Initializer for the board. """ self.white_pick: List[Tuple[int, str]] = [] self.black_pick: List[Tuple[int, str]] = [] self.white_recycled: List[Tuple[int, str]] = [] @@ -19,6 +22,8 @@ class Board: self.played_cards: List[Tuple[Tuple[int, str], Player]] = [] def reveal_next_black_card(self) -> None: + """ Fetch the next black card and reveal it. The current card (if any) + moves to the recycling heap. """ if self.current_black_card is not None: self.black_recycled.append(self.current_black_card) self.current_black_card = None @@ -33,6 +38,7 @@ class Board: self.current_black_card = self.black_pick.pop() def pick_white_card(self) -> Tuple[int, str]: + """ Fetch and return the next white card. """ if not self.white_pick: # If we have no more cards in the deck, we need to reform one using # the cards that have been recycled. @@ -43,12 +49,15 @@ class Board: return self.white_pick.pop() def play_card(self, player: Player, card: Tuple[int, str]) -> None: + """ Add a card to the played cards for this round. """ self.played_cards.append((card, player)) def shuffle_played_cards(self) -> None: + """ Shuffle the heap of played cards. """ random.shuffle(self.played_cards) def recycle_played_cards(self) -> None: + """ Move the played cards to the recycling heap of white cards. """ self.white_recycled += [i[0] for i in self.played_cards] self.played_cards = [] diff --git a/swiftstory/cards.py b/swiftstory/cards.py index 7f28919..3c11f49 100644 --- a/swiftstory/cards.py +++ b/swiftstory/cards.py @@ -1,3 +1,5 @@ +""" Module that defines helpers to read cards from the filesystem. """ + import json import os from typing import List @@ -6,6 +8,8 @@ from pkg_resources import resource_stream class Cards: + """ Dummy class that provides helper functions to retrieve the cards from + the FS. """ @staticmethod def get_white_cards(lang: str) -> List[str]: ''' Read the file containing the white cards and return a list of cards ''' diff --git a/swiftstory/client.py b/swiftstory/client.py index 28fd6c0..cd5e82a 100644 --- a/swiftstory/client.py +++ b/swiftstory/client.py @@ -1,3 +1,5 @@ +""" Module that defines the client class. """ + import asyncio import logging from typing import Optional @@ -23,6 +25,7 @@ class Client: self.player: Optional[Player] = None def join_game(self, game_name: str, lang: Optional[str]) -> str: + """ Attempt to join a game and return an answer. """ if self.game is not None: raise WrongAction('You are already in a game') @@ -42,6 +45,7 @@ class Client: return status def play_white_card(self, card_id: int) -> str: + """ Play a card and return an answer. """ if self.game is None: raise WrongAction('You have to join a game first') if self.player is None: @@ -49,6 +53,7 @@ class Client: return self.game.try_play_card(self.player, card_id) def pick_black_card(self) -> str: + """ Pick a black card (and become the judge) and return an answer. """ if self.game is None: raise WrongAction('You have to join a game first') if self.player is None: @@ -56,6 +61,7 @@ class Client: return self.game.try_become_judge(self.player) def collect_cards(self) -> str: + """ Collect the played cards and return an answer. """ if self.game is None: raise WrongAction('You have to join a game first') if self.player is None: @@ -63,6 +69,7 @@ class Client: return self.game.try_collect_cards(self.player) def designate_card(self, card_id: Optional[int]) -> str: + """ Designate the best card and return an answer. """ if self.game is None: raise WrongAction('You have to join a game first') if self.player is None: @@ -70,6 +77,7 @@ class Client: return self.game.try_designate_card(self.player, card_id) def view_player_cards(self) -> str: + """ View our own cards and return an answer. """ if self.game is None: raise WrongAction('You have to join a game first') if self.player is None: @@ -77,6 +85,7 @@ class Client: return self.game.try_view_player_cards(self.player) def view_played_cards(self) -> str: + """ View the cards played at this round and return an answer. """ if self.game is None: raise WrongAction('You have to join a game first') if self.player is None: @@ -84,6 +93,7 @@ class Client: return self.game.try_view_played_cards(self.player) def view_black_card(self) -> str: + """ View the current black card and return an answer. """ if self.game is None: raise WrongAction('You have to join a game first') if self.player is None: @@ -104,6 +114,7 @@ class Client: asyncio.create_task(f()) def disconnect(self) -> None: + """ Detach from the player. """ if self.player is not None: if self.game is None: raise ValueError("Disconnect from inexistent game.") diff --git a/swiftstory/exception.py b/swiftstory/exception.py index 764289f..ad7a894 100644 --- a/swiftstory/exception.py +++ b/swiftstory/exception.py @@ -1,9 +1,14 @@ +""" Define a few exceptions types to be used. """ + class WrongAction(Exception): - pass + """ Exception to be raised when a player performs an action that is not + permitted. """ class UnsupportedLanguage(Exception): - pass + """ Exception to be raised when trying to join a game in a language that is + not supported. """ + class JoinError(Exception): - pass + """ Exception to be raised when a game/room cannot be joined. """ diff --git a/swiftstory/game.py b/swiftstory/game.py index c46df4b..b2ec493 100644 --- a/swiftstory/game.py +++ b/swiftstory/game.py @@ -1,3 +1,5 @@ +""" Module that defines the main component of the game. """ + from enum import Enum, auto import random from typing import List, Optional, Tuple @@ -9,12 +11,14 @@ from swiftstory.status import error, success class GameState(Enum): + """ Enumeration of the different game states. """ WAITING_NEW_JUDGE = auto(), WAITING_COLLECTION = auto(), WAITING_DESIGNATION = auto(), class Game: + """ Represent a game, including the board, players and state. """ def __init__(self, white_desc: List[str], black_desc: List[str]) -> None: self.state = GameState.WAITING_NEW_JUDGE @@ -31,6 +35,7 @@ class Game: random.shuffle(self.board.black_pick) def try_join(self, player: Player) -> str: + """ Attempt to join the game. Return an answer. """ if len(self.players) >= 10: raise JoinError('too many players in this game') @@ -64,6 +69,7 @@ class Game: def try_become_judge(self, player: Player) -> str: + """ Attempt to become the judge of the game. Return an answer. """ if self.state is not GameState.WAITING_NEW_JUDGE: # TODO what if the judge has quit ? raise WrongAction('Someone is judge already') @@ -81,6 +87,7 @@ class Game: def try_play_card(self, player: Player, card_id: int) -> str: + """ Attempt to play a card. Return an answer. """ if self.state is not GameState.WAITING_COLLECTION: raise WrongAction('Who asked you to play now ?!') @@ -106,6 +113,8 @@ class Game: def try_collect_cards(self, player: Player) -> str: + """ Attempt to collect the cards play in the current round. Return an + answer. """ if self.state is not GameState.WAITING_COLLECTION: raise WrongAction("Do you think it's the moment for collection !?") @@ -125,6 +134,7 @@ class Game: def try_designate_card(self, player: Player, card_id: Optional[int]) -> str: + """ Attempt to designate the best card. Return an answer. """ if self.state is not GameState.WAITING_DESIGNATION: raise WrongAction('Not now, moron !') @@ -177,15 +187,19 @@ class Game: return move_on() def try_view_player_cards(self, player: Player) -> str: + """ Attempt to view the cards of the given player. Return an answer. """ return success([(idx, desc) for idx, (_, desc) in player.cards.items()]) def try_view_played_cards(self, player: Player) -> str: + """ Attempt to view the cards that have been played. Return an answer. + """ if self.state is not GameState.WAITING_DESIGNATION: raise WrongAction('Not now, moron !') return success([desc for (_, desc), _ in self.board.played_cards]) def try_view_black_card(self, player: Player) -> str: + """ Attempt to view the black card. Return an answer. """ card = self.board.current_black_card if card is not None: @@ -194,6 +208,7 @@ class Game: raise WrongAction('The black card has not been revealed yet') def disconnect(self, player: Player) -> None: + """ Deatch a player from the game. """ if self.judge is player: self.judge = None diff --git a/swiftstory/game_manager.py b/swiftstory/game_manager.py index 56279a6..aa951f5 100644 --- a/swiftstory/game_manager.py +++ b/swiftstory/game_manager.py @@ -1,3 +1,6 @@ +""" Module defining a class to store the games/rooms in the different +languages. """ + from dataclasses import dataclass import logging from typing import Dict, List @@ -10,7 +13,7 @@ from swiftstory.cards import Cards class NoSuchGameError(Exception): - """ Exception to be raised when no game is found matching the criterias. + """ Exception to be raised when no game is found matching the criterion. """ def __init__(self, message: str = "", game_name: str = "", lang: str = "") -> None: self.game_name = game_name @@ -20,14 +23,14 @@ class NoSuchGameError(Exception): @dataclass class LangContainer: - """ Container for game ojects in a given language. """ + """ Container for game objects in a given language. """ black_cards: List[str] white_cards: List[str] games: Dict[str, Game] class GameManager: - + """ Store the different rooms/games of the different languages. """ def __init__(self) -> None: self.lang_containers: Dict[str, LangContainer] = {} diff --git a/swiftstory/interface/ws.py b/swiftstory/interface/ws.py index a86c730..082ed1a 100644 --- a/swiftstory/interface/ws.py +++ b/swiftstory/interface/ws.py @@ -1,3 +1,6 @@ +""" Module that defines the interface (using WebSockets) between the GUI and +the game itself. """ + import contextlib import json import logging @@ -18,6 +21,7 @@ class WebsocketsInterface: self.game_manager = game_manager async def connection_handler(self, websocket: WebSocketServerProtocol, path: str) -> None: + """ Coroutine that handles one websocket connection. """ client = Client(websocket, self.game_manager) with contextlib.suppress(websockets.exceptions.ConnectionClosed): @@ -27,6 +31,7 @@ class WebsocketsInterface: client.disconnect() def message_received_handler(self, client: Client, message: Union[bytes, str]) -> str: + """ Handle a message and return an answer. """ def join_game() -> str: try: game_name = json_msg['game_name'] diff --git a/swiftstory/player.py b/swiftstory/player.py index 7243585..2df6882 100644 --- a/swiftstory/player.py +++ b/swiftstory/player.py @@ -1,9 +1,12 @@ +""" Module defining the player class. """ + import asyncio import json from typing import Any, Dict, Tuple class Player: + """ Represent a player. """ def __init__(self) -> None: self.cards: Dict[int, Tuple[int, str]] = {} self.next_idx = 0 @@ -16,9 +19,11 @@ class Player: self.notifications: asyncio.Queue = asyncio.Queue() def pop_card(self, card_id: int) -> Tuple[int, str]: + """ Take and return the card at index card_id. """ return self.cards.pop(card_id) def inc_score(self) -> None: + """ Increase the score by one. """ self.score += 1 self.register_notification({ 'op': 'updated_score', @@ -26,11 +31,13 @@ class Player: }) def receive_card(self, card: Tuple[int, str]) -> int: + """ Receive a card and return its index. """ self.cards[self.next_idx] = card self.next_idx += 1 return self.next_idx - 1 def register_notification(self, obj: Any) -> None: + """ Register a notification to be picked up by the client. """ message = json.dumps({'type': 'notification', 'content': obj}) self.notifications.put_nowait(message) diff --git a/swiftstory/status.py b/swiftstory/status.py index d794580..a35f66a 100644 --- a/swiftstory/status.py +++ b/swiftstory/status.py @@ -1,9 +1,13 @@ +""" Module defining helpers to craft answers to be sent to clients. """ + from typing import Any import json def error(msg: str, code: int = 255) -> str: + """ Generate an error. """ return json.dumps({'type': 'response', 'content': {'status': code, 'info': msg}}) def success(obj: Any) -> str: + """ Generate a success message. """ return json.dumps({'type': 'response', 'content': {'status': 0, 'result': obj}}) |