2
\$\begingroup\$

I have just finished a big project in Python. It is a card game.

Here are the rules:

There are 30 cards in the deck. Before the game starts, the deck is shuffled. Each card has a colour (red, black or yellow) and a number (1-10).

There are 15 rounds in the game. In each round both players take 1 card from the top of the deck.

The winner of each round depends on the colour of the card.

Red beats black. Black beats yellow. Yellow beats red.

If both cards have the same colour than the winner is the card with the highest number.

If both cards have the same colour and the same number then that round is a draw.

The winner of the game is the person with the most cards.


from random import shuffle
from time import sleep
from random import randint

from FileFunctions import *

# Card index constants
COLOUR = 0
NUMBER = 1

# Colour constants
RED = 'red'
BLACK = 'black'
YELLOW = 'yellow'

# Player constants
DRAW = 'draw'
PLAYER1 = '1'
PLAYER2 = '2'



def main():

    login()

    menu_loop = True

    while menu_loop:

        print('=======================================\n')

        print('1 - Play game')
        print('2 - Create new deck')
        print('3 - Change the speed of the game')
        print('4 - View the leaderboard')
        print('5 - Quit')

        menu_option = input('\nEnter menu option: ')

        print('\n=======================================')

        if menu_option == '1':
            play_game()
            input('Press enter to continue.')

        elif menu_option == '2':
            new_deck_menu()
            input('Press enter to continue.')

        elif menu_option == '3':
            change_speed()
            input('Press enter to continue.')

        elif menu_option == '4':
            top5 = read_top5()
            display_leaderboard(top5)
            input('Press enter to continue.')

        elif menu_option == '5':
            print('Goodbye.')
            menu_loop = False

        else:
            print('\nPlease choose a number from the menu.\n')



def login():

    # The passcode (for now) is 'Python'.
    password = get_passcode()

    valid = False

    while not valid:

        password_attempt = input('Enter password: ')

        if password_attempt == password:
            print('Welcome.')
            valid = True
        else:
            print('Incorrect passcode.')

    print('\n\n')


# Returns a tuple containing a colour and a number
def new_card(colour):
    return (colour, randint(1, 10))


# Creates a new random deck
def new_random_deck():

    deck = []

    for i in range(10):
        deck.append(new_card(RED))
        deck.append(new_card(BLACK))
        deck.append(new_card(YELLOW))

    write_deck(deck)



# Returns the name of the winner of the game and the winning cards as a tuple
def play_game():

    print('\n\n')

    valid = False

    while not valid:
        player1_name = input('Enter player 1\'s name: ')
        if '_' in player1_name:
            print('Names cannot contain underscores.') 
        else:
            valid = True

    valid = False

    while not valid:
        player2_name = input('Enter player 2\'s name: ')
        if '_' in player2_name:
            print('Names cannot contain underscores.')
        elif player2_name == player1_name:
            print('Player 1 and player 2 must have different names.')
        else:
            valid = True

    deck = load_deck()

    round_delay = load_round_delay()

    play_again = True

    while play_again:

        player1_cards = []
        player2_cards = []

        # Read the deck from the deck file.

        shuffle(deck)

        game_round = 1

        print('\n\n')

        while len(deck) > 0:

            sleep(round_delay)

            player1_card = deck[-1]
            player2_card = deck[-2]

            deck.pop()
            deck.pop()

            print('ROUND', game_round, '\n')

            display_cards(player1_card, player2_card)

            winner = compare_cards(player1_card, player2_card)

            if winner == PLAYER1:
                print('\nWinner:', player1_name)
            elif winner == PLAYER2:
                print('\nWinner:', player2_name)
            else:
                print('\nWinner: draw')

            print('\n\n')

            if winner == PLAYER1:
                player1_cards.append(player1_card)
                player1_cards.append(player2_card)

            elif winner == PLAYER2:
                player2_cards.append(player1_card)
                player2_cards.append(player2_card)

            game_round += 1

        if len(player1_cards) > len(player2_cards):
            winner = player1_name
            winning_cards = player1_cards

        elif len(player1_cards) < len(player2_cards):
            winner = player2_name
            winning_cards = player2_cards

        else:
            winner = DRAW

        if winner != DRAW:
            write_name_and_cards(winner, winning_cards)

        print('Winner of game:', winner)

        valid = False

        while not valid:
            yes_or_no = input('\nWould you like to play again? (y/n)').lower()
            valid = True
            if yes_or_no == 'n':
                play_again = False
            elif yes_or_no != 'y':
                print('Please answer with \'y\' or \'n\'.')
                valid = False

    print('\n\n')



# Returns the winner of 2 cards
def compare_cards(card1, card2):

    if card1[COLOUR] == card2[COLOUR]:

        if card1[NUMBER] > card2[NUMBER]:
            return PLAYER1
        elif card1[NUMBER] < card2[NUMBER]:
            return PLAYER2
        else:
            return DRAW

    else:

        if card1[COLOUR] == RED:
            return PLAYER1 if card2[COLOUR] == BLACK else PLAYER2

        elif card1[COLOUR] == BLACK:
            return PLAYER1 if card2[COLOUR] == YELLOW else PLAYER2

        elif card1[COLOUR] == YELLOW:
            return PLAYER1 if card2[COLOUR] == RED else PLAYER2



