Skip to content

Thor mead windows compatibility branch #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pypokerengine/api/game.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def register_player(self, name, algorithm):

# Wrap the function with a timeout
default_action_info = "fold"
algorithm.declare_action = timeout2(0.5,default_action_info)(algorithm.declare_action)
#algorithm.declare_action = timeout2(0.5,default_action_info)(algorithm.declare_action)
info = { "name" : name, "algorithm" : algorithm }
self.players_info.append(info)

Expand Down
125 changes: 125 additions & 0 deletions pypokerengine/gametree.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import itertools
import random

class PokerNode:
def __init__(self, player, action=None, amount=0, pot=0, hole_cards=None, community_cards=None, parent=None, is_chance_node=False):
self.player = player
self.action = action
self.amount = amount
self.pot = pot
self.hole_cards = hole_cards
self.community_cards = community_cards
self.parent = parent
self.is_chance_node = is_chance_node
self.children = []

def add_child(self, child):
self.children.append(child)

class LimitPokerTree:
SMALL_BLIND = 10
BIG_BLIND = 20
MAX_RAISES = 4

def __init__(self, my_hole_cards, deck):
self.root = None
self.my_hole_cards = my_hole_cards
self.deck = deck # Instance of Deck class, already shuffled and with known cards removed
self.current_pot = self.SMALL_BLIND + self.BIG_BLIND

def build_tree(self):
self.root = PokerNode(player='small_blind', pot=self.current_pot, hole_cards=self.my_hole_cards)
self.process_player_decision(self.root, self.my_hole_cards, [])
return self.root


def process_player_decision(self, parent_node):
# Generate possible actions for a player: fold, call, raise (if raises are left)
actions = ['fold', 'call']
if parent_node.action != 'raise' or parent_node.amount < self.MAX_RAISES:
actions.append('raise')

for action in actions:
if action == 'fold':
# Add a fold node and no further children
fold_node = PokerNode(player=parent_node.player, action='fold', pot=parent_node.pot, parent=parent_node)
parent_node.add_child(fold_node)
else:
pot_after_action = parent_node.pot
if action == 'call':
pot_after_action += self.BIG_BLIND
elif action == 'raise':
pot_after_action += self.BIG_BLIND # Assuming a fixed raise amount

# Create a node for the action
action_node = PokerNode(player=parent_node.player, action=action, pot=pot_after_action, parent=parent_node, amount=parent_node.amount + (1 if action == 'raise' else 0))
parent_node.add_child(action_node)

# Determine the next player's action or proceed to nature's turn
next_player = 'big_blind' if parent_node.player == 'small_blind' else 'small_blind'
if next_player == 'big_blind' and action == 'call':
# Nature's turn to deal the flop
self.deal_community_cards(action_node, 3)
else:
# Continue with the next player's decision
self.process_player_decision(action_node)


def deal_community_cards(self, parent_node, num_cards, excluded_cards):
community_cards = self.deck.draw_cards(num_cards)
community_node = PokerNode(player='nature', community_cards=community_cards, parent=parent_node, is_chance_node=True)
parent_node.add_child(community_node)

# Exclude the known cards from the deck for further community card dealing
for card in excluded_cards:
if card in self.deck.deck:
self.deck.deck.remove(card)


# After dealing, proceed based on the round
if round_name == 'flop':
# The 'flop' has been dealt, proceed to betting round for the 'flop'
self.process_player_decision(community_node, self.my_hole_cards, community_cards, 'turn')
elif round_name == 'turn':
# The 'turn' card has been dealt, proceed to betting round for the 'turn'
self.process_player_decision(community_node, self.my_hole_cards, community_cards, 'river')
elif round_name == 'river':
# The 'river' card has been dealt, this is the final betting round
self.process_player_decision(community_node, self.my_hole_cards, community_cards, 'showdown')


def evaluate_and_propagate(self, node):
# Base case: if this is a terminal node, evaluate it directly
if self.is_terminal(node):
node.score = self.evaluate_node(node)
return node.score

# If this is a decision node for the agent, choose the action that maximizes score
if node.player == 'my_player':
best_score = float('-inf')
for child in node.children:
child_score = self.evaluate_and_propagate(child)
best_score = max(best_score, child_score)
node.score = best_score
return best_score

# If this is a decision node for the opponent, assume they choose the action that minimizes your score
else:
worst_score = float('inf')
for child in node.children:
child_score = self.evaluate_and_propagate(child)
worst_score = min(worst_score, child_score)
node.score = worst_score
return worst_score

def evaluate_node(self, node):
# Evaluate the strength of the hand at the terminal node and return its score
# Placeholder for actual hand evaluation
return 0 # Replace with actual evaluation logic

def is_terminal(self, node):
# Determine if the node is a terminal node
# Placeholder for actual terminal node check
return not node.children # In a real game, you'd also check if the hand is complete


64 changes: 64 additions & 0 deletions pypokerengine/smartplayer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from pypokerengine.players import BasePokerPlayer
import random as rand


class SmartPlayer(BasePokerPlayer):
def declare_action(self, valid_actions, hole_card, round_state):
# Evaluate the current hand strength
hand_strength = self.evaluate_hand(hole_card, round_state)

# Simple strategy based on hand strength
if hand_strength > 0.7:
# Strong hand, attempt to raise
action_info = self.find_action(valid_actions, "raise")
if action_info:
return action_info["action"], action_info["amount"]["max"]
elif hand_strength > 0.4:
# Decent hand, attempt to call or check
action_info = self.find_action(valid_actions, "call")
if not action_info:
action_info = self.find_action(valid_actions, "check")
return action_info["action"], action_info.get("amount", 0)
else:
# Weak hand, check if possible, otherwise fold
action_info = self.find_action(valid_actions, "check")
if not action_info:
return "fold", 0

# Default fallback (shouldn't reach here in theory)
return valid_actions[0]["action"], valid_actions[0].get("amount", 0)

def find_action(self, valid_actions, action_name):
"""Helper method to find a specific action in the valid_actions."""
for action in valid_actions:
if action["action"] == action_name:
return action
return None

def evaluate_hand(self, hole_card, round_state):
"""
Simplified hand evaluation. This should be replaced with a more comprehensive
evaluation method that considers the community cards, the round of betting,
and potentially even modeling of the opponents' hands.
"""
# Placeholder for simplicity - always returns a random strength
# You should replace this with actual logic
return random.random()

def receive_game_start_message(self, game_info):
pass

def receive_round_start_message(self, round_count, hole_card, seats):
pass

def receive_street_start_message(self, street, round_state):
pass

def receive_game_update_message(self, action, round_state):
pass

def receive_round_result_message(self, winners, hand_info, round_state):
pass

def setup_ai():
return SmartPlayer()