Final commit
This commit is contained in:
parent
174b53bd22
commit
c6e189d392
220
5-Card_Stud_Poker.py
Normal file
220
5-Card_Stud_Poker.py
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
# 5-Card_Stud_Poker.py
|
||||||
|
|
||||||
|
import random
|
||||||
|
from collections import Counter
|
||||||
|
from hand_utils import evaluate_hand, Tuple, List, Card, SUITS, RANKS
|
||||||
|
|
||||||
|
rank_counts = Counter()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def setup_players() -> List["Player"]:
|
||||||
|
num_players = int(input("Enter number of players (2–5): "))
|
||||||
|
if not 2 <= num_players <= 5:
|
||||||
|
raise ValueError("Must be between 2 and 5 players.")
|
||||||
|
return [Player(f"Player {i+1}") for i in range(num_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):
|
||||||
|
best_score = (-1, -1)
|
||||||
|
winner = None
|
||||||
|
|
||||||
|
for player in players:
|
||||||
|
if player.folded:
|
||||||
|
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:
|
||||||
|
print(f"\n🏆 {winner.name} wins with: {winner.reveal_full_hand()}")
|
||||||
|
|
||||||
|
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 play():
|
||||||
|
deck = Deck()
|
||||||
|
players = setup_players()
|
||||||
|
deal_initial_cards(deck, players)
|
||||||
|
|
||||||
|
for round_num in range(2, 5): # 3 more face-up cards
|
||||||
|
# deal_round(deck, players, round_num)
|
||||||
|
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())
|
||||||
|
|
||||||
|
print("\n--- Showdown ---")
|
||||||
|
for player in players:
|
||||||
|
print(player.reveal_full_hand())
|
||||||
|
|
||||||
|
def betting_round(players: list, current_bet: int, pot: int) -> tuple[int, int]:
|
||||||
|
print(f"\nCurrent bet: {current_bet}")
|
||||||
|
for player in players:
|
||||||
|
if player.folded:
|
||||||
|
continue
|
||||||
|
|
||||||
|
print(f"\n{player.name}'s turn")
|
||||||
|
print(f"Visible cards: {' '.join(str(card) for card in player.face_up_cards)}")
|
||||||
|
decision = input("Choose action (call, raise, fold): ").strip().lower()
|
||||||
|
|
||||||
|
if decision == 'fold':
|
||||||
|
player.folded = True
|
||||||
|
print(f"{player.name} folds.")
|
||||||
|
elif decision == 'call':
|
||||||
|
pot += current_bet
|
||||||
|
print(f"{player.name} calls {current_bet}.")
|
||||||
|
elif decision == 'raise':
|
||||||
|
try:
|
||||||
|
raise_amount = int(input("Enter raise amount: "))
|
||||||
|
current_bet += raise_amount
|
||||||
|
pot += current_bet
|
||||||
|
print(f"{player.name} raises to {current_bet}.")
|
||||||
|
except ValueError:
|
||||||
|
print("Invalid raise amount. Treating as call.")
|
||||||
|
pot += current_bet
|
||||||
|
else:
|
||||||
|
print("Invalid input. Treating as fold.")
|
||||||
|
player.folded = True
|
||||||
|
|
||||||
|
return current_bet, pot
|
||||||
|
|
||||||
|
|
||||||
|
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):
|
||||||
|
self.name = name
|
||||||
|
self.hold_card: Card = None
|
||||||
|
self.face_up_cards: List[Card] = []
|
||||||
|
self.hand: List[Card] = []
|
||||||
|
self.folded = False
|
||||||
|
|
||||||
|
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 'call'
|
||||||
|
else:
|
||||||
|
return 'fold'
|
||||||
|
|
||||||
|
def hand_rank_name(rank: int) -> str:
|
||||||
|
names = {
|
||||||
|
9: "Royal Flush",
|
||||||
|
8: "Straight Flush",
|
||||||
|
7: "Four of a Kind",
|
||||||
|
6: "Full House",
|
||||||
|
5: "Flush",
|
||||||
|
4: "Straight",
|
||||||
|
3: "Three of a Kind",
|
||||||
|
2: "Two Pair",
|
||||||
|
1: "One Pair",
|
||||||
|
0: "High Card"
|
||||||
|
}
|
||||||
|
return names.get(rank, "Unknown Hand")
|
||||||
|
|
||||||
|
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!")
|
||||||
|
deck = Deck()
|
||||||
|
players = setup_players()
|
||||||
|
deal_initial_cards(deck, players)
|
||||||
|
|
||||||
|
current_bet = 10
|
||||||
|
pot = 0
|
||||||
|
|
||||||
|
for round_num in range(2, 5):
|
||||||
|
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)
|
||||||
|
print(f"\nTotal pot: {pot}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
BIN
__pycache__/hand_utils.cpython-313.pyc
Normal file
BIN
__pycache__/hand_utils.cpython-313.pyc
Normal file
Binary file not shown.
78
hand_utils.py
Normal file
78
hand_utils.py
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
# hand_utils.py
|
||||||
|
|
||||||
|
from typing import List, Tuple
|
||||||
|
from collections import Counter
|
||||||
|
|
||||||
|
SUITS = ['\u2665', '\u2663', '\u2660', '\u2666'] # Hearts, Clubs, Spades, Diamonds
|
||||||
|
RANKS = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
|
||||||
|
RANK_VALUES = {rank: i for i, rank in enumerate(RANKS, 2)}
|
||||||
|
|
||||||
|
class Card:
|
||||||
|
def __init__(self, rank: str, suit: str):
|
||||||
|
self.rank = rank.strip().upper()
|
||||||
|
self.suit = suit.strip().capitalize()
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"{self.rank} of {self.suit}"
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return isinstance(other, Card) and self.rank == other.rank and self.suit == other.suit
|
||||||
|
# return str(self) == str(other) # Alternative comparison method
|
||||||
|
|
||||||
|
def get_rank_counts(ranks: List[int]) -> Counter:
|
||||||
|
return Counter(ranks)
|
||||||
|
|
||||||
|
def is_flush(suits: List[str]) -> bool:
|
||||||
|
return len(set(suits)) == 1
|
||||||
|
|
||||||
|
def is_straight(ranks: List[int]) -> bool:
|
||||||
|
sorted_ranks = sorted(ranks, reverse=True)
|
||||||
|
return all(sorted_ranks[i] - 1 == sorted_ranks[i + 1] for i in range(len(sorted_ranks) - 1))
|
||||||
|
|
||||||
|
def evaluate_hand(hand: List[Card]) -> Tuple[int, List[int]]:
|
||||||
|
if len(hand) != 5:
|
||||||
|
raise ValueError("Hand must contain exactly 5 cards.")
|
||||||
|
|
||||||
|
ranks = sorted([RANK_VALUES[card.rank] for card in hand], reverse=True)
|
||||||
|
suits = [card.suit for card in hand]
|
||||||
|
rank_counts = get_rank_counts(ranks)
|
||||||
|
|
||||||
|
# Handle Ace-low straight
|
||||||
|
if ranks == [14, 5, 4, 3, 2]:
|
||||||
|
ranks = [5, 4, 3, 2, 1]
|
||||||
|
straight = True
|
||||||
|
else:
|
||||||
|
straight = is_straight(ranks)
|
||||||
|
|
||||||
|
flush = is_flush(suits)
|
||||||
|
|
||||||
|
if flush and ranks == [14, 13, 12, 11, 10]:
|
||||||
|
return (9, ranks) # Royal Flush
|
||||||
|
if flush and straight:
|
||||||
|
return (8, ranks) # Straight Flush
|
||||||
|
if 4 in rank_counts.values():
|
||||||
|
four = max(rank for rank, count in rank_counts.items() if count == 4)
|
||||||
|
kicker = max(rank for rank in ranks if rank != four)
|
||||||
|
return (7, [four]*4 + [kicker]) # Four of a Kind
|
||||||
|
if 3 in rank_counts.values() and 2 in rank_counts.values():
|
||||||
|
three = max(rank for rank, count in rank_counts.items() if count == 3)
|
||||||
|
pair = max(rank for rank, count in rank_counts.items() if count == 2)
|
||||||
|
return (6, [three]*3 + [pair]*2) # Full House
|
||||||
|
if flush:
|
||||||
|
return (5, ranks) # Flush
|
||||||
|
if straight:
|
||||||
|
return (4, ranks) # Straight
|
||||||
|
if 3 in rank_counts.values():
|
||||||
|
three = max(rank for rank, count in rank_counts.items() if count == 3)
|
||||||
|
kickers = sorted([rank for rank in ranks if rank != three], reverse=True)
|
||||||
|
return (3, [three]*3 + kickers) # Three of a Kind
|
||||||
|
if list(rank_counts.values()).count(2) == 2:
|
||||||
|
pairs = sorted([rank for rank, count in rank_counts.items() if count == 2], reverse=True)
|
||||||
|
kicker = max(rank for rank in ranks if rank not in pairs)
|
||||||
|
return (2, pairs*2 + [kicker]) # Two Pair
|
||||||
|
if 2 in rank_counts.values():
|
||||||
|
pair = max(rank for rank, count in rank_counts.items() if count == 2)
|
||||||
|
kickers = sorted([rank for rank in ranks if rank != pair], reverse=True)
|
||||||
|
return (1, [pair]*2 + kickers) # One Pair
|
||||||
|
return (0, ranks) # High Card
|
||||||
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import random
|
import random
|
||||||
from typing import List, Tuple
|
from typing import List, Tuple
|
||||||
|
|
||||||
SUITS = ['Hearts', 'Diamonds', 'Clubs', 'Spades']
|
SUITS = ['Hearts', 'Diamonds', 'Clubs', 'Spades'] #'\u2665', '\u2663', '\u2660', '\u2666'
|
||||||
RANKS = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
|
RANKS = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
|
||||||
RANK_VALUES = {rank: i for i, rank in enumerate(RANKS, 2)}
|
RANK_VALUES = {rank: i for i, rank in enumerate(RANKS, 2)}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user