shortdeck1.0
This commit is contained in:
BIN
shortdeck_arena/__pycache__/actor.cpython-313.pyc
Normal file
BIN
shortdeck_arena/__pycache__/actor.cpython-313.pyc
Normal file
Binary file not shown.
BIN
shortdeck_arena/__pycache__/agent.cpython-313.pyc
Normal file
BIN
shortdeck_arena/__pycache__/agent.cpython-313.pyc
Normal file
Binary file not shown.
BIN
shortdeck_arena/__pycache__/card.cpython-313.pyc
Normal file
BIN
shortdeck_arena/__pycache__/card.cpython-313.pyc
Normal file
Binary file not shown.
BIN
shortdeck_arena/__pycache__/main.cpython-313.pyc
Normal file
BIN
shortdeck_arena/__pycache__/main.cpython-313.pyc
Normal file
Binary file not shown.
BIN
shortdeck_arena/__pycache__/simulation.cpython-313.pyc
Normal file
BIN
shortdeck_arena/__pycache__/simulation.cpython-313.pyc
Normal file
Binary file not shown.
41
shortdeck_arena/agent.py
Normal file
41
shortdeck_arena/agent.py
Normal file
@@ -0,0 +1,41 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from .simulation import Simulation
|
||||
|
||||
|
||||
class Agent:
|
||||
def __init__(self, pid: int):
|
||||
self.pid = pid
|
||||
|
||||
def try_act(self, sim: 'Simulation'):
|
||||
return None
|
||||
|
||||
def __str__(self):
|
||||
return f"Agent({self.pid})"
|
||||
|
||||
|
||||
class HumanAgent(Agent):
|
||||
def try_act(self, sim: 'Simulation'):
|
||||
return None
|
||||
|
||||
def __str__(self):
|
||||
return "HumanAgent"
|
||||
|
||||
|
||||
class RandomAgent(Agent):
|
||||
def try_act(self, sim: 'Simulation'):
|
||||
import random
|
||||
info = sim.node_info()
|
||||
choices = ["fold", "call"]
|
||||
if info.get("bet_max", 0) > 0:
|
||||
choices.append("bet")
|
||||
|
||||
action = random.choice(choices)
|
||||
if action == "bet":
|
||||
amt = random.randint(max(1, info.get("bet_min", 1)), info.get("bet_max", 1))
|
||||
sim.apply_action(self.pid, "bet", amt)
|
||||
else:
|
||||
sim.apply_action(self.pid, action)
|
||||
52
shortdeck_arena/card.py
Normal file
52
shortdeck_arena/card.py
Normal file
@@ -0,0 +1,52 @@
|
||||
"""ShortDeck card model (6-A, 36 cards)."""
|
||||
from __future__ import annotations
|
||||
|
||||
from enum import IntEnum
|
||||
from typing import List
|
||||
|
||||
|
||||
class Suit(IntEnum):
|
||||
S = 0
|
||||
H = 1
|
||||
D = 2
|
||||
C = 3
|
||||
|
||||
def __str__(self) -> str:
|
||||
return "shdc"[self.value]
|
||||
|
||||
|
||||
class Rank(IntEnum):
|
||||
R6 = 6
|
||||
R7 = 7
|
||||
R8 = 8
|
||||
R9 = 9
|
||||
RT = 10
|
||||
RJ = 11
|
||||
RQ = 12
|
||||
RK = 13
|
||||
RA = 14
|
||||
|
||||
def __str__(self):
|
||||
if self.value <= 9:
|
||||
return str(self.value)
|
||||
return {10: "T", 11: "J", 12: "Q", 13: "K", 14: "A"}[self.value]
|
||||
|
||||
|
||||
class Card:
|
||||
def __init__(self, rank: Rank, suit: Suit):
|
||||
self.rank = rank
|
||||
self.suit = suit
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"{str(self.rank)}{str(self.suit)}"
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.__repr__()
|
||||
|
||||
@classmethod
|
||||
def all_short(cls) -> List["Card"]:
|
||||
cards: List[Card] = []
|
||||
for r in [Rank.R6, Rank.R7, Rank.R8, Rank.R9, Rank.RT, Rank.RJ, Rank.RQ, Rank.RK, Rank.RA]:
|
||||
for s in Suit:
|
||||
cards.append(Card(r, s))
|
||||
return cards
|
||||
23
shortdeck_arena/main.py
Normal file
23
shortdeck_arena/main.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
from .agent import HumanAgent, RandomAgent
|
||||
from .simulation import Simulation
|
||||
|
||||
|
||||
def main():
|
||||
agents = [HumanAgent(0), RandomAgent(1)]
|
||||
sim = Simulation(agents)
|
||||
|
||||
print("Player cards:")
|
||||
for i in range(len(agents)):
|
||||
print(i, sim.player_cards(i))
|
||||
|
||||
print("Random agent acting...")
|
||||
agents[1].try_act(sim)
|
||||
print("History:", sim.history)
|
||||
sim.dump_data(Path.cwd() / "shortdeck_arena_history.jsonl")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
65
shortdeck_arena/simulation.py
Normal file
65
shortdeck_arena/simulation.py
Normal file
@@ -0,0 +1,65 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import random
|
||||
from pathlib import Path
|
||||
from typing import List, Dict, Optional
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from .agent import Agent
|
||||
from .card import Card
|
||||
|
||||
|
||||
class Simulation:
|
||||
def __init__(self, agents: List[Agent]):
|
||||
self.agents = agents
|
||||
self.history: List[Dict] = []
|
||||
self.cards: List[Card] = []
|
||||
self.saved = False
|
||||
self.new_round()
|
||||
|
||||
def new_round(self):
|
||||
self.history = []
|
||||
self.cards = Card.all_short()
|
||||
random.shuffle(self.cards)
|
||||
self.saved = False
|
||||
|
||||
def player_cards(self, pid: int) -> List[Card]:
|
||||
return self.cards[pid * 2 : pid * 2 + 2]
|
||||
|
||||
def board_cards(self, street: str) -> List[Card]:
|
||||
nplayers = len(self.agents)
|
||||
idx_start = nplayers * 2
|
||||
if street == "flop":
|
||||
return self.cards[idx_start: idx_start + 3]
|
||||
if street == "turn":
|
||||
return self.cards[idx_start: idx_start + 4]
|
||||
if street == "river":
|
||||
return self.cards[idx_start: idx_start + 5]
|
||||
return []
|
||||
|
||||
def node_info(self) -> Dict:
|
||||
return {"bet_min": 1, "bet_max": 100}
|
||||
|
||||
def apply_action(self, pid: int, action: str, amount: Optional[int] = None):
|
||||
self.history.append({"pid": pid, "action": action, "amount": amount})
|
||||
|
||||
def to_save_data(self) -> Dict:
|
||||
players = [f"Agent{a.pid}" for a in self.agents]
|
||||
return {
|
||||
"history": self.history,
|
||||
"players": players,
|
||||
"player_cards": ["".join(str(c) for c in self.player_cards(i)) for i in range(len(self.agents))],
|
||||
"board": "".join(str(c) for c in self.board_cards("river")),
|
||||
}
|
||||
|
||||
def dump_data(self, path: Path | None = None):
|
||||
if self.saved:
|
||||
return
|
||||
if path is None:
|
||||
path = Path.cwd() / "shortdeck_arena_history.jsonl"
|
||||
with path.open("a", encoding="utf-8") as f:
|
||||
f.write(json.dumps(self.to_save_data(), ensure_ascii=False))
|
||||
f.write("\n")
|
||||
self.saved = True
|
||||
Reference in New Issue
Block a user