146 lines
4.8 KiB
Python
146 lines
4.8 KiB
Python
import random
|
||
from typing import List, Tuple
|
||
|
||
SUITS = ['Hearts', 'Diamonds', 'Clubs', 'Spades']
|
||
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
|
||
|
||
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, deck: Deck):
|
||
self.name = name
|
||
self.hand: List[Card] = deck.deal_hand()
|
||
|
||
def show_hand(self):
|
||
return '\n '.join(str(card) for card in self.hand)
|
||
|
||
def replace_card(self, old_card: Card, new_card: Card) -> bool:
|
||
for i, card in enumerate(self.hand):
|
||
if card == old_card:
|
||
self.hand[i] = new_card
|
||
return True
|
||
return False
|
||
|
||
def hand_rank(self) -> Tuple[int, List[int]]:
|
||
ranks = sorted([RANK_VALUES[card.rank] for card in self.hand], reverse=True)
|
||
suits = [card.suit for card in self.hand]
|
||
rank_counts = {r: ranks.count(r) for r in ranks}
|
||
is_flush = len(set(suits)) == 1
|
||
is_straight = all(ranks[i] - 1 == ranks[i+1] for i in range(len(ranks)-1))
|
||
|
||
# Handle Ace-low straight
|
||
if ranks == [14, 5, 4, 3, 2]:
|
||
is_straight = True
|
||
ranks = [5, 4, 3, 2, 1]
|
||
|
||
if is_flush and ranks == [14, 13, 12, 11, 10]:
|
||
return (9, ranks) # Royal Flush
|
||
|
||
counts = sorted(rank_counts.values(), reverse=True)
|
||
|
||
if is_straight and is_flush:
|
||
return (8, ranks) # Straight Flush
|
||
elif counts[0] == 4:
|
||
return (7, ranks) # Four of a Kind
|
||
elif counts[0] == 3 and counts[1] == 2:
|
||
return (6, ranks) # Full House
|
||
elif is_flush:
|
||
return (5, ranks) # Flush
|
||
elif is_straight:
|
||
return (4, ranks) # Straight
|
||
elif counts[0] == 3:
|
||
return (3, ranks) # Three of a Kind
|
||
elif counts[0] == 2 and counts[1] == 2:
|
||
return (2, ranks) # Two Pair
|
||
elif counts[0] == 2:
|
||
return (1, ranks) # One Pair
|
||
else:
|
||
return (0, ranks) # High Card
|
||
|
||
class Game:
|
||
def __init__(self):
|
||
self.deck = Deck()
|
||
self.player1 = Player("Player 1", self.deck)
|
||
self.player2 = Player("Player 2", self.deck)
|
||
|
||
def prompt_card_replacement(self, player: Player):
|
||
while True:
|
||
try:
|
||
num = int(input(f"{player.name}, how many cards do you want to pull? (0–3): "))
|
||
if 0 <= num <= 3:
|
||
break
|
||
else:
|
||
print("Invalid number. Please choose between 0 and 3.")
|
||
except ValueError:
|
||
print("Invalid input. Please enter a number between 0 and 3.")
|
||
|
||
replacements_done = 0
|
||
while replacements_done < num:
|
||
print("\nYour current hand:\n", player.show_hand())
|
||
user_input = input("Enter a card to replace (e.g., A of Spades): ").strip()
|
||
|
||
if ' of ' not in user_input:
|
||
print("Invalid format. Use 'Rank of Suit'.")
|
||
continue
|
||
|
||
rank, suit = user_input.split(' of ', 1)
|
||
old_card = Card(rank, suit)
|
||
|
||
if old_card not in player.hand:
|
||
print(f"{old_card} not found in your hand. Please try again.")
|
||
continue
|
||
|
||
new_card = self.deck.deal_card()
|
||
if player.replace_card(old_card, new_card):
|
||
print(f"Replaced {old_card} with {new_card}")
|
||
replacements_done += 1
|
||
else:
|
||
print("Replacement failed unexpectedly.")
|
||
|
||
def play(self):
|
||
print("Initial hands:")
|
||
print("Player 1:\n", self.player1.show_hand())
|
||
print("Player 2:\n", self.player2.show_hand())
|
||
|
||
self.prompt_card_replacement(self.player1)
|
||
self.prompt_card_replacement(self.player2)
|
||
|
||
rank1 = self.player1.hand_rank()
|
||
rank2 = self.player2.hand_rank()
|
||
|
||
print("\nFinal hands:")
|
||
print("Player 1:\n", self.player1.show_hand())
|
||
print("Player 2:\n", self.player2.show_hand())
|
||
|
||
if rank1 > rank2:
|
||
print("Player 1 wins!", rank1)
|
||
elif rank2 > rank1:
|
||
print("Player 2 wins!", rank2)
|
||
else:
|
||
print("It's a tie!")
|
||
|
||
if __name__ == "__main__":
|
||
Game().play() |