Skip to content

Commit

Permalink
Merge pull request #44 from hildjj/day22
Browse files Browse the repository at this point in the history
Day 22
  • Loading branch information
hildjj authored Dec 22, 2024
2 parents dcaf401 + 830b70a commit 7b1cfea
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 1 deletion.
4 changes: 4 additions & 0 deletions day22.peggy
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
lines = (@num "\n")*

num = n:$[0-9]+ { return BigInt(n) }
_ = [ \t]+
57 changes: 57 additions & 0 deletions day22.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { type MainArgs, parseFile } from './lib/utils.ts';
import { Counter } from './lib/counter.ts';
import { Ring } from './lib/ring.ts';

type Parsed = bigint[];

// Has to be bigints, since we go over 2^32.
const PRUNE = 16777216n;
function nextSecret(n: bigint): bigint {
n = ((n * 64n) ^ n) % PRUNE;
n = ((n / 32n) ^ n) % PRUNE;
n = ((n * 2048n) ^ n) % PRUNE;
return n;
}

function part1(inp: Parsed): bigint {
let tot = 0n;
for (let n of inp) {
for (let i = 0; i < 2000; i++) {
n = nextSecret(n);
}
tot += n;
}
return tot;
}

function part2(inp: Parsed): number {
const patterns = new Counter();
for (let n of inp) {
const c = new Ring<bigint>(4);
const seen = new Set<string>();
let cost = n % 10n;

for (let i = 0; i < 2000; i++) {
const nextN = nextSecret(n);
const nextCost = nextN % 10n;
c.push(nextCost - cost);

if (c.full) {
const key = c.get().join(',');
if (!seen.has(key)) {
patterns.sum(Number(nextCost), key);
seen.add(key);
}
}
[n, cost] = [nextN, nextCost];
}
}

const [_maxKey, max] = patterns.max()!;
return max;
}

export default async function main(args: MainArgs): Promise<[bigint, number]> {
const inp = await parseFile<Parsed>(args);
return [part1(inp), part2(inp)];
}
2 changes: 1 addition & 1 deletion inputs
87 changes: 87 additions & 0 deletions lib/ring.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/**
* Ring Buffer.
* TODO (@hildjj): allow destructive reads.
*/
export class Ring<T> {
#length: number;
#buf: T[];
#count = 0;

/**
* Creates an initially-empty buffer.
*
* @param length Maximum number of things to store.
*/
constructor(length: number) {
this.#length = length;
this.#buf = Array.from({ length });
}

/**
* Add a value to the end, bumping off the oldest entry if the buffer
* is full.
*
* @param val
*/
push(val: T): void {
this.#buf[this.#count++ % this.#length] = val;
}

/**
* Get the current buffer contents.
*
* @returns A copy of the current contents, in logical order.
*/
get(): T[] {
if (this.#count < this.#length) {
return this.#buf.slice(0, this.#count);
}
const pos = this.#count % this.#length;
if (pos === 0) {
return this.#buf.slice(0);
}
return [...this.#buf.slice(pos), ...this.#buf.slice(0, pos)];
}

/**
* How many times has this buffer been added to?
*
* @readonly
* @type {number}
*/
get count(): number {
return this.#count;
}

/**
* Current size. Maxes out at length;
*
* @readonly
* @type {number}
*/
get size(): number {
return (this.#count > this.#length) ? this.#length : this.#count;
}

/**
* Is the buffer full already?
*
* @readonly
* @type {boolean}
*/
get full(): boolean {
return this.#count >= this.#length;
}

/**
* Get the original length of the buffer.
* TODO (@hildjj): Allow setting the length to a new value, potentially
* losing data from the beginning of the buffer.
*
* @readonly
* @type {number}
*/
get length(): number {
return this.#length;
}
}
32 changes: 32 additions & 0 deletions lib/test/ring.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { assertEquals } from '@std/assert/equals';
import { Ring } from '../ring.ts';

Deno.test('Ring', async (t) => {
await t.step('create', () => {
const r = new Ring<number>(4);
assertEquals(r.get(), []);
assertEquals(r.size, 0);
assertEquals(r.count, 0);
assertEquals(r.full, false);

r.push(1);
assertEquals(r.get(), [1]);
assertEquals(r.size, 1);
assertEquals(r.count, 1);
assertEquals(r.full, false);

r.push(2);
r.push(3);
r.push(4);
assertEquals(r.get(), [1, 2, 3, 4]);
assertEquals(r.size, 4);
assertEquals(r.count, 4);
assertEquals(r.full, true);

r.push(5);
assertEquals(r.get(), [2, 3, 4, 5]);
assertEquals(r.size, 4);
assertEquals(r.count, 5);
assertEquals(r.full, true);
});
});
1 change: 1 addition & 0 deletions test/day22.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default [20071921341n, 2242];

0 comments on commit 7b1cfea

Please sign in to comment.