fix: bound chat latency and clarify blackjack flow
This commit is contained in:
@@ -4,11 +4,11 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "jwebot-official-extensions"
|
||||
version = "0.6.1a0+1015"
|
||||
version = "0.6.2a0+1015"
|
||||
description = "Reviewed local command adapters and broker implementation for JWeBot"
|
||||
requires-python = ">=3.9"
|
||||
dependencies = [
|
||||
"jwebot-sdk==0.6.1a0+1015",
|
||||
"jwebot-sdk==0.6.2a0+1015",
|
||||
]
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
|
||||
@@ -62,4 +62,4 @@ __all__ = [
|
||||
"render_feature_list",
|
||||
]
|
||||
|
||||
__version__ = "0.6.1a0+1015"
|
||||
__version__ = "0.6.2a0+1015"
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ from jwebot_sdk import Event, ExtensionResult, ReplyPlan, SingleGroupContext
|
||||
PROFILE = 'single-player-games'
|
||||
AUTHOR = 'jwebot'
|
||||
DESCRIPTION = '本人虚拟金币账户、抽奖、彩票和单人21点'
|
||||
HELP_ENTRIES = ('/金币 /wallet;/抽奖 [金额] /draw;/买彩票 [号码] [金额] /lottery', '/21点 开始|要牌|停牌|状态|结束;/blackjack start|hit|stand|status|end', '/游戏帮助;/games')
|
||||
HELP_ENTRIES = ('/金币 /wallet;/抽奖 [金额] /draw;/买彩票 [号码] [金额] /lottery', '/21点 开始 [金额](金额=本局下注,默认50,空格可省略)', '/21点 要牌|停牌|状态|结束;/blackjack hit|stand|status|end', '/游戏帮助;/games')
|
||||
COMMANDS = ('/金币', '/wallet', '/抽奖', '/draw', '/买彩票', '/lottery', '/21点', '/二十一点', '/blackjack', '/游戏帮助', '/games')
|
||||
|
||||
|
||||
|
||||
@@ -123,7 +123,8 @@ LOCAL_EXTENSIONS = (
|
||||
description="本人虚拟金币账户、抽奖、彩票和单人21点",
|
||||
help_entries=(
|
||||
"/金币 /wallet;/抽奖 [金额] /draw;/买彩票 [号码] [金额] /lottery",
|
||||
"/21点 开始|要牌|停牌|状态|结束;/blackjack start|hit|stand|status|end",
|
||||
"/21点 开始 [金额](金额=本局下注,默认50,空格可省略)",
|
||||
"/21点 要牌|停牌|状态|结束;/blackjack hit|stand|status|end",
|
||||
"/游戏帮助;/games",
|
||||
),
|
||||
command_kinds=("wallet", "prize_draw", "lottery", "blackjack", "game_rules"),
|
||||
|
||||
+58
-19
@@ -11,6 +11,23 @@ from typing import Any
|
||||
INITIAL_COINS = 1000
|
||||
MAX_BET = 100
|
||||
GAME_TIMEOUT_SECONDS = 600
|
||||
BLACKJACK_ACTIONS = {
|
||||
"要牌": "hit",
|
||||
"hit": "hit",
|
||||
"停牌": "stand",
|
||||
"stand": "stand",
|
||||
"状态": "status",
|
||||
"status": "status",
|
||||
"结束": "end",
|
||||
"end": "end",
|
||||
}
|
||||
BLACKJACK_START = re.compile(
|
||||
r"^(?:开始|start)(?P<bet>\d{1,3})?$"
|
||||
)
|
||||
BLACKJACK_COMBINED_ACTION = re.compile(
|
||||
r"^(?:开始|start)(?P<bet>\d{1,3})?"
|
||||
r"(?:要牌|hit|停牌|stand)$"
|
||||
)
|
||||
|
||||
|
||||
def card_label(card: int) -> str:
|
||||
@@ -37,8 +54,9 @@ class PlayerGames:
|
||||
return (
|
||||
"单人游戏:每人首次使用获 1000 虚拟金币;每次下注 2~100。\n"
|
||||
"/金币 /wallet;/抽奖 [金额] /draw;/买彩票 [000~999] [金额] /lottery;"
|
||||
"/21点 开始 [金额] /blackjack start。\n"
|
||||
"21点:/21点 要牌|停牌|状态|结束(hit|stand|status|end);"
|
||||
"21点先用 /21点 开始 [金额] 进场,金额是本局下注,默认50;空格可省略。\n"
|
||||
"看到牌后再单独发送 /21点 要牌|停牌|状态|结束"
|
||||
"(/blackjack hit|stand|status|end);"
|
||||
"每人最多一局,10分钟无操作视为认输,结束不退下注。\n"
|
||||
"抽奖:5%返5倍、20%返2倍,其余无返还;彩票命中返500倍;"
|
||||
"21点获胜返2倍、平局返下注、自然21点返2.5倍向下取整,庄家软17停牌。"
|
||||
@@ -64,25 +82,40 @@ class PlayerGames:
|
||||
number = int(match[1]) if match[1] is not None else None
|
||||
bet = int(match[2] or 10)
|
||||
elif kind == "blackjack":
|
||||
parts = arguments.casefold().split()
|
||||
action = parts[0] if parts else "状态"
|
||||
actions = {"开始": "start", "start": "start", "要牌": "hit", "hit": "hit",
|
||||
"停牌": "stand", "stand": "stand", "状态": "status", "status": "status",
|
||||
"结束": "end", "end": "end"}
|
||||
action = actions.get(action, "")
|
||||
if not action or (action != "start" and len(parts) > 1) or len(parts) > 2:
|
||||
return "用法:/21点 开始 [金额]|要牌|停牌|状态|结束(/blackjack start|hit|stand|status|end)"
|
||||
if action == "start":
|
||||
if len(parts) == 2 and not re.fullmatch(r"\d{1,3}", parts[1]):
|
||||
return "21点下注必须为 2~100 的整数金币"
|
||||
bet = int(parts[1]) if len(parts) == 2 else 50
|
||||
compacted = re.sub(r"\s+", "", arguments.casefold()) or "状态"
|
||||
start = BLACKJACK_START.fullmatch(compacted)
|
||||
if start is not None:
|
||||
action = "start"
|
||||
bet = int(start["bet"] or 50)
|
||||
else:
|
||||
action = BLACKJACK_ACTIONS.get(compacted, "")
|
||||
bet = 0
|
||||
if not action:
|
||||
combined = BLACKJACK_COMBINED_ACTION.fullmatch(compacted)
|
||||
if combined is not None:
|
||||
amount = combined["bet"] or "50"
|
||||
return (
|
||||
"21点要分两步:先发送 /21点 开始 "
|
||||
f"{amount}({amount} 是本局下注);看到牌后再单独发送 "
|
||||
"/21点 要牌 或 /21点 停牌"
|
||||
)
|
||||
return (
|
||||
"用法:先 /21点 开始 [2~100](金额是本局下注,默认50);"
|
||||
"开局后再单独发送 /21点 要牌|停牌|状态|结束;空格可省略"
|
||||
)
|
||||
else:
|
||||
bet = 0
|
||||
if kind in {"prize_draw", "lottery"} or kind == "blackjack" and action == "start":
|
||||
if not 2 <= bet <= MAX_BET:
|
||||
return "下注必须为 2~100 的整数金币"
|
||||
person = self.ledger.resolve_person(
|
||||
str(row["group_fingerprint"]),
|
||||
str(row["sender"]),
|
||||
)
|
||||
player_label = self.display_label(person["display_name"])
|
||||
|
||||
def blackjack_reply(text: str) -> str:
|
||||
return f"{player_label}:{text}"
|
||||
|
||||
def execute(account: dict[str, Any]) -> str:
|
||||
expired = ""
|
||||
@@ -97,11 +130,15 @@ class PlayerGames:
|
||||
f"已结算胜 {account['wins']} / 负 {account['losses']} / 平 {account['ties']}。"
|
||||
"首次赠送1000仅发一次;/游戏帮助 查看规则")
|
||||
if kind == "blackjack" and action in {"hit", "stand", "status", "end"}:
|
||||
return expired + self.play_blackjack(account, action)
|
||||
return blackjack_reply(
|
||||
expired + self.play_blackjack(account, action)
|
||||
)
|
||||
if account.get("game"):
|
||||
return expired + "你已有一局21点,请先 /21点 停牌 或 /21点 结束"
|
||||
message = expired + "你已有一局21点,请先 /21点 停牌 或 /21点 结束"
|
||||
return blackjack_reply(message) if kind == "blackjack" else message
|
||||
if account["balance"] < bet:
|
||||
return expired + f"金币不足:余额 {account['balance']},本次需要 {bet}"
|
||||
message = expired + f"金币不足:余额 {account['balance']},本次需要 {bet}"
|
||||
return blackjack_reply(message) if kind == "blackjack" else message
|
||||
account["balance"] -= bet
|
||||
if kind == "blackjack":
|
||||
deck = list(range(52))
|
||||
@@ -110,8 +147,10 @@ class PlayerGames:
|
||||
"dealer": deck[2:4], "updated_at": time.time()}
|
||||
account["game"] = game
|
||||
if hand_value(game["player"]) == 21 or hand_value(game["dealer"]) == 21:
|
||||
return expired + self.finish_blackjack(account, natural=True)
|
||||
return expired + self.show_hand(game)
|
||||
return blackjack_reply(
|
||||
expired + self.finish_blackjack(account, natural=True)
|
||||
)
|
||||
return blackjack_reply(expired + self.show_hand(game))
|
||||
if kind == "prize_draw":
|
||||
roll = self.rng.randrange(100)
|
||||
payout = bet * (5 if roll < 5 else 2 if roll < 25 else 0)
|
||||
|
||||
Reference in New Issue
Block a user