Hi. Before I start I'll just let you know that this isn't for school, I'm just doing python as a hobby which I have pretty much taught my self.
I'm working on a project, it is the "cheat!" card game written in python, currently CLI but when it is bug-free and clean I'll try making a GUI. I made this a while ago, by myself, and it never actually completely worked. Now I've written it a second time, much more efficient, cleaner and legible. But it still is in the debugging stage. Right now, the IDE I use (PyScripter, I recommend it) crashes when it gets to a certain point in it, and command prompt just stops and does nothing when it gets to that point, being when a player wins. I will attach the file as a .txt file and paste it here. Just save it and then rename it with a .py extension and then open it up in your IDE if you want to look at it.
I have no specific questions, but take a look if you want, maybe some suggestions and comments or questions, constructive criticism, if you're feeling very generous test and debug it to find what's wrong (not that I expect you to).
Thats all for now.
Here's the code:
# "cheat.py" Module
# Created on 14-June-2009
# compiled with python 3.0.1 -> www.python.org
# edited with PyScripter -> http://pyscripter.googlepages.com
# by Mitchell Kember
# Copyright (c) 2009. All rights reserved.
"""
Created on 14-June-2009
This python script is Cheat version 2, the "Cheat" card game. It
is played using the command line. Future versions will use a GUI.
@author: Mitchell Kember
"""
from random import randint
from random import shuffle
from re import split
class player:
"""A player in the cheat game."""
def __init__(self, name):
"""Creates a player.
params: name - The name of the player."""
self.name = name
self.hand = []
def __eq__(self, obj):
"""How to comare two player objects for equality."""
if not isinstance(obj, player):
return False
return self.name == obj.name and self.hand == obj.hand
def __ne__(self, obj):
"""How to comare two player objects for inequality."""
return not self.__eq__(obj)
def __str__(self):
"""The string representation of a player object."""
return self.name
class human(player):
"""A human player in the cheat game."""
def __init__(self, name):
"""Creates a human (human) player.
params: name - See player class"""
super(human, self).__init__(name)
def __eq__(self, obj):
"""How to compare two human objects for equality."""
return super(human, self).__eq__(obj)
def __ne__(self, obj):
"""How to compare two human objects for inequality."""
return not self.__eq__(obj)
class computer(player):
"""A computer player in the cheat game."""
def __init__(self, name, difficulty=randint(1, 3)):
"""Creates a player and then initializes computer-specific fields.
params: name: See player class.
[difficulty = randint(1, 3)] - The difficulty of the computer player."""
super(computer, self).__init__(name)
self.difficulty = difficulty
def __eq__(self, obj):
"""How to compare two computer objects for equality."""
return super(computer, self).__eq__
(obj) and self.difficulty == obj.difficulty
def __ne__(self, obj):
"""How to compare two computer objects for inequality."""
return not self.__eq__(obj)
class diff:
"""Enum class for a computer player's difficulty."""
unknown = 0
EASY = 1
MEDIUM = 2
HARD = 3
def get_name(difficulty):
"""Returns the name of the difficulty level."""
return ['easy', 'medium', 'hard'][difficulty]
class deck:
"""Deck of 52 cards for the cheat game."""
def __init__(self, shuffled=True):
"""Creates a new deck of 52 regular playing cards.
params: [shuffled = true] - Whether deck will be shuffled or not."""
self.cards = []
for s in range(1, 5):
for v in range(1, 14):
self.cards.append(card(v, s))
if shuffled:
self.shuffle_deck()
def shuffle_deck(self):
"""Shuffles the deck."""
shuffle(self.cards)
def sort_hand(hand):
"""Sorts a player's hand of cards by value (ace through king).
params: hand - The list of card objects to sort."""
vals = []
for c in hand:
vals.append((c, c.val))
vals.sort(key=lambda a:a[1])
return [c[0] for c in vals]
class card:
"""A card in that makes up a deck."""
def __init__(self, value, suit):
"""Creates a card.
params: value - The card's value. (see the value class)
suit - The card's suit. (see the suit class)"""
self.val = value
self.su = suit
def __str__(self):
"""Returns the name of the card. (Format: \"The [value] of [suit]\")"""
return "the " + value.get_name(self.val) + " of " + \
suit.get_name(self.su)
def __eq__(self, obj):
"""How to compare two card objects for equality."""
if not isinstance(obj, card):
return False
return self.val == obj.val and self.su == obj.su
def __ne__(self, obj):
"""How to compare two card objects for inequality."""
return not self.__eq__(obj)
def __gt__(self, obj):
"""How to compare two objects for the greatest."""
if not isinstance(obj, card):
raise TypeError
return self.val > obj.val
def __ge__(self, obj):
"""How to compare two objects for the greatest or equality."""
if not isinstance(obj, card):
raise TypeError
return self > obj or self.val == obj.val
class value:
"""Enum class for a card's value."""
unknown = 0
ACE = 1
TWO = 2
THREE = 3
FOUR = 4
FIVE = 5
SIX = 6
SEVEN = 7
EIGHT = 8
NINE = 9
TEN = 10
JACK = 11
QUEEN = 12
KING = 13
def get_name(value):
"""Returns the name of a value.
params: value - The value to get the name of."""
return ['unknown', 'ace', 'two', 'three', 'four', 'five', 'six',
'seven', 'eight', 'nine', 'ten', 'jack', 'queen', 'king'][value]
class suit:
"""Enum class for a card's suit."""
unknown = 0
SPADES = 1
CLUBS = 2
HEARTS = 3
DIAMONDS = 4
def get_name(suit):
"""Returns the name of a suit.
params: suit - The suit to get the name of."""
return ['unknown', 'spades', 'clubs', 'hearts', 'diamonds'][suit]
def get_colour(suit):
"""Returns the colour of a suit.
params: suit - The suit to get the colour of."""
if suit == 1 or suit == 2:
return 'black'
elif suit == 3 or suit == 4:
return 'red'
else:
return 'unknown'
class game:
"""Cheat cardgame."""
# game.gameplay: The rules of cheat and how it is played.
gameplay = """ Cheat gameplay:
\tThe object of the game is to get rid of all your cards. The winner is the first
person to get rid of all their cards.
\tTo start the game, the entire deck of 52 cards is dealt evenly to everyone. Now,
the player with the ace of spades will start. On this first turn, he or she is
allowed to put down all of his or her aces. He or she will take the cards, place
them face-down on the pile of cards and say the number of cards they are putting
down and that turn's card (ex \"2 twos\", \"1 jack\"). The next player will put
down twos, the next three, etc. until king, then it goes back to aces.
\tOn each player's turn, they will have to cheat if they do not have
any of the correct card. This means they will put down cards other than the correct
ones. You are NOT allowed to put down your cards and say that you are putting down
a different number of cards (ex say \"1 king\" but actually put down two). So
you can put down an ace and an eight when you are supposed to put down kings
and say \"2 kings\". You can also cheat even if you don't have to, if you are
supposed to put down fours and you have 2 fours, you could put the fours down
and also put a queen and say \"3 fours\", or even put down a jack and say
\"1 four\", and not even put down the fours that you have at all!
\tAfter any player's turn, any other player can challenge them by accusing
\"Cheat!\". If the player cheated, they must take up the entire pile. If the
player hasn't cheated, the challenger must add the entire pile to their hand.
\tThis will continue until a player wins, and then the other players may
keep playing to get a 2nd place winner, and 3rd place winner, etc."""
# Ranks for the winners
ranks = ['first', 'second', 'third', 'fourth', 'fifth', 'sixth',
'seventh', 'eighth']
def __init__(self, *players):
"""Creates a new game.
params: *players - the players in this game."""
self.players = list(players) # (So that it is mutable)
# Make sure there are no more than eight players:
if len(self.players) > 8:
print("There cannot be more than 8 players.")
return
# Make sure all players are instances of the class player
for p in self.players:
if not isinstance(p, player):
print('Error: players are not player objects.')
return
# self.c_player: The player whose turn it is.
# self.c_value: This turn's card value (ace through king).
self.winners = []
self.deck = deck()
self.pile = []
self.player_iter = iter(self.players)
self.c_player = None
self.value_iter = iter(range(1, 14))
self.c_value = 0
self.deal_cards()
# Move the player with the ace of spades to the front of the list
for ind, p in enumerate(self.players):
for c in p.hand:
if c == card(value.ACE, suit.SPADES):
self.players[0], self.players[ind] = \
self.players[ind], self.players[0]
self.next_turn()
def reset_player_iter(self):
"""Resets the player iterator by re-assigning it."""
self.player_iter = iter(self.players)
def reset_value_iter(self):
"""Resets the value iterator by re-assigning it."""
self.value_iter = iter(range(1, 14))
def deal_cards(self):
"""Deals the deck to each player."""
i = 0
for c in self.deck.cards:
if i == len(self.players):
i = 0
self.players[i].hand.append(c)
i += 1
# Delete self.deck, and use self.pile instead so to not have to use
# self.deck.cards.
del self.deck
def update_current(self):
"""Updates the current player and current value instance variables."""
while True:
# Go to the next player in the self.players list
try:
self.c_player = next(self.player_iter)
# If at the end of the list, go back to the start by calling
# self.reset_player_iter().
except StopIteration:
self.reset_player_iter()
self.c_player = next(self.player_iter)
if self.c_player not in self.winners:
break
# Go to the next card value in the list of numbers 1 through 14
# (enum values of the value class).
try:
self.c_value = next(self.value_iter)
# If at the end of the list, go back to the start by calling
# self.reset_value_iter().
except StopIteration:
self.reset_value_iter()
self.c_value = next(self.value_iter)
def next_turn(self):
"""Goes to the next turn in the game."""
# Check to see if there is only one player left (game is over).
# If there is, then print the ranks and end.
if len([p for p in self.players if p not in self.winners]) == 1:
print("The game is over.\n\nThe ranks:\n")
for place, p in enumerate(self.winners):
print("{0}: {1}".format(game.ranks[place], p))
print("{0}. {1}".format(game.ranks[len(self.winners)], self.c_player))
return
# Update self.c_player and self.c_value instance variables.
self.update_current()
print(" {0} ".format(len(self.c_player.hand))*10)
print("It's {0}'s turn. {0}, put down your {1}s.".format(
self.c_player, value.get_name(self.c_value)), end=' '*6)
input("Press enter to continue...")
# Go on to either human_turn() or computer_turn()
if isinstance(self.c_player, computer):
self.computer_turn()
elif isinstance(self.c_player, human):
self.human_turn()
else:
print("Error: Players are not human or computer objects.")
def human_turn(self):
"""Executed when it is a human player's turn."""
# Sort the player's cards by values, so that they go from ace to king.
self.c_player.hand = deck.sort_hand(self.c_player.hand)
print("{0}, here are your cards.".format(self.c_player) + \
"Type the number keys of the cards you want to play" , end=' '*6)
input("Press enter to continue...")
# Print the player's cards, and
# if the card's value is the self_c_value, then print it in CAPS.
for ind, c in enumerate(self.c_player.hand):
print("{0} : ".format(ind), end='')
if c.val == self.c_value:
print(str(c).upper())
else:
print(c)
# Loop until atleast one valid card is chosen by the human
while True:
# del_indexes: list to contain indexes of elements in card_indexes to
# delete. They can't be deleted in the for loop because it would
# mess it up if they are deleted while it is iterating them.
del_indexes = []
# card_indexes: The indexes of the cards put down.
# The indexes can be entered seperated by spaces or commas.
card_indexes = split('\W+', input("Enter the number keys: "))
for ind, c in enumerate(card_indexes):
# Make sure that each index is a number (digit).
if not c.isdigit():
del_indexes.append(ind)
continue
# Make sure the index is valid, that it is one of the indexes
# in the player's hand of cards.
if int(c) >= len(self.c_player.hand) or int(c) < 0:
del_indexes.append(ind)
# Delete the indexes that were appended to del_indexes
for ind in del_indexes:
del card_indexes[ind]
# Make sure at least one card is chosen.
if not card_indexes:
print("You have to chose at least one card.")
else:
break
del del_indexes
self.finish_turn(card_indexes)
def computer_turn(self):
"""Executed when it is a computer player's turn."""
card_indexes = []
skip = False
# If the player only has one card then just chose that one.
if len(self.c_player.hand) == 1:
card_indexes = [0]
skip = True
# If the computer player's difficulty is not diff.EASY, or if it is
# and a random number from 1 to 3 is 1 (33% chance), then find all
# the cards that the computer player has and can put down without
# cheating.
if (self.c_player.difficulty != diff.EASY or randint(1, 3) == 1) \
and not skip:
for ind, c in enumerate(self.c_player.hand):
if c.val == self.c_value:
card_indexes.append(ind)
# What the EASY computer player does:
if self.c_player.difficulty == diff.EASY and not skip:
# If the computer player already put down some cards from the
# 33% chance above, half the time leave it and don't add any more.
# Add either 1, 2, 3 or 4 more random cards
if not card_indexes or randint(1, 2) == 1:
for i in range(randint(1, 4)):
while True:
rand_num = randint(0, len(self.c_player.hand)-1)
if rand_num not in card_indexes:
card_indexes.append(rand_num)
break
# What the MEDIUM computer player does:
elif self.c_player.difficulty == diff.MEDIUM and not skip:
# It will add up to 3 cards if to the card_indexes if it is empy,
# or 1/5 of the time when card_indexes is not empty
if not card_indexes or randint(1, 5) == 1:
for i in range(randint(1, 3)):
while True:
rand_num = randint(0, len(self.c_player.hand)-1)
if rand_num not in card_indexes:
card_indexes.append(rand_num)
break
# What the HARD computer player does:
elif self.c_player.difficulty == diff.HARD and not skip:
pass
self.finish_turn(card_indexes)
def finish_turn(self, card_indexes):
"""Finishes the turn, human or computer.
params: card_indexes - The indexes of the cards that are chosen."""
print("{0} put down {1} {2}(s).".format(
self.c_player, len(card_indexes), value.get_name(self.c_value)))
# cards: The actual card objects that were put down.
cards = [self.c_player.hand[int(i)] for i in card_indexes]
# challenges: Get the challenges from other players.
challenges = self.get_challenges(len(card_indexes))
cheat = False
# If there are any challenges:
if challenges:
# Maybe later make this only include one challenge
for ch in challenges:
if ch == challenges[-1]:
print("Cheat! called by {0}.".format(ch.name),
end=' '*6)
else:
print("Cheat! called by {0}.".format(ch.name))
input("Press enter to continue...")
for c in cards:
# If the player cheated...
if c.val != self.c_value:
cheat = True
break
# If the player has cheated:
if cheat:
print("{0} Cheated! {0} gets to pick up the pile!".format(
self.c_player), end=' '*6)
self.c_player.hand += self.pile
self.pile = []
# If the player has not cheated:
else:
print("{0} is innocent! {1} gets to pick up the pile!".format(
self.c_player, challenges[0]), end=' '*6)
for c in cards:
self.c_player.hand.remove(c)
self.pile.append(c)
challenges[0].hand += self.pile
self.pile = []
# If the player has not been challenged:
else:
print("No one has accused {0} of cheating".format(self.c_player), end=' '*6)
for c in cards:
self.c_player.hand.remove(c)
self.pile.append(c)
input("Press enter to continue...")
# If the player has won (has no cards left):
if not self.c_player.hand:
print("{0} won in {1} place!".format(self.c_player, game.ranks[len(self.winners)]))
print("The game will continue.")
input("Press enter to continue...")
self.winners.append(self.c_player)
self.next_turn()
def get_challenges(self, cards_len):
"""Gets the challenges from other players.
params: cards_len - The amount of cards the player put down."""
if randint(1, 2) == 1:
return self.human_challenge(cards_len) + self.computer_challenge(cards_len)
else:
return self.computer_challenge(cards_len) + self.human_challenge(cards_len)
def human_challenge(self, cards_len):
"""Asks the human players if they would like to challenge.
params: cards_len - The amount of cards the player put down."""
# Get the human instances from the self.players list
human_players = [p for p in self.players if isinstance(p, human) and p not in self.winners]
# If the player whose turn it is is a human, remove him/her from the
# list (if the player isn't a human, he/she wouldn't be in the list
# anyway).
if isinstance(self.c_player, human):
human_players.remove(self.c_player)
if not human_players:
return []
shuffle(human_players)
human_challenges = []
# Go through each player in human_players and ask if they want
# to challenge, and give them information like how many cards the
# the player put down, and how many this human already has.
for h in human_players:
num_cards = 0
for c in h.hand:
if c.val == self.c_value:
num_cards += 1
print("{0}: Do you think {1} is cheating?".format(
h, self.c_player), end=' '*6)
input("Press enter for more info...")
print("{0} claims to have put down {1} {2}(s).".format(
self.c_player, cards_len, value.get_name(self.c_value)), end=' '*6)
input("Press enter for more info...")
print("You have {0} {1}(s).".format(num_cards, value.get_name(self.c_value)))
challenge = input('Enter Cheat, or press enter to pass... ')
if 'cheat' in challenge.lower():
human_challenges.append(h)
return human_challenges
def computer_challenge(self, cards_len):
"""Gets the challengese from the computer players.
params: cards_len - The amount of cards the player put down."""
# Get the computer instances from the self.players list
computer_players = [p for p in self.players if isinstance(p, computer) and p not in self.winners]
# If the player whose turn it is is a computer player, remove him/her
# from the list (if the player isn't a computer player, he/she
# wouldn't be in the list anyway).
if isinstance(self.c_player, computer):
computer_players.remove(self.c_player)
if not computer_players:
return []
shuffle(computer_players)
computer_challenges = []
for c in computer_players:
# unless the computer player's difficulty is diff.EASY, challenge
# if the number of cards the player put down plus the number of
# this computer player has is more then four.
if c.difficulty != diff.EASY:
num_cards = 0
for ca in c.hand:
if ca.val == self.c_value:
num_cards += 1
if num_cards + cards_len > 4:
computer_challenges.append(c)
continue
# Easy computer player challenges 1/5 of the time.
if c.difficulty == diff.EASY:
if randint(1, 5) == 1:
computer_challenges.append(c)
elif c.difficulty == diff.MEDIUM:
pass
elif c.difficulty == diff.HARD:
pass
return computer_challenges
if __name__ == "__main__":
game(computer('Bob', diff.EASY), computer('Bill', diff.EASY), computer('Tristan', diff.EASY))
sorry that its so long.. maybe I shouldn't havae posted it all..