Exemple #1
0
 def test_draw_card_fresh_deck(self):
     deck = Deck(colors=('red', 'blue'), numbers=(1, 2, 3))
     len_before = len(deck)
     card = deck.draw_card()
     len_after = len(deck)
     assert len_before == len_after + 1
     assert card not in deck.card_list
 def test_init_deck(self):
     deck = Deck()
     deck.initialize()
     unique_cards = set(deck.cards)
     self.assertEqual(self.deck_size, len(unique_cards))
     for card in unique_cards:
         self.assertTrue(isinstance(card, Card))
Exemple #3
0
 def test_draw_card_empty(self):
     deck = Deck(colors=('red', ), numbers=(1, 2))
     card1 = deck.draw_card()
     card2 = deck.draw_card()
     assert len(deck) == 0
     assert card1 not in deck.card_list
     assert card2 not in deck.card_list
     with pytest.raises(IndexError) as excinfo:
         card3 = deck.draw_card()
     assert str(excinfo.value) == "Cannot draw card from an empty deck."
Exemple #4
0
 def test_draw_card_multiple_draws(self):
     deck = Deck(colors=('red', 'blue'), numbers=(1, 2, 3))
     len_before = len(deck)
     card1 = deck.draw_card()
     card2 = deck.draw_card()
     card3 = deck.draw_card()
     len_after = len(deck)
     assert len_before == len_after + 3
     assert card1 not in deck.card_list
     assert card2 not in deck.card_list
     assert card3 not in deck.card_list
Exemple #5
0
 def test_deck_correctness(self):
     deck = Deck(shuffle=True, is_small=False)
     cards = [deck.pull_out() for _ in range(52)]
     with self.subTest():
         with self.assertRaises(EmptyDeckException):
             deck.pull_out()
     with self.subTest():
         sorted_cards = []
         for suit in SUIT:
             for value in VALUE:
                 sorted_cards.append(Card(suit, value))
         self.assertNotEqual(cards, sorted_cards)
 def test_deal(self):
     player1 = Player("player1", 1000)
     player2 = Player("player2", 1000)
     seating = Seating([player1, player2])
     deck = Deck()
     deck.initialize()
     dealer = Dealer(deck, seating)
     dealer.deal_cards_to_players()
     hand_size = 2
     cards_dealt = len(seating.players) * hand_size
     self.assertEqual(cards_dealt, len(set(player1.cards + player2.cards)))
     expected_remaining_card_count = TestDeck.deck_size - cards_dealt
     self.assertEqual(expected_remaining_card_count, len(deck.cards))
Exemple #7
0
 def __init__(self, players, deck_seed=False):
     num_players = len(players)
     if not 2 <= num_players <= 5:
         raise Exception("There must be between 2 and 5 players")
     for player in players:
         if not isinstance(player, Player):
             raise Exception("All players must inherit from the Player class.")
     self.colors = ('r', 'y', 'g', 'w', 'b')  # TODO: rainbow/mixed/wilds
     self.numbers = (1, 1, 1, 2, 2, 3, 3, 4, 4, 5)
     self.players = players
     self.deck = Deck(colors=self.colors, numbers=self.numbers, seed=deck_seed)
     self.player_hands = [[] for _ in range(len(self.players))]
     self.master_game_state = GameState(Board(self.deck), self.player_hands)
     self.game_almost_over = None
