Add CPU opponents and a table type selector (cash only / friends / CPU)
- Create screen: choose キャッシュオンリー (real cards, chips only), 友人戦 (server deals and settles) or CPU戦 (友人戦 plus 1–8 CPU players); replaces the card toggle. The lobby shows each table's type - Poker AI written from scratch (server/ai.js, no libraries): fast 7-card evaluator (checked against bestHand), Monte Carlo equity, and decisions from hand rank, pot odds, raise count, opponents and a per-CPU style (aggression, bluff rate); continuation bets via the last aggressor. It never sees other players' hole cards - CPU seats: think time of 0.7–1.8s (faster when no human is left in the hand), automatic rebuy, never the host, no new hand unless a human is playing, re-think after pause - Play UI: robot avatars and a "考えています…" status for CPU turns - Tests for the evaluator, equity, legality of AI actions and CPU tables Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
66907345ff
commit
0d3a054f0d
12 files changed
+550
-46
No files matched your search
+16
-1
@@ -29,6 +29,10 @@ class Hand {
|
||||
this.pot = 0; // 前のストリートまでに集めた額
|
||||
this.currentBet = 0;
|
||||
this.minRaise = bb;
|
||||
this.raises = 0; // このストリートのベット・レイズの回数(CPU の判断用)
|
||||
this.actions = 0; // アクションの通し番号(CPU の手番の管理用)
|
||||
this.aggressor = null; // このストリートで最後にベット・レイズした席(CPU の判断用)
|
||||
this.prevAggressor = null; // 前のストリートで最後にベット・レイズした席
|
||||
this.toAct = null;
|
||||
this.finished = false;
|
||||
this.showdown = false;
|
||||
@@ -75,6 +79,11 @@ class Hand {
|
||||
return this.list.filter((p) => !p.folded);
|
||||
}
|
||||
|
||||
// 前のストリートまでのポット + このストリートのベット
|
||||
get potTotal() {
|
||||
return this.pot + this.list.reduce((sum, p) => sum + p.bet, 0);
|
||||
}
|
||||
|
||||
put(p, amount) {
|
||||
const s = this.seats[p.seat];
|
||||
s.stack -= amount;
|
||||
@@ -163,9 +172,11 @@ class Hand {
|
||||
const raiseSize = amount - this.currentBet;
|
||||
this.put(p, amount - p.bet);
|
||||
p.last = { type: o.isBet ? 'BET' : 'RAISE', amount };
|
||||
this.aggressor = seat;
|
||||
if (raiseSize >= this.minRaise) {
|
||||
// 正規のレイズ: 他の人はもう一度アクションできる
|
||||
this.minRaise = raiseSize;
|
||||
this.raises++;
|
||||
for (const q of this.list) if (q !== p) q.acted = false;
|
||||
}
|
||||
// 足りないオールインのレイズはアクション済みの人に再レイズ権を与えない
|
||||
@@ -175,6 +186,7 @@ class Hand {
|
||||
}
|
||||
if (p.allIn) p.last = { type: 'ALLIN', amount: p.bet };
|
||||
p.acted = true;
|
||||
this.actions++;
|
||||
this.setNextActor(seat);
|
||||
return null;
|
||||
}
|
||||
@@ -225,6 +237,9 @@ class Hand {
|
||||
if (this.live().length === 1) return this.finishFoldWin();
|
||||
this.currentBet = 0;
|
||||
this.minRaise = this.bb;
|
||||
this.raises = 0;
|
||||
this.prevAggressor = this.aggressor;
|
||||
this.aggressor = null;
|
||||
|
||||
const noMoreBetting = this.live().filter((p) => !p.allIn).length < 2;
|
||||
if (!this.cards) {
|
||||
@@ -365,7 +380,7 @@ class Hand {
|
||||
runout: this.runout,
|
||||
street: this.street,
|
||||
pot: this.pot,
|
||||
potTotal: this.pot + this.list.reduce((sum, p) => sum + p.bet, 0),
|
||||
potTotal: this.potTotal,
|
||||
currentBet: this.currentBet,
|
||||
button: this.button,
|
||||
sbSeat: this.sbSeat,
|
||||
|
||||
Reference in new issue
Block a user