ChatDev/WareHouse/Poker1_DefaultOrganization_20231006035628/game.py

255 lines
11 KiB
Python

'''
Game module that manages the Texas Hold'em Poker game.
'''
from player import HumanPlayer, AIPlayer
from deck import Deck
class Game:
def __init__(self):
self.players = []
self.deck = Deck()
self.community_cards = []
self.small_blind = 5
self.big_blind = 10
self.current_bet = 0
self.pot = 0
def start(self):
self.initialize_players()
self.initialize_blinds()
self.play_round()
def initialize_players(self):
self.players.append(HumanPlayer("Human", 1000))
self.players.append(AIPlayer("AI 1", 1000))
self.players.append(AIPlayer("AI 2", 1000))
self.players.append(AIPlayer("AI 3", 1000))
self.players.append(AIPlayer("AI 4", 1000))
def initialize_blinds(self):
for player in self.players:
if player.name == "AI 4":
player.blind = self.small_blind
elif player.name == "Human":
player.blind = self.big_blind
def play_round(self):
while len(self.players) > 1:
self.deck.shuffle()
self.reset_round()
self.collect_blinds()
self.deal_hole_cards()
self.play_betting_round()
if len(self.players) > 1:
self.deal_community_cards()
self.play_betting_round()
self.deal_community_cards()
self.play_betting_round()
self.deal_community_cards()
self.play_betting_round()
if len(self.players) > 1:
self.determine_winner()
elif len(self.players) == 1:
self.players[0].chips += pot
def reset_round(self):
self.community_cards = []
self.current_bet = 0
self.pot = 0
for player in self.players:
player.reset()
def collect_blinds(self):
for player in self.players:
if player.blind == self.small_blind:
self.pot += player.blind_bet(self.small_blind)
elif player.blind == self.big_blind:
self.pot += player.blind_bet(self.big_blind)
def deal_hole_cards(self):
for player in self.players:
player.receive_cards(self.deck.draw(2))
def play_betting_round(self):
for player in self.players:
if len(self.community_cards) != 0:
player.previous_bet = 0
player.blind = 0
self.current_bet = 0
else:
self.current_bet = 10
if len(self.community_cards) != 0:
print (f"Community cards: {self.community_cards}")
print (f"Pot: {self.pot}")
current_player_index = self.get_next_player_index(0)
last_raiser_index = None
while True:
current_player = self.players[current_player_index]
if current_player.is_active():
action = current_player.make_decision(self.current_bet)
if action == "fold":
current_player.fold()
elif action == "check":
if last_raiser_index is not None:
if (self.current_bet > current_player.previous_bet):
print(f"{current_player.name} attempted to check. Forcing fold...")
current_player.fold() #Bot likes to check to avoid calling, force them to fold with this
else:
current_player.check()
elif action == "call":
if last_raiser_index is not None: #Someone raised
if (amount >= current_player.chips): #All in
self.pot += current_player.all_in()
else: #Has the chips to call
prev_bet = current_player.call(self.current_bet - current_player.previous_bet - current_player.blind)
self.pot += prev_bet
current_player.previous_bet += prev_bet + current_player.blind
current_player.blind = 0
else: #No one raised, pay big blind
self.pot += current_player.call(self.big_blind - current_player.blind)
self.previous_bet = 10
current_player.previous_bet = 10
current_player.blind = 0
elif action == "raise":
amount = current_player.get_raise_amount(self.current_bet)
new_amount = amount + self.current_bet*2 - current_player.blind - current_player.previous_bet
self.current_bet = new_amount + current_player.blind + current_player.previous_bet
current_player.blind = 0
self.pot += current_player.raise_bet(new_amount)
print(f"Current top bet is: {self.current_bet}")
last_raiser_index = current_player_index
current_player.previous_bet = self.current_bet
current_player_index = self.get_next_player_index(current_player_index)
if current_player_index == last_raiser_index:
break
def deal_community_cards(self):
if len(self.players[0].community_cards) == 0:
self.community_cards.extend(self.deck.draw(3))
elif len(self.players[0].community_cards) == 3:
self.community_cards.extend(self.deck.draw(1))
elif len(self.players[0].community_cards) == 4:
self.community_cards.extend(self.deck.draw(1))
for player in self.players:
player.receive_community_cards(self.community_cards)
def determine_winner(self):
best_hand_value = 0
winners = []
for player in self.players:
if player.is_active():
hand_value = self.calculate_hand_value(player)
if hand_value > best_hand_value:
best_hand_value = hand_value
winners = [player]
elif hand_value == best_hand_value:
winners.append(player)
if len(winners) == 1:
winning_player = winners[0]
print(f"{winning_player.name} wins with {self.get_hand_name(best_hand_value)}!")
winning_player.chips += self.pot
else:
print("It's a tie!")
def calculate_hand_value(self, player):
# Implement logic to calculate the unique hand value as described in the provided information.
hand_type = self.determine_hand_type(player.hand)
card_values = [self.get_card_value(card) for card in player.hand]
hand_value = hand_type
for card_value in card_values:
hand_value = (hand_value << 4) + card_value
print(f"{player.name} with cards: {player.hand} has hand value: {hand_value}")
return hand_value
def determine_hand_type(self, hand):
# Sort the hand in descending order based on card values
sorted_hand = sorted(hand, key=lambda card: self.get_card_value(card), reverse=True)
# Check for specific hand types in decreasing order of rank
if self.is_royal_flush(sorted_hand):
return 9 # Royal flush
if self.is_straight_flush(sorted_hand):
return 8 # Straight flush
if self.is_four_of_a_kind(sorted_hand):
return 7 # Four of a kind
if self.is_full_house(sorted_hand):
return 6 # Full house
if self.is_flush(sorted_hand):
return 5 # Flush
if self.is_straight(sorted_hand):
return 4 # Straight
if self.is_three_of_a_kind(sorted_hand):
return 3 # Three of a kind
if self.is_two_pair(sorted_hand):
return 2 # Two pair
if self.is_pair(sorted_hand):
return 1 # Pair
return 0 # High card
def get_card_value(self, card):
# Map card ranks (2, 3, 4, etc.) to their corresponding values (0 to 12)
rank_to_value = {
"2": 0, "3": 1, "4": 2, "5": 3, "6": 4, "7": 5, "8": 6,
"9": 7, "10": 8, "J": 9, "Q": 10, "K": 11, "A": 12
}
rank = card.split()[0] # Extract the rank from the card string
return rank_to_value.get(rank, 0) # Default to 0 for unknown ranks
def get_hand_name(self, hand_type):
# Map hand types to their human-readable names
hand_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: "Pair", 0: "High card"
}
return hand_names.get(hand_type, "Unknown")
def is_royal_flush(self, hand):
# Check for a Royal flush (A, K, Q, J, 10 of the same suit)
return self.is_straight_flush(hand) and self.get_card_value(hand[0]) == 12
def is_straight_flush(self, hand):
# Check for a Straight flush (five consecutive cards of the same suit)
return self.is_straight(hand) and self.is_flush(hand)
def is_four_of_a_kind(self, hand):
# Check for Four of a kind (four cards of the same rank)
return self.has_n_of_a_kind(hand, 4)
def is_full_house(self, hand):
# Check for a Full house (three cards of one rank and two cards of another rank)
return self.has_n_of_a_kind(hand, 3) and self.has_n_of_a_kind(hand, 2)
def is_flush(self, hand):
# Check for a Flush (five cards of the same suit)
suits = [card.split()[-1] for card in hand]
return all(suit == suits[0] for suit in suits)
def is_straight(self, hand):
# Check for a Straight (five consecutive cards of different suits)
values = [self.get_card_value(card) for card in hand]
values.sort()
return all(values[i] == values[i - 1] + 1 for i in range(1, len(values)))
def is_three_of_a_kind(self, hand):
# Check for Three of a kind (three cards of the same rank)
return self.has_n_of_a_kind(hand, 3)
def is_two_pair(self, hand):
# Check for Two pair (two cards of one rank and two cards of another rank)
ranks = [self.get_card_value(card) for card in hand]
rank_counts = {rank: ranks.count(rank) for rank in set(ranks)}
return list(rank_counts.values()).count(2) == 2
def is_pair(self, hand):
# Check for a Pair (two cards of the same rank)
return self.has_n_of_a_kind(hand, 2)
def has_n_of_a_kind(self, hand, n):
# Helper function to check if there are 'n' cards of the same rank in the hand
ranks = [self.get_card_value(card) for card in hand]
rank_counts = {rank: ranks.count(rank) for rank in set(ranks)}
return n in rank_counts.values()
def get_next_player_index(self, current_index):
next_index = current_index + 1
if next_index >= len(self.players):
next_index = 0
return next_index