fix reversed A/C chair mapping and update hot/cold on round end

CHAIRS mapping was {1:A, 2:B, 3:C} but the API's country field has
1=C and 3=A. Fixed the mapping in backend and both frontends, added a
startup migration to swap A↔C columns in existing DB data, corrected
multiIf SQL queries that hardcoded the wrong winner→column mapping,
and moved _save_round() to the ENDED status block so hot/cold stats
reflect the latest round immediately.
This commit is contained in:
2026-02-25 20:49:16 +05:00
parent 3016f33783
commit e65b6b2cfb
6 changed files with 39 additions and 6 deletions

View File

@@ -33,7 +33,7 @@ VALUES = {1: "A", 2: "2", 3: "3", 4: "4", 5: "5", 6: "6", 7: "7",
8: "8", 9: "9", 10: "10", 11: "J", 12: "Q", 13: "K", 14: "A"}
HAND_TYPES = {1: "High Card", 2: "Pair", 3: "Flush", 4: "Straight",
5: "Straight Flush", 6: "Trail"}
CHAIRS = {1: "A", 2: "B", 3: "C"}
CHAIRS = {1: "C", 2: "B", 3: "A"}
STATUS_NAMES = {0: "NEW", 1: "BETTING", 2: "REVEALING", 3: "ENDED"}
# Environment

View File

@@ -13,6 +13,7 @@ log = logging.getLogger(__name__)
_client = None
_lock = threading.Lock()
_migrations_applied = False
def get_client():
@@ -34,6 +35,34 @@ def get_client():
return _client
def run_migrations():
"""Run one-time data migrations on startup."""
global _migrations_applied
if _migrations_applied:
return
client = get_client()
client.command(
"CREATE TABLE IF NOT EXISTS _migrations ("
" name String, applied_at DateTime DEFAULT now()"
") ENGINE = MergeTree() ORDER BY name"
)
result = client.query(
"SELECT count() FROM _migrations WHERE name = 'swap_ac_chairs'"
)
if result.result_rows[0][0] == 0:
log.info("Running migration: swap_ac_chairs")
client.command(
"ALTER TABLE games UPDATE "
"hand_a = hand_c, hand_c = hand_a, "
"bet_a = bet_c, bet_c = bet_a, "
"hand_type_a = hand_type_c, hand_type_c = hand_type_a "
"WHERE 1=1"
)
client.insert("_migrations", [["swap_ac_chairs"]], column_names=["name"])
log.info("Migration swap_ac_chairs applied")
_migrations_applied = True
def _with_lock(fn):
"""Decorator to serialize all ClickHouse operations."""
def wrapper(*args, **kwargs):
@@ -213,7 +242,7 @@ def get_win_distribution() -> dict:
FROM (
SELECT
bet_a, bet_b, bet_c,
multiIf(winner = 1, bet_a, winner = 2, bet_b, bet_c) AS winner_bet
multiIf(winner = 3, bet_a, winner = 2, bet_b, bet_c) AS winner_bet
FROM games
WHERE bet_a + bet_b + bet_c > 0
)
@@ -414,7 +443,7 @@ def get_analytics(period: str = "all") -> dict:
FROM (
SELECT
bet_a, bet_b, bet_c,
multiIf(winner = 1, bet_a, winner = 2, bet_b, bet_c) AS winner_bet
multiIf(winner = 3, bet_a, winner = 2, bet_b, bet_c) AS winner_bet
FROM games
{game_where + ' AND' if game_where else 'WHERE'} bet_a + bet_b + bet_c > 0
)
@@ -431,7 +460,7 @@ def get_analytics(period: str = "all") -> dict:
hand_type_result = client.query(
f"""
SELECT hand_type, count() AS cnt FROM (
SELECT multiIf(winner = 1, hand_type_a, winner = 2, hand_type_b, hand_type_c) AS hand_type
SELECT multiIf(winner = 3, hand_type_a, winner = 2, hand_type_b, hand_type_c) AS hand_type
FROM games
{game_where}
)

View File

@@ -152,6 +152,8 @@ class GamePoller:
start_ts = self.round_data.get("time_start_ts", 0)
self.round_data["duration_s"] = round(time.time() - start_ts)
self._save_round()
await self.broadcast("round_result", {
"game_no": gn,
"winner": gi.get("gameResult"),

View File

@@ -12,6 +12,7 @@ import signal
from .server import WebServer
from .streamkar_ws import StreamKarWSClient
from .game_poller import GamePoller
from . import db
logging.basicConfig(
level=logging.INFO,
@@ -39,6 +40,7 @@ async def main():
loop.add_signal_handler(sig, shutdown)
log.info("Starting Teen Patti Live Monitor")
await loop.run_in_executor(None, db.run_migrations)
log.info("Dashboard: http://localhost:8765")
tasks = [

View File

@@ -333,7 +333,7 @@ const escHtml = s => {
return d.innerHTML;
};
const CHAIRS = {1:'A', 2:'B', 3:'C'};
const CHAIRS = {1:'C', 2:'B', 3:'A'};
const CHAIR_COLORS = {A:'#3b82f6', B:'#ec4899', C:'#f59e0b'};
const HAND_TYPES = {1:'High Card', 2:'Pair', 3:'Flush', 4:'Straight', 5:'Str. Flush', 6:'Trail'};

View File

@@ -775,7 +775,7 @@ const fmtFull = n => {
return Number(n).toLocaleString();
};
const CHAIRS = {1:'A', 2:'B', 3:'C'};
const CHAIRS = {1:'C', 2:'B', 3:'A'};
const CHAIR_COLORS = {A:'#3b82f6', B:'#ec4899', C:'#f59e0b'};
const HAND_TYPES = {1:'High Card', 2:'Pair', 3:'Flush', 4:'Straight', 5:'Str. Flush', 6:'Trail'};
const HAND_RANK = {1:1, 2:2, 3:3, 4:4, 5:5, 6:6};