chore: clean up dice roller

This commit is contained in:
hypercross 2026-02-28 17:46:41 +08:00
parent 1f5ee24a0f
commit b49de62e2c
3 changed files with 5 additions and 123 deletions

View File

@ -8,7 +8,7 @@
点击下面的骰子来掷骰:
:md-dice[2d6]
:md-dice[2d6] :md-dice[{d4, d8}]
:md-dice[3d6kh1] :md-dice[3d6dl2-1]

View File

@ -42,8 +42,8 @@ const App: Component = () => {
<h1 class="text-2xl font-bold text-gray-900">TTRPG Tools</h1>
</div>
</header>
<main class="max-w-4xl mx-auto px-4 py-8 pt-20 md:ml-64 print:p-0">
<Article class="prose-sm" src={currentPath()} />
<main class="max-w-4xl mx-auto px-4 py-8 pt-20 md:ml-64 2xl:ml-auto flex justify-center items-center">
<Article class="prose-sm max-w-none flex-1" src={currentPath()} />
</main>
</div>
);

View File

@ -1,129 +1,11 @@
import { customElement, noShadowDOM } from "solid-element";
import { createSignal, onMount } from "solid-js";
import {rollFormula} from "./md-commander/hooks";
export interface DiceProps {
key?: string;
}
interface RollResult {
total: number;
rolls: number[];
detail: string;
}
function rollDice(formula: string): RollResult {
const allRolls: number[] = [];
let total = 0;
const details: string[] = [];
// 解析骰子公式,支持 + 和 - 运算符
// 先按 + 和 - 分割,但保留运算符
const tokens = formula
.split(/([+-])/)
.map((t) => t.trim())
.filter((t) => t.length > 0);
let sign = 1;
for (let i = 0; i < tokens.length; i++) {
const token = tokens[i];
if (token === "+") {
sign = 1;
continue;
}
if (token === "-") {
sign = -1;
continue;
}
// 处理 kh/kl/dh/dl 运算符
let processedToken = token;
let keepHigh = false;
let keepLow = false;
let dropHigh = false;
let dropLow = false;
let keepCount = 0;
let dropCount = 0;
const khMatch = token.match(/^(.+?)kh(\d+)$/i);
const klMatch = token.match(/^(.+?)kl(\d+)$/i);
const dhMatch = token.match(/^(.+?)dh(\d+)$/i);
const dlMatch = token.match(/^(.+?)dl(\d+)$/i);
if (khMatch) {
processedToken = khMatch[1];
keepHigh = true;
keepCount = parseInt(khMatch[2]);
} else if (klMatch) {
processedToken = klMatch[1];
keepLow = true;
keepCount = parseInt(klMatch[2]);
} else if (dhMatch) {
processedToken = dhMatch[1];
dropHigh = true;
dropCount = parseInt(dhMatch[2]);
} else if (dlMatch) {
processedToken = dlMatch[1];
dropLow = true;
dropCount = parseInt(dlMatch[2]);
}
const match = processedToken.match(/^(\d+)?d(\d+)$/i);
if (match) {
const count = parseInt(match[1] || "1");
const sides = parseInt(match[2]);
const rolls: number[] = [];
for (let j = 0; j < count; j++) {
rolls.push(Math.floor(Math.random() * sides) + 1);
}
let processedRolls = [...rolls];
let detail = `${count}d${sides}`;
// 处理 keep/drop 运算符
if (keepHigh || keepLow || dropHigh || dropLow) {
const sorted = [...processedRolls].sort((a, b) => a - b);
if (dropHigh && dropCount > 0) {
processedRolls = sorted.slice(0, sorted.length - dropCount);
detail += `d${dropCount}h`;
} else if (dropLow && dropCount > 0) {
processedRolls = sorted.slice(dropCount);
detail += `d${dropCount}l`;
} else if (keepHigh && keepCount > 0) {
processedRolls = sorted.slice(-keepCount);
detail += `kh${keepCount}`;
} else if (keepLow && keepCount > 0) {
processedRolls = sorted.slice(0, keepCount);
detail += `kl${keepCount}`;
}
}
const partTotal = processedRolls.reduce((a, b) => a + b, 0);
total += sign * partTotal;
allRolls.push(...processedRolls);
details.push(
`${detail}=[${processedRolls.join(",")}]${sign < 0 ? " (负)" : ""}`,
);
} else {
// 处理固定数字
const num = parseInt(token);
if (!isNaN(num)) {
total += sign * num;
details.push(`${num}${sign < 0 ? " (负)" : ""}`);
}
}
}
return {
total,
rolls: allRolls,
detail: details.join(" + "),
};
}
// 从 URL 参数获取骰子结果
function getDiceResultFromUrl(key: string): number | null {
if (typeof window === "undefined") return null;
@ -174,7 +56,7 @@ customElement("md-dice", { key: "" }, (props, { element }) => {
const handleRoll = () => {
// 点击骰子图标:总是重 roll
const rollResult = rollDice(formula);
const rollResult = rollFormula(formula).result;
setResult(rollResult.total);
setRollDetail(rollResult.detail);
setIsRolled(true);