예제 #1
0
    def getInput(self):
        # get user input, :: printed by GUI thread already
        command = input('')
        data = None

        # first check command isn't empty
        if command != '':
            # draw cards
            if command[0] == 'D':
                data = Move('Draw', self.gui.active_draw)
            # pickup discard pile
            elif command[0] == 'P':
                data = Move('Pickup')
            # select which cards to play facedown
            elif command[0] == 'F':
                try:
                    data = self.inputToMove('Facedown',
                                            command[1:])  # strip the leading F
                except Exception as e:
                    print(e)
            # otherwise assume it is a list of cards to play
            else:
                data = self.inputToMove('Play', command)

        return data
예제 #2
0
    def play_cards(self, index):  # make index an array to play multiple cards

        try:  # try to pop selected cards out of player hand
            _, active_hand = self.valid_cards()
            cards = [
                active_hand.pop(i) for i in sorted(index, reverse=True)
            ]  # Pop indexed cards, need to pop in reverse over to preserve index

        except IndexError:  # if we can't pop cards, we have been given bad index so is_valid is False
            return False

        log.debug(f'2. Cards: {cards}')

        move = Move('Play', cards)
        is_valid, move_return = self.game.do_move(
            self.id, move
        )  # do_move will return the card if not valid move, otherwise empty

        # Need to make this return card to same position it was played out of,
        # perhaps if unsuccessful, don't send any card data just say it failed sorry fam
        if len(move_return) > 0:

            for i, ind in enumerate(index):
                self.in_hand[ind:ind] = [move_return[i]]

        log.debug(f'4. Move is {is_valid}')
        return is_valid
예제 #3
0
    def on_block_button_press_event(self, widget, event, block):
        if self.current_piece is None:
            return

        # Filter double/triple click events
        if event.type != Gdk.EventType.BUTTON_PRESS:
            return

        if event.button == 1:
            move = Move(
                player_id=self.player_id,
                piece_id=self.current_piece.piece_id,
                rotation=self.current_piece_rotation,
                mirror=self.current_piece_mirror,
                position=self.index(block),
            )
            if self.is_valid_move(move):
                self.move_queue.put(move, block=False)
                self.on_block_leave(widget, event, block)
                self.current_piece = None
            else:
                print self._valid_reason
        elif event.button == 2:
            self.on_block_leave(widget, event, block)
            self.current_piece_mirror = not self.current_piece_mirror
            self.on_block_enter(widget, event, block)
        elif event.button == 3:
            self.on_block_leave(widget, event, block)
            self.current_piece_rotation = (self.current_piece_rotation + 1) % 4
            self.on_block_enter(widget, event, block)
예제 #4
0
    def guiThread(self):

        data = self.getInput()

        # send move if we have data
        if data is not None:
            self.socket.send(data.encode())
            log.debug('Sent play')
        # if we have no data, send out null will only cost 26 bytes
        else:
            self.socket.send(Move().encode())
예제 #5
0
    def get_move(self):
        for piece in self.board.get_remaining_piece_ids(self.player_id):
            for rotation in xrange(4):
                for mirror in (False, True):
                    for x in xrange(self.board.cols):
                        for y in xrange(self.board.rows):
                            move = Move(self.player_id, piece, rotation,
                                        mirror, (x, y))
                            if self.board.is_valid_move(move):
                                return move

        return super(ExhaustiveSearchBot, self).get_move()
예제 #6
0
    def thread(self):
        while self.player.valid_cards() != ([], None):
            try:
                package = self.listen_for_moves()
            except BufferError:  # except network error, want to shut down thread/connection
                log.warning(f'Player {self.id} disconnected')
                # client has disconnected so stop trying to send data
                Client.clients = [
                    client for client in Client.clients if client.id != self.id
                ]
                break

            log.info('Handling package')
            move = Move(**package)
            was_valid = self.player.execute_move(move)

            try:
                if was_valid is True:
                    log.info('Sending package to all')
                    self.sendTo(Client.clients, Client.observers,
                                f'Yeet from server courtesy of {self.id}')
                else:
                    log.info(f'Sending package to {self.id}')
                    # need to wrap self in a list here as we try to iterate over it
                    self.sendTo([self], [],
                                f'Yeet from server courtesy of {self.id}')
            except Exception as e:
                print(e)

        if Client.game.current_turn != 0:
            # if we have got to this point we have no cards or disconnected from server mid game and
            # so we should be removed from the game
            Client.game.remove_player(self.id)

            # if we remove a client, we sync client.id with player id
            for client in Client.clients:
                client.id = client.player.id

            # allow player to spectate the rest of the game
            while Client.game.winner is False:
                try:
                    # send updates
                    pass
                except KeyboardInterrupt:
                    break  # Go straight to exit
        else:
            for client in Client.clients:
                if client.id > self.id:
                    client.id -= 1
                    client.player = Client.game.players[client.id]

        self.id = 99  # do this so we can easily identify the current client so we can close it
        self.close()  # remove client and close thread
