gametree1.0:fix

This commit is contained in:
2025-11-05 17:50:56 +08:00
parent 699b79d0da
commit 61923407af
4 changed files with 28 additions and 110 deletions

2
.gitignore vendored
View File

@@ -8,3 +8,5 @@ wheels/
# Virtual environments # Virtual environments
.venv .venv
data/

View File

@@ -5,7 +5,6 @@ import random
from .model import PlayerId, Action, ActionType, Street from .model import PlayerId, Action, ActionType, Street
from .card import Card from .card import Card
# from .dealing import deal_hand_cards, deal_flop, deal_turn, deal_river
from .hand_evaluator import HandEvaluator from .hand_evaluator import HandEvaluator
from .deck import DeckManager from .deck import DeckManager
@@ -496,6 +495,7 @@ class Game:
def get_raise_bounds(self, player_id: PlayerId) -> Tuple[Optional[int], Optional[int]]: def get_raise_bounds(self, player_id: PlayerId) -> Tuple[Optional[int], Optional[int]]:
# raise total # raise total
# todo :to raise
player = self._get_player(player_id) player = self._get_player(player_id)
if not player: if not player:
return (None, None) return (None, None)
@@ -557,7 +557,7 @@ class Game:
# 1.翻牌 # 1.翻牌
# 2.跟注、加注、弃牌 # 2.跟注、加注、弃牌
# 3.跟注、弃牌 # 3.跟注、弃牌
# 疑问为什么玩家1可以开启加注轮 # 疑问为什么玩家1可以开启加注轮,如果可以开启的话,下面的逻辑需要修改
if self.invalid_raise: if self.invalid_raise:
if to_call == 0: if to_call == 0:
if player.stack > 0: if player.stack > 0:
@@ -585,6 +585,7 @@ class Game:
if max_raise_to < min_raise_to: if max_raise_to < min_raise_to:
if player.stack >= to_call: if player.stack >= to_call:
actions.append(ActionType.CALL) actions.append(ActionType.CALL)
actions.append(ActionType.ALL_IN)
else: else:
actions.append(ActionType.ALL_IN) actions.append(ActionType.ALL_IN)
self.invalid_raise = True self.invalid_raise = True
@@ -596,7 +597,6 @@ class Game:
return actions return actions
def evaluate_hand(self, player_id: PlayerId) -> Optional[Any]: def evaluate_hand(self, player_id: PlayerId) -> Optional[Any]:
"""评估玩家手牌"""
if player_id not in self.hand_cards or len(self.board) < 5: if player_id not in self.hand_cards or len(self.board) < 5:
return None return None

View File

@@ -3,7 +3,8 @@
"0": "a", "0": "a",
"1": "b", "1": "b",
"2": "c", "2": "c",
"3": "d" "3": "d",
"4": "e"
}, },
"game_state": { "game_state": {
"players_init": [ "players_init": [
@@ -22,87 +23,41 @@
[ [
3, 3,
500 500
],
[
4,
500
] ]
], ],
"dealer_idx": 0, "dealer_idx": 0,
"small_blind": 5, "small_blind": 5,
"big_blind": 10, "big_blind": 10,
"current_street": "RIVER", "current_street": "PREFLOP",
"all_actions": [ "all_actions": [
{ {
"type": "CALL", "type": "CALL",
"actor": 3, "actor": 3,
"amount": null "amount": null
}, },
{
"type": "CALL",
"actor": 4,
"amount": null
},
{ {
"type": "CALL", "type": "CALL",
"actor": 0, "actor": 0,
"amount": null "amount": null
}, },
{ {
"type": "CALL", "type": "ALL_IN",
"actor": 1, "actor": 1,
"amount": null "amount": null
}, },
{ {
"type": "BET", "type": "ALL_IN",
"actor": 1,
"amount": 40
},
{
"type": "CALL",
"actor": 2, "actor": 2,
"amount": null "amount": null
},
{
"type": "CALL",
"actor": 3,
"amount": null
},
{
"type": "CALL",
"actor": 0,
"amount": null
},
{
"type": "BET",
"actor": 1,
"amount": 40
},
{
"type": "CALL",
"actor": 2,
"amount": null
},
{
"type": "CALL",
"actor": 3,
"amount": null
},
{
"type": "CALL",
"actor": 0,
"amount": null
},
{
"type": "BET",
"actor": 1,
"amount": 40
},
{
"type": "CALL",
"actor": 2,
"amount": null
},
{
"type": "CALL",
"actor": 3,
"amount": null
},
{
"type": "CALL",
"actor": 0,
"amount": null
} }
] ]
} }

View File

