实现21点与轮盘游戏

This commit is contained in:
2025-10-31 12:09:07 +08:00
parent cef684f64b
commit 1f10799562
2 changed files with 731 additions and 0 deletions

View File

@@ -114,12 +114,30 @@ def get_help_message() -> str:
- `.aiconfig host=xxx port=xxx model=xxx` - 配置Ollama服务地址和模型 - `.aiconfig host=xxx port=xxx model=xxx` - 配置Ollama服务地址和模型
### 🎰 赌场系统 ### 🎰 赌场系统
**大小游戏**
- `.赌场 大小 open <最小> <最大> <赔率>` - 庄家开启大小游戏 - `.赌场 大小 open <最小> <最大> <赔率>` - 庄家开启大小游戏
- `.赌场 大小 bet <大/小> <金额>` - 下注 - `.赌场 大小 bet <大/小> <金额>` - 下注
- `.赌场 大小 status` - 查看状态 - `.赌场 大小 status` - 查看状态
- `.赌场 大小 settle` - 庄家结算(系统随机) - `.赌场 大小 settle` - 庄家结算(系统随机)
- `.赌场 大小 cancel` - 庄家放弃游戏(返还下注) - `.赌场 大小 cancel` - 庄家放弃游戏(返还下注)
**轮盘游戏**
- `.赌场 轮盘 open <最小> <最大>` - 庄家开启轮盘游戏
- `.赌场 轮盘 bet <类型> <选项> <金额>` - 下注(数字/颜色/奇偶/大小/区间)
- `.赌场 轮盘 status` - 查看状态
- `.赌场 轮盘 settle` - 庄家结算系统随机0-36
- `.赌场 轮盘 cancel` - 庄家放弃游戏(返还下注)
**21点游戏**
- `.赌场 21点 open <最小> <最大> [黑杰克倍数]` - 庄家开启21点游戏
- `.赌场 21点 bet <金额>` - 下注
- `.赌场 21点 deal` - 庄家发牌
- `.赌场 21点 hit` - 玩家要牌
- `.赌场 21点 stand` - 玩家停牌
- `.赌场 21点 status` - 查看状态
- `.赌场 21点 settle` - 庄家结算
- `.赌场 21点 cancel` - 庄家放弃游戏(返还下注)
### 其他 ### 其他
- `.help` - 显示帮助 - `.help` - 显示帮助
- `.stats` - 查看个人统计 - `.stats` - 查看个人统计

View File

