From 0fb08748e5285e5d4adc6135eec8889887a63299 Mon Sep 17 00:00:00 2001 From: Olivier Gayot Date: Sun, 14 Jun 2015 22:31:48 +0100 Subject: use a python package instead of just modules The package is contained in the CAO/ folder. server.py is still at the root of the repository though. Signed-off-by: Olivier Gayot --- CAO/Board.py | 55 ++++++++++++++ CAO/Cards.py | 13 ++++ CAO/Client.py | 73 +++++++++++++++++++ CAO/Game.py | 206 +++++++++++++++++++++++++++++++++++++++++++++++++++++ CAO/GameManager.py | 34 +++++++++ CAO/Player.py | 43 +++++++++++ CAO/Status.py | 7 ++ CAO/__init__.py | 0 CAO_Board.py | 55 -------------- CAO_Cards.py | 13 ---- CAO_Client.py | 73 ------------------- CAO_Game.py | 206 ----------------------------------------------------- CAO_GameManager.py | 34 --------- CAO_Player.py | 43 ----------- CAO_Status.py | 7 -- server.py | 10 +-- 16 files changed, 436 insertions(+), 436 deletions(-) create mode 100644 CAO/Board.py create mode 100644 CAO/Cards.py create mode 100644 CAO/Client.py create mode 100644 CAO/Game.py create mode 100644 CAO/GameManager.py create mode 100644 CAO/Player.py create mode 100644 CAO/Status.py create mode 100644 CAO/__init__.py delete mode 100644 CAO_Board.py delete mode 100644 CAO_Cards.py delete mode 100644 CAO_Client.py delete mode 100644 CAO_Game.py delete mode 100644 CAO_GameManager.py delete mode 100644 CAO_Player.py delete mode 100644 CAO_Status.py diff --git a/CAO/Board.py b/CAO/Board.py new file mode 100644 index 0000000..4f4e7c6 --- /dev/null +++ b/CAO/Board.py @@ -0,0 +1,55 @@ +import random + +class Board(): + def __init__(self, white_cards, black_cards): + self.white_pick = white_cards + self.black_pick = black_cards + + self.white_recycled = [] + self.black_recycled = [] + + self.current_black_card = None + + # tupple of cards / player currently being played + self.played_cards = [] + + random.shuffle(self.white_pick) + random.shuffle(self.black_pick) + + def reveal_black_card(self): + if not self.black_pick: + self.black_pick = self.black_recycle + + random.shuffle(self.black_pick) + + self.black_recycled = [] + + card = self.black_pick.pop() + + self.current_black_card = card + + def recycle_black_card(self): + self.black_recycled.append(self.current_black_card) + + def pick_white_card(self): + if not self.white_pick: + self.white_pick = self.white_recycled + + random.shuffle(self.white_pick) + + self.white_recycled = [] + + card = self.white_pick.pop() + + return card + + def play_card(self, player, card): + self.played_cards.append((card, player)) + + def shuffle_played_cards(self): + random.shuffle(self.played_cards) + + def recycle_played_cards(self): + self.white_recycled += [i[0] for i in self.played_cards] + + self.played_cards = [] diff --git a/CAO/Cards.py b/CAO/Cards.py new file mode 100644 index 0000000..b796b97 --- /dev/null +++ b/CAO/Cards.py @@ -0,0 +1,13 @@ +class Cards(): + @staticmethod + def get_white_cards(lang): + ''' Read the file containing the white cards and return a list of cards ''' + with open('lang/' + lang + '/cards/white') as fd: + return [line.strip() for line in fd] + + @staticmethod + def get_black_cards(lang): + ''' Read the file containing the black cards and return a list of cards ''' + + with open('lang/' + lang + '/cards/black') as fd: + return [line.strip() for line in fd] diff --git a/CAO/Client.py b/CAO/Client.py new file mode 100644 index 0000000..03bb68d --- /dev/null +++ b/CAO/Client.py @@ -0,0 +1,73 @@ +from CAO.Status import cao_error +from CAO.Game import Game + +class Client(): + def __init__(self, socket, handler, game_manager): + self.game = None + self.game_manager = game_manager + + self.handler = handler + self.socket = socket + self.player = None + + def join_game(self, game_name, lang): + if self.game is not None: + return cao_error('You are already in a game') + + if lang is None: + lang = 'en' + + game = self.game_manager.join_game(game_name, lang) + # XXX self.game will be assigned by game.try_join() + + if game is None: + return cao_error('Invalid language') + + return game.try_join(self) + + def set_game(self, game): + self.game = game + def set_player(self, player): + self.player = player + + def play_white_card(self, card_id): + if self.game is None: + return cao_error('You have to join a game first') + return self.game.try_play_card(self.player, card_id) + + def pick_black_card(self): + if self.game is None: + return cao_error('You have to join a game first') + return self.game.try_become_judge(self.player) + + def collect_cards(self): + if self.game is None: + cao_error('You have to join a game first') + return self.game.try_collect_cards(self.player) + + def designate_card(self, card_id): + if self.game is None: + return cao_error('You have to join a game first') + return self.game.try_designate_card(self.player, card_id) + + def view_player_cards(self): + if self.game is None: + return cao_error('You have to join a game first') + return self.game.try_view_player_cards(self.player) + + def view_played_cards(self): + if self.game is None: + return cao_error('You have to join a game first') + return self.game.try_view_played_cards(self.player) + + def view_black_card(self): + if self.game is None: + return cao_error('You have to join a game first') + return self.game.try_view_black_card(self.player) + + def send_notification(self, message): + self.socket.send_message(self.handler, message) + + def disconnect(self): + if self.player is not None: + self.player.client = None diff --git a/CAO/Game.py b/CAO/Game.py new file mode 100644 index 0000000..f4123d4 --- /dev/null +++ b/CAO/Game.py @@ -0,0 +1,206 @@ +from CAO.Player import Player +from CAO.Board import Board + +from CAO.Status import cao_error, cao_success + +import json + +class Game(): + WAITING_NEW_JUDGE = 0, + WAITING_COLLECTION = 1, + WAITING_DESIGNATION = 2, + + + def __init__(self, white_desc, black_desc): + self.white_desc = white_desc + self.black_desc = black_desc + + white_pick = [i for i in range(len(self.white_desc))] + black_pick = [i for i in range(len(self.black_desc))] + + self.state = self.WAITING_NEW_JUDGE + + self.players = [] + + self.judge = None + + self.board = Board(white_pick, black_pick) + + def try_join(self, client): + if len(self.players) >= 10: + return cao_error('too many players in this game') + + cards = [] + + try: + for i in range(10): + cards.append(self.board.pick_white_card()) + except IndexError: + return cao_error('no enough white cards for player') + + player = Player(client) + + for card in cards: + player.receive_card(card) + + client.set_player(player) + client.set_game(self) + + self.players.append(player) + + for p in self.players: + if p is not player: + p.send_notification({'op': 'player_joined_game'}) + + cards = self.__view_player_cards(player) + + if self.state is self.WAITING_NEW_JUDGE: + state = 'waiting_judge' + elif self.state is self.WAITING_COLLECTION: + state = 'waiting_collection' + else: + state = 'waiting_designation' + + return cao_success({'cards': cards, 'game_state': state}) + + + def try_become_judge(self, player): + if self.state is not self.WAITING_NEW_JUDGE: + # TODO what if the judge has quit ? + return cao_error('Someone is judge already') + + self.judge = player + self.board.reveal_black_card() + + self.state = self.WAITING_COLLECTION + + for p in self.players: + if p is not player: + p.send_notification({'op': 'judge_designed'}) + + return self.try_view_black_card(player) + + + def try_play_card(self, player, card_id): + if self.state is not self.WAITING_COLLECTION: + return cao_error('Who asked you to play now ?!') + + if self.judge is player: + return cao_error('You\'re the judge, you silly') + elif player.get_has_played(): + return cao_error('You already played, you dumb ass') + + try: + card = player.pop_card(card_id) + except IndexError: + return cao_error('Invalid card id') + + player.set_has_played() + + self.board.play_card(player, card) + + self.judge.send_notification({'op': 'card_played'}) + + return cao_success({'card_id': card_id}) + + + def try_collect_cards(self, player): + if self.state is not self.WAITING_COLLECTION: + return cao_error('Do you think it\'s the moment for colletion !?') + + if self.judge is not player: + return cao_error('You\'re not the judge, you fool!') + + self.board.shuffle_played_cards() + + # we prevent the others to play + self.state = self.WAITING_DESIGNATION + + for p in self.players: + if p is not player: + p.send_notification({'op': 'cards_collected'}) + + return self.try_view_played_cards(player) + + + def try_designate_card(self, player, card_id): + if self.state is not self.WAITING_DESIGNATION: + return cao_error('Not now, moron !') + + if self.judge is not player: + return cao_error('Who do you think you are !?') + + if card_id is None and len(self.board.played_cards) > 0: + return cao_error('There are cards on the board, pick one !') + + if card_id is not None or len(self.board.played_cards) > 0: + # if there are cards on the board + # TODO check exception + try: + card, winner = self.board.played_cards[card_id] + except IndexError: + return cao_error('Invalid card') + + winner.inc_score() + + # put the cards back in the deck + self.board.recycle_played_cards() + + # reset the state of the players + for p in self.players: + if p.get_has_played: + idx = p.receive_card(self.board.pick_white_card()) + card_idx = p.cards[idx] + card_desc = self.white_desc[card_idx] + + p.send_notification({ + 'op': 'received_card', + 'content': { + 'card': { + 'id': idx, + 'desc': card_desc, + }, + }, + }) + p.set_has_played(False) + + self.board.recycle_black_card() + self.judge = None # useful or not ... + + for p in self.players: + if p is not player: + p.send_notification({'op': 'judge_needed'}) + + self.state = self.WAITING_NEW_JUDGE + + return cao_success(None) + + def __view_player_cards(self, player): + cards = [] + + for card in player.cards: + cards.append((card, self.white_desc[player.cards[card]])) + + return cards + + def try_view_player_cards(self, player): + return cao_success(self.__view_player_cards(player)) + + def try_view_played_cards(self, player): + if self.state is not self.WAITING_DESIGNATION: + return cao_error('Not now, moron !') + + cards = [] + + for card, unused in self.board.played_cards: + cards.append(self.white_desc[card]) + + return cao_success(cards) + + def try_view_black_card(self, player): + card = self.board.current_black_card + + if card is not None: + return cao_success(self.black_desc[card]) + + return cao_error('The black card has not been revealed yet') diff --git a/CAO/GameManager.py b/CAO/GameManager.py new file mode 100644 index 0000000..5600f1e --- /dev/null +++ b/CAO/GameManager.py @@ -0,0 +1,34 @@ +from CAO.Game import Game +from CAO.Cards import Cards + +import os + +class GameManager(): + def __init__(self): + self.langs = {} + + for filename in next(os.walk('lang'))[1]: + self.langs[filename] = {} + + for lang in self.langs: + self.langs[lang]['black_cards'] = Cards.get_black_cards(lang) + self.langs[lang]['white_cards'] = Cards.get_white_cards(lang) + + self.langs[lang]['games'] = {} + + def join_game(self, game_name, lang): + if self.langs.get(lang) is None: + return None + + games = self.langs[lang]['games'] + black_cards = self.langs[lang]['black_cards'] + white_cards = self.langs[lang]['white_cards'] + + game = games.get(game_name) + + if game is None: + print('Starting new game') + + game = games[game_name] = Game(white_cards, black_cards) + + return game diff --git a/CAO/Player.py b/CAO/Player.py new file mode 100644 index 0000000..cc64d17 --- /dev/null +++ b/CAO/Player.py @@ -0,0 +1,43 @@ +import json + +class Player(): + def __init__(self, client): + self.cards = {} + self.next_idx = 0 + + self.client = client + + self.score = 0 + + self.has_played = False + + self.name = 'default' + + def pop_card(self, card_id): + return self.cards.pop(card_id) + + def get_has_played(self): + return self.has_played + + def set_has_played(self, has=True): + self.has_played = has + + def inc_score(self): + self.score += 1 + self.send_notification({ + 'op': 'updated_score', + 'content': self.score, + }) + + def receive_card(self, card): + self.cards[self.next_idx] = card + self.next_idx += 1 + return self.next_idx - 1 + + def send_notification(self, obj): + if self.client is None: + return + + message = json.dumps({'type': 'notification', 'content': obj}) + + self.client.send_notification(message) diff --git a/CAO/Status.py b/CAO/Status.py new file mode 100644 index 0000000..782a0b4 --- /dev/null +++ b/CAO/Status.py @@ -0,0 +1,7 @@ +import json + +def cao_error(msg, code=255): + return json.dumps({'type': 'response', 'content': {'status': code, 'info': msg}}) + +def cao_success(obj): + return json.dumps({'type': 'response', 'content': {'status': 0, 'result': obj}}) diff --git a/CAO/__init__.py b/CAO/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/CAO_Board.py b/CAO_Board.py deleted file mode 100644 index 0fd595b..0000000 --- a/CAO_Board.py +++ /dev/null @@ -1,55 +0,0 @@ -import random - -class CAO_Board(): - def __init__(self, white_cards, black_cards): - self.white_pick = white_cards - self.black_pick = black_cards - - self.white_recycled = [] - self.black_recycled = [] - - self.current_black_card = None - - # tupple of cards / player currently being played - self.played_cards = [] - - random.shuffle(self.white_pick) - random.shuffle(self.black_pick) - - def reveal_black_card(self): - if not self.black_pick: - self.black_pick = self.black_recycle - - random.shuffle(self.black_pick) - - self.black_recycled = [] - - card = self.black_pick.pop() - - self.current_black_card = card - - def recycle_black_card(self): - self.black_recycled.append(self.current_black_card) - - def pick_white_card(self): - if not self.white_pick: - self.white_pick = self.white_recycled - - random.shuffle(self.white_pick) - - self.white_recycled = [] - - card = self.white_pick.pop() - - return card - - def play_card(self, player, card): - self.played_cards.append((card, player)) - - def shuffle_played_cards(self): - random.shuffle(self.played_cards) - - def recycle_played_cards(self): - self.white_recycled += [i[0] for i in self.played_cards] - - self.played_cards = [] diff --git a/CAO_Cards.py b/CAO_Cards.py deleted file mode 100644 index 1feecef..0000000 --- a/CAO_Cards.py +++ /dev/null @@ -1,13 +0,0 @@ -class CAO_Cards(): - @staticmethod - def get_white_cards(lang): - ''' Read the file containing the white cards and return a list of cards ''' - with open('lang/' + lang + '/cards/white') as fd: - return [line.strip() for line in fd] - - @staticmethod - def get_black_cards(lang): - ''' Read the file containing the black cards and return a list of cards ''' - - with open('lang/' + lang + '/cards/black') as fd: - return [line.strip() for line in fd] diff --git a/CAO_Client.py b/CAO_Client.py deleted file mode 100644 index c3554ac..0000000 --- a/CAO_Client.py +++ /dev/null @@ -1,73 +0,0 @@ -from CAO_Status import cao_error -from CAO_Game import CAO_Game - -class CAO_Client(): - def __init__(self, socket, handler, game_manager): - self.game = None - self.game_manager = game_manager - - self.handler = handler - self.socket = socket - self.player = None - - def join_game(self, game_name, lang): - if self.game is not None: - return cao_error('You are already in a game') - - if lang is None: - lang = 'en' - - game = self.game_manager.join_game(game_name, lang) - # XXX self.game will be assigned by game.try_join() - - if game is None: - return cao_error('Invalid language') - - return game.try_join(self) - - def set_game(self, game): - self.game = game - def set_player(self, player): - self.player = player - - def play_white_card(self, card_id): - if self.game is None: - return cao_error('You have to join a game first') - return self.game.try_play_card(self.player, card_id) - - def pick_black_card(self): - if self.game is None: - return cao_error('You have to join a game first') - return self.game.try_become_judge(self.player) - - def collect_cards(self): - if self.game is None: - cao_error('You have to join a game first') - return self.game.try_collect_cards(self.player) - - def designate_card(self, card_id): - if self.game is None: - return cao_error('You have to join a game first') - return self.game.try_designate_card(self.player, card_id) - - def view_player_cards(self): - if self.game is None: - return cao_error('You have to join a game first') - return self.game.try_view_player_cards(self.player) - - def view_played_cards(self): - if self.game is None: - return cao_error('You have to join a game first') - return self.game.try_view_played_cards(self.player) - - def view_black_card(self): - if self.game is None: - return cao_error('You have to join a game first') - return self.game.try_view_black_card(self.player) - - def send_notification(self, message): - self.socket.send_message(self.handler, message) - - def disconnect(self): - if self.player is not None: - self.player.client = None diff --git a/CAO_Game.py b/CAO_Game.py deleted file mode 100644 index aac2c57..0000000 --- a/CAO_Game.py +++ /dev/null @@ -1,206 +0,0 @@ -from CAO_Player import CAO_Player -from CAO_Board import CAO_Board - -from CAO_Status import cao_error, cao_success - -import json - -class CAO_Game(): - WAITING_NEW_JUDGE = 0, - WAITING_COLLECTION = 1, - WAITING_DESIGNATION = 2, - - - def __init__(self, white_desc, black_desc): - self.white_desc = white_desc - self.black_desc = black_desc - - white_pick = [i for i in range(len(self.white_desc))] - black_pick = [i for i in range(len(self.black_desc))] - - self.state = self.WAITING_NEW_JUDGE - - self.players = [] - - self.judge = None - - self.board = CAO_Board(white_pick, black_pick) - - def try_join(self, client): - if len(self.players) >= 10: - return cao_error('too many players in this game') - - cards = [] - - try: - for i in range(10): - cards.append(self.board.pick_white_card()) - except IndexError: - return cao_error('no enough white cards for player') - - player = CAO_Player(client) - - for card in cards: - player.receive_card(card) - - client.set_player(player) - client.set_game(self) - - self.players.append(player) - - for p in self.players: - if p is not player: - p.send_notification({'op': 'player_joined_game'}) - - cards = self.__view_player_cards(player) - - if self.state is self.WAITING_NEW_JUDGE: - state = 'waiting_judge' - elif self.state is self.WAITING_COLLECTION: - state = 'waiting_collection' - else: - state = 'waiting_designation' - - return cao_success({'cards': cards, 'game_state': state}) - - - def try_become_judge(self, player): - if self.state is not self.WAITING_NEW_JUDGE: - # TODO what if the judge has quit ? - return cao_error('Someone is judge already') - - self.judge = player - self.board.reveal_black_card() - - self.state = self.WAITING_COLLECTION - - for p in self.players: - if p is not player: - p.send_notification({'op': 'judge_designed'}) - - return self.try_view_black_card(player) - - - def try_play_card(self, player, card_id): - if self.state is not self.WAITING_COLLECTION: - return cao_error('Who asked you to play now ?!') - - if self.judge is player: - return cao_error('You\'re the judge, you silly') - elif player.get_has_played(): - return cao_error('You already played, you dumb ass') - - try: - card = player.pop_card(card_id) - except IndexError: - return cao_error('Invalid card id') - - player.set_has_played() - - self.board.play_card(player, card) - - self.judge.send_notification({'op': 'card_played'}) - - return cao_success({'card_id': card_id}) - - - def try_collect_cards(self, player): - if self.state is not self.WAITING_COLLECTION: - return cao_error('Do you think it\'s the moment for colletion !?') - - if self.judge is not player: - return cao_error('You\'re not the judge, you fool!') - - self.board.shuffle_played_cards() - - # we prevent the others to play - self.state = self.WAITING_DESIGNATION - - for p in self.players: - if p is not player: - p.send_notification({'op': 'cards_collected'}) - - return self.try_view_played_cards(player) - - - def try_designate_card(self, player, card_id): - if self.state is not self.WAITING_DESIGNATION: - return cao_error('Not now, moron !') - - if self.judge is not player: - return cao_error('Who do you think you are !?') - - if card_id is None and len(self.board.played_cards) > 0: - return cao_error('There are cards on the board, pick one !') - - if card_id is not None or len(self.board.played_cards) > 0: - # if there are cards on the board - # TODO check exception - try: - card, winner = self.board.played_cards[card_id] - except IndexError: - return cao_error('Invalid card') - - winner.inc_score() - - # put the cards back in the deck - self.board.recycle_played_cards() - - # reset the state of the players - for p in self.players: - if p.get_has_played: - idx = p.receive_card(self.board.pick_white_card()) - card_idx = p.cards[idx] - card_desc = self.white_desc[card_idx] - - p.send_notification({ - 'op': 'received_card', - 'content': { - 'card': { - 'id': idx, - 'desc': card_desc, - }, - }, - }) - p.set_has_played(False) - - self.board.recycle_black_card() - self.judge = None # useful or not ... - - for p in self.players: - if p is not player: - p.send_notification({'op': 'judge_needed'}) - - self.state = self.WAITING_NEW_JUDGE - - return cao_success(None) - - def __view_player_cards(self, player): - cards = [] - - for card in player.cards: - cards.append((card, self.white_desc[player.cards[card]])) - - return cards - - def try_view_player_cards(self, player): - return cao_success(self.__view_player_cards(player)) - - def try_view_played_cards(self, player): - if self.state is not self.WAITING_DESIGNATION: - return cao_error('Not now, moron !') - - cards = [] - - for card, unused in self.board.played_cards: - cards.append(self.white_desc[card]) - - return cao_success(cards) - - def try_view_black_card(self, player): - card = self.board.current_black_card - - if card is not None: - return cao_success(self.black_desc[card]) - - return cao_error('The black card has not been revealed yet') diff --git a/CAO_GameManager.py b/CAO_GameManager.py deleted file mode 100644 index 8c01547..0000000 --- a/CAO_GameManager.py +++ /dev/null @@ -1,34 +0,0 @@ -from CAO_Game import CAO_Game -from CAO_Cards import CAO_Cards - -import os - -class CAO_GameManager(): - def __init__(self): - self.langs = {} - - for filename in next(os.walk('lang'))[1]: - self.langs[filename] = {} - - for lang in self.langs: - self.langs[lang]['black_cards'] = CAO_Cards.get_black_cards(lang) - self.langs[lang]['white_cards'] = CAO_Cards.get_white_cards(lang) - - self.langs[lang]['games'] = {} - - def join_game(self, game_name, lang): - if self.langs.get(lang) is None: - return None - - games = self.langs[lang]['games'] - black_cards = self.langs[lang]['black_cards'] - white_cards = self.langs[lang]['white_cards'] - - game = games.get(game_name) - - if game is None: - print('Starting new game') - - game = games[game_name] = CAO_Game(white_cards, black_cards) - - return game diff --git a/CAO_Player.py b/CAO_Player.py deleted file mode 100644 index d08a0a1..0000000 --- a/CAO_Player.py +++ /dev/null @@ -1,43 +0,0 @@ -import json - -class CAO_Player(): - def __init__(self, client): - self.cards = {} - self.next_idx = 0 - - self.client = client - - self.score = 0 - - self.has_played = False - - self.name = 'default' - - def pop_card(self, card_id): - return self.cards.pop(card_id) - - def get_has_played(self): - return self.has_played - - def set_has_played(self, has=True): - self.has_played = has - - def inc_score(self): - self.score += 1 - self.send_notification({ - 'op': 'updated_score', - 'content': self.score, - }) - - def receive_card(self, card): - self.cards[self.next_idx] = card - self.next_idx += 1 - return self.next_idx - 1 - - def send_notification(self, obj): - if self.client is None: - return - - message = json.dumps({'type': 'notification', 'content': obj}) - - self.client.send_notification(message) diff --git a/CAO_Status.py b/CAO_Status.py deleted file mode 100644 index 782a0b4..0000000 --- a/CAO_Status.py +++ /dev/null @@ -1,7 +0,0 @@ -import json - -def cao_error(msg, code=255): - return json.dumps({'type': 'response', 'content': {'status': code, 'info': msg}}) - -def cao_success(obj): - return json.dumps({'type': 'response', 'content': {'status': 0, 'result': obj}}) diff --git a/server.py b/server.py index 7391e8e..5d117e9 100755 --- a/server.py +++ b/server.py @@ -1,16 +1,16 @@ #!/usr/bin/env python from websocket_server import WebsocketServer -import CAO_GameManager -import CAO_Client -from CAO_Status import cao_error +import CAO.GameManager +import CAO.Client +from CAO.Status import cao_error import json -game_manager = CAO_GameManager.CAO_GameManager() +game_manager = CAO.GameManager.GameManager() def new_client_handler(client, server): - client['cao_client'] = CAO_Client.CAO_Client(server, client, game_manager) + client['cao_client'] = CAO.Client.Client(server, client, game_manager) def client_left_handler(client, server): client['cao_client'].disconnect(); -- cgit v1.2.3