Exemple #8
0
    def __init__(self):

        # sub-objects
        self.players = dict()
        self.transitions = None
        self.deck = Deck()

        # shared game state
        self.pot = 0
        self.stack = 8
        self.kobayakawa = None
        self.discarded = []

        # transient state variables (used during betting round)
        self._contenders = []
        self._turn_winner = None
 def test_collect_blinds(self):
     initial_stack = 1000
     small_blind_size = 5
     big_blind_size = small_blind_size * 2
     button_player = self.setup_new_player("Button", initial_stack)
     player2 = self.setup_new_player("SmallBlind", initial_stack)
     player3 = self.setup_new_player("BigBlind", initial_stack)
     seating = Seating([button_player, player2, player3])
     deck = Deck()
     dealer = Dealer(deck, seating)
     dealer.pot = Pot()
     dealer.collect_blinds(small_blind_size)
     self.assertEqual(initial_stack, button_player.stack)
     self.assertEqual(initial_stack - small_blind_size, player2.stack)
     self.assertEqual(initial_stack - big_blind_size, player3.stack)
     self.assertEqual(big_blind_size + small_blind_size,
                      dealer.pot.total_count())
     dealer.move_button()
     dealer.pot = Pot()
     dealer.collect_blinds(small_blind_size)
     self.assertEqual(initial_stack - big_blind_size, button_player.stack)
     self.assertEqual(initial_stack - small_blind_size, player2.stack)
     self.assertEqual(initial_stack - big_blind_size - small_blind_size,
                      player3.stack)
     self.assertEqual(big_blind_size + small_blind_size,
                      dealer.pot.total_count())
     self.assertTrue(button_player in dealer.pot.chips_per_player)
     self.assertTrue(player3 in dealer.pot.chips_per_player)
 def test_move_button__when5players(self):
     player1 = self.setup_new_player("Player1", 100)
     player2 = self.setup_new_player("Player2", 100)
     initial_button_player = self.setup_new_player("Button", 100)
     initial_sb_player = self.setup_new_player("SmallBlind", 100)
     initial_bb_player = self.setup_new_player("BigBlind", 100)
     seating = Seating([
         player1, player2, initial_button_player, initial_sb_player,
         initial_bb_player
     ])
     deck = Deck()
     dealer = Dealer(deck, seating)
     dealer.move_button()
     seating.button_position = 0
     dealer.move_button()
     seating.button_position = 1
     dealer.move_button()
     seating.button_position = 2
     dealer.move_button()
     seating.button_position = 3
     dealer.move_button()
     seating.button_position = 4
     dealer.move_button()
     seating.button_position = 5
     dealer.move_button()
     seating.button_position = 0
Exemple #11
0
 def setUp(self):
     self.controller_1 = ManualController(0)
     self.controller_2 = ManualController(1)
     self.user_1 = User(0, self.controller_1)
     self.user_2 = User(1, self.controller_2)
     self.engine = Engine()
     self.engine.add_user(self.user_1)
     self.engine.add_user(self.user_2)
     self.engine.deck = Deck(shuffle=False, is_small=False)
Exemple #12
0
    def __init__(self):
        self.card_images = []
        deck = Deck().all_cards
        for card in deck:
            photo = Image.open('graphics/images/c{}.jpg'.format(card))
            self.card_images.append(ImageTk.PhotoImage(photo))

        photo = Image.open('graphics/images/cardback.jpg')
        self.card_back = ImageTk.PhotoImage(photo)
 def start_game_awaiting(self):
     resp = requests.post(server_url + '/start', json={'id': client_id})
     data = resp.json()
     while self.players_info:
         self.menu.rem_player()
     for player in data['players']:
         self.menu.add_player(username=player[0], ai=False)
     if data['status'] == 'OK' and data['ready']:
         self.start_game(Deck(str_deck=data['deck']))
     else:
         self.after(100, self.start_game_awaiting)
 def test_move_button__when2players(self):
     initial_button_player = self.setup_new_player("Button", 100)
     initial_bb_player = self.setup_new_player("BigBlind", 100)
     seating = Seating([initial_button_player, initial_bb_player])
     deck = Deck()
     dealer = Dealer(deck, seating)
     dealer.move_button()
     seating.button_position = 0
     dealer.move_button()
     seating.button_position = 1
     dealer.move_button()
     seating.button_position = 0
    def test_shuffle(self):
        def is_deck_shuffled(list1, list2):
            is_different = False
            for i in range(len(list1)):
                if list1[i] != list2[i]:
                    is_different = True
            return is_different

        deck = Deck()
        deck.initialize()
        list_of_cards1 = list(deck.cards)
        deck.shuffle()
        list_of_cards2 = list(deck.cards)
        self.assertTrue(is_deck_shuffled(list_of_cards1, list_of_cards2))
        deck.shuffle()
        list_of_cards3 = list(deck.cards)
        self.assertTrue(is_deck_shuffled(list_of_cards3, list_of_cards2))
 def start_game(self, deck=None):
     self.master.geometry('1100x250')
     deck = Deck() if deck is None else deck
     self.engine = Engine(deck)
     for user in self.users:
         self.engine.add_user(user)
     self.engine.init_game()
     self.engine.update_users()
     for user in self.engine.get_active_users():
         self.active_users_queue.put(user)
     user = self.active_users_queue.get()
     self.engine.process_turn(
         user, user.make_turn(*self.engine.get_game_table_info()))
     if self.engine.is_ended():
         self.engine.outcomes_notify(self.engine.generate_outcomes())
 def test_collect_blinds__when_player_dont_have_enough_chips(self):
     initial_stack = 100
     small_blind_size = 5
     big_blind_size = small_blind_size * 2
     button_player = self.setup_new_player("Button", 100)
     player2 = self.setup_new_player("SmallBlind", small_blind_size - 1)
     player3 = self.setup_new_player("BigBlind", big_blind_size - 1)
     seating = Seating([button_player, player2, player3])
     deck = Deck()
     dealer = Dealer(deck, seating)
     dealer.pot = Pot()
     dealer.collect_blinds(small_blind_size)
     self.assertEqual(initial_stack, button_player.stack)
     self.assertEqual(0, player2.stack)
     self.assertEqual(0, player3.stack)
     self.assertEqual(13, dealer.pot.total_count())
     self.assertTrue(player2 in dealer.pot.chips_per_player)
     self.assertTrue(player3 in dealer.pot.chips_per_player)
