blackjack-theory-game/game_logic.py
2026-06-09 20:07:08 +02:00

180 lines
8.9 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from constants import SUITS, RANKS
import random
def deal_card():
"""Simulates drawing a card. Returns a card name (e.g., 'card_clubs_02', 'card_clubs_K')."""
return f"card_{random.choice(SUITS)}_{random.choice(RANKS)}"
def calculate_hand_total(hand):
"""Calculates the total value of a hand, adjusting for Aces if necessary."""
numerical_values = []
for card in hand:
# Extract the rank from the card name (e.g., 'card_clubs_02' -> '02')
rank = card.split('_')[-1]
# Convert rank to numerical value
if rank in ['J', 'Q', 'K']:
numerical_values.append(10)
elif rank == 'A':
numerical_values.append(11)
else:
numerical_values.append(int(rank))
total = sum(numerical_values)
aces = numerical_values.count(11)
# Adjust for Aces if the total exceeds 21
while total > 21 and aces:
total -= 10 # Change an Ace from 11 to 1
aces -= 1
return total
def has_blackjack(hand):
"""Check if the hand is a Blackjack (Ace + 10-value card)."""
return len(hand) == 2 and calculate_hand_total(hand) == 21
def can_split(player_hand):
"""Checks if the player can split their hand."""
if len(player_hand) != 2:
return False
# Get ranks of both cards
rank1 = player_hand[0].split('_')[-1]
rank2 = player_hand[1].split('_')[-1]
# Consider all 10-value cards as splittable with each other
ten_value_cards = ['10', 'J', 'Q', 'K']
# Case 1: Exact same rank
if rank1 == rank2:
return True
# Case 2: Both are 10-value cards
elif rank1 in ten_value_cards and rank2 in ten_value_cards:
return True
return False
def get_split_decision(player_hand, dealer_card):
"""Returns the correct decision for splitting based on the player's pair and the dealer's card."""
pair_card = player_hand[0].split('_')[-1]
# Define splitting rules
if pair_card == "05": # 5s
return "Double", "Never split 5s; double down instead."
elif pair_card == "08": # 8s
return "Split", "Always split 8s."
elif pair_card in ['10', 'J', 'Q', 'K']: # 10s
return "Stand", "Never split 10s; stand instead."
elif pair_card == "A": # Aces
return "Split", "Always split Aces."
elif pair_card in ["02", "03", "04", "06", "07", "09"]: # Other pairs
if pair_card == "02" or pair_card == "03":
if dealer_card in ["02", "03", "04", "05", "06", "07"]:
return "Split", f"Split {pair_card}s vs dealer's 27. Note: This assumes doubling after splitting (DAS) is allowed. If DAS is not allowed, do not split {pair_card}s vs dealer's 23."
else:
return "Hit", f"Do not split {pair_card}s vs dealer's 8Ace; hit instead."
elif pair_card == "04": # 4s
if dealer_card in ["05", "06"]:
return "Split", f"Split {pair_card}s vs dealer's 56. Note: This assumes doubling after splitting (DAS) is allowed. If DAS is not allowed, do not split {pair_card}s."
else:
return "Hit", f"Do not split {pair_card}s vs dealer's 24 or 7Ace; hit instead."
elif pair_card == "06": # 6s
if dealer_card in ["02", "03", "04", "05", "06"]:
return "Split", f"Split {pair_card}s vs dealer's 26. Note: This assumes doubling after splitting (DAS) is allowed. If DAS is not allowed, do not split {pair_card}s vs dealer's 2."
else:
return "Hit", f"Do not split {pair_card}s vs dealer's 7Ace; hit instead."
elif pair_card == "07":
if dealer_card in ["02", "03", "04", "05", "06", "07"]:
return "Split", f"Split {pair_card}s vs dealer's 27."
else:
return "Hit", f"Do not split {pair_card}s vs dealer's 8Ace; hit instead."
elif pair_card == "09":
if dealer_card in ["02", "03", "04", "05", "06", "08", "09"]:
return "Split", f"Split {pair_card}s vs dealer's 26, 8, or 9."
else:
return "Stand", f"Do not split {pair_card}s vs dealer's 7, 10, or Ace; stand instead."
return "No rule defined", "No rule defined for this pair."
def get_correct_decision(player_hand, player_total, dealer_card):
"""Returns the correct decision based on the player's hand and the dealer's card."""
# Check if the hand is a soft total (contains an Ace counted as 11)
is_soft = 'A' in [card.split('_')[-1] for card in player_hand] and player_total <= 21
# Soft totals (Ace + 2 to Ace + 9)
if is_soft:
if player_total == 13: # Ace + 2
if dealer_card.split('_')[-1] in ['05', '06']:
return "Double", "Double when you have A,2 vs dealer's 56."
else:
return "Hit", "Hit when you have A,2 vs dealer's 24 or 7Ace."
elif player_total == 14: # Ace + 3
if dealer_card.split('_')[-1] in ['05', '06']:
return "Double", "Double when you have A,3 vs dealer's 56."
else:
return "Hit", "Hit when you have A,3 vs dealer's 24 or 7Ace."
elif player_total == 15: # Ace + 4
if dealer_card.split('_')[-1] in ['04', '05', '06']:
return "Double", "Double when you have A,4 vs dealer's 46."
else:
return "Hit", "Hit when you have A,4 vs dealer's 23 or 7Ace."
elif player_total == 16: # Ace + 5
if dealer_card.split('_')[-1] in ['04', '05', '06']:
return "Double", "Double when you have A,5 vs dealer's 46."
else:
return "Hit", "Hit when you have A,5 vs dealer's 23 or 7Ace."
elif player_total == 17: # Ace + 6
if dealer_card.split('_')[-1] in ['03', '04', '05', '06']:
return "Double", "Double when you have A,6 vs dealer's 36."
else:
return "Hit", "Hit when you have A,6 vs dealer's 2 or 7Ace."
elif player_total == 18: # Ace + 7
if dealer_card.split('_')[-1] in ['03', '04', '05', '06']: # Double vs. 36
return "Double", "Double when you have A,7 vs dealer's 36. Note: Some casinos may restrict doubling on certain hands, so check the rules."
elif dealer_card.split('_')[-1] in ['02', '07', '08']: # Stand vs. 2, 7, 8
if dealer_card.split('_')[-1] == '02':
return "Stand", "Stand on A,7 vs dealer's 2. However, some players choose to Double in this situation as a risky option. Note: Some casinos may restrict doubling on certain hands, so check the rules."
else:
return "Stand", "Stand on A,7 vs dealer's 7 or 8."
else: # Hit vs. 9, 10, Ace
return "Hit", "Hit on A,7 vs dealer's 9, 10, or Ace, as the dealer has a strong chance of making a good hand."
elif player_total == 19: # Ace + 8
if dealer_card.split('_')[-1] == '06':
return "Stand", "Stand on A,8 vs dealer's 6. However, some players choose to Double in this situation as a risky option. Note: This depends on casino rules."
else:
return "Stand", "Stand on A,8 vs dealer's 25 or 7Ace."
elif player_total == 20: # Ace + 9
return "Stand", "Stand on A,9 (soft 20)."
elif player_total == 21: # Ace + 10
return "Stand", "Stand on A,10 (Blackjack)."
# Hard totals (no Ace or Ace counted as 1)
if player_total < 9:
return "Hit", "Always Hit when your total is less than 9."
if player_total == 9:
if dealer_card.split('_')[-1] in ['03', '04', '05', '06']:
return "Double", "Double on 9 vs dealer's 36."
else:
return "Hit", "Hit on 9 vs dealer's 2, 7Ace."
elif player_total == 10:
if dealer_card.split('_')[-1] in ['02', '03', '04', '05', '06', '07', '08', '09']:
return "Double", "Double on 10 vs dealer's 29."
else:
return "Hit", "Hit on 10 vs dealer's 10 or Ace."
elif player_total == 11:
return "Double", "Always Double on 11."
elif player_total == 12:
if dealer_card.split('_')[-1] in ['04', '05', '06']:
return "Stand", "Stand on 12 vs dealer's 46."
else:
return "Hit", "Hit on 12 vs dealer's 23 or 7Ace."
elif 13 <= player_total <= 16:
if dealer_card.split('_')[-1] in ['02', '03', '04', '05', '06']:
return "Stand", "Stand on 1316 vs dealer's 26."
else:
return "Hit", "Hit on 1316 vs dealer's 7Ace."
elif player_total >= 17:
return "Stand", "Always Stand on 17 or higher."
return "No rule defined", "No rule defined for this scenario."