@@ -14,6 +14,11 @@ from gametree.model import act_fold, act_call, act_check, act_bet, act_raise, ac
GAME_FILE = "pg.json" GAME_FILE = "pg.json"
def create_file_idx():
files = list(Path("data").glob("pg_*.json"))
game_id = len(files) + 1
return f"data/pg_{game_id:03d}.json"
def create_simple_game(player_names: List[str], def create_simple_game(player_names: List[str],
small_blind: int = 5, small_blind: int = 5,
big_blind: int = 10, big_blind: int = 10,
@@ -44,31 +49,6 @@ def save_simple_game(path: str, game: Game, players) -> None:
} }
p.write_text(json.dumps(data, indent=2), encoding="utf-8") p.write_text(json.dumps(data, indent=2), encoding="utf-8")
# 单开不加载
# def load_simple_game(path: str) -> Tuple[Game, Dict[int,str]]:
# p = Path(path)
# data = json.loads(p.read_text(encoding="utf-8"))
# player_names = {int(k): v for k, v in data["player_names"].items()}
# gs = data["game_state"]
# players_init = [(PlayerId(pid), stack) for pid, stack in gs.get("players_init", [])]
# game = Game(players_init=players_init,
# dealer_idx=gs.get("dealer_idx", 0),
# small_blind=gs.get("small_blind", 5),
# big_blind=gs.get("big_blind", 10))
# for ad in gs.get("all_actions", []):
# try:
# act = Action(type=ActionType[ad["type"]], actor=PlayerId(ad["actor"]), amount=ad.get("amount"))
# game.add_action(act)
# except Exception:
# continue
# target = gs.get("current_street")
# if target:
# from .model import Street as _Street
# target_st = _Street[target]
# while game.current_street != target_st and not getattr(game, "terminal", False):
# game.advance_to_next_street()
# return game, player_names
def display_game_status(game: Game, player_names: Dict[int,str], show_cards_for: Optional[str] = None) -> None: def display_game_status(game: Game, player_names: Dict[int,str], show_cards_for: Optional[str] = None) -> None:
print(f"Street: {game.current_street.name}") print(f"Street: {game.current_street.name}")
board = game.get_current_board() board = game.get_current_board()
@@ -184,7 +164,7 @@ def main():
return None, None return None, None
def cmd_set(args): def cmd_set(args):
global GAME, P_NAME, P_IDS global GAME, P_NAME, P_IDS, GAME_FILE
input_line = args.split() input_line = args.split()
if len(input_line) < 3: if len(input_line) < 3:
print("usage: set <small>/<big> [player ...] [--stack N]") print("usage: set <small>/<big> [player ...] [--stack N]")
@@ -199,7 +179,7 @@ def main():
if len(input_line) >= 4 and input_line[-2] == '--stack': if len(input_line) >= 4 and input_line[-2] == '--stack':
stack = int(input_line[-1]) stack = int(input_line[-1])
names = input_line[1:-2] names = input_line[1:-2]
GAME_FILE = create_file_idx()
game, pname_map, pids = create_simple_game(names, game, pname_map, pids = create_simple_game(names,
small_blind=int(blinds[0]), small_blind=int(blinds[0]),
big_blind=int(blinds[1]), big_blind=int(blinds[1]),
@@ -257,14 +237,6 @@ def main():
def cmd_status(args): def cmd_status(args):
# 单开
# if GAME is None:
# if os.path.exists(GAME_FILE):
# g, names = load_simple_game(GAME_FILE)
# display_game_status(g, names, show_cards_for=args.strip() if args else None)
# else:
# print("no game")
# else:
if GAME is None or P_NAME is None: if GAME is None or P_NAME is None:
print("no game to display") print("no game to display")
return return
@@ -288,24 +260,14 @@ def main():
save_simple_game(GAME_FILE, GAME, P_NAME) save_simple_game(GAME_FILE, GAME, P_NAME)
print(" saved", GAME_FILE) print(" saved", GAME_FILE)
# def cmd_load(args):
# global GAME, P_NAME, P_IDS
# if not os.path.exists(GAME_FILE):
# print("no saved game file.")
# return
# GAME, P_NAME = load_simple_game(GAME_FILE)
# P_IDS = [PlayerId(i, name) for i, name in P_NAME.items()]
# print(" Loaded", GAME_FILE)
# display_game_status(GAME, P_NAME)
# display_player_turn()
def cmd_reset(args): def cmd_reset(args):
global GAME, P_NAME, P_IDS global GAME, P_NAME, P_IDS, GAME_FILE
if os.path.exists(GAME_FILE): if os.path.exists(GAME_FILE):
os.remove(GAME_FILE) os.remove(GAME_FILE)
GAME = None GAME = None
P_NAME = None P_NAME = None
P_IDS = None P_IDS = None
GAME_FILE = "pg.json"
print(" reset game file") print(" reset game file")
def cmd_help(args): def cmd_help(args):
@@ -314,7 +276,6 @@ def main():
print(" act <player> <fold|call|check|bet|raise|all_in> [amount]") print(" act <player> <fold|call|check|bet|raise|all_in> [amount]")
print(" status [player|all] ") print(" status [player|all] ")
print(" save ") print(" save ")
# print(" load ") 单开不加载
print(" reset ") print(" reset ")
print(" ? ") print(" ? ")
print(" q|e ") print(" q|e ")