Exemple #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
Exemple #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
Exemple #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)
Exemple #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())
Exemple #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()
Exemple #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
Exemple #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)
Exemple #8
0
    def player(self, player_id):
        l = threading.local()
        l.is_first_move = True

        with self.lock:
            l.sock, l.user = self.server.get_connection()
            self.socks[player_id] = l.sock

        m = Message(l.sock)
        if not m.match(Message.TYPE_CONTROL, "JOIN"):
            raise
        print "Got JOIN from %s (assigned player_id %d)" % (l.user, player_id)

        Message.serialized(l.sock, Message.TYPE_ID, player_id)
        Message.serialized(l.sock, Message.TYPE_BOARD, self.board)

        Message.serialized(l.sock, Message.TYPE_CONTROL, "WAIT")

        self.arrival_sem.release()

        while True:
            self.go_sem[player_id].acquire()

            if self.done:
                break

            if not self.skips[player_id]:
                if len(self.board.get_remaining_piece_ids(player_id)) == 0:
                    move = Move.skip(player_id)
                else:
                    try:
                        Message.serialized(l.sock, Message.TYPE_CONTROL,
                                           "TURN")

                        m = Message(l.sock, Message.TYPE_MOVE)
                        move = m.message_object
                    except IOError:
                        move = Move.dropped_skip(player_id)

                    if not self.board.is_valid_move(move):
                        Message.serialized(l.sock, Message.TYPE_STATUS,\
                                [Bot.STATUS_SKIPPED, "Illegal Move"])
                        print 'ILLEGAL:', move
                        print ' REASON:', self.board._valid_reason
                        move = Move.illegal(player_id)
                    else:
                        l.is_first_move = False

                if move.is_skip():
                    self.skips[player_id] = True

                    if sum(self.skips) == 4:
                        self.game_logger.add_move(move)
                        print "=================="
                        print "4 skips. Game Over"
                        for s in self.socks:
                            Message.serialized(s,
                                               Message.TYPE_MOVE,
                                               move,
                                               suppress_err=True)
                        self.done = True
                        for s in self.go_sem:
                            s.release()
                        break

                self.game_logger.add_move(move)

                for s in self.socks:
                    Message.serialized(s,
                                       Message.TYPE_MOVE,
                                       move,
                                       suppress_err=True)

            self.go_sem[(player_id + 1) % 4].release()

        Message.serialized(l.sock, Message.TYPE_STATUS,\
                [Bot.STATUS_GAME_OVER, "This game has ended"])
Exemple #9
0
 def get_move(self):
     assert not hasattr(super(Bot), 'get_move')
     return Move.skip(self.player_id)
Exemple #10
0
 def get_move(self):
     assert not hasattr(super(Bot), 'get_move')
     return Move.skip(self.player_id)
Exemple #11
0
 def on_skip(self, widget, data=None):
     move = Move.skip(self.player_id)
     self.move_queue.put(move, block=False)
     self.current_piece = None
Exemple #12
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
Exemple #13
0
    def player(self, player_id):
        l = threading.local()
        l.is_first_move = True

        with self.lock:
            l.sock, l.user = self.server.get_connection()
            self.socks[player_id] = l.sock

        m = Message(l.sock)
        if not m.match(Message.TYPE_CONTROL, "JOIN"):
            raise
        print "Got JOIN from %s (assigned player_id %d)" % (l.user, player_id)

        Message.serialized(l.sock, Message.TYPE_ID, player_id)
        Message.serialized(l.sock, Message.TYPE_BOARD, self.board)

        Message.serialized(l.sock, Message.TYPE_CONTROL, "WAIT")

        self.arrival_sem.release()

        while True:
            self.go_sem[player_id].acquire()

            if self.done:
                break

            if not self.skips[player_id]:
                if len(self.board.get_remaining_piece_ids(player_id)) == 0:
                    move = Move.skip(player_id)
                else:
                    try:
                        Message.serialized(l.sock, Message.TYPE_CONTROL, "TURN")

                        m = Message(l.sock, Message.TYPE_MOVE)
                        move = m.message_object
                    except IOError:
                        move = Move.dropped_skip(player_id)

                    if not self.board.is_valid_move(move):
                        Message.serialized(l.sock, Message.TYPE_STATUS,\
                                [Bot.STATUS_SKIPPED, "Illegal Move"])
                        print 'ILLEGAL:',move
                        print ' REASON:',self.board._valid_reason
                        move = Move.illegal(player_id)
                    else:
                        l.is_first_move = False

                if move.is_skip():
                    self.skips[player_id] = True

                    if sum(self.skips) == 4:
                        self.game_logger.add_move(move)
                        print "=================="
                        print "4 skips. Game Over"
                        for s in self.socks:
                            Message.serialized(s, Message.TYPE_MOVE, move, suppress_err=True)
                        self.done = True
                        for s in self.go_sem:
                            s.release()
                        break

                self.game_logger.add_move(move)

                for s in self.socks:
                    Message.serialized(s, Message.TYPE_MOVE, move, suppress_err=True)

            self.go_sem[(player_id+1) % 4].release()

        Message.serialized(l.sock, Message.TYPE_STATUS,\
                [Bot.STATUS_GAME_OVER, "This game has ended"])
Exemple #14
0
 def on_skip(self, widget, data=None):
     move = Move.skip(self.player_id)
     self.move_queue.put(move, block=False)
     self.current_piece = None