feat: 鎵╁睍鏁版嵁搴撴敮鎸佽疆鐩樺拰21鐐规父鎴?- 娣诲姞鍒楀瓨鍦ㄦ€ф鏌ヨ緟鍔╂柟娉?- 鎵╁睍casino_sessions鍜宑asino_bets琛ㄦ坊鍔犳柊瀛楁 - 鍒涘缓casino_blackjack_hands琛ㄥ瓨鍌?1鐐规墜鐗?- 淇敼create_casino_session鏀寔鍗曞満闄愬埗鍜屾柊瀛楁 - 鎵╁睍create_casino_bet鏀寔杞洏鍜?1鐐逛笓鐢ㄥ瓧娈?- 娣诲姞21鐐规墜鐗岀鐞嗘柟娉曢泦
This commit is contained in:
227
core/database.py
227
core/database.py
@@ -54,6 +54,37 @@ class Database:
|
||||
raise
|
||||
return self._conn
|
||||
|
||||
def _column_exists(self, table_name: str, column_name: str) -> bool:
|
||||
"""检查表中列是否存在
|
||||
|
||||
Args:
|
||||
table_name: 表名
|
||||
column_name: 列名
|
||||
|
||||
Returns:
|
||||
是否存在
|
||||
"""
|
||||
cursor = self.conn.cursor()
|
||||
cursor.execute(f"PRAGMA table_info({table_name})")
|
||||
columns = [row[1] for row in cursor.fetchall()]
|
||||
return column_name in columns
|
||||
|
||||
def _add_column_if_not_exists(self, table_name: str, column_name: str, column_def: str):
|
||||
"""安全地添加列(如果不存在)
|
||||
|
||||
Args:
|
||||
table_name: 表名
|
||||
column_name: 列名
|
||||
column_def: 列定义(如 "INTEGER" 或 "TEXT DEFAULT ''")
|
||||
"""
|
||||
if not self._column_exists(table_name, column_name):
|
||||
try:
|
||||
cursor = self.conn.cursor()
|
||||
cursor.execute(f"ALTER TABLE {table_name} ADD COLUMN {column_name} {column_def}")
|
||||
logger.info(f"为表 {table_name} 添加列 {column_name}")
|
||||
except Exception as e:
|
||||
logger.warning(f"添加列失败: {e}")
|
||||
|
||||
def init_tables(self):
|
||||
"""初始化数据库表"""
|
||||
cursor = self.conn.cursor()
|
||||
@@ -166,6 +197,20 @@ class Database:
|
||||
)
|
||||
""")
|
||||
|
||||
# 21点手牌表
|
||||
cursor.execute("""
|
||||
CREATE TABLE IF NOT EXISTS casino_blackjack_hands (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
session_id INTEGER NOT NULL,
|
||||
user_id INTEGER NOT NULL,
|
||||
hand_data TEXT NOT NULL,
|
||||
hand_status TEXT DEFAULT 'playing',
|
||||
created_at INTEGER NOT NULL,
|
||||
updated_at INTEGER NOT NULL,
|
||||
FOREIGN KEY (session_id) REFERENCES casino_sessions(id)
|
||||
)
|
||||
""")
|
||||
|
||||
# 创建索引
|
||||
cursor.execute("""
|
||||
CREATE INDEX IF NOT EXISTS idx_casino_bets
|
||||
@@ -177,6 +222,21 @@ class Database:
|
||||
ON casino_sessions(chat_id, game_type, status)
|
||||
""")
|
||||
|
||||
cursor.execute("""
|
||||
CREATE INDEX IF NOT EXISTS idx_casino_blackjack_hands
|
||||
ON casino_blackjack_hands(session_id, user_id)
|
||||
""")
|
||||
|
||||
# 兼容性检查:为casino_sessions表添加新字段
|
||||
self._add_column_if_not_exists('casino_sessions', 'current_phase', "TEXT DEFAULT 'betting'")
|
||||
self._add_column_if_not_exists('casino_sessions', 'blackjack_multiplier', 'REAL DEFAULT 1.5')
|
||||
|
||||
# 兼容性检查:为casino_bets表添加新字段(轮盘和21点专用)
|
||||
self._add_column_if_not_exists('casino_bets', 'bet_category', "TEXT")
|
||||
self._add_column_if_not_exists('casino_bets', 'bet_number', 'INTEGER')
|
||||
self._add_column_if_not_exists('casino_bets', 'bet_value', "TEXT")
|
||||
self._add_column_if_not_exists('casino_bets', 'hand_status', "TEXT")
|
||||
|
||||
logger.info("数据库表初始化完成")
|
||||
|
||||
# ===== 用户相关操作 =====
|
||||
@@ -654,9 +714,31 @@ class Database:
|
||||
|
||||
# ===== 赌场相关操作 =====
|
||||
|
||||
def get_any_active_casino_session(self, chat_id: int) -> Optional[Dict]:
|
||||
"""获取任意活跃的游戏会话(用于单场限制检查)
|
||||
|
||||
Args:
|
||||
chat_id: 会话ID
|
||||
|
||||
Returns:
|
||||
会话信息字典或None
|
||||
"""
|
||||
cursor = self.conn.cursor()
|
||||
cursor.execute("""
|
||||
SELECT * FROM casino_sessions
|
||||
WHERE chat_id = ? AND status = 'open'
|
||||
ORDER BY id DESC LIMIT 1
|
||||
""", (chat_id,))
|
||||
row = cursor.fetchone()
|
||||
|
||||
if row:
|
||||
return dict(row)
|
||||
return None
|
||||
|
||||
def create_casino_session(self, chat_id: int, game_type: str, banker_id: int,
|
||||
min_bet: int, max_bet: int, multiplier: float,
|
||||
house_fee: float = 0.05) -> int:
|
||||
house_fee: float = 0.05, current_phase: str = 'betting',
|
||||
blackjack_multiplier: float = 1.5) -> int:
|
||||
"""创建新的赌场游戏会话
|
||||
|
||||
Args:
|
||||
@@ -667,6 +749,8 @@ class Database:
|
||||
max_bet: 最大下注金额
|
||||
multiplier: 赔率
|
||||
house_fee: 抽水率
|
||||
current_phase: 当前阶段(默认'betting')
|
||||
blackjack_multiplier: 21点黑杰克倍数(默认1.5)
|
||||
|
||||
Returns:
|
||||
session_id
|
||||
@@ -674,20 +758,28 @@ class Database:
|
||||
cursor = self.conn.cursor()
|
||||
current_time = int(time.time())
|
||||
|
||||
# 检查是否已有活跃的会话
|
||||
# 检查是否已有活跃的会话(单场限制:同一chat_id只能有一个活跃游戏)
|
||||
existing = self.get_any_active_casino_session(chat_id)
|
||||
if existing:
|
||||
# 如果已有活跃游戏,返回其ID(保持向后兼容,但实际应该在应用层阻止)
|
||||
return existing['id']
|
||||
|
||||
# 检查是否已有相同game_type的活跃会话(向后兼容)
|
||||
cursor.execute("""
|
||||
SELECT id FROM casino_sessions
|
||||
WHERE chat_id = ? AND game_type = ? AND status = 'open'
|
||||
""", (chat_id, game_type))
|
||||
existing = cursor.fetchone()
|
||||
if existing:
|
||||
return existing['id']
|
||||
existing_same_type = cursor.fetchone()
|
||||
if existing_same_type:
|
||||
return existing_same_type['id']
|
||||
|
||||
cursor.execute("""
|
||||
INSERT INTO casino_sessions
|
||||
(chat_id, game_type, banker_id, min_bet, max_bet, multiplier, house_fee, status, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, 'open', ?)
|
||||
""", (chat_id, game_type, banker_id, min_bet, max_bet, multiplier, house_fee, current_time))
|
||||
(chat_id, game_type, banker_id, min_bet, max_bet, multiplier, house_fee,
|
||||
status, created_at, current_phase, blackjack_multiplier)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, 'open', ?, ?, ?)
|
||||
""", (chat_id, game_type, banker_id, min_bet, max_bet, multiplier, house_fee,
|
||||
current_time, current_phase, blackjack_multiplier))
|
||||
|
||||
return cursor.lastrowid
|
||||
|
||||
@@ -714,16 +806,22 @@ class Database:
|
||||
return None
|
||||
|
||||
def create_casino_bet(self, chat_id: int, game_type: str, user_id: int,
|
||||
bet_type: str, amount: int, multiplier: float) -> int:
|
||||
bet_type: str, amount: int, multiplier: float,
|
||||
bet_category: str = None, bet_number: int = None,
|
||||
bet_value: str = None, hand_status: str = None) -> int:
|
||||
"""创建下注记录
|
||||
|
||||
Args:
|
||||
chat_id: 会话ID
|
||||
game_type: 游戏类型
|
||||
user_id: 用户ID
|
||||
bet_type: 下注类型
|
||||
bet_type: 下注类型(大小游戏:"大"/"小";21点:"标准"等)
|
||||
amount: 下注金额
|
||||
multiplier: 赔率
|
||||
bet_category: 下注类别(轮盘游戏:["数字"/"颜色"/"奇偶"/"大小"/"区间"])
|
||||
bet_number: 数字下注(轮盘游戏:0-36)
|
||||
bet_value: 下注值(轮盘游戏:如"红色"、"奇数"、"1-12"等)
|
||||
hand_status: 手牌状态(21点游戏:["playing"/"stood"/"busted"/"blackjack"])
|
||||
|
||||
Returns:
|
||||
bet_id
|
||||
@@ -733,9 +831,11 @@ class Database:
|
||||
|
||||
cursor.execute("""
|
||||
INSERT INTO casino_bets
|
||||
(chat_id, game_type, user_id, bet_type, amount, multiplier, status, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, 'pending', ?)
|
||||
""", (chat_id, game_type, user_id, bet_type, amount, multiplier, current_time))
|
||||
(chat_id, game_type, user_id, bet_type, amount, multiplier, status, created_at,
|
||||
bet_category, bet_number, bet_value, hand_status)
|
||||
VALUES (?, ?, ?, ?, ?, ?, 'pending', ?, ?, ?, ?, ?)
|
||||
""", (chat_id, game_type, user_id, bet_type, amount, multiplier, current_time,
|
||||
bet_category, bet_number, bet_value, hand_status))
|
||||
|
||||
return cursor.lastrowid
|
||||
|
||||
@@ -871,6 +971,107 @@ class Database:
|
||||
WHERE chat_id = ? AND game_type = ? AND status = 'open'
|
||||
""", (current_time, chat_id, game_type))
|
||||
|
||||
# ===== 21点手牌管理 =====
|
||||
|
||||
def create_blackjack_hand(self, session_id: int, user_id: int,
|
||||
hand_data: List[int], hand_status: str = 'playing') -> int:
|
||||
"""创建21点手牌记录
|
||||
|
||||
Args:
|
||||
session_id: 会话ID
|
||||
user_id: 用户ID(0表示庄家)
|
||||
hand_data: 手牌列表
|
||||
hand_status: 手牌状态
|
||||
|
||||
Returns:
|
||||
hand_id
|
||||
"""
|
||||
cursor = self.conn.cursor()
|
||||
current_time = int(time.time())
|
||||
hand_data_json = json.dumps(hand_data)
|
||||
|
||||
cursor.execute("""
|
||||
INSERT INTO casino_blackjack_hands
|
||||
(session_id, user_id, hand_data, hand_status, created_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
""", (session_id, user_id, hand_data_json, hand_status, current_time, current_time))
|
||||
|
||||
return cursor.lastrowid
|
||||
|
||||
def get_blackjack_hand(self, session_id: int, user_id: int) -> Optional[Dict]:
|
||||
"""获取21点手牌
|
||||
|
||||
Args:
|
||||
session_id: 会话ID
|
||||
user_id: 用户ID
|
||||
|
||||
Returns:
|
||||
手牌信息字典或None
|
||||
"""
|
||||
cursor = self.conn.cursor()
|
||||
cursor.execute("""
|
||||
SELECT * FROM casino_blackjack_hands
|
||||
WHERE session_id = ? AND user_id = ?
|
||||
ORDER BY id DESC LIMIT 1
|
||||
""", (session_id, user_id))
|
||||
row = cursor.fetchone()
|
||||
|
||||
if row:
|
||||
hand_dict = dict(row)
|
||||
hand_dict['hand_data'] = json.loads(hand_dict['hand_data'])
|
||||
return hand_dict
|
||||
return None
|
||||
|
||||
def update_blackjack_hand(self, session_id: int, user_id: int,
|
||||
hand_data: List[int], hand_status: str):
|
||||
"""更新21点手牌
|
||||
|
||||
Args:
|
||||
session_id: 会话ID
|
||||
user_id: 用户ID
|
||||
hand_data: 手牌列表
|
||||
hand_status: 手牌状态
|
||||
"""
|
||||
cursor = self.conn.cursor()
|
||||
current_time = int(time.time())
|
||||
hand_data_json = json.dumps(hand_data)
|
||||
|
||||
cursor.execute("""
|
||||
UPDATE casino_blackjack_hands
|
||||
SET hand_data = ?, hand_status = ?, updated_at = ?
|
||||
WHERE session_id = ? AND user_id = ?
|
||||
""", (hand_data_json, hand_status, current_time, session_id, user_id))
|
||||
|
||||
def get_all_blackjack_hands(self, session_id: int) -> Dict[int, Dict]:
|
||||
"""获取所有21点手牌(用于结算)
|
||||
|
||||
Args:
|
||||
session_id: 会话ID
|
||||
|
||||
Returns:
|
||||
手牌字典 {user_id: {'cards': [...], 'status': ...}, ...}
|
||||
"""
|
||||
cursor = self.conn.cursor()
|
||||
cursor.execute("""
|
||||
SELECT * FROM casino_blackjack_hands
|
||||
WHERE session_id = ?
|
||||
ORDER BY user_id, id DESC
|
||||
""", (session_id,))
|
||||
rows = cursor.fetchall()
|
||||
|
||||
hands_dict = {}
|
||||
for row in rows:
|
||||
hand_dict = dict(row)
|
||||
user_id = hand_dict['user_id']
|
||||
# 只保留最新的手牌(每个用户)
|
||||
if user_id not in hands_dict:
|
||||
hands_dict[user_id] = {
|
||||
'cards': json.loads(hand_dict['hand_data']),
|
||||
'status': hand_dict['hand_status']
|
||||
}
|
||||
|
||||
return hands_dict
|
||||
|
||||
def close(self):
|
||||
"""关闭数据库连接"""
|
||||
if self._conn:
|
||||
|
||||
Reference in New Issue
Block a user