## 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",
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)]

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

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

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()
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):
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 :)