git @ Cat's Eye Technologies NaNoGenLab / master narrated-card-game / narrated-card-game.py
master

Tree @master (Download .tar.gz)

narrated-card-game.py @masterraw · history · blame

#!/usr/bin/env python

from optparse import OptionParser
import random


SUITS = [
    'hearts',
    'diamonds',
    'clubs',
    'spades',
]

RANKS = [
    'ace',
    'two',
    'three',
    'four',
    'five',
    'six',
    'seven',
    'eight',
    'nine',
    'ten',
    'jack',
    'queen',
    'king',
]


class Card(object):
    def __init__(self, rank, suit):
        self.rank = rank
        self.suit = suit

    def __str__(self):
        return "the %s of %s" % (RANKS[self.rank-1], self.suit)


class Pile(object):
    def __init__(self):
        self.cards = []

    def add(self, card):
        self.cards.append(card)

    def add_to_bottom(self, card):
        self.cards.insert(0, card)

    def take(self):
        return self.cards.pop(-1)

    def shuffle(self):
        random.shuffle(self.cards)

    def __len__(self):
        return len(self.cards)

    def __str__(self):
        return ', '.join([str(card) for card in self.cards])


def create_deck():
    pile = Pile()
    for rank in xrange(1, 13+1):
        for suit in SUITS:
            pile.add(Card(rank, suit))
    return pile


class Actor(object):
    def __init__(self, name, posessive='its', accusative='it', reflexive='itself', monitor=None):
        self.name = name
        self.posessive = posessive
        self.accusative = accusative
        self.reflexive = reflexive
        self.monitor = monitor
        self.hand = Pile()
        self.bank = Pile()  # when they are the dealer only

    def get_deck(self):
        self.bank = create_deck()
        self.monitor.report("%s took a deck of cards out of the drawer." % self.name)

    def shuffle(self):
        self.bank.shuffle()
        self.monitor.report("%s shuffled the cards." % self.name)

    def deal_card(self, other):
        card = self.bank.take()
        other.hand.add(card)
        other_name = other.name
        if self is other:
            other_name = self.reflexive
        self.monitor.report("%s dealt a card to %s." % (self.name, other_name))

    def deal(self, others):
        other_num = 0
        random.shuffle(others)
        while self.bank:
            self.deal_card(others[other_num])
            other_num += 1
            other_num = other_num % len(others)

    def play_card(self, face_down=False):
        card = self.hand.take()
        card_desc = str(card)
        if face_down:
            card_desc = 'a card'
        verb = 'turned up'
        if face_down:
            verb = 'laid down'
        self.monitor.report("%s %s %s." % (self.name, verb, card_desc))
        return card

    def take(self, card, silent=False):
        self.hand.add_to_bottom(card)
        if not silent:
            self.monitor.report(
                "%s picked up %s and added it to the bottom of %s pile." %
                (self.name, card, self.posessive)
            )

    def take_many(self, cards):
        if len(cards) == 1:
            self.take(card)
        else:
            random.shuffle(cards)
            for card in cards:
                self.take(card, silent=True)
            if len(cards) == 2:
                self.monitor.report(
                    "%s picked up both cards and added them to the bottom of %s pile." %
                    (self.name, self.posessive)
                )
            else:
                self.monitor.report(
                    "%s picked up all %s cards and added them to the bottom of %s pile." %
                    (self.name, len(cards), self.posessive)
                )

    def look_at_cards(self):
        self.monitor.report(
            "%s looked at %s cards and saw that %s had %s cards: %s." % (
                self.name, self.posessive, self.accusative, len(self.hand), self.hand
            )
        )
    
    def shout(self, what):
        self.monitor.report('%s shouted "%s"' % (self.name, what))

    def concede(self, other):
        self.monitor.report(
            '"Well," said %s, "I\'m out of cards.  I guess you win, %s!"' % (
                self.name, other.name,
            )
        )

    def accept_concession(self, other):
        self.monitor.report(
            '"Thanks for the game, %s," said %s, smiling.' % (
                other.name, self.name,
            )
        )

    def put_deck_away(self):
        self.monitor.report(
            '%s put the deck of cards back in the drawer.' % self.name
        )

    def ask_about_game(self, other):
        self.monitor.report(
            '"%s, would you like to play a game of War?" asked %s.' % (
                other.name, self.name
            )
        )

    def decide_about_game(self, other):
        if random.randint(1, 5) > 1:
            self.monitor.report(
                '"No thanks, %s," said %s.' % (
                    other.name, self.name
                )
            )
            return False
        else:
            self.monitor.report(
                '"Sure, why not?" said %s.' % self.name
            )
            return True

    def announce_begin(self, other):
        self.monitor.report(
            '"Okay, %s, let\'s begin," said %s.' % (other.name, self.name)
        )


