feat: add range support for spark table cell matching

This commit is contained in:
hypercross 2026-07-08 00:37:01 +08:00
parent 03671583cd
commit 376dde44b5
1 changed files with 39 additions and 8 deletions

View File

@ -188,6 +188,43 @@ export function scanSparkTables(
}));
}
// ---------------------------------------------------------------------------
// Range parsing
// ---------------------------------------------------------------------------
/**
* Parse a cell value like "1-3", "4-6", or "10-20" into { min, max }.
* Returns null if the cell doesn't represent a range.
*/
function parseRange(cell: string): { min: number; max: number } | null {
const trimmed = cell.trim();
const m = /^(\d+)\s*-\s*(\d+)$/.exec(trimmed);
if (!m) return null;
const min = parseInt(m[1], 10);
const max = parseInt(m[2], 10);
if (isNaN(min) || isNaN(max)) return null;
return { min, max };
}
/** Test whether a rolled total matches a cell value */
function matchesCell(diceCell: string, rolledValue: number): boolean {
const trimmed = diceCell.trim();
// Exact integer match
const cellNum = parseInt(trimmed, 10);
if (!isNaN(cellNum) && rolledValue === cellNum) return true;
// Exact string match (for non-numeric labels)
if (String(rolledValue) === trimmed) return true;
// Range match (e.g. "1-3")
const range = parseRange(trimmed);
if (range && rolledValue >= range.min && rolledValue <= range.max)
return true;
return false;
}
// ---------------------------------------------------------------------------
// Rolling
// ---------------------------------------------------------------------------
@ -207,17 +244,11 @@ export function rollSparkTable(meta: SparkTableMeta): SparkTableResult {
const roll = rollFormula(meta.notation);
const rolledValue = roll.result.total;
// Find the row matching the rolled value — compare as integers,
// falling back to string comparison.
// Find the row matching the rolled value
let value = `(no row for ${rolledValue})`;
for (const row of meta.rows) {
const diceCell = row[0] ?? "";
const cellNum = parseInt(diceCell.trim(), 10);
const match =
!isNaN(cellNum) && rolledValue === cellNum
? true
: String(rolledValue) === diceCell.trim();
if (match) {
if (matchesCell(diceCell, rolledValue)) {
value = row[colIdx + 1] ?? "";
break;
}