Skip to content
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
dist
build
docs/site/*
.venv/
7 changes: 4 additions & 3 deletions pypokerengine/api/game.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
def setup_config(max_round, initial_stack, small_blind_amount, ante=0):
return Config(max_round, initial_stack, small_blind_amount, ante)

def start_poker(config, verbose=2):
def start_poker(config, verbose=2, hand_history_writer=None):
config.validation()
dealer = Dealer(config.sb_amount, config.initial_stack, config.ante)
dealer.set_verbose(verbose)
dealer.set_blind_structure(config.blind_structure)
if hand_history_writer:
dealer.set_hand_history_writer(hand_history_writer)
for info in config.players_info:
dealer.register_player(info["name"], info["algorithm"])
result_message = dealer.start_game(config.max_round)
Expand Down Expand Up @@ -46,5 +48,4 @@ def validation(self):
if player_num < 2:
detail_msg = "no player is registered yet" if player_num==0 else "you registered only 1 player"
base_msg = "At least 2 players are needed to start the game"
raise Exception("%s (but %s.)" % (base_msg, detail_msg))

raise Exception("%s (but %s.)" % (base_msg, detail_msg))
7 changes: 6 additions & 1 deletion pypokerengine/engine/action_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,12 @@ def legal_actions(self, players, player_pos, sb_amount):
min_raise = self.__min_raise_amount(players, sb_amount)
max_raise = players[player_pos].stack + players[player_pos].paid_sum()
if max_raise < min_raise:
min_raise = max_raise = -1
if max_raise > self.agree_amount(players):
# Player can't meet min raise but has more than call amount → allow all-in
min_raise = max_raise
else:
# Player can't even cover the call → raise not possible
min_raise = max_raise = -1
return [
{ "action" : "fold" , "amount" : 0 },
{ "action" : "call" , "amount" : self.agree_amount(players) },
Expand Down
59 changes: 56 additions & 3 deletions pypokerengine/engine/dealer.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ def __init__(self, small_blind_amount=None, initial_stack=None, ante=None):
self.message_summarizer = MessageSummarizer(verbose=0)
self.table = Table()
self.blind_structure = {}
self.hand_history_writer = None

def set_hand_history_writer(self, writer):
self.hand_history_writer = writer

def register_player(self, player_name, algorithm):
self.__config_check()
Expand All @@ -42,6 +46,8 @@ def start_game(self, max_round):

def play_round(self, round_count, blind_amount, ante, table):
state, msgs = RoundManager.start_new_round(round_count, blind_amount, ante, table)
if self.hand_history_writer:
self.__notify_writer_round_start(round_count, state)
while True:
self.__message_check(msgs, state["street"])
if state["street"] != Const.Street.FINISHED: # continue the round
Expand Down Expand Up @@ -85,6 +91,9 @@ def __notify_game_start(self, max_round):
start_msg = MessageBuilder.build_game_start_message(config, self.table.seats)
self.message_handler.process_message(-1, start_msg)
self.message_summarizer.summarize(start_msg)
if self.hand_history_writer:
game_info = start_msg["message"]["game_information"]
self.hand_history_writer.on_game_start(game_info)

def __is_game_finished(self, table):
return len([player for player in table.seats.players if player.is_active()]) == 1
Expand All @@ -99,8 +108,53 @@ def __message_check(self, msgs, street):
def __publish_messages(self, msgs):
for address, msg in msgs[:-1]:
self.message_handler.process_message(address, msg)
if self.hand_history_writer:
self.__notify_writer_message(msg)
self.message_summarizer.summarize_messages(msgs)
return self.message_handler.process_message(*msgs[-1])
result = self.message_handler.process_message(*msgs[-1])
if self.hand_history_writer:
self.__notify_writer_message(msgs[-1][1])
return result

def __notify_writer_round_start(self, round_count, state):
players = state["table"].seats.players
hole_cards_by_uuid = {
p.uuid: [str(c) for c in p.hole_card]
for p in players if p.hole_card
}
from pypokerengine.engine.data_encoder import DataEncoder
seats = DataEncoder.encode_seats(state["table"].seats)["seats"]
self.hand_history_writer.on_round_start(
round_count=round_count,
dealer_btn=state["table"].dealer_btn,
hole_cards_by_uuid=hole_cards_by_uuid,
seats=seats,
)

def __notify_writer_message(self, msg):
content = msg["message"]
message_type = content["message_type"]
if message_type == MessageBuilder.STREET_START_MESSAGE:
rs = content["round_state"]
self.hand_history_writer.on_street_start(
street=content["street"],
community_card=rs["community_card"],
)
elif message_type == MessageBuilder.GAME_UPDATE_MESSAGE:
action = content["action"]
rs = content["round_state"]
self.hand_history_writer.on_action(
actor_uuid=action["player_uuid"],
action=action["action"].lower(),
amount=action["amount"],
seats=rs["seats"],
)
elif message_type == MessageBuilder.ROUND_RESULT_MESSAGE:
self.hand_history_writer.on_round_result(
winners=content["winners"],
hand_info=content["hand_info"],
round_state=content["round_state"],
)

def __exclude_short_of_money_players(self, table, ante, sb_amount):
sb_pos, bb_pos = self.__steal_money_from_poor_player(table, ante, sb_amount)
Expand Down Expand Up @@ -271,5 +325,4 @@ def summarize_game_result(self, message):

def summairze_blind_level_update(self, round_count, old_ante, new_ante, old_sb_amount, new_sb_amount):
base = 'Blind level update at round-%d : Ante %s -> %s, SmallBlind %s -> %s'
return base % (round_count, old_ante, new_ante, old_sb_amount, new_sb_amount)

return base % (round_count, old_ante, new_ante, old_sb_amount, new_sb_amount)
Loading