class Monitor(object):
    def __init__(self, fh):
        self.fh = fh

    def report(self, string):
        self.fh.write(string + ' ')
        self.fh.flush()

    def pause(self):
        self.fh.write('\n\n')


def main(argv):
    optparser = OptionParser(__doc__)
    optparser.add_option("--debug", default=False, action='store_true',
                         help="lemme know what cards they've got")
    optparser.add_option("--seed", default=None,
                         help="specify a random seed (integer)")
    optparser.add_option("--print-seed", default=False, action='store_true',
                         help="print out the seed")
    (options, args) = optparser.parse_args(argv[1:])
    if options.seed is None:
        options.seed = random.randint(0, 1000000000)
        if options.print_seed:
            sys.stdout.write("(Seed is %s)\n\n" % options.seed)
    options.seed = int(options.seed)
    random.seed(options.seed)

    monitor = Monitor(sys.stdout)

    actors = [
        Actor("Alice", posessive='her', accusative='she', reflexive='herself', monitor=monitor),
        Actor("Bob", posessive='his', accusative='he', reflexive='himself', monitor=monitor)
    ]
    random.shuffle(actors)
    alice = actors[0]  # alice is sometimes Bob
    bob = actors[1]    # bob is sometimes Alice

    alice.get_deck()
    alice.shuffle()
    monitor.pause()

    alice.ask_about_game(bob)
    result = bob.decide_about_game(alice)
    monitor.pause()
    if not result:
        alice.put_deck_away()
        monitor.pause()
        sys.exit(0)

    alice.deal([alice, bob])
    monitor.pause()
    alice.announce_begin(bob)
    monitor.pause()

    if options.debug:
        alice.look_at_cards()
        bob.look_at_cards()
        monitor.pause()

    def play_turn(cards_a, cards_b):
        if not alice.hand:
            return
        cards_a.append(alice.play_card())
        if not bob.hand:
            return
        cards_b.append(bob.play_card())
        if (cards_a[-1].rank > cards_b[-1].rank):
            alice.take_many(cards_a + cards_b)
            return
        elif (cards_a[-1].rank < cards_b[-1].rank):
            bob.take_many(cards_a + cards_b)
            return
        else:
            alice.shout("WAR!")
            bob.shout("WAR!")
            for x in xrange(0, 3):
                if not alice.hand:
                    return
                card = alice.play_card(face_down=True)
                cards_a.append(card)
                if not bob.hand:
                    return
                card = bob.play_card(face_down=True)
                cards_b.append(card)
            play_turn(cards_a, cards_b)

    done = False
    while not done:
        play_turn([], [])
        monitor.pause()

        if options.debug:
            alice.look_at_cards()
            bob.look_at_cards()
            monitor.pause()

        if not alice.hand:
            alice.concede(bob)
            monitor.pause()
            bob.accept_concession(alice)
            bob.put_deck_away()
            done = True

        if not bob.hand:
            bob.concede(alice)
            monitor.pause()
            alice.accept_concession(bob)
            alice.put_deck_away()
            done = True

    monitor.pause()

if __name__ == '__main__':
    import sys
    main(sys.argv)