Example #1
1
    def turn(self):
        '''Tell the players whos turn it is.'''
        if not self.turn_order:
            return gr('The game has yet to start. No turns yet.')
        else:
            s = 'It is %s\'s turn to play.' % self.turn_order[0]
            if not self.notes_up in self.notes:
                s += ' (Note: no hints remaining.)'

            return gr(s)
Example #2
0
    def swap_cards(self, A, B):
        '''swap a card within a hand. output is for the group. A and B
        are the position-based index of the cards.'''
        i = self.card_index(A.upper())
        j = self.card_index(B.upper())
        if i is None or j is None:
            message = '!swap card argument must be one of %s' % ', '.join(sorted([c.mark for c in self.hand]))
            return gr(private={self.name: message})

        self.hand[i], self.hand[j] = self.hand[j], self.hand[i]
        return gr(private={self.name:'Swapped cards %s and %s' % (A, B)})
Example #3
0
    def get_table(self):
        ret = gr()
        table = list()
        # sorting by color each time is horrible. 
        for color in sorted(self.table.keys()):
            cards = self.table[color]
            nums = ''.join(sorted([str(c.number) for c in cards]))
            if nums:
                if color == 'rainbow':
                    table.append(self.markup.color('RNBW' + nums, color))
                else:
                    table.append(self.markup.color(color.upper()[0] + nums, color))

        if not table:
            ret.public.append(self.markup.underline('Table: empty'))
        else:
            ret.public.append(self.markup.underline('Table: %s' % ', '.join(table)))

        ret.public.append('Notes: %s, Storms: %s, %d cards remaining.' %
                         (''.join(sorted(self.notes)), ''.join(sorted(self.storms)), len(self.deck)))

        if len(self.discards.keys()):
            ret.public.append(self._get_discards_string())

        if not self._is_game_over():
            ret.merge(self.turn())

            for p in self._players:
                ret.merge(self.get_hands(p))

            for w in self._watchers:
                ret.merge(self.get_hands(w))

        return ret
Example #4
0
    def add_watcher(self, nick):
        if not self._playing:
            return gr(private={nick:'There is no active game.'})
        
        retVal = gr()
        if nick in self._watchers:
            retVal.private[nick].append('You are already observing the game.')
        elif nick in self._players.keys():
            retVal.private[nick].append('You are already in the game as a '
                                        'player. You cannot also watch the '
                                        'game!')
        else: 
            self._watchers.append(nick)
            retVal.public.append('%s is observing the game.' % nick)

        return retVal
Example #5
0
    def _end_game(self):
        score = self.score()

        self._game_over = True
        self._playing = False
        pub = ['-------------------------']
        pub.append('The game is over. Final score is %d.' % score)
        if 0 <= score <= 5:
            pub.append('Oh dear! The crowd booed.')
        elif 6 <= score <= 10:
            pub.append('Poor! Hardly any applause.')
        elif 11 <= score <= 15:
            pub.append('OK! The audience has seen better.')
        elif 16 <= score <= 20:
            pub.append('Good! The audience is pleased!')
        elif 21 <= score <= 24:
            pub.append('Very good! The audience is enthusiastic!')
        elif score == 25:
            if not self._rainbow_game:
                pub.append('Congratulations! It\'s a perfect game! 25 points!')
            else:
                pub.append('Awesome Job!')
        elif 25 <= score <= 29:    # can happen with rainbow cards
            pub.append('Unbelievable! Well done! The audience is amazed!')
        elif score == 30:
            pub.append('Well, aren\'t you all amazing? A perfect score! The audience\'s brains have melted under the onslaught of beauty!')
        else:
            pub.append('Hmm. score should only be in range 0 to 25 (or 30 w/rainbow cards). Somthing is amiss. Might as well play again...')

        pub.append('Final hands are:')
        for player in self._players.values():
            pub.append(player.get_hand())
        
        pub += ['-------------------------']
        return gr(pub)
