# 5-Card_Stud_Poker_Game.py import random from collections import Counter from hand_utils import evaluate_hand, Tuple, List, Card, SUITS, RANKS starting_chips = 0 # Default starting chips for each player rank_counts = Counter() @staticmethod def setup_players(): num_players = int(input("Enter number of players (2–5): ")) while True: if 2 <= num_players <= 5: break else: print("Invalid number of players. Please enter a number between 2 and 5.") num_players = int(input("Enter number of players (2–5): ")) players = [] for i in range(num_players): name = input(f"Enter name for Player {i+1} (or press Enter for default): ").strip() if not name: name = f"Player {i+1}" while True: try: starting_chips = int(input(f"Enter starting chips for {name}: ")) if starting_chips <= 0: print("Starting chips must be a positive number.") continue break except ValueError: print("Please enter a valid integer.") player = Player(name=name, starting_chips=starting_chips) player.active = True # Ensure player is active at start players.append(player) return players @staticmethod def deal_round(deck, players, round_num): print(f"\n--- Round {round_num} ---") for player in players: if not player.folded: player.receive_card(deck.deal_card()) print(player.show_hand()) @staticmethod def determine_winner(players, pot): best_score = (-1, -1) winner = None pot = pot for player in players: if player.folded: player.active = False continue full_hand = [player.hole_card] + player.face_up_cards score = evaluate_hand(full_hand) print(f"{player.name} hand score: {score}") if score > best_score: best_score = score winner = player if winner: winner.chips += pot print(f"\nšŸ† {winner.name} wins the pot with: {winner.reveal_full_hand()} and {winner.chips} chips") def deal_initial_cards(deck, players): for player in players: player.receive_hole_card(deck.deal_card()) # face-down player.receive_face_up_card(deck.deal_card()) # first face-up @staticmethod def betting_round(players, current_bet, pot): print("\n--- Betting Round ---") for player in players: if player.folded: continue print(f"\n{player.name}'s turn. Current bet: {current_bet}. Chips: {player.chips}") while True: action = input(f"{player.name}, do you want to call, raise or fold 'c', 'r', or 'f'? ").strip().lower() if action == 'f': player.folded = True print(f"{player.name} folds.") # Check if only one player remains active_players = [p for p in players if not p.folded and p.active and p.chips > 0] if len(active_players) == 1: winner = active_players[0] winner.chips += pot print(f"{winner.name} wins the pot of {pot} chips by default!") show_final_stacks(players, pot) continue_prompt(players) break else: players.remove(player) # Remove folded player from active players break elif action == 'c': try: bet = player.place_bet(current_bet) pot += bet print(f"{player.name} calls and bets {bet}.") break except ValueError as e: print(e) elif action == 'r': try: raise_amount = int(input("Enter raise amount: ")) total_bet = current_bet + raise_amount bet = player.place_bet(total_bet) current_bet = total_bet pot += bet print(f"{player.name} raises to {total_bet}.") break except ValueError as e: print(e) else: print("Invalid action. Please enter 'call', 'raise', or 'fold', 'c', 'r' or 'f'.") return current_bet, pot @staticmethod def play(players): deck = Deck() deal_initial_cards(deck, players) current_bet = 10 pot = 0 # Run betting round, determine winner, update chips for round_num in range(1, 4): print(f"\n--- Round {round_num} ---") for player in players: if not player.folded: player.receive_face_up_card(deck.deal_card()) print(player.show_hand()) current_bet, pot = betting_round(players=players, current_bet=current_bet, pot=pot) print("\n--- Showdown ---") for player in players: if not player.folded: print(player.reveal_full_hand()) print(f"\nTotal pot: {pot}") # Simulate betting round current_bet, pot = betting_round(players, current_bet, pot) pot += current_bet * sum(1 for p in players if not p.folded) # Showdown print("\n--- Showdown ---") for player in players: if not player.folded: print(player.reveal_full_hand()) determine_winner(players, pot) show_final_stacks(players, pot) def show_final_stacks(players, pot): print(f"\nTotal pot: {pot}") print("\n--- Final Chip Stacks ---") for player in players: print(f"{player.name}: {player.chips} chips") continue_prompt(players) def continue_prompt(players): response = input("Play another round? (y/n): ").lower() if response == 'y': add_new_players(players) reset_round(players) play(players) return True else: print("Game over. Thanks for playing!") exit() return False def add_new_players(players): while True: name = input("Enter new player name (or press Enter to skip): ") if not name: reset_round(players) play(players) break while True: try: starting_chips = int(input(f"Enter starting chips for {name}: ")) if starting_chips <= 0: print("Starting chips must be a positive number.") continue break except ValueError: print("Please enter a valid integer.") continue player = Player(name=name, starting_chips=starting_chips) player.active = True # Ensure new player is active at start print(f"{player.name} enters the game with {player.chips} chips.") players.append(player) # Default starting chips for new players reset_round(players) play(players) return players def reset_round(players): for p in players: if p.active and p.chips <= 0: print(f"{p.name} is out of chips and removed from the game.") players.remove(p) continue elif not p.active and p.chips > 0: p.active = True print(f"{p.name} re-enters the game with {p.chips} chips.") # Discard active player's previous hands, reset round-specific flags p.folded = False p.active = True p.hand = [] p.face_up_cards = [] p.hole_card = None elif p.active and p.chips > 0: p.folded = False p.hand = [] p.face_up_cards = [] p.hole_card = None class Deck: def __init__(self): self.cards: List[Card] = [Card(rank, suit) for suit in SUITS for rank in RANKS] random.shuffle(self.cards) def deal_card(self) -> Card: return self.cards.pop(0) def deal_hand(self, num: int = 5) -> List[Card]: hand = self.cards[:num] del self.cards[:num] return hand class Player: def __init__(self, name: str, starting_chips: int): self.name = name self.hold_card: Card = None self.face_up_cards: List[Card] = [] self.hand: List[Card] = [] self.folded = False self.chips = starting_chips self.active = False def place_bet(self, amount): if amount > self.chips: raise ValueError(f"{self.name} doesn't have enough chips to bet {amount}.") self.chips -= amount return amount def receive_hole_card(self, card): self.hole_card = card def receive_face_up_card(self, card): self.face_up_cards.append(card) def show_hand(self): return f"{self.name}: | {' | '.join(str(card) for card in self.face_up_cards)} |" def reveal_full_hand(self): return f"{self.name}: | {str(self.hole_card)} | {' | '.join(str(card) for card in self.face_up_cards)} |" def hand_rank(self) -> Tuple[int, List[int]]: return evaluate_hand(self.hand) def make_decision(self): high_ranks = {'J', 'Q', 'K', 'A'} visible_ranks = [card.rank for card in self.face_up_cards] if any(rank in high_ranks for rank in visible_ranks): return 'c' else: return 'f' class Game: def __init__(self): self.deck = Deck() self.players = setup_players() for player in self.players: player.hand = self.deck.deal_hand() def deal_initial_cards(deck, players): for player in players: player.receive_card(deck.deal_card()) # hole card player.receive_card(deck.deal_card()) # first face-up card def deal_round(deck, players, round_num): print(f"\n--- Round {round_num} ---") for player in players: if not player.folded: player.receive_card(deck.deal_card()) print(player.show_hand()) def main(): print("Welcome to 5-Card Stud Poker!") players = setup_players() while True: play(players) # Pass persistent player list if not continue_prompt(players): break if __name__ == "__main__": main()