diff options
| author | Olivier Gayot <duskcoder@gmail.com> | 2015-06-14 22:31:48 +0100 | 
|---|---|---|
| committer | Olivier Gayot <duskcoder@gmail.com> | 2015-06-14 22:37:40 +0100 | 
| commit | 0fb08748e5285e5d4adc6135eec8889887a63299 (patch) | |
| tree | 3a82c2899f33a8d4234b07799cff00865c8e141c /CAO | |
| parent | ad12c67adcc8e3c0f29814b1b95959ac4b9f4a4d (diff) | |
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 <duskcoder@gmail.com>
Diffstat (limited to 'CAO')
| -rw-r--r-- | CAO/Board.py | 55 | ||||
| -rw-r--r-- | CAO/Cards.py | 13 | ||||
| -rw-r--r-- | CAO/Client.py | 73 | ||||
| -rw-r--r-- | CAO/Game.py | 206 | ||||
| -rw-r--r-- | CAO/GameManager.py | 34 | ||||
| -rw-r--r-- | CAO/Player.py | 43 | ||||
| -rw-r--r-- | CAO/Status.py | 7 | ||||
| -rw-r--r-- | CAO/__init__.py | 0 | 
8 files changed, 431 insertions, 0 deletions
| 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 --- /dev/null +++ b/CAO/__init__.py | 