Example #6
0
    def get_discard_pile(self, nick):
        retVal = gr()
        if not len(self.discards.keys()):
            retVal.private[nick].append('There are no cards in the discard pile.')
            return retVal

        retVal.private[nick].append(self._get_discards_string())
        return retVal
Example #7
0
    def stop_game(self, nick):
        retVal = gr()
        if not nick in self._players.keys():
            retVal.public.append('You must be in the game to stop it.')
        else:
            retVal.merge(self._end_game())

        return retVal
Example #8
0
    def play_card(self, nick, X):
        '''Have player "nick" play card X from his/her hand. "X" is the 
        card ID, e.g. A, B, C, ... N. The output is for group
        consumption.'''
        retVal = gr()
        if not self._in_game_is_turn(nick, retVal):
            return retVal

        i = self._players[nick].card_index(X)
        if i is None:
            retVal.private[nick].append('You tried to play card %s, oops.' % X)
            retVal.private[nick].append('Card must be one of %s' %
                        ', '.join(sorted([c.mark for c in self._players[nick].hand])))
            return retVal

        c = self._players[nick].hand.pop(i)
        if self._is_valid_play(c):
            self.table[c.color].append(c)
            self.table[c.color].sort()
            retVal.public.append('%s successfully added %s to the %s group.' %
                       (nick, str(c), c.color))
            if len(self.table[c.color]) == 5:
                retVal.public.append('Bonus for finishing %s group: one note token '
                           'recovered!' % c.color)
                self._flip(self.notes, self.notes_down, self.notes_up)
        else:
            retVal.public.append('%s guessed wrong with %s! One storm token '
                          'flipped up!' % (nick, str(c)))
            self._flip(self.storms, self.storms_down, self.storms_up)
            self.discards[c.color].append(c.number)
            self.discards[c.color].sort()

        if len(self.deck):
            self._players[nick].add_card(self.deck.pop(0), self.options['repeat_backs']['value'])
            retVal.public.append('%s drew a new card from the deck into his or her hand.' % nick)

        self.turn_order.append(self.turn_order.pop(0))

        if 0 == len(self.deck):
            self.last_round = self.last_round + 1 if self.last_round is not None else 0

        retVal.merge(self.get_table())

        if 0 == len(self.deck):
            retVal.public.append('Turns remaining in game: %d' % (
                len(self._players)-self.last_round))

        if self._is_game_over():
            retVal.merge(self._end_game())
        else:
            # tell the next player it is their turn.
            s = 'It is your turn in Hanabi.'
            if not self.notes_up in self.notes:
                s += ' (Note: no hints remaining.)'

            retVal.private[self.turn_order[0]].append(s)

        return retVal
Example #9
0
    def swap_cards(self, nick, A, B):
        '''In nick's hand, swap cards A and B.'''
        retVal = gr()
        if not nick in self._players.keys():
            retVal.private[nick].append('You are not in the game.')
            return retVal

        retVal.merge(self._players[nick].swap_cards(A, B))
        retVal.merge(self.get_hands(nick))
        return retVal
Example #10
0
    def sort_cards(self, nick):
        '''In nick's hand, sort cards to "original" A-E order.'''
        retVal = gr()
        if not nick in self._players.keys():
            retVal.private[nick].append('You are not in game %s.')
            return retVal

        retVal.merge(self._players[nick].sort_cards())
        retVal.merge(self.get_hands(nick))
        return retVal
Example #11
0
    def move_card(self, nick, A, i):
        '''In nick's hand, move card A to slot i.'''
        retVal = gr()
        if not nick in self._players.keys():
            retVal.private[nick].append('You are not in game %s.')
            return retVal

        retVal.merge(self._players[nick].move_card(A, i))
        retVal.merge(self.get_hands(nick))
        return retVal
