Switch to chips-only play: real cards at the table, winners picked on screen
- Remove the deck, hole cards, board, hand evaluator and reveal logic (cards are dealt physically; the site only tracks bets, pots and stacks) - Showdown now waits for a winner per pot (main/side), chosen by a player still in the hand or the host; multiple winners split the pot - All-in with no further betting goes straight to showdown - Remove the 30s action clock / auto sit-out (everyone is at the same table) - UI: winner picker panel (main winner auto-fills side pots), compact table Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
8de55f7ca5
commit
b5d84e5f65
11 files changed
+408
-605
No files matched your search
+33
-45
@@ -96,13 +96,13 @@ class Table {
|
||||
return free;
|
||||
}
|
||||
|
||||
leave(token, now = Date.now()) {
|
||||
leave(token) {
|
||||
const i = this.seatOf(token);
|
||||
if (i < 0 || this.seats[i].left) return false;
|
||||
if (this.hand && this.hand.players.has(i)) {
|
||||
// 結果表示やポット計算のため、ハンドが終わるまで席は残す
|
||||
this.seats[i].left = true;
|
||||
this.hand.forceFold(i, now);
|
||||
this.hand.forceFold(i);
|
||||
} else {
|
||||
this.seats[i] = null;
|
||||
}
|
||||
@@ -125,7 +125,7 @@ class Table {
|
||||
return null;
|
||||
}
|
||||
|
||||
startNewHand(now) {
|
||||
startNewHand() {
|
||||
this.removeLeftSeats();
|
||||
const eligible = this.eligibleSeats();
|
||||
this.buttonSeat =
|
||||
@@ -139,26 +139,41 @@ class Table {
|
||||
this.handNumber++;
|
||||
const { sb, bb } = this.blinds;
|
||||
this.nextHandAt = null;
|
||||
this.hand = new Hand({ number: this.handNumber, seats: this.seats, order, button: this.buttonSeat, sb, bb, now });
|
||||
this.hand = new Hand({ number: this.handNumber, seats: this.seats, order, button: this.buttonSeat, sb, bb });
|
||||
}
|
||||
|
||||
// ---- プレイヤー操作(エラー時はメッセージを返す) ----
|
||||
|
||||
act(token, type, amount, now = Date.now()) {
|
||||
act(token, type, amount) {
|
||||
const i = this.seatOf(token);
|
||||
if (i < 0) return '着席していません';
|
||||
if (!this.handActive) return 'ハンドが進行していません';
|
||||
if (this.paused) return '一時停止中です';
|
||||
return this.hand.act(i, type, amount, now);
|
||||
return this.hand.act(i, type, amount);
|
||||
}
|
||||
|
||||
setSittingOut(token, value, now = Date.now()) {
|
||||
// ショーダウンの勝者を選べるのは、ショーダウンに残った人とホスト
|
||||
canAward(token) {
|
||||
if (!this.handActive || !this.hand.awaitingWinners) return false;
|
||||
const i = this.seatOf(token);
|
||||
const p = i >= 0 ? this.hand.players.get(i) : null;
|
||||
return this.isHost(token) || Boolean(p && !p.folded && !this.seats[i].left);
|
||||
}
|
||||
|
||||
award(token, winners) {
|
||||
if (!this.handActive || !this.hand.awaitingWinners) return 'ショーダウンではありません';
|
||||
if (!this.canAward(token)) return 'ショーダウンに残った人かホストが選んでください';
|
||||
if (this.paused) return '一時停止中です';
|
||||
return this.hand.award(winners);
|
||||
}
|
||||
|
||||
setSittingOut(token, value) {
|
||||
const i = this.seatOf(token);
|
||||
if (i < 0) return '着席していません';
|
||||
const s = this.seats[i];
|
||||
s.sittingOut = value;
|
||||
// 手番中に離席したら、その場でチェック/フォールド
|
||||
if (value && this.handActive && this.hand.toAct === i && !this.paused) this.hand.autoAct(now);
|
||||
if (value && this.handActive && this.hand.toAct === i && !this.paused) this.hand.autoAct();
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -182,7 +197,7 @@ class Table {
|
||||
if (this.eligibleSeats().length < 2) return '2人以上必要です';
|
||||
this.started = true;
|
||||
if (this.timerEnabled) this.levelEndsAt = now + this.intervalMs;
|
||||
this.startNewHand(now);
|
||||
this.startNewHand();
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -190,12 +205,8 @@ class Table {
|
||||
if (!this.isHost(token)) return 'ホストのみ操作できます';
|
||||
if (!this.started) return 'まだ開始していません';
|
||||
if (this.paused) {
|
||||
// 止めていた時間だけ各期限を後ろにずらす
|
||||
const shift = now - this.pausedAt;
|
||||
const h = this.hand;
|
||||
if (h && h.deadline != null) h.deadline += shift;
|
||||
if (h && h.runoutAt != null) h.runoutAt += shift;
|
||||
if (this.nextHandAt != null) this.nextHandAt += shift;
|
||||
// 止めていた時間だけ次のハンドの開始を後ろにずらす
|
||||
if (this.nextHandAt != null) this.nextHandAt += now - this.pausedAt;
|
||||
if (this.timerEnabled) this.levelEndsAt = now + this.levelRemainingMs;
|
||||
this.paused = false;
|
||||
this.pausedAt = null;
|
||||
@@ -210,7 +221,7 @@ class Table {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 時間で進む処理(ブラインドタイマー・手番の時間切れ・オールイン時のめくり・次のハンド)
|
||||
// 時間で進む処理(ブラインドタイマー・次のハンドの開始)
|
||||
// 状態が変わったら true
|
||||
tick(now) {
|
||||
let changed = false;
|
||||
@@ -221,24 +232,11 @@ class Table {
|
||||
}
|
||||
if (this.paused) return changed;
|
||||
|
||||
const h = this.hand;
|
||||
if (h && !h.finished) {
|
||||
if (h.toAct != null && now >= h.deadline) {
|
||||
this.seats[h.toAct].sittingOut = true; // 時間切れの人は離席扱い(戻るボタンで復帰)
|
||||
h.timeout(now);
|
||||
changed = true;
|
||||
}
|
||||
if (h.runoutAt != null && now >= h.runoutAt) {
|
||||
h.runoutStep(now);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.hand && this.hand.finished) {
|
||||
if (this.nextHandAt == null) {
|
||||
this.nextHandAt = now + (this.hand.showdown ? config.SHOWDOWN_MS : config.FOLD_WIN_MS);
|
||||
} else if (now >= this.nextHandAt) {
|
||||
if (this.canDeal()) this.startNewHand(now);
|
||||
if (this.canDeal()) this.startNewHand();
|
||||
else {
|
||||
this.hand = null;
|
||||
this.nextHandAt = null;
|
||||
@@ -250,7 +248,7 @@ class Table {
|
||||
if (!this.canDeal()) this.nextHandAt = null;
|
||||
else if (this.nextHandAt == null) this.nextHandAt = now + config.NEXT_HAND_DELAY_MS;
|
||||
else if (now >= this.nextHandAt) {
|
||||
this.startNewHand(now);
|
||||
this.startNewHand();
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
@@ -276,28 +274,17 @@ class Table {
|
||||
};
|
||||
}
|
||||
|
||||
// token = 閲覧者のトークン(他人のトークンや手札は送らない)
|
||||
// token = 閲覧者のトークン(他人のトークンは送らない)
|
||||
publicState(token, connectedTokens) {
|
||||
const now = Date.now();
|
||||
const { sb, bb } = this.blinds;
|
||||
const next = Blinds.blindsAt(this.baseSmallBlind, this.baseBigBlind, this.level + 1);
|
||||
const mySeat = this.seatOf(token);
|
||||
const h = this.hand;
|
||||
const hv = h ? h.view(mySeat, token) : null;
|
||||
const hv = h ? h.view() : null;
|
||||
const me = mySeat >= 0 ? this.seats[mySeat] : null;
|
||||
const inLiveHand = Boolean(this.handActive && h.players.has(mySeat) && !h.players.get(mySeat).folded);
|
||||
|
||||
let turn = null;
|
||||
if (this.handActive && h.toAct != null) {
|
||||
const remainingMs = Math.max(0, h.deadline - (this.paused ? this.pausedAt : now));
|
||||
turn = {
|
||||
seat: h.toAct,
|
||||
endsAt: this.paused ? null : h.deadline,
|
||||
remainingMs,
|
||||
totalMs: config.ACTION_TIME_MS,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
id: this.id,
|
||||
name: this.name,
|
||||
@@ -319,7 +306,7 @@ class Table {
|
||||
paused: this.paused,
|
||||
handNumber: this.handNumber,
|
||||
hand: hv,
|
||||
turn,
|
||||
toAct: this.handActive ? h.toAct : null,
|
||||
seats: this.seats.map((s, i) =>
|
||||
s && !s.left
|
||||
? {
|
||||
@@ -342,6 +329,7 @@ class Table {
|
||||
sittingOut: me.sittingOut,
|
||||
canRebuy: me.stack === 0 && !inLiveHand,
|
||||
options: this.handActive && !this.paused ? h.options(mySeat) : null,
|
||||
canAward: this.canAward(token),
|
||||
}
|
||||
: null,
|
||||
isHost: this.isHost(token),
|
||||
|
||||
Reference in new issue
Block a user