Exemple #18
0
 def construct_inferred_deck(self, game_state):
     new_deck = Deck(colors=game_state.board.deck_colors,
                     numbers=game_state.board.deck_numbers,
                     seed=42)
     # remove cards that have been discarded
     for card in game_state.board.discard:
         new_deck.card_list.remove(card)
     # remove cards in other player's hands
     hand_indexes = range(len(game_state.player_hands))
     hand_indexes.remove(game_state.player_id)
     for hand_id in hand_indexes:
         for card in game_state.player_hands[hand_id]:
             new_deck.card_list.remove(card)
     # remove cards that have already scored points
     for color, stacked_cards in game_state.board.card_stacks.iteritems():
         for card in stacked_cards.cards_played:
             new_deck.card_list.remove(card)
     return new_deck
Exemple #19
0
 def test_init_defaults(self):
     deck = Deck()
     # Ensure card count == whatever defaults should predict
     assert len(deck) == len(deck.card_colors) * len(deck.card_numbers)
from flask import Flask, jsonify, request
from engine.deck import Deck

app = Flask(__name__)

players_count = 2
users = {}
deck = Deck()
whose_turn, turn_result = 0, None
next_turn, step_number = None, 0
accept_turn = set()


@app.route("/connect", methods=['POST'])
def connect():
    data = request.get_json()
    if data['name'] and data['name'] not in map(lambda v: v['name'],
                                                users.values()):
        if players_count > len(users):
            new_id = len(users)
            users[new_id] = {
                'id': new_id,
                'name': data['name'],
                'ready': False
            }
            return jsonify(status='OK', id=new_id)
        return jsonify(status='FAIL', error_msg='Server is full.')
    return jsonify(status='FAIL', error_msg='The nickname is already taken')


@app.route("/start", methods=['POST'])
Exemple #21
0
 def __init__(self, deck=None):
     self.users = []
     self.deck = Deck(shuffle=True,
                      is_small=False) if deck is None else deck
     self.bj_gametable = None
     self.is_inited = False
Exemple #22
0
 def test_shuffle_no_seed(self, mock_seed, mock_shuffle):
     # call it twice, ensure it's the same order?
     deck = Deck()
     deck.shuffle()
     assert not mock_seed.called, 'seed was set and should not have been'
     mock_shuffle.assert_called_once_with(deck.card_list)