Example #12
0
    def move_card(self, A, i):
        '''swap a card within a hand. A is the card, i is the 1-based index or where
        to put it within the hand.'''
        try:
            i = int(i)
        except ValueError:
            return gr(private={self.name:'move index arugment must be an integer.'})

        if not (1 <= i <= len(self.hand)):
            message = 'move index argument must between 1 and %d' % len(self.hand)
            return gr(private={self.name: message})

        j = self.card_index(A.upper())
        if j is None:
            message = 'move card argument must be one of %s' % ', '.join(sorted([c.mark for c in self.hand]))
            return gr(private={self.name: message})

        self.hand.insert(i-1, self.hand.pop(j))
        return gr(private={self.name: 'Moved card %s to position %d.' % (A, i)})
Example #13
0
    def remove_player(self, nick):
        '''remove players and watchers from the game.'''
        if not nick in self._players.keys() + self._watchers:
            return gr(private={nick: 'You are not in the game. You cannot be removed '
                               'from a game you are not in.'})

        retVal = gr()
        role = 'a player' if nick in self._players else 'an observer'
        retVal.public.append('Removing %s from the game as %s.' % (nick, role))
        retVal.private[nick].append('You\'ve been removed from the game.')
        if nick in self._players:
            if self._players[nick].hand:
                retVal.public.append('Putting %s\'s cards back in the deck and reshuffling.' % nick)
                self.deck += self._players[nick].hand
                random.shuffle(self.deck)

            del self._players[nick]

            if len(self._players) < 2:
                retVal.public.append('Stopping the game as there are fewer than two people left in '
                           'the game.')
                self._playing = False
                self._game_over = True

            elif len(self._players) < 4:
                retVal.public.append('Now that there are fewer than four players, everyone gets '
                           'another card. Adding card to everyone\'s hand.')
                for p in self._players.values():
                    if len(self.deck):
                        p.add_card(self.deck.pop(0), self.options['repeat_backs']['value'])

            if self._playing:
                if nick == self.turn_order[0]:
                    retVal.public.append('It is now %s\'s turn.' % self.turn_order[1])
       
                del self.turn_order[0]

        if nick in self._watchers:
            self._watchers.remove(nick)

        return retVal
Example #14
0
 def get_hands(self, nick):
     retVal = gr()
     hands = []
     for p in self.turn_order:
         if self._players[p].name != nick:
             hands.append(self._players[p].get_hand())
         else:
             hands.append(self._players[p].get_hand(hidden=True))
     
     # Now let's all join hands...
     retVal.private[nick].append('Current hands: %s' % ', '.join(hands))
     return retVal
Example #15
0
    def add_player(self, nick):
        if self._playing:
            return gr(private={nick:'Game already started.'})

        retVal = gr()
        if len(self._players) >= self.max_players:
            retVal.private[nick].append('Max players already in the game.')
        else:
            if nick in self._players.keys():
                retVal.private[nick].append('You are already in the game.')
            elif nick in self._watchers:
                retVal.private[nick].append('You cannot be both an observer and'
                                            ' a player. Please !leave as oserver'
                                            ' before joining the game.')
            else: 
                self._players[nick] = Player(nick)
                retVal.public.append('%s has joined the game.' % nick)
                if len(self._players) > 1:
                    retVal.public.append('The game has enough players and can be started '
                               'with the start command !start.')

        return retVal
Example #16
0
    def hints(self, nick, show_all=False):
        retVal = gr()
        retVal.private[nick].append('You\'ve yet to get any hints.')
        if show_all:
            all_hints = [hint for p in self._hints.values() for hint in p]
            if all_hints:
                retVal.private[nick] = all_hints

        else:
            if self._hints[nick]:
                retVal.private[nick] = self._hints[nick]

        return retVal
Example #17
0
    def game_option(self, opts):
        '''handle in game options.'''
        retVal = gr()
        if not opts:
            retVal.public.append('Available options:')
            for opt, info in self.options.iteritems():
                retVal.public.append('%s (current value: %s): %s' % (
                    opt, str(info['value']), info['help']))

            return retVal

        for opt in opts:
            if not opt in self.options.keys():
                retVal.public.append('Unsupported option: %s' % opt)
            else:
                # current options are all just True/False toggles.
                self.options[opt]['value'] = not self.options[opt]['value']
                retVal.public.append('%s is now set to %s' % (
                    opt, self.options[opt]['value']))

        return retVal
