kripke: add history
This commit is contained in:
4
apps/web/src/lib/global.d.ts
vendored
4
apps/web/src/lib/global.d.ts
vendored
@@ -40,10 +40,6 @@ interface ReadonlyArray<T> {
|
|||||||
): searchElement is T extends LiteralUnionLike<T> ? T : never;
|
): searchElement is T extends LiteralUnionLike<T> ? T : never;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Map<K> {
|
|
||||||
has(key: Weaken<K>): key is K;
|
|
||||||
}
|
|
||||||
|
|
||||||
declare module "*&enhanced" {
|
declare module "*&enhanced" {
|
||||||
import type { Picture } from "vite-imagetools";
|
import type { Picture } from "vite-imagetools";
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ import Game, { type GameStatus } from "./components/game.svelte";
|
|||||||
import Rules from "./components/rules.svelte";
|
import Rules from "./components/rules.svelte";
|
||||||
import Share from "./components/share.svelte";
|
import Share from "./components/share.svelte";
|
||||||
|
|
||||||
|
import { daily } from "./lib/store";
|
||||||
import { getFrameBySeed, getTimeUntilNextGame } from "./lib/system";
|
import { getFrameBySeed, getTimeUntilNextGame } from "./lib/system";
|
||||||
import { daily } from "./store";
|
|
||||||
|
|
||||||
let { data } = $props();
|
let { data } = $props();
|
||||||
const seed = data.seed;
|
const seed = data.seed;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { type Formula, prettyPrint, tryParse } from "@cannorin/kripke";
|
import { type Formula, prettyPrint, tryParse } from "@cannorin/kripke";
|
||||||
|
import { formulaHistory } from "../lib/store";
|
||||||
|
|
||||||
let {
|
let {
|
||||||
formula = $bindable<Formula | undefined>(undefined),
|
formula = $bindable<Formula | undefined>(undefined),
|
||||||
@@ -11,6 +12,12 @@ let {
|
|||||||
|
|
||||||
let input = $state(formula ? prettyPrint(formula) : "");
|
let input = $state(formula ? prettyPrint(formula) : "");
|
||||||
let error = $state(false);
|
let error = $state(false);
|
||||||
|
let history = $derived(
|
||||||
|
[...$formulaHistory]
|
||||||
|
.toSorted(([_a, ac], [_b, bc]) => bc - ac)
|
||||||
|
.slice(0, 10)
|
||||||
|
.map(([a, _ac]) => a),
|
||||||
|
);
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
const fml = tryParse(input);
|
const fml = tryParse(input);
|
||||||
@@ -24,7 +31,16 @@ $effect(() => {
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
{#if history.length > 0}
|
||||||
|
<datalist id="formula">
|
||||||
|
{#each history as fml}
|
||||||
|
<option value={fml}></option>
|
||||||
|
{/each}
|
||||||
|
</datalist>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<input
|
<input
|
||||||
|
id="formula"
|
||||||
class={["rounded border border-foreground ring-0 focus:outline-none focus:ring-0 p-2 w-full", error && "border-primary"]}
|
class={["rounded border border-foreground ring-0 focus:outline-none focus:ring-0 p-2 w-full", error && "border-primary"]}
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Enter modal formula"
|
placeholder="Enter modal formula"
|
||||||
|
|||||||
54
apps/web/src/routes/kripke/lib/multiset.ts
Normal file
54
apps/web/src/routes/kripke/lib/multiset.ts
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
37
apps/web/src/routes/kripke/lib/store.ts
Normal file
37
apps/web/src/routes/kripke/lib/store.ts
Normal 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),
|
||||||
|
});
|
||||||
@@ -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;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
Reference in New Issue
Block a user