feat: add gameplay assists and variant generator

This commit is contained in:
2026-08-30 17:47:10 +02:00
parent 659640b231
commit 4a9869baa0
29 changed files with 2899 additions and 110 deletions
+57
View File
@@ -0,0 +1,57 @@
import type { DigitCompletion } from "../state/gameplayHelpers";
import { symbolFor } from "../state/session";
function completionLabel(item: DigitCompletion, size: number): string {
const symbol = symbolFor(item.digit, size);
if (item.status === "done")
return `Digit ${symbol}: complete, ${String(item.placed)} of ${String(item.target)} placed`;
if (item.status === "overdone")
return `Digit ${symbol}: overdone by ${String(item.excess)}, ${String(item.placed)} of ${String(item.target)} placed`;
return `Digit ${symbol}: ${String(item.remaining)} remaining, ${String(item.placed)} of ${String(item.target)} placed`;
}
export function DigitCompletionBar({
size,
completions,
highlightedDigit,
highlightingEnabled,
onHighlight,
}: {
size: number;
completions: readonly DigitCompletion[];
highlightedDigit: number | null;
highlightingEnabled: boolean;
onHighlight: (digit: number) => void;
}) {
return (
<section className="digit-completion" aria-label="Digit completion">
<div className="digit-completion__heading">
<span>Digit progress</span>
<small>muted = complete · red = too many</small>
</div>
<div
className={`digit-completion__bar${size > 9 ? " digit-completion__bar--wide" : ""}`}
role="group"
aria-label="Highlight matching digits"
>
{completions.map((item) => (
<button
key={item.digit}
type="button"
className={`digit-completion__digit is-${item.status}${highlightedDigit === item.digit ? " is-highlighted" : ""}`}
aria-label={completionLabel(item, size)}
aria-pressed={highlightedDigit === item.digit}
disabled={!highlightingEnabled}
title={completionLabel(item, size)}
onClick={() => onHighlight(item.digit)}
>
<strong>{symbolFor(item.digit, size)}</strong>
<span>
{item.placed}/{item.target}
</span>
</button>
))}
</div>
</section>
);
}