# Load required libraries
pacman::p_load(pacman, dplyr, grid, gridExtra, png)
# Create the full deck of cards based on the number of decks
suits <- c("Hearts", "Diamonds", "Clubs", "Spades")
values <- c(2:10, "J", "Q", "K", "A")
# Shuffle function to create a deck with multiple packs
shuffle_deck <- function(num_decks = 1) {
deck <- expand.grid(Value = values, Suit = suits, stringsAsFactors = FALSE)
full_deck <- do.call(rbind, replicate(num_decks, deck, simplify = FALSE)) # Replicate the deck based on num_decks
full_deck <- full_deck[sample(nrow(full_deck)), ] # Shuffle the deck
full_deck$Value <- as.character(full_deck$Value) # Ensure 'Value' column is treated as characters
return(full_deck)
}
# Blackjack card values
blackjack_values <- c("2" = 2, "3" = 3, "4" = 4, "5" = 5, "6" = 6, "7" = 7, "8" = 8, "9" = 9, "10" = 10,
"J" = 10, "Q" = 10, "K" = 10, "A" = 11) # Ace can also be 1, handle separately
# Function to get the blackjack value of a card
get_blackjack_value <- function(card) {
return(blackjack_values[as.character(card)])
}
# Function to calculate the value of a hand in Blackjack
calculate_hand_value <- function(cards) {
values <- sapply(cards$Value, get_blackjack_value) # Get the numeric values of the cards
total_value <- sum(values) # Sum up the values
# Adjust for Aces (Ace can be 1 or 11)
num_aces <- sum(cards$Value == "A")
while (total_value > 21 && num_aces > 0) {
total_value <- total_value - 10 # Treat an Ace as 1 instead of 11
num_aces <- num_aces - 1
}
return(total_value)
}
# Function to display card images
display_card_image <- function(value, suit, face_down = FALSE) {
if (face_down) {
file_name <- "back_of_card.png" # Path to the back of the card image
} else {
file_name <- paste0(tolower(value), "_of_", tolower(suit), ".png")
}
# Load the image from the file path
img_path <- file.path("cards", file_name)
if (file.exists(img_path)) {
img <- readPNG(img_path)
return(rasterGrob(img))
} else {
cat("Card image not found:", img_path, "\n")
return(NULL)
}
}
# Function to display the cards in two rows (with dealer's face-down card option)
display_blackjack_table <- function(dealer_cards, player_cards, reveal_dealer = FALSE) {
dealer_images <- lapply(1:nrow(dealer_cards), function(i) {
face_down <- ifelse(i == 2 && !reveal_dealer, TRUE, FALSE) # Dealer's second card face down if not reveal_dealer
display_card_image(dealer_cards$Value[i], dealer_cards$Suit[i], face_down = face_down)
})
player_images <- lapply(1:nrow(player_cards), function(i) {
display_card_image(player_cards$Value[i], player_cards$Suit[i])
})
# Arrange dealer and player cards in rows
grid.arrange(gridExtra::arrangeGrob(grobs = dealer_images, ncol = nrow(dealer_cards)),
gridExtra::arrangeGrob(grobs = player_images, ncol = nrow(player_cards)),
nrow = 2)
}
# Main game function for Blackjack with deck selection and replay option
play_blackjack <- function(deck = NULL, num_decks = NULL) {
# If no deck is provided (first game or reshuffle), ask how many decks to use
if (is.null(deck) || nrow(deck) < 10) { # Check if deck needs reshuffling
if (is.null(num_decks)) {
num_decks <- as.integer(readline(prompt = "How many decks do you want to play with? (Typical casino uses 6 or 8): "))
if (is.na(num_decks) || num_decks < 1) {
cat("Invalid input. Using 1 deck.\n")
num_decks <- 1
}
}
deck <- shuffle_deck(num_decks) # Shuffle new deck with selected number of decks
} else {
cat("Continuing with the current deck...\n")
}
# Deal two cards to both player and dealer
player_cards <- deck[1:2, ]
dealer_cards <- deck[3:4, ]
deck <- deck[-(1:4), ] # Remove the dealt cards from the deck
# Display the initial deal with dealer's second card face down
cat("Initial cards dealt:\n")
display_blackjack_table(dealer_cards, player_cards, reveal_dealer = FALSE) # Face down for dealer's second card
# Player's turn
player_hand_value <- calculate_hand_value(player_cards)
while (player_hand_value < 21) {
cat("Your hand value is:", player_hand_value, "\n")
action <- readline(prompt = "Do you want to hit or stand? (h/s): ")
if (tolower(action) == "h") {
new_card <- deck[1, ]
deck <- deck[-1, ] # Remove the new card from the deck
player_cards <- rbind(player_cards, new_card)
display_blackjack_table(dealer_cards, player_cards, reveal_dealer = FALSE) # Still face down
player_hand_value <- calculate_hand_value(player_cards)
} else if (tolower(action) == "s") {
break
} else {
cat("Invalid input. Please enter 'h' for hit or 's' for stand.\n")
}
}
if (player_hand_value > 21) {
cat("Bust! Your hand value is:", player_hand_value, ". You lose.\n")
replay_game(deck, num_decks) # Pass the current deck and num_decks to the replay function
return()
}
# Dealer's turn: reveal face-down card and follow rules
cat("\nDealer's turn:\n")
display_blackjack_table(dealer_cards, player_cards, reveal_dealer = TRUE) # Reveal dealer's second card
dealer_hand_value <- calculate_hand_value(dealer_cards)
# Dealer hits until hand value is 17 or higher OR until the hand value is at least as high as the player's hand (without busting)
while (dealer_hand_value < 17 || (dealer_hand_value < player_hand_value && dealer_hand_value <= 21)) {
cat("Dealer's hand value is:", dealer_hand_value, "\n")
new_card <- deck[1, ]
deck <- deck[-1, ]
dealer_cards <- rbind(dealer_cards, new_card)
display_blackjack_table(dealer_cards, player_cards, reveal_dealer = TRUE)
dealer_hand_value <- calculate_hand_value(dealer_cards)
}
# Determine the outcome without printing the bust message twice
if (dealer_hand_value > 21) {
cat("Dealer busts! Dealer's hand value is:", dealer_hand_value, ". You win!\n")
} else {
cat("Dealer stands with a hand value of:", dealer_hand_value, "\n")
# Determine the final outcome after the dealer stands
if (dealer_hand_value > player_hand_value) {
cat("Dealer wins with a hand value of:", dealer_hand_value, "\n")
} else if (dealer_hand_value < player_hand_value) {
cat("You win with a hand value of:", player_hand_value, "\n")
} else {
cat("It's a tie! Both have a hand value of:", player_hand_value, "\n")
}
}
# Ask if the player wants to play again
replay_game(deck, num_decks)
}
# Function to ask if the player wants to play again, without shuffling if they continue
replay_game <- function(deck, num_decks) {
play_again <- readline(prompt = "Do you want to play again? (y/n): ")
if (tolower(play_again) == "y") {
play_blackjack(deck, num_decks) # Continue with the same deck and number of decks
} else {
cat("Thanks for playing!\n")
}
}
# Start the game with no deck passed initially (fresh start)
play_blackjack()