def clear():
    global users, deck, whose_turn, turn_result
    users = {}
    deck = Deck()
    whose_turn, turn_result = 0, None
    return jsonify(status='OK')
Exemple #24
0
 def test_init_empty_numbers(self):
     with pytest.raises(ValueError) as excinfo:
         numbers = ()
         deck = Deck(numbers=numbers)
     assert str(
         excinfo.value) == "Decks must have at least one card number."
Exemple #25
0
 def test_shuffle_seed(self, mock_seed, mock_shuffle):
     # Assert the seed is used before shuffle is called
     deck = Deck()
     deck.shuffle(seed=1234)
     mock_seed.assert_called_once_with(1234)
     mock_shuffle.assert_called_once_with(deck.card_list)
Exemple #26
0
 def test_init_empty_colors(self):
     with pytest.raises(ValueError) as excinfo:
         colors = ()
         deck = Deck(colors=colors)
     assert str(excinfo.value) == "Decks must have at least one card color."
Exemple #27
0
 def test_init_custom_everything(self):
     numbers = (1, 2, 3)
     colors = ('red', 'blue')
     deck = Deck(colors=colors, numbers=numbers)
     assert len(deck) == 6
Exemple #28
0
 def test_init_custom_numbers(self):
     numbers = (1, 2, 3)
     deck = Deck(numbers=numbers)
     assert len(deck) == len(deck.card_colors) * 3
Exemple #29
0
 def test_init_custom_colors(self):
     colors = ('red', 'blue')
     deck = Deck(colors=colors)
     assert len(deck) == 2 * len(deck.card_numbers)
