Day 11 – Capstone Project

Write a text based Blackjack game.

My Solution:

import random # needed to draw a random item from the list
from art import logo
import os

# sets up the card we can play with
cards = [11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10]

def deal_card():
    """Returns a random card from the deck"""
    card = random.choice(cards)
    return card

def check_ace(cards):
    """Take a list of cards and check of the ace should be 1 or 11"""
    if 11 in cards and sum(cards) > 21:
        cards.remove(11)
        cards.append(1)
    return sum(cards)

def is_blackjack(hand):
    """Take a list of cards and return True if it's a blackjack, False otherwise"""
    # NOTE I did not include checks for only two cards - I need to revisit this, but
    # it is used in result which takes scores not cards so needs adjusting as well

    if sum(hand) == 21 and len(hand) == 2:
        return True
    else:
        return False

def is_bust(score):
    """Take a score and return True if the score is over 21, False otherwise"""
    if score > 21:
        return True
    else:
        return False

def result(u_score, c_score):
    """Take two scores and compare them to determine the winner"""
    # define complex messages
    player_win = f"\n{'*' * 20} \n You win \n{'*' * 20}"
    dealer_win = f"\n{'*' * 20} \n Dealer wins \n{'*' * 20}"
    draw = f"\n{'*' * 20} \n !Draw! \n{'*' * 20}"
    player_bust = f"\n{'*' * 20} \n Your score {u_score}. You Bust. You lose \n{'*' * 20}"
    dealer_bust = f"\n{'*' * 20} \n Dealer score {c_score}. Dealer Bust. You win \n{'*' * 20}"
    if u_score > c_score and not is_bust(u_score):
        return player_win
    elif c_score > u_score and not is_bust(c_score):
        return dealer_win
    elif u_score == c_score:
        return draw
    elif is_bust(u_score):
        return player_bust
    elif is_bust(c_score):
        return dealer_bust

def play_game():
    """Play a single game of blackjack"""
    # Setup empty lists to hold each players cards
    user_cards = []
    dealer_cards = []

    # set the game_over token to false
    is_game_over = False

    # deal the first two cards
    # the _ can be used when you don't need the value in range inside the loop
    # for example: for i in range(2): would work but we never need to know the value of i
    # so we can use an underscore instead

    for _ in range(2):
        user_cards.append(deal_card())
        dealer_cards.append(deal_card())

    # play the game until it ends
    while not is_game_over:
        # calculate the scores from the list items
        user_score = check_ace(user_cards)
        dealer_score = check_ace(dealer_cards)
        print(f"User cards {user_cards} Total {user_score}")
        print(f"Dealers first card {dealer_cards[0]}")

        # Check if either player has blackjack. if they do the game ends
        if is_blackjack(dealer_cards):
            is_game_over = True
            return result(user_score, dealer_score)
        elif is_blackjack(user_cards):
            is_game_over = True
            return result(user_score, dealer_score)


        if is_game_over:    # This would be true if either player had blackjack or had already bust.
            return result(user_score, dealer_score)
        else: # If neither player has blackjack or has gone bust, the user needs to decide if they want more cards
            # Ask the user if they want another card
            user_should_deal = input("++Type 'y' to get another card, type 'n' to pass: ")
            while user_should_deal == "y" and not is_game_over: # as long as the user say yes
                user_cards.append(deal_card())                  # deal another card to the dealer
                user_score = check_ace(user_cards)              # calculate the score and check for aces
                if is_bust(user_score):                         # check user score for > 21
                    print(f"User's cards {user_cards} Total {user_score}.")
                    is_game_over = True
                    return result(user_score, dealer_score)
                else:                                           # if not == 21 nor > 21
                    print(f"Player's cards {user_cards} Total {user_score}.")
                    user_should_deal = input("--Type 'y' to get another card, type 'n' to pass: ") # ask if they want another card

            while dealer_score < 17 and not is_game_over:       # One the player has stopped taking cards. If the game has not ended
                dealer_cards.append(deal_card())                # deal another card to the dealer
                dealer_score = check_ace(dealer_cards)          # add up the dealers score
                if is_bust(dealer_score):                       # check for bust
                    print("dealer bust")
                    is_game_over = True
                    return result(user_score, dealer_score)

                                                                            # once the dealer score > 17 stop
            print(f"User's cards {user_cards} Total {user_score}.")         # print the hands
            print(f"Dealer's cards {dealer_cards} Total {dealer_score}.")   # print the scores'
            return result(user_score, dealer_score)                         # calculate and print the result

play = 'y'
print(logo)
while play == 'y':
    message = play_game()
    print(message)
    play = input("\nDo you want to play again? (y/n): ")
    if play == 'n':
        print("Thanks for playing!")
    else:
        os.system('cls')
        print(logo)