Skip to content

Instantly share code, notes, and snippets.

@Alwinfy
Last active December 12, 2024 20:00
Show Gist options
  • Save Alwinfy/77ace3d76cbaf28215fd4d8be44203f8 to your computer and use it in GitHub Desktop.
Save Alwinfy/77ace3d76cbaf28215fd4d8be44203f8 to your computer and use it in GitHub Desktop.
well well well if it isnt the coroutines wacko
function biLen(value: bigint, base: bigint): number {
let acc = 1;
while (value >= base) {
acc++;
value /= base;
}
return acc;
}
function pow(base: bigint, pow: number): bigint {
let acc = 1n;
while (pow) {
if (pow & 1) acc *= base;
pow >>= 1;
base *= base;
}
return acc;
}
type RecursiveCoro<Is extends readonly any[], O> = Generator<Is, O, O>;
function* countBlinks(value: bigint): RecursiveCoro<[typeof value], bigint> {
if (value == 0n) {
return yield [1n];
}
const len = biLen(value, 10n);
if (len & 1) {
return yield [2024n * value];
}
const split = pow(10n, len >> 1);
return (yield [value % split]) + (yield [value / split]);
}
function setDefault<K, V>(map: Map<K, V>, key: K, ctor: () => V): V {
return map.get(key) ?? (x => (map.set(key, x), x))(ctor());
}
type CacheKind<Is extends readonly any[], O> = Is extends [] ? Map<number, O> : Is extends [infer H, ...infer Ts] ? Map<H, CacheKind<Ts, O>> : never;
function cacheRead<Is extends readonly any[], O>(cache: CacheKind<Is, O>, value: Is, time: number): O | undefined {
let step: Map<any, any> | undefined = cache; // KLUDGE: ts struggles destructuring dependent types
for (const entry of value) {
step = step.get(entry);
if (step === undefined) {
return undefined;
}
}
return step.get(time);
}
function cacheWrite<Is extends readonly any[], O>(cache: CacheKind<Is, O>, value: Is, time: number, cachee: O) {
let step: Map<any, any> = cache; // KLUDGE: ts struggles destructuring dependent types
for (const entry of value) {
step = setDefault(step, entry, () => new Map());
}
step.set(time, cachee);
}
function blinkRunner<Is extends readonly any[], O>(baseCase: O, makeCoro: (...args: Is) => RecursiveCoro<Is, O>): (time: number, ...args: Is) => O {
interface Frame {
value: Is;
time: number;
coro: RecursiveCoro<Is, O>;
}
const cache: CacheKind<Is, O> = new Map() as CacheKind<Is, O>;
const push = (stack: Frame[], value: Is, time: number): O | null => {
const hit = cacheRead(cache, value, time);
if (time == 0) {
return baseCase;
} else if (hit !== undefined) {
return hit;
} else {
stack.push({
value, time,
coro: makeCoro(...value),
});
return null;
}
}
return (time, ...value) => {
const stack: Frame[] = [];
let ledger = push(stack, value, time);
while (stack.length) {
let tail = stack[stack.length - 1];
const res = tail.coro.next(ledger!!);
if (res.done) {
cacheWrite(cache, tail.value, tail.time, ledger = res.value);
stack.pop();
} else {
ledger = push(stack, res.value, tail.time - 1);
}
}
return ledger!!;
};
}
const ns = [0, 7, 198844, 5687836, 58, 2478, 25475, 894];
const br = blinkRunner(1n, countBlinks);
for (const count of [25, 75]) {
console.log(ns.map(n => br(count, BigInt(n))).reduce((x, y) => x + y));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment