kripke: add history

This commit is contained in:
2025-02-22 13:11:22 +09:00
parent ca13b55dc0
commit e78c755799
6 changed files with 108 additions and 29 deletions

View File

@@ -40,10 +40,6 @@ interface ReadonlyArray<T> {
): searchElement is T extends LiteralUnionLike<T> ? T : never;
}
interface Map<K> {
has(key: Weaken<K>): key is K;
}
declare module "*&enhanced" {
import type { Picture } from "vite-imagetools";

View File

@@ -11,8 +11,8 @@ import Game, { type GameStatus } from "./components/game.svelte";
import Rules from "./components/rules.svelte";
import Share from "./components/share.svelte";
import { daily } from "./lib/store";
import { getFrameBySeed, getTimeUntilNextGame } from "./lib/system";
import { daily } from "./store";
let { data } = $props();
const seed = data.seed;

View File

@@ -1,5 +1,6 @@
<script lang="ts">
import { type Formula, prettyPrint, tryParse } from "@cannorin/kripke";
import { formulaHistory } from "../lib/store";
let {
formula = $bindable<Formula | undefined>(undefined),
@@ -11,6 +12,12 @@ let {
let input = $state(formula ? prettyPrint(formula) : "");
let error = $state(false);
let history = $derived(
[...$formulaHistory]
.toSorted(([_a, ac], [_b, bc]) => bc - ac)
.slice(0, 10)
.map(([a, _ac]) => a),
);
$effect(() => {
const fml = tryParse(input);
@@ -24,7 +31,16 @@ $effect(() => {
});
</script>
{#if history.length > 0}
<datalist id="formula">
{#each history as fml}
<option value={fml}></option>
{/each}
</datalist>
{/if}
<input
id="formula"
class={["rounded border border-foreground ring-0 focus:outline-none focus:ring-0 p-2 w-full", error && "border-primary"]}
type="text"
placeholder="Enter modal formula"

View File

@@ -0,0 +1,54 @@
export class MultiSet<T> extends Map<T, number> {
constructor(iterable?: Iterable<readonly [T, number]>) {
super();
if (iterable) {
for (const [item, count] of iterable) {
this.add(item, count);
}
}
}
/**
* Adds the specified item to the multiset.
* If the item already exists, its count is incremented.
*
* @param item The element to add.
* @param count The number of times to add the element (default is 1).
* @returns The current instance for chaining.
*/
add(item: T, count = 1): this {
const currentCount = this.get(item) ?? 0;
this.set(item, currentCount + count);
return this;
}
/**
* Removes one or more instances of the specified item.
*
* @param item The element to remove.
* @param count The number of times to remove the element (default is 1).
* @returns True if the element was present, false otherwise.
*/
remove(item: T, count = 1): boolean {
const currentCount = this.get(item);
if (currentCount === undefined) {
return false;
}
if (currentCount <= count) {
this.delete(item);
} else {
this.set(item, currentCount - count);
}
return true;
}
/**
* Retrieves the count of the specified item.
*
* @param item The element whose count is to be retrieved.
* @returns The number of occurrences of the element.
*/
count(item: T): number {
return this.get(item) ?? 0;
}
}

View File

@@ -0,0 +1,37 @@
import { persisted } from "svelte-persisted-store";
import type { Move } from "../components/game.svelte";
import { MultiSet } from "./multiset";
import { date } from "./system";
export type Daily = {
date: string;
moves: Move[];
};
export const daily = persisted<Daily>(
"daily",
{
date: date(),
moves: [],
},
{
syncTabs: true,
storage: "local",
beforeRead: (value) => {
if (value.date !== date()) return { date: date(), moves: [] };
return value;
},
},
);
export type FormulaHistory = MultiSet<string>;
export const formulaHistory = persisted<
FormulaHistory,
readonly [string, number][]
>("formula-history", new MultiSet(), {
syncTabs: true,
storage: "local",
beforeWrite: (val) => [...val],
beforeRead: (val) => new MultiSet(val),
});

View File

@@ -1,24 +0,0 @@
import { persisted } from "svelte-persisted-store";
import type { Move } from "./components/game.svelte";
import { date } from "./lib/system";
export type Daily = {
date: string;
moves: Move[];
};
export const daily = persisted<Daily>(
"daily",
{
date: date(),
moves: [],
},
{
syncTabs: true,
storage: "local",
beforeRead: (value) => {
if (value.date !== date()) return { date: date(), moves: [] };
return value;
},
},
);