I implemented a card game using pygame, the game is a game of war and using png files that I made in Microsoft paint. I tried to keep the object classes as separated from the pygame module as possible. The idea of this is so I can use the CardClasses module with other graphical interfaces, and to reuse it on different games whose displays will be different. When I go to rewrite this, or something similar the idea is to plan on using a Game class as opposed to the more function paradigm I wrote here. I learned that I cant upload the card image files here so I will upload the code in hopes that some brave soul will comb through the lines and give me some feedback. Looking at how to rewrite the doc strings, I feel as though they are weak and only give the idea of the functions or classes they represent.
CardClasses.py
"""Created: 3/30/2019
Objects to represent a playing Card, playing Deck, and Player
"""
from enum import Enum
from itertools import product
from random import shuffle
class ranks(Enum):
TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE = range(2, 15)
class suits(Enum):
CLUBS,DIAMONDS,HEARTS,SPADES = range(1, 5)
class Card(object):
"""Card object represents a standard playing card.
The object attributes, suit and rank, are implemented as enums whose values determine the weight of the card
"""
def __init__(self, suit, rank, in_deck = False, image = None):
if rank in ranks and suit in suits:
self.rank = rank
self.suit = suit
else:
self.rank = None
self.suit = None
self.in_deck = in_deck
self.image = image
self.position_x, self.position_y = 0,0
self.horizontal_demension = None
self.vertical_demension = None
def __str__(self):
return str(self.rank.name) + " " + str(self.suit.name)
def __eq__(self, other):
return True if self.rank == other.rank and self.suit == other.suit else False
def __gt__(self, other):
"""Tests suit precedence, if suits are equal then checks ranks precedence"""
if self.suit == other.suit:
if self.rank.value > other.rank.value:
return True
if self.suit.value > other.suit.value:
return True
return False
class Deck(object):
"""A deck is a collection of 52 Card objects
Object attributes: cards, removed
methods: draw(range = 1), deck_shuffle()
"""
def __init__(self):
self.cards = [Card(suit, rank, in_deck = True) for suit, rank in product(suits, ranks)]
self.removed = []
def __str__(self):
return str([str(card) for card in self.cards])
def draw(self, range = 1):
"""Draw card(s) by removing them from deck"""
drawn_cards = self.cards[:range]
for card in drawn_cards:
card.in_deck = False
del self.cards[:range]
self.removed.append(drawn_cards)
return drawn_cards
def deck_shuffle(self):
"""Shuffles deck object in place"""
shuffle(self.cards)
class Player(object):
"""Implementation of a player object
Object attributes: name, hand, score, turn, card_selected
methods: remove_from_hand(card)
"""
def __init__(self, name, hand = None, score = 0, turn = False):
self.name = name
self.hand = hand
self.score = score
self.turn = turn
self.selected_card = None
def __str__(self):
return str(self.name)
def remove_from_hand(self, card):
"""Removes a card object from the players hand"""
if card and card in self.hand:
position = self.hand.index(card)
del self.hand[position]
return card
return None
Game.py
"""3/31/2019
Implementation of game of war using pygame and CardClasses
"""
from CardClasses import *
import pygame
green = (0, 200, 50)
def show_hand(screen, player):
"""Displays all cards in hand of player on pygame display object"""
x, y, space_between_cards = 5, 462, 5
for card in player.hand:
card.position_x, card.position_y = x, y
screen.blit(card.image, (x, y))
x += card.horizontal_demension + space_between_cards
def select_card(player, mouse_x, mouse_y):
"""Player selects a card to play"""
if mouse_x:
for card in player.hand:
lower_x, upper_x = (card.position_x, card.position_x + card.horizontal_demension)
lower_y, upper_y = (card.position_y, card.position_y + card.vertical_demension)
if mouse_x > lower_x and mouse_x < upper_x:
if mouse_y > lower_y and mouse_y < upper_y:
player.selected_card = card
def load_card_images(player):
"Loads image, and demensions to card objects"
for card in player.hand:
card.image = pygame.image.load("Cards/" + str(card) + ".png")
width, hieght = card.image.get_size()
card.horizontal_demension = width
card.vertical_demension = hieght
def play_selected_card(screen, player):
"""Display card that is selected on pygame display object"""
x = player.selected_card.position_x = 220
y = player.selected_card.position_y
screen.blit(player.selected_card.image, (x,y))
def show_winner(screen, player1, player2, my_font):
"""Display text stating game winner at end of game"""
screen.fill(green)
winner = str(player1) if player1.score > player2.score else str(player2)
textsurface = my_font.render("The winner is: " + winner, False, (0, 0, 0))
screen.blit(textsurface, (100, 270))
def update_selected_card_position(player, new_y_position):
"""Change the Y position of selected card to move card to played position"""
if player.selected_card:
player.selected_card.position_y = new_y_position
def evaluate(player1, player2):
"""determines who won round and updates their score"""
round_winner = None
if player1.selected_card and player2.selected_card:
pygame.time.delay(1000)
round_winner = player1 if player1.selected_card > player2.selected_card else player2
round_winner.score += 1
player1.selected_card, player2.selected_card = None, None
return round_winner
def show_player_scores(screen, player1, player2):
"""Left corner is player 1 score, right corner is player 2 score"""
font_size = 12
my_font = pygame.font.SysFont('Times New Roman', font_size)
textsurface1 = my_font.render("Player 1 score: " + str(player1.score), False, (0, 0, 0))
textsurface2 = my_font.render("Player 2 score: " + str(player2.score), False, (0, 0, 0))
screen.blit(textsurface1, (0,0))
screen.blit(textsurface2, (470,0))
def flip_turns(player1, player2):
"""Negates Turn attributes of player1 and player2"""
player1.turn = not player1.turn
player2.turn = not player2.turn
def turn(player, mouse_x, mouse_y, new_y_position):
"""Player will select card using mouse_x, and mouse_y, card will be removed from hand and played"""
select_card(player, mouse_x, mouse_y)
player.remove_from_hand(player.selected_card)
update_selected_card_position(player, new_y_position)
def winner_goes_first(winner, loser):
"""Sets the winner to the starter of the next round"""
winner.turn = True
loser.turn = False
def main():
"""GAME of war, each player is given a hand of 10 cards, on each turn a player will select a card to play,
players cards will be compared and the player with the greater in value card will be assigned a point for round victory.
When all cards in hand have been played game ends and winner is displayed
"""
sc_width, sc_height = 555, 555
selected_card_y_pos_player_1 = 330
selected_card_y_pos_player_2 = 230
font_size = 30
delay_time_ms = 1000
number_of_cards = 10
turn_count = 1
deck = Deck()
deck.deck_shuffle()
player1 = Player(input("Player 1 name: "), hand = deck.draw(number_of_cards), turn = True)
player2 = Player(input("Player 2 name: "), hand = deck.draw(number_of_cards))
pygame.init()
screen = pygame.display.set_mode((sc_width, sc_height))
load_card_images(player1)
load_card_images(player2)
pygame.font.init()
my_font = pygame.font.SysFont('Times New Roman', font_size)
"""Main Game Loop"""
game_is_running = True
while game_is_running:
screen.fill(green)
mouse_x, mouse_y = None, None
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
game_is_running = False
quit()
if event.type == pygame.MOUSEBUTTONUP:
mouse_x, mouse_y = pygame.mouse.get_pos()
if player1.turn:
show_hand(screen, player1)
turn(player1, mouse_x, mouse_y, selected_card_y_pos_player_1)
if player1.selected_card:
flip_turns(player1, player2)
else:
show_hand(screen, player2)
turn(player2, mouse_x, mouse_y, selected_card_y_pos_player_2)
if player2.selected_card:
flip_turns(player1, player2)
if player1.selected_card:
play_selected_card(screen, player1)
if player2.selected_card:
play_selected_card(screen, player2)
show_player_scores(screen, player1, player2)
pygame.display.update()
winner = evaluate(player1,player2)
if winner:
if winner == player1:
winner_goes_first(player1, player2)
else:
winner_goes_first(player2, player1)
if not player1.hand and not player2.hand:
show_winner(screen, player1, player2, my_font)
pygame.display.update()
pygame.time.delay(delay_time_ms)
game_is_running = False
if __name__ == '__main__':
main()