Thursday, April 15, 2010

Card Simulation

Lately I have been documenting my experience with creating a deck simulator here, which is being written with Python 2.5.6.


I plan to continue documenting my progress at the link above, as well as on this blog. I posted the above link so that anyone that would like to can see all previous posts I've made up to my current point of development, which will be explained throughout this post.


I have chosen to create a card game called MauMau. MauMau is a game very similar to Uno, the main difference being that MauMau is played with a traditional deck of cards.


I currently have created a card class, deck class, MauMau class, and hand class. I manipulate these within the main function, which is the game loop. I also have created a function for determining if a player move is a valid move.


My immediate plans for the game is to:


- Create the used stack pile.
- Allow players to make a move by playing a card onto the used stack pile.
- Create an Ai which plays available cards, and draws if unavailable.
- Create rules for unique cards, like lose a turn, etc.



Here is my current build:


"""
To do:
- Create the used stack pile.
- Allow players to make a move by playing a card onto the used stack pile.
- Create an Ai which plays available cards, and draws if unavailable.
- Create rules for unique cards, like lose a turn, etc.

Created by: CecilSunkure
"""

import sys
import random

ACES_HIGH = True
GAME_RUNNING = True

class card:
    suits = ["Clubs",
             "Diamonds",
             "Hearts",
             "Spades" ]
    ranks = ["Ace",
             "2",
             "3",
             "4",
             "5",
             "6",
             "7",
             "8",
             "9",
             "10",
             "Jack",
             "Queen",
             "King" ]

    def __init__(self, suit=0, rank=0):
        self.suit = suit
        self.rank = rank

    def __str__(self):
        return (self.ranks[self.rank] + " of " + self.suits[self.suit])

class deck:
    def __init__(self):
        self.cards = []
        for suit in range(4):
            for rank in range(12):
                self.cards.append(card(suit, rank))

    def __str__(self):
        s = ''
        for i in range(len(self.cards)):
            s = s + str(self.cards[i]) + '\n'
        return s
          

    def shuffle(self):
        import random
        cards_length = len(self.cards)
        for i in range(cards_length):
            j = random.randrange(i, cards_length)
            self.cards[i], self.cards[j] = self.cards[j], self.cards[i]

    def remove(self, card):
        if card in self.cards:
            self.cards.remove(card)
            return True
        else:
            return False

    def draw(self):
        return self.cards.pop()

    def is_empty(self):
        return (len(self.cards) == 0)

    def deal(self, hands, num_cards=999):
        for i in range(num_cards):
            if self.is_empty(): break
            card = self.pop()
            hand = hands[i % len(hands)]
            hand.add(card)

    def pop(self):
        return self.cards.pop()


class hand(deck):
    def __init__(self, player=''):
        self.cards = []
        self.player = player

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

    def __str__(self):
        s = self.player + "'s Hand"
        t = 0
        if self.is_empty():
            s = s + " is empty\n"
        else:
            s = s + " contains\n"
        for i in range(len(self.cards)):
            t += 1
            s = s + str(t) + '. ' + str(self.cards[i]) + '\n'
        return s

class MauMau:
    def __init__(self, stack=0, topCard=0):
        self.deck = deck()
        self.deck.shuffle()
        self.players = []
        self.stack = stack
        self.topCard = topCard

    def getName(self):
        print('Welcome to Mau Mau!')
        player = raw_input()
        print('What is your name?')
        player = raw_input()
        print('')
        return player

    def startCard(self):
        self.topCard = self.deck.pop()

    def cmp_topCard(self, other):
        if self.topCard.suit == other.suit:
            if self.topCard.rank == other.rank:
                return True

def isValidMove(move, hand, game, handlen):
    """Used to determine if a move by checking to see if the move is an integer, followed by and testing to see
    if the proposed move is within the length of the hand passed to this function. Finally, this function
    makes sure that the proposed card to be played is valid within the rules of the game (same rank)."""
    x = []
    for i in range(1, (handlen+2)):
        x.append(i)
  
    try:
        int(move)
    except:
        print('That is not a valid move (not int).\n')
        return False

    if int(move) not in x:
        print('That is not a valid move (not 1-' + str(handlen+1) + ').\n')
        return False

    if move != str(handlen+1):
        if game.topCard.rank == hand.cards[(int(move)-1)].rank:
            return True
        else:
            return False
    elif move == str(handlen+1):
        return True

def main():
    """This function is the main loop used for running the Class MauMau. The turns between Ai and human are
    represented by integers, and those integers are used in if statements to determine which player is currently
    taking their turn."""
    #turn = random.randrange(2) + 1 <-- A comment for now, so for testing the human always goes.
    turn = 0
    game = MauMau()
    name = game.getName()
    hand1 = hand(name)
    hand2 = hand("CPU")
    game.deck.deal([hand1], 5)
    game.deck.deal([hand2], 5)
    game.startCard()
  
    if turn == 1:
        print('The computer will go first, as decided at random.')
    else:
        print('You will move first, as decided at random.')
  
    while GAME_RUNNING:
        print ('///' + '\n' + '/// ' + str(game.topCard) + '\n' + '///' + '\n')
        print (hand1)

        if turn == 1:
            print ('The computer will now take its turn, hit enter to proceed.')
            Move = raw_input()
        else:
            print ('Choose a card to play (1-' + str(len(hand1.cards)) + ') or draw a card (' + str((len(hand1.cards)+1)) + ').')
            Move = raw_input()

            if isValidMove(Move, hand1, game, len(hand1.cards)):
                print('Valid move check passed.\n')

                if Move == str(len(hand1.cards)+1):
                    hand1.add(game.deck.draw())
            else:
                print('Valid move check failed.\n')
              

if __name__ == "__main__":
    main()


In order to use the stack of cards for the face up cards that were already played, I plan to implement a common stack. A stack would be a list or array that is used to grab values out of in the order of the last appended first. I created a test module (.py file) before actually using it in the game. I have yet to implement something similar, but the source for this test is here:

 #A test module for creating a stack.

run = True
stack = []

while run:
    print('Stack, Pop, end, or continue? (1, 2, 3, enter)')
    yesno = raw_input()

    if yesno == '1':
        print('Enter a value to stack')
        a = raw_input()
        stack.append(a)

    if yesno == '2':
        try:
            stack.pop()
            b = stack.pop()
            print(b)
        except:
            print('Stack is empty.\n')

    if yesno == '3':
        run = False


    
Development is moving at a decent pace. Most of the time I am debugging the code I have written, but I am learning a ton. I've become very much more familiar with object orientation through the use of all my classes, and this project is definitely helping to enhance my overall coding ability. It's really pretty exciting :)

Here is a link to a .exe of my current build: http://download503.mediafire.com/m5ydqyl9zzng/nyfzyamykzi/Cards.7z

1 comment:

Note: Only a member of this blog may post a comment.