Exemple #30
0
class GameEngine:
    """
    Administrates and monitors all aspect of a game of Kobayakawa
    Maintaining the progression indicator is delegated to GameTransitionIterator
    Dealing with players actions is delegated to functions in engine.actions
    """
    def __init__(self):

        # sub-objects
        self.players = dict()
        self.transitions = None
        self.deck = Deck()

        # shared game state
        self.pot = 0
        self.stack = 8
        self.kobayakawa = None
        self.discarded = []

        # transient state variables (used during betting round)
        self._contenders = []
        self._turn_winner = None

    """
        External API
    """

    def attach_player(self, player):
        self.players[player.name] = player
        GameEvent(Events.PLAYER_JOINED, player.name)

    def start_game(self, starting_player_name):

        assert len(self.players) > 0
        assert starting_player_name in self.players_by_name

        self.transitions = GameStateIterator(self, starting_player_name)
        self.transitions.start_of_phase = self._resolve_start_of_phase
        self.transitions.end_of_phase = self._resolve_end_of_phase
        self.transitions.end_of_turn = self._resolve_end_of_turn
        self.transitions.end_of_game = self._resolve_end_of_game

        self.pot = 0

        for transition in self.transitions:
            player_name = transition.active_player
            player = self.players[player_name]
            move = player.do(self.transitions.current_phase)
            move(player, self)

    def terminate(self):
        # detach all players from positions
        players = list(self.players.keys())
        for player in players:
            self.players[player] = None

    @property
    def players_by_name(self):
        return list(self.players.keys())

    def place_forced_bet(self):
        minimum_bet = 1
        if self.transitions.turn_number == 7:
            minimum_bet = 2
        self.pot, self.stack = self.pot + minimum_bet, self.stack - minimum_bet

    @property
    def contenders(self):
        return self._contenders[:]  # return a COPY of that list

    def add_contender(self, player_name):
        assert player_name in self.players_by_name
        assert player_name not in self._contenders
        self._contenders.append(player_name)

    """
        API for player agents
    """

    def sees(self, player_name):

        # can see all discarded cards
        # can see kobayakawa and previously covered kobayakawa
        # can see stack from players other than itself
        # can see current bets
        # can see past actions of all players in the current turn (redundant?)

        assert player_name in self.players_by_name
        players = self.players.values()
        discarded = set(self.discarded)
        for p in players:
            discarded = set(chain(discarded, p.discarded))
        players_stack = {p.name: p.stack for p in players}
        players_bet = {p.name: p.has_bet for p in players}

        from collections import namedtuple
        GameData = namedtuple('GameData',
                              'players discarded kobayakawa stacks bets')

        return GameData(self.players_by_name, discarded, self.kobayakawa,
                        players_stack, players_bet)

    """
    State machine internal transition methods
    """

    def _resolve_start_of_phase(self):
        self.transitions.current_phase.on_start()

    def _resolve_end_of_phase(self):
        GameEvent(Events.END_OF_PHASE, self.transitions.turn_number,
                  self.transitions.current_phase.name)
        self.transitions.current_phase.on_end()

    def _reset(self):
        """
        self called in between turns
        Note that self.stack is not reset
        """
        self.pot = 0
        self.kobayakawa = None
        self.discarded = []

        # get all cards into random.deck and shuffles
        for player in self.players.values():
            player.reset()

        self.deck.reset()

    def _ascertain_winner(self):
        """
        I tell who the winner is at the end of turn
        """

        if len(self._contenders) == 0:
            # this means that nobody has bet, can only happen by chance when all players positions
            # are random agents. the winner should be the last player to have played
            winner = self.transitions.active_player
        elif len(self._contenders) == 1:
            # automatic winner, no showdown
            winner = self._contenders[0]
        else:
            """
            SHOWDOWN!!!!!
            """
            for player_name in self._contenders:
                card = self.players[player_name].has_card
                GameEvent(Events.PLAYER_SHOWDOWN, player_name, card)

            player_cards = {
                self.players[name].has_card: name
                for name in self._contenders
            }
            min_card = min(player_cards.keys())
            max_card = max(player_cards.keys())

            if min_card + self.kobayakawa > max_card:
                winner = player_cards[min_card]
                GameEvent(Events.WINNING_FIGURE_MIN, min_card, self.kobayakawa,
                          max_card)

            elif max_card > min_card + self.kobayakawa:
                winner = player_cards[max_card]
                GameEvent(Events.WINNING_FIGURE_MAX, max_card, min_card,
                          self.kobayakawa)

            else:  # it's a draw
                GameEvent(Events.DRAW, max_card, min_card, self.kobayakawa)
                player_a = player_cards[min_card]
                player_b = player_cards[max_card]

                winner = self.transitions.closest_from_first_player(
                    player_a, player_b)

        self._contenders = []

        return winner

    def _check_eliminated_players(self):
        """
        part of end of turn resolution
        I check whether players have a zero stack at the end of the turn
        so they can be eliminated from the game
        :return: the list of remaining players in the game (by name
        """
        eliminated = []
        kept_players = []
        for (player_name, player) in self.players.items():
            if player.stack == 0:
                eliminated.append(player_name)
            else:
                kept_players.append(player_name)

        if len(eliminated):
            for player_name in eliminated:
                GameEvent(Events.PLAYER_OFF, player_name)
                del self.players[player_name]

        return self.players_by_name

    def _resolve_end_of_turn(self):
        # who has won?
        self._turn_winner = self._ascertain_winner()

        # update game state and give the winner its reward
        gain = self.pot
        self.pot = 0
        self.players[self._turn_winner].stack += gain

        GameEvent(Events.TURN_WINNER, self._turn_winner, gain)

        # clean up broke players
        kept_players = self._check_eliminated_players()
        self.transitions.update_players_list(self._turn_winner, kept_players)

        # reset state for a new turn
        self._reset()

    def _resolve_end_of_game(self):
        players_stacks = [(player.stack, player.name)
                          for player in self.players.values()]
        players_stacks = sorted(players_stacks,
                                key=lambda t: t[0],
                                reverse=True)
        gain, winner = players_stacks[0]
        winners = [winner]
        for (stack, player) in players_stacks[1:]:
            if stack == gain:
                winners.append(player)
        if len(winners) > 1:
            s = ', '.join(winners[:-1]) + ' and ' + winners[-1]
            GameEvent(Events.GAME_END_MULTIPLE_WINNERS, s, gain)
        else:
            GameEvent(Events.GAME_END_SINGLE_WINNER, winner, gain)