예제 #7
0
    def inputToMove(self, action, string):

        str_cards = '[' + string + ']'  # convert input into string list

        # try to eval sting list into valid list
        try:
            cards = list(literal_eval(str_cards))
            assert (any(isinstance(x, int) for x in cards))
        # if we can't convert to a valid list, we start again
        except (AssertionError, SyntaxError, ValueError):
            print('Not a valid command, try again you derelict')
            return self.getInput()

        return Move(action, cards)
예제 #8
0
    def is_valid_move(self, player, move):

        action = move.action
        cards = move.cards
        is_valid = False

        if player == self.current_player:
            if action == 'Draw':
                # If current draw cards, valid to draw
                if cards == self.no_to_draw:
                    is_valid = True

                # Also check that we cannot play anything else so draw won't be a valid move
                playing_from, other_cards = self.players[player].valid_cards()

                # Deal with playing from facedown as a legit move
                if playing_from != 'face_down':
                    for card in other_cards:
                        _, other_valid = self.is_valid_move(
                            player, Move('Play', [card]))
                        if other_valid:
                            is_valid = False
                            break
                # Insert gambling logic here
                else:
                    pass

            elif action == 'Play':
                no_cards = len(cards)

                log.info(f'\nsame active cards: {self.same_active_cards}')
                log.info(f'len cards: {len(cards)}\n')

                # Check if we are trying to play more than one card
                if no_cards > 1:
                    # Need to be same value if playing multiple cards
                    values = [card.value for card in cards]
                    same_cards = len(set(values)) == 1
                    if not same_cards:
                        # Return straight away if not the same cards
                        return action, False

                # Normal gameplay
                if self.active_draw_card is None:
                    # This takes into account power cards: 6 >= 7 is True, Draw 4 >= Draw 2 == False
                    if cards[0] >= self.active_card:
                        is_valid = True

                        # Check for burns
                        if len(self.discard_pile.deck) != 0:

                            if cards[0].value == self.discard_pile.deck[
                                    0].value:
                                log.info(
                                    f'inn turnn burn, 4 should be {no_cards + self.same_active_cards}'
                                )
                                if no_cards + self.same_active_cards == 4:
                                    action = 'Burn'

                            # 10 auto burns, easy case
                            elif len(cards) == 4 or cards[0].value == '10':
                                action = 'Burn'

                        elif len(cards) == 4 or cards[0].value == '10':
                            action = 'Burn'

                # There is an active draw card
                else:
                    if cards[0] >= self.active_draw_card:
                        is_valid = True
                        # Still want to burn
                        if cards[0].value == self.discard_pile.deck[0].value:
                            if no_cards + self.same_active_cards == 4:
                                action = 'Burn'

            elif action == 'Pickup':

                # cannot pickup if there is a draw card
                if self.active_draw_card is None:

                    # otherwise assume pickup is true
                    is_valid = True
                    active_hand, playable_cards = self.players[
                        player].valid_cards()

                    # if we are playing out of face down cards, pickup will always be true
                    # however if you can play something else, not valid to pickup
                    for card in playable_cards:
                        print(f'card: {card.value}')
                        _, other_valid = self.is_valid_move(
                            player, Move('Play', [card]))
                        print(other_valid)
                        if other_valid is True:
                            is_valid = False
                            break
        else:
            if action == 'Play':

                # Check if we are trying to play more than one card
                if len(cards) > 1:
                    # Need to be same value if playing multiple cards
                    values = [card.value for card in cards]
                    same_cards = len(set(values)) == 1
                    if not same_cards:
                        # Return straight away if not the same cards
                        return action, False

                # Deal with the case when we are playing the first card
                if self.active_card == '':
                    log.debug(f'3. Playing on {self.active_card}')

                    # Need to be same value if playing multiple cards
                    values = [card.value for card in cards]
                    log.debug(f'3.1 Values: {values}')
                    same_cards = set(values) == set(
                        ['4'])  # Check we are playing a 4
                    log.debug(f'3.2 Same cards: {same_cards}')
                    if same_cards:
                        # TO DO: EXPAND THIS IF NO 4s (pretty rare I think)
                        # MAKE PEOPLE PICK UP IN ORDER TILL SOMEONE HAS A 4 to play
                        # P(No 4s) = C(124/HAND SIZE * NO PLAYERS) / C(132/HAND SIZE * NO PLAYERS) = 0.6%
                        is_valid = True

                # Otherwise assume we are trying to burn out of turn
                else:
                    if len(self.discard_pile.deck) != 0:
                        if cards[0].value == self.discard_pile.deck[0].value:
                            if len(cards) + self.same_active_cards == 4:
                                log.info('out of turn burnnnnnnn')
                                action = 'Burn'
                                is_valid = True

        log.info(f'action {action}, valid {is_valid}')
        return action, is_valid