Example #18
0
    def discard_card(self, nick, X):
        '''Discard the card with ID X.'''
        retVal = gr()
        if not self._in_game_is_turn(nick, retVal):
            return retVal
        
        i = self._players[nick].card_index(X)
        if i is None:
            retVal.private[nick].append('You tried to discard card %s, oops.' % X)
            retVal.private[nick].append('Card must be one of %s' %
                        ', '.join(sorted([c.mark for c in self._players[nick].hand])))
            return retVal
            
        c = self._players[nick].hand.pop(i)
        if len(self.deck):
            self._players[nick].add_card(self.deck.pop(0),
                                         self.options['repeat_backs']['value'])
       
        retVal.public.append('%s has discarded %s' % (nick, str(c)))
        self.discards[c.color].append(c.number)
        self.discards[c.color].sort()
        self._flip(self.notes, self.notes_down, self.notes_up)
        self.turn_order.append(self.turn_order.pop(0))

        if 0 == len(self.deck):
            self.last_round = self.last_round + 1 if self.last_round is not None else 0

        retVal.merge(self.get_table())

        if 0 == len(self.deck):
            retVal.public.append('Turns remaining in game: %d' % (
                len(self._players)-self.last_round))

        if self._is_game_over():
            retVal.merge(self._end_game())
        else:
            # tell the next player it is their turn.
            retVal.private[self.turn_order[0]].append('It is your turn in Hanabi.')

        return retVal
Example #19
0
 def turns(self):
     '''Tell the players whos turn it is.'''
     if not self.turn_order:
         return gr('Turn order not decided yet; the game has not started.')
     else:
         return gr('Upcoming turns and turn order: %s' % ', '.join(self.turn_order))
Example #20
0
 def sort_cards(self):
     '''
     re-sort the card into "orginal" positions.
     '''
     self.hand = sorted(self.hand, key=lambda x: x.mark)
     return gr(private={self.name: 'Your cards have been sorted.'})
Example #21
0
    def start_game(self, nick, opts=None):
        '''Start an existing game. Will fail if called by someone not in the game
        or if there are not enough players.'''
        retVal = gr()
        if not nick in self._players.keys():
            retVal.private[nick].append('You are not in the game.')
            return retVal

        if self._playing:
            retVal.private[nick].append('The game has already begun.')
            return retVal

        if len(self._players) > 1:
            self._playing = True
            retVal.public.append('The Hanabi game has started!')
            self.turn_order = random.sample(self._players.keys(), len(self._players))
        else:
            retVal.public.append('There are not enough players in the game, not starting.')
            return retVal
       
        if opts:
            for opt, val in opts.iteritems():
                # only one valid option for now.
                if opt.startswith('rainbow'):
                    self._rainbow_game = True
                    self.colors.append('rainbow')
                    if opt.endswith('5'):
                        self._game_type = 'rainbow 5'
                        retVal.public.append('Adding 5 rainbow cards to the deck')
                        self.deck += [Card('rainbow', i) for i in xrange(1,6)]
                    else:
                        self._game_type = 'rainbow 10'
                        retVal.public.append('Adding 10 rainbow cards to the deck')
                        self.deck += [Card('rainbow', i) for i in self.card_distribution]

                    random.shuffle(self.deck)
                
                    if self.options['solvable_rainbow_5'] and self._game_type == 'rainbow 5':
                        retVal.public.append('Warning: the solvable rainbow 5 option is set. '
                                             'This means that the deck is stacked a bit: hanabot'
                                             ' ensures that there is no rainbow 1, 2, 3, or 4 '
                                             'card on the bottom of the deck. If you\'d like '
                                             ' a "natural" shuffle, do "!option '
                                             'solvable_rainbow_5" and !delete, then restart the '
                                             'game.')
                        last_card = self.deck[len(self.deck)-1]
                        while last_card.color == 'rainbow' and last_card.number != 5:
                            log.debug('reshuffling as last card is %s' %
                                      str(self.deck[len(self.deck)-1]))
                            log.debug('...and solvable_rainbow_5 is toggled to True')
                            random.shuffle(self.deck)
                            last_card = self.deck[len(self.deck)-1]

                else:
                    retVal.public.append('Invalid option to start command: %s' % opt)
                    retVal.public.append('Game not started.')
                    return retVal

        card_count = 5 if len(self._players) < 4 else 4
        for player in self._players.values():
            for c in self.deck[:card_count]:
                player.add_card(c, self.options['repeat_backs']['value'])

            self.deck = self.deck[card_count:]

        retVal.merge(self.get_table())
        return retVal