def display_cards(card1, card2):

    print('=======================================')
    print('PLAYER 1                 PLAYER 2')
    print('=======================================')

    print('colour:', card1[COLOUR], end='')
    space_length = 17 - len(card1[COLOUR])
    print(space_length * ' ', end='')
    print('colour:', card2[COLOUR])

    print('number:', card1[NUMBER], end='')
    space_length = 17 - len(str(card1[NUMBER]))
    print(space_length * ' ', end='')
    print('number:', card2[NUMBER])



def display_leaderboard(players):

    print('\nLEADERBOARD')

    for i in range(len(players)):
        score = len(players[i]) - 1
        print(str(i+1), ')', players[i][0], '-', score)

    print('\n')

def new_deck_menu():

    print('\n\n')

    valid = False

    while not valid:

        yes_or_no = input('\nCreating a new deck will overwrite the current deck. Do you wish to proceed? (y/n)')
        yes_or_no = yes_or_no.lower()

        valid = True

        if yes_or_no == 'y':
            new_random_deck()
            print('\nThe new deck has been created.')

        elif yes_or_no == 'n':
            print('\nCreation of new deck has been cancelled.')

        else:
            print('\nPlease answer with \'y\' or \'n\'.')
            valid = False

    print('\n\n')



def change_speed():

    valid = False

    current_delay = load_round_delay()

    while not valid:

        print('The current round delay is %f.' % (current_delay))

        yes_or_no = input('Are you sure you want to change the speed of the game? (y/n)').lower()
        valid = True

        if yes_or_no == 'y':

            global round_delay

            input_loop = True

            while input_loop:

                input_loop = False

                try:
                    seconds = float(input('\nEnter delay between each round in seconds: '))
                except ValueError:
                    input_loop = True
                    print('Please enter a float or an integer.')

            write_round_delay(seconds)

            print('\nThe new round delay has been saved.')

        elif yes_or_no == 'n':
            print('\nChanging of game speed has been cancelled.')

        else:
            print('\nPlease answer with \'y\' or \'n\'.\n')
            valid = False




if __name__ == '__main__':
    main()

FileFunctions.py:

from pickle import load

EmptyLine = IndexError

# Writes deck to deck.txt
def write_deck(deck_array):

    with open('deck.txt', 'w') as deck_file:

        for card in deck_array:

            deck_file.write(card[0])
            deck_file.write(',')
            deck_file.write(str(card[1]))
            deck_file.write('\n')

def load_deck():

    deck_array = []

    with open('deck.txt', 'r') as deck_file:
        deck_text = deck_file.read()

    deck_text = deck_text.split('\n')

    for card_string in deck_text:

        try:
            card = card_string.split(',')
            card[1] = int(card[1])
            deck_array.append( (card[0], card[1]) )
        except EmptyLine:
            continue

    return deck_array


def get_passcode():
    with open('passcode.bin', 'rb') as passcode_file:
        return load(passcode_file)


# Writes name and cards to win.txt
def write_name_and_cards(name, cards):

    with open('win.txt', 'a') as win_file:

        win_file.write(name)

        for card in cards:

            win_file.write('\n')
            win_file.write(card[0])
            win_file.write(',')
            win_file.write(str(card[1]))

        win_file.write('_')


# Returns the top 5 players as a tuple
def read_top5():

    with open('win.txt', 'r') as win_file:
        players = win_file.read()

    players = players.split('_')

    for i in range(len(players)):
        players[i] = players[i].split('\n')

    try:
        while players[-1] == ['']:
            players.pop()
    except IndexError: # The players array might be empty
        pass

    # The players variable now stores a 2d array

    top5 = []

    maximum = 5 if len(players) >= 5 else len(players)

    while len(top5) < maximum:

        index_of_highest = 0

        for i in range(len(players)):

            if len(players[i]) > len(players[index_of_highest]):
                index_of_highest = i

        top5.append(players[index_of_highest])
        players.pop(index_of_highest)

    return top5

def write_round_delay(seconds):
    with open('round_delay.txt', 'w') as rd_file:
        rd_file.write(str(seconds))

def load_round_delay():
    with open('round_delay.txt', 'r') as rd_file:
        return float(rd_file.read())

deck.txt:

red,6
black,5
yellow,6
red,9
black,8
yellow,8
red,5
black,9
yellow,3
red,7
black,2
yellow,9
red,10
black,2
yellow,3
red,5
black,3
yellow,6
red,6
black,3
yellow,7
red,2
black,1
yellow,5
red,3
black,1
yellow,10
red,6
black,10
yellow,2

round_delay.txt:

1

win.txt is empty at first.

passcode.bin contains the string "Python"

Edit: How can I improve the code?

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.