@@ -1,6 +1,7 @@
"""赌场游戏模块""" """赌场游戏模块"""
import logging import logging
import random import random
from typing import List
from games.base import BaseGame from games.base import BaseGame
from utils.parser import CommandParser from utils.parser import CommandParser
from core.database import get_db from core.database import get_db
@@ -604,4 +605,716 @@ class CasinoGame(BaseGame):
except Exception as e: except Exception as e:
logger.error(f"轮盘下注失败: {e}", exc_info=True) logger.error(f"轮盘下注失败: {e}", exc_info=True)
return f"❌ 下注失败: {str(e)}" return f"❌ 下注失败: {str(e)}"
async def _status_roulette(self, chat_id: int) -> str:
"""查看轮盘游戏状态"""
session = self.db.get_active_casino_session(chat_id, '轮盘')
if not session:
return "❌ 当前没有进行中的轮盘游戏"
bets = self.db.get_pending_bets(chat_id, '轮盘')
# 统计下注情况
bet_stats = {}
for bet in bets:
category = bet.get('bet_category', '未知')
value = bet.get('bet_value') or str(bet.get('bet_number', ''))
key = f"{category}-{value}"
if key not in bet_stats:
bet_stats[key] = {'amount': 0, 'count': 0}
bet_stats[key]['amount'] += bet['amount']
bet_stats[key]['count'] += 1
banker_display_name = self.db.get_user_display_name(session['banker_id'])
text = f"## 🎰 轮盘游戏状态\n\n"
text += f"**庄家**{banker_display_name}\n\n"
text += f"**最小下注**{session['min_bet']}\n\n"
text += f"**最大下注**{session['max_bet']}\n\n"
text += "---\n\n"
text += f"**当前下注统计**\n"
for key, stat in bet_stats.items():
parts = key.split('-', 1)
text += f"- {parts[0]}{' - ' + parts[1] if len(parts) > 1 else ''}{stat['amount']} 分({stat['count']}注)\n"
text += f"\n**总下注**{len(bets)}\n\n"
text += "---\n\n"
text += "💡 庄家可以使用 `.赌场 轮盘 settle` 结算"
return text
async def _settle_roulette(self, chat_id: int, user_id: int) -> str:
"""庄家结算轮盘游戏(系统随机生成结果)"""
try:
# 系统随机生成0-36的数字
result_number = random.randint(0, 36)
# 结算
settlement = self.db.settle_casino_bets(
chat_id, '轮盘', str(result_number), user_id,
result_number=result_number
)
# 构建结算报告
text = f"## 🎰 轮盘游戏结算\n\n"
text += f"**结算结果**:🎲 **{result_number}**\n\n"
text += "---\n\n"
text += f"**赢家**{len(settlement['winners'])}\n"
text += f"**输家**{len(settlement['losers'])}\n\n"
if settlement['winners']:
text += "**赢家明细**\n"
for winner in settlement['winners']:
winner_display_name = self.db.get_user_display_name(winner['user_id'])
text += f"- {winner_display_name}: 下注{winner['amount']}分,赢得{winner['win_amount']}\n"
text += "\n"
if settlement['losers']:
text += "**输家明细**\n"
for loser in settlement['losers']:
loser_display_name = self.db.get_user_display_name(loser['user_id'])
text += f"- {loser_display_name}: 下注{loser['amount']}\n"
text += "\n"
text += "---\n\n"
text += "✅ 游戏已结束,欢迎再次游戏!"
return text
except ValueError as e:
return f"{str(e)}"
except Exception as e:
logger.error(f"轮盘结算失败: {e}", exc_info=True)
return f"❌ 结算失败: {str(e)}"
async def _cancel_roulette(self, chat_id: int, user_id: int) -> str:
"""庄家放弃轮盘游戏"""
try:
session = self.db.get_active_casino_session(chat_id, '轮盘')
if not session:
return "❌ 当前没有进行中的游戏"
if session['banker_id'] != user_id:
return "❌ 只有庄家可以放弃游戏"
bets = self.db.get_pending_bets(chat_id, '轮盘')
return_amount = 0
for bet in bets:
self.db.add_points(bet['user_id'], bet['amount'], 'casino_cancel',
"庄家放弃游戏,返还下注")
return_amount += bet['amount']
self.db.close_casino_session(chat_id, '轮盘')
cursor = self.db.conn.cursor()
cursor.execute("""
UPDATE casino_bets
SET status = 'cancelled'
WHERE chat_id = ? AND game_type = ? AND status = 'pending'
""", (chat_id, '轮盘'))
banker_display_name = self.db.get_user_display_name(user_id)
text = f"## 🎰 游戏已放弃\n\n"
text += f"**庄家**{banker_display_name}\n\n"
text += f"**总返还积分**{return_amount}\n\n"
text += f"**返还人数**{len(bets)}\n\n"
text += "---\n\n"
text += "✅ 所有下注已返还,游戏已关闭"
return text
except Exception as e:
logger.error(f"放弃轮盘游戏失败: {e}", exc_info=True)
return f"❌ 放弃游戏失败: {str(e)}"
def _get_roulette_help(self) -> str:
"""获取轮盘游戏帮助信息"""
return """## 🎰 轮盘游戏帮助
### 庄家命令
- `.赌场 轮盘 open <最小> <最大>` - 开启游戏
- 示例:`.赌场 轮盘 open 10 100`
- `.赌场 轮盘 settle` - 结算游戏系统随机生成0-36
- `.赌场 轮盘 cancel` - 放弃游戏(返还所有下注)
### 玩家命令
- `.赌场 轮盘 bet <类型> <选项> <金额>` - 下注
- 数字:`.赌场 轮盘 bet 数字 17 100` 押数字17100分35倍赔率
- 颜色:`.赌场 轮盘 bet 红色 50` 押红色50分2倍赔率
- 奇偶:`.赌场 轮盘 bet 奇数 30` 押奇数30分2倍赔率
- 大小:`.赌场 轮盘 bet 大 40` 押大19-3640分2倍赔率
- 区间:`.赌场 轮盘 bet 1-12 60` 押1-1260分3倍赔率
### 通用命令
- `.赌场 轮盘 status` - 查看当前状态
### 游戏规则
- 数字0-360为绿色其他数字为红色或黑色
- 数字下注35倍赔率
- 颜色/奇偶/大小2倍赔率
- 区间1-12/13-24/25-363倍赔率
- 系统抽水5%"""
# ===== 21点游戏 =====
async def _handle_blackjack(self, args: str, chat_id: int, user_id: int) -> str:
"""处理21点游戏"""
if not args:
return self._get_blackjack_help()
parts = args.split(maxsplit=1)
action = parts[0].lower()
sub_args = parts[1] if len(parts) > 1 else ""
if action in ['open', '开启', '开始']:
return await self._open_blackjack(sub_args, chat_id, user_id)
elif action in ['bet', '下注', '']:
return await self._bet_blackjack(sub_args, chat_id, user_id)
elif action in ['deal', '发牌']:
return await self._deal_blackjack(chat_id, user_id)
elif action in ['hit', '要牌']:
return await self._hit_blackjack(chat_id, user_id)
elif action in ['stand', '停牌']:
return await self._stand_blackjack(chat_id, user_id)
elif action in ['status', '状态', '查看']:
return await self._status_blackjack(chat_id)
elif action in ['settle', '结算']:
return await self._settle_blackjack(chat_id, user_id)
elif action in ['cancel', '放弃', '关闭']:
return await self._cancel_blackjack(chat_id, user_id)
elif action in ['help', '帮助']:
return self._get_blackjack_help()
else:
return f"❌ 未知命令: {action}\n\n{self._get_blackjack_help()}"
async def _open_blackjack(self, args: str, chat_id: int, user_id: int) -> str:
"""庄家开启21点游戏"""
try:
parts = args.split()
if len(parts) < 2:
return "❌ 参数格式错误!\n\n正确格式:`.赌场 21点 open <最小下注> <最大下注> [黑杰克倍数]`\n\n示例:`.赌场 21点 open 10 100 1.5`"
try:
min_bet = int(parts[0])
max_bet = int(parts[1])
blackjack_multiplier = float(parts[2]) if len(parts) > 2 else 1.5
except ValueError:
return "❌ 参数必须是数字!"
if min_bet <= 0 or max_bet <= 0:
return "❌ 下注金额必须大于0"
if min_bet > max_bet:
return "❌ 最小下注不能大于最大下注!"
if max_bet > 10000:
return "❌ 最大下注不能超过10000分"
if blackjack_multiplier <= 0:
return "❌ 黑杰克倍数必须大于0"
existing = self.db.get_any_active_casino_session(chat_id)
if existing:
return f"⚠️ 当前已有进行中的游戏({existing['game_type']}),请先结算后再开启新游戏。"
session_id = self.db.create_casino_session(
chat_id=chat_id,
game_type='21点',
banker_id=user_id,
min_bet=min_bet,
max_bet=max_bet,
multiplier=1.0, # 21点标准赔率1:1
house_fee=0.05,
current_phase='betting',
blackjack_multiplier=blackjack_multiplier
)
banker_display_name = self.db.get_user_display_name(user_id)
text = f"## 🎰 21点游戏已开启\n\n"
text += f"**庄家**{banker_display_name}\n\n"
text += f"**最小下注**{min_bet}\n\n"
text += f"**最大下注**{max_bet}\n\n"
text += f"**黑杰克倍数**{blackjack_multiplier}\n\n"
text += f"**抽水率**5%\n\n"
text += "---\n\n"
text += "💡 提示:玩家下注后,庄家使用 `.赌场 21点 deal` 发牌"
return text
except Exception as e:
logger.error(f"开启21点游戏失败: {e}", exc_info=True)
return f"❌ 开启游戏失败: {str(e)}"
async def _bet_blackjack(self, args: str, chat_id: int, user_id: int) -> str:
"""玩家下注21点"""
try:
try:
amount = int(args.strip())
except ValueError:
return "❌ 下注金额必须是数字!\n\n正确格式:`.赌场 21点 bet <金额>`"
session = self.db.get_active_casino_session(chat_id, '21点')
if not session:
return "❌ 当前没有进行中的游戏,请等待庄家开启游戏。"
if session['current_phase'] != 'betting':
return "❌ 当前不是下注阶段,无法下注。"
if amount < session['min_bet']:
return f"❌ 下注金额太小!最小下注:{session['min_bet']}"
if amount > session['max_bet']:
return f"❌ 下注金额太大!最大下注:{session['max_bet']}"
user_points = self.db.get_user_points(user_id)
if user_points['points'] < amount:
return f"❌ 积分不足!需要 {amount} 分,当前可用 {user_points['points']}"
if not self.db.consume_points(user_id, amount, 'casino_bet', "21点游戏下注"):
return "❌ 扣除积分失败!"
bet_id = self.db.create_casino_bet(
chat_id=chat_id,
game_type='21点',
user_id=user_id,
bet_type='标准',
amount=amount,
multiplier=1.0, # 标准赔率1:1
hand_status='playing'
)
updated_points = self.db.get_user_points(user_id)
text = f"## 🎲 下注成功\n\n"
text += f"**下注金额**{amount}\n\n"
text += f"**剩余积分**{updated_points['points']}\n\n"
text += "---\n\n"
text += "💡 等待庄家发牌..."
return text
except Exception as e:
logger.error(f"21点下注失败: {e}", exc_info=True)
return f"❌ 下注失败: {str(e)}"
def _draw_card(self) -> int:
"""抽取一张牌1-13其中1=A11=J12=Q13=K"""
return random.randint(1, 13)
def _calculate_points(self, cards: List[int]) -> int:
"""计算21点手牌点数复用数据库方法逻辑"""
return self.db._calculate_blackjack_points(cards)
def _check_blackjack(self, cards: List[int]) -> bool:
"""检查是否为黑杰克A+10/J/Q/K"""
if len(cards) != 2:
return False
has_ace = 1 in cards
has_ten = any(card >= 11 for card in cards) or 10 in cards
return has_ace and has_ten
async def _deal_blackjack(self, chat_id: int, user_id: int) -> str:
"""庄家发初始牌"""
try:
session = self.db.get_active_casino_session(chat_id, '21点')
if not session:
return "❌ 当前没有进行中的游戏"
if session['banker_id'] != user_id:
return "❌ 只有庄家可以发牌"
if session['current_phase'] != 'betting':
return "❌ 当前阶段不是下注阶段,无法发牌"
bets = self.db.get_pending_bets(chat_id, '21点')
if not bets:
return "❌ 还没有玩家下注,无法发牌"
session_id = session['id']
# 为庄家发两张牌
banker_cards = [self._draw_card(), self._draw_card()]
banker_points = self._calculate_points(banker_cards)
banker_status = 'blackjack' if self._check_blackjack(banker_cards) else 'playing'
self.db.create_blackjack_hand(session_id, 0, banker_cards, banker_status)
# 为每个下注的玩家发两张牌
player_hands = {}
for bet in bets:
player_cards = [self._draw_card(), self._draw_card()]
player_points = self._calculate_points(player_cards)
player_status = 'blackjack' if self._check_blackjack(player_cards) else 'playing'
self.db.create_blackjack_hand(session_id, bet['user_id'], player_cards, player_status)
player_hands[bet['user_id']] = {
'cards': player_cards,
'points': player_points,
'status': player_status
}
# 更新session阶段
cursor = self.db.conn.cursor()
cursor.execute("""
UPDATE casino_sessions
SET current_phase = 'playing'
WHERE id = ?
""", (session_id,))
# 构建发牌结果
text = f"## 🎰 发牌完成\n\n"
text += f"**庄家手牌**{self._format_cards(banker_cards)} ({banker_points}点)\n\n"
if banker_status == 'blackjack':
text += "**庄家黑杰克!**\n\n"
text += "---\n\n"
text += "**玩家手牌**\n"
for user_id, hand in player_hands.items():
player_name = self.db.get_user_display_name(user_id)
text += f"- {player_name}{self._format_cards(hand['cards'])} ({hand['points']}点)"
if hand['status'] == 'blackjack':
text += " **黑杰克!**"
text += "\n"
text += "\n---\n\n"
text += "💡 玩家可以使用 `.赌场 21点 hit` 要牌或 `.赌场 21点 stand` 停牌"
return text
except Exception as e:
logger.error(f"21点发牌失败: {e}", exc_info=True)
return f"❌ 发牌失败: {str(e)}"
def _format_cards(self, cards: List[int]) -> str:
"""格式化手牌显示"""
card_names = {
1: 'A',
11: 'J',
12: 'Q',
13: 'K'
}
formatted = []
for card in cards:
if card in card_names:
formatted.append(card_names[card])
else:
formatted.append(str(card))
return ' '.join(formatted)
async def _hit_blackjack(self, chat_id: int, user_id: int) -> str:
"""玩家要牌"""
try:
session = self.db.get_active_casino_session(chat_id, '21点')
if not session:
return "❌ 当前没有进行中的游戏"
if session['current_phase'] != 'playing':
return "❌ 当前不是游戏阶段,无法要牌"
# 检查玩家是否有下注
bets = self.db.get_pending_bets(chat_id, '21点')
user_bet = next((b for b in bets if b['user_id'] == user_id), None)
if not user_bet:
return "❌ 您没有下注,无法要牌"
# 获取玩家手牌
session_id = session['id']
hand = self.db.get_blackjack_hand(session_id, user_id)
if not hand:
return "❌ 未找到手牌信息"
if hand['hand_status'] != 'playing':
return f"❌ 当前手牌状态为:{hand['hand_status']},无法要牌"
# 抽一张新牌
new_card = self._draw_card()
cards = hand['hand_data'] + [new_card]
points = self._calculate_points(cards)
# 判断状态
if points > 21:
status = 'busted'
elif points == 21:
status = 'stood'
else:
status = 'playing'
# 更新手牌
self.db.update_blackjack_hand(session_id, user_id, cards, status)
player_name = self.db.get_user_display_name(user_id)
text = f"## 🎲 要牌\n\n"
text += f"**玩家**{player_name}\n\n"
text += f"**新手牌**{self._format_cards(cards)} ({points}点)\n\n"
if status == 'busted':
text += "**爆牌!** ❌\n\n"
elif points == 21:
text += "**21点** ✅\n\n"
text += "---\n\n"
if status == 'playing':
text += "💡 可以继续要牌或停牌"
elif status == 'stood':
text += "💡 21点自动停牌"
else:
text += "💡 已爆牌,等待结算"
return text
except Exception as e:
logger.error(f"21点要牌失败: {e}", exc_info=True)
return f"❌ 要牌失败: {str(e)}"
async def _stand_blackjack(self, chat_id: int, user_id: int) -> str:
"""玩家停牌"""
try:
session = self.db.get_active_casino_session(chat_id, '21点')
if not session:
return "❌ 当前没有进行中的游戏"
if session['current_phase'] != 'playing':
return "❌ 当前不是游戏阶段,无法停牌"
session_id = session['id']
hand = self.db.get_blackjack_hand(session_id, user_id)
if not hand:
return "❌ 未找到手牌信息"
if hand['hand_status'] != 'playing':
return f"❌ 当前手牌状态为:{hand['hand_status']},无法停牌"
# 更新状态为停牌
self.db.update_blackjack_hand(session_id, user_id, hand['hand_data'], 'stood')
points = self._calculate_points(hand['hand_data'])
player_name = self.db.get_user_display_name(user_id)
text = f"## 🎲 停牌\n\n"
text += f"**玩家**{player_name}\n\n"
text += f"**最终手牌**{self._format_cards(hand['hand_data'])} ({points}点)\n\n"
text += "---\n\n"
text += "💡 已停牌,等待其他玩家操作或庄家结算"
return text
except Exception as e:
logger.error(f"21点停牌失败: {e}", exc_info=True)
return f"❌ 停牌失败: {str(e)}"
async def _status_blackjack(self, chat_id: int) -> str:
"""查看21点游戏状态"""
session = self.db.get_active_casino_session(chat_id, '21点')
if not session:
return "❌ 当前没有进行中的21点游戏"
session_id = session['id']
bets = self.db.get_pending_bets(chat_id, '21点')
hands = self.db.get_all_blackjack_hands(session_id)
banker_display_name = self.db.get_user_display_name(session['banker_id'])
text = f"## 🎰 21点游戏状态\n\n"
text += f"**庄家**{banker_display_name}\n\n"
text += f"**当前阶段**{session['current_phase']}\n\n"
text += f"**最小下注**{session['min_bet']}\n\n"
text += f"**最大下注**{session['max_bet']}\n\n"
text += f"**黑杰克倍数**{session.get('blackjack_multiplier', 1.5)}\n\n"
# 显示庄家手牌
banker_hand = hands.get(0)
if banker_hand:
banker_points = self._calculate_points(banker_hand['cards'])
text += f"**庄家手牌**{self._format_cards(banker_hand['cards'])} ({banker_points}点)"
if banker_hand['status'] == 'blackjack':
text += " **黑杰克!**"
text += "\n\n"
text += "---\n\n"
text += f"**玩家下注**{len(bets)}\n\n"
# 显示玩家手牌
if hands:
text += "**玩家手牌**\n"
for user_id, hand in hands.items():
if user_id == 0: # 跳过庄家
continue
player_name = self.db.get_user_display_name(user_id)
player_bet = next((b for b in bets if b['user_id'] == user_id), None)
if player_bet:
points = self._calculate_points(hand['cards'])
text += f"- {player_name}{self._format_cards(hand['cards'])} ({points}点) - 下注{player_bet['amount']}"
if hand['status'] == 'blackjack':
text += " **黑杰克!**"
elif hand['status'] == 'busted':
text += " **爆牌**"
elif hand['status'] == 'stood':
text += " **已停牌**"
text += "\n"
text += "\n"
text += "---\n\n"
if session['current_phase'] == 'betting':
text += "💡 庄家可以使用 `.赌场 21点 deal` 发牌"
elif session['current_phase'] == 'playing':
text += "💡 玩家可以使用 `.赌场 21点 hit` 要牌或 `.赌场 21点 stand` 停牌\n"
text += "💡 庄家可以使用 `.赌场 21点 settle` 结算"
else:
text += "💡 庄家可以使用 `.赌场 21点 settle` 结算"
return text
async def _settle_blackjack(self, chat_id: int, user_id: int) -> str:
"""庄家结算21点游戏"""
try:
session = self.db.get_active_casino_session(chat_id, '21点')
if not session:
return "❌ 当前没有进行中的游戏"
if session['banker_id'] != user_id:
return "❌ 只有庄家可以结算游戏"
if session['current_phase'] == 'betting':
return "❌ 还未发牌,无法结算"
session_id = session['id']
hands = self.db.get_all_blackjack_hands(session_id)
# 获取庄家手牌
banker_hand = hands.get(0, {})
banker_cards = banker_hand.get('cards', [])
banker_points = self._calculate_points(banker_cards)
banker_status = banker_hand.get('status', 'stood')
# 如果庄家还在playing状态自动要牌到17点以上
while banker_status == 'playing' and banker_points < 17:
new_card = self._draw_card()
banker_cards.append(new_card)
banker_points = self._calculate_points(banker_cards)
if banker_points > 21:
banker_status = 'busted'
elif banker_points >= 17:
banker_status = 'stood'
# 更新庄家手牌
self.db.update_blackjack_hand(session_id, 0, banker_cards, banker_status)
# 更新hands字典
hands[0] = {'cards': banker_cards, 'status': banker_status}
#進行结算
settlement = self.db.settle_casino_bets(
chat_id, '21点', f"庄家{banker_points}", user_id,
hands_dict=hands
)
# 构建结算报告
text = f"## 🎰 21点游戏结算\n\n"
text += f"**庄家最终手牌**{self._format_cards(banker_cards)} ({banker_points}点)\n\n"
if banker_status == 'blackjack':
text += "**庄家黑杰克!**\n\n"
elif banker_status == 'busted':
text += "**庄家爆牌!**\n\n"
text += "---\n\n"
text += f"**赢家**{len(settlement['winners'])}\n"
text += f"**输家**{len(settlement['losers'])}\n\n"
if settlement['winners']:
text += "**赢家明细**\n"
for winner in settlement['winners']:
winner_display_name = self.db.get_user_display_name(winner['user_id'])
player_hand = hands.get(winner['user_id'], {})
player_points = self._calculate_points(player_hand.get('cards', []))
text += f"- {winner_display_name}: {self._format_cards(player_hand.get('cards', []))} ({player_points}点) - 下注{winner['amount']}分,赢得{winner['win_amount']}\n"
text += "\n"
if settlement['losers']:
text += "**输家明细**\n"
for loser in settlement['losers']:
loser_display_name = self.db.get_user_display_name(loser['user_id'])
player_hand = hands.get(loser['user_id'], {})
player_points = self._calculate_points(player_hand.get('cards', []))
text += f"- {loser_display_name}: {self._format_cards(player_hand.get('cards', []))} ({player_points}点) - 下注{loser['amount']}\n"
text += "\n"
text += "---\n\n"
text += "✅ 游戏已结束,欢迎再次游戏!"
return text
except ValueError as e:
return f"{str(e)}"
except Exception as e:
logger.error(f"21点结算失败: {e}", exc_info=True)
return f"❌ 结算失败: {str(e)}"
async def _cancel_blackjack(self, chat_id: int, user_id: int) -> str:
"""庄家放弃21点游戏"""
try:
session = self.db.get_active_casino_session(chat_id, '21点')
if not session:
return "❌ 当前没有进行中的游戏"
if session['banker_id'] != user_id:
return "❌ 只有庄家可以放弃游戏"
bets = self.db.get_pending_bets(chat_id, '21点')
return_amount = 0
for bet in bets:
self.db.add_points(bet['user_id'], bet['amount'], 'casino_cancel',
"庄家放弃游戏,返还下注")
return_amount += bet['amount']
self.db.close_casino_session(chat_id, '21点')
cursor = self.db.conn.cursor()
cursor.execute("""
UPDATE casino_bets
SET status = 'cancelled'
WHERE chat_id = ? AND game_type = ? AND status = 'pending'
""", (chat_id, '21点'))
banker_display_name = self.db.get_user_display_name(user_id)
text = f"## 🎰 游戏已放弃\n\n"
text += f"**庄家**{banker_display_name}\n\n"
text += f"**总返还积分**{return_amount}\n\n"
text += f"**返还人数**{len(bets)}\n\n"
text += "---\n\n"
text += "✅ 所有下注已返还,游戏已关闭"
return text
except Exception as e:
logger.error(f"放弃21点游戏失败: {e}", exc_info=True)
return f"❌ 放弃游戏失败: {str(e)}"
def _get_blackjack_help(self) -> str:
"""获取21点游戏帮助信息"""
return """## 🎰 21点游戏帮助
### 庄家命令
- `.赌场 21点 open <最小> <最大> [黑杰克倍数]` - 开启游戏
- 示例:`.赌场 21点 open 10 100 1.5`
- `.赌场 21点 deal` - 发牌(所有玩家下注后)
- `.赌场 21点 settle` - 结算游戏自动要牌到17点以上后结算
- `.赌场 21点 cancel` - 放弃游戏(返还所有下注)
### 玩家命令
- `.赌场 21点 bet <金额>` - 下注
- 示例:`.赌场 21点 bet 50`
- `.赌场 21点 hit` - 要牌
- `.赌场 21点 stand` - 停牌
### 通用命令
- `.赌场 21点 status` - 查看当前状态
### 游戏规则
- 目标手牌点数尽可能接近21点但不能超过
- 黑杰克A+10/J/Q/K赢得1.5倍(默认)
- 玩家点数>庄家点数且未爆牌赢得1:1
- 平局:返还下注
- 爆牌:失去下注
- 庄家自动要牌到17点以上
- 系统抽水5%"""