Example #22
0
    def hint_player(self, nick, player, hint):
        '''
            hint_player: hint another player about thier hand.

            nick: who is hinting
            player: the hintee
            hint: can be one of: 
                string: a valid color
                int: a valid number (int)

            hint_player validates input.
        '''
        retVal = gr()
        if not self._in_game_is_turn(nick, retVal):
            return retVal
        
        if nick == player:
            retVal.private[nick].append('You really want to give a hint to yourself? Too bad '
                        'no information leak here.')
            return retVal

        try:
            hint = int(hint)
        except ValueError:
            try: 
                hint = str(hint)
            except ValueError:
                retVal.private[nick].append('The hint command must be a string (color) or '
                            'an integer (card number). Valid colors are %s '
                            ' or the first charecter  of the word (all case '
                            'insensitive.' % ', '.join(self.colors))
                return retVal

        if not player in self._players.keys():
            retVal.private[nick].append('player %s is not in the game.' % player)
            return retVal

        if isinstance(hint, str):
            hint = hint.lower()

            # convert partial hint into full color string.
            for c in self.colors:
                if c.startswith(hint):
                    hint = c

            log.debug('Found color %s from hint', hint)

            if not hint in self.colors: 
                retVal.public.append('Invalid hint given by %s, still their turn.' % nick)
                retVal.private[nick].append('%s is not a valid color. Valid colors are %s.' %
                        (hint, ', '.join(self.colors)))
                return retVal


        elif isinstance(hint, int) and not 0 < hint < 6:
            retVal.public.append('Invalid hint given by %s, still their turn.' % nick)
            retVal.private[nick].append('numbers must be between 1 and 5 inclusive.')
            return retVal

        # valid hint command, do the action.
        if not self.notes_up in self.notes:
            retVal.public.append('Oh no! %s gave a hint when all notes were turned '
                       'over. ' % nick)
            retVal.public.append('So, ya know, just disregard anything they said.')
            return retVal

        cards = self._get_cards(player, hint)

        if not len(cards):
            hint_str = ('%s has given %s a hint: you have no %s cards' % (
                       (nick, player, str(hint))))
        else:
            plural = 's ' if len(cards) > 1 else ' '
            is_are = 'are ' if len(cards) > 1 else 'is '
            a = 'a ' if isinstance(hint, int) else ''
            hint_str = ('%s has given %s a hint: your card%s%s %s%s%s' % (
                       (nick, player, plural, ', '.join([c.mark for c in cards]), is_are, 
                        a, str(hint))))

        retVal.public.append('======== %s' % hint_str)
        self._hints[player].append(hint_str)

        self.turn_order.append(self.turn_order.pop(0))
        self._flip(self.notes, self.notes_up, self.notes_down)

        if 0 == len(self.deck):
            self.last_round = self.last_round + 1 if self.last_round is not None else 0

        retVal.merge(self.get_table())

        if 0 == len(self.deck):
            retVal.public.append('Turns remaining in game: %d' % (
                len(self._players)-self.last_round))

        if self._is_game_over():
            retVal.merge(self._end_game())
        else:
            # tell the next player it is their turn.
            s = 'It is your turn in Hanabi.'
            if not self.notes_up in self.notes:
                s += ' (Note: no hints remaining.)'

            retVal.private[self.turn_order[0]].append(s)

        return retVal