diff --git a/deno.jsonc b/deno.jsonc index c18304c..07a2638 100644 --- a/deno.jsonc +++ b/deno.jsonc @@ -2,8 +2,8 @@ "$schema": "https://deno.land/x/deno/cli/schemas/config-file.v1.json", "tasks": { "check": "deno fmt --check && deno lint && deno check **/*.ts **/*.js", - "test": "rm -rf coverage && deno test -A --coverage --parallel --shuffle && deno coverage coverage --html && deno coverage coverage --lcov --output=coverage/lcov.info --exclude='test/**/*'", - "ci": "deno test -A --coverage && deno coverage coverage --lcov --output=coverage/lcov.info", + "test": "rm -rf coverage && deno test -A --coverage --parallel --shuffle && deno coverage coverage --html --exclude='test/**/*' --exclude=day.ts && deno coverage coverage --lcov --output=coverage/lcov.info", + "ci": "deno test -A --coverage && deno coverage coverage --lcov --output=coverage/lcov.info --exclude='test/**/*' --exclude=day.ts", "update": "deno run -A jsr:@molt/cli --dry-run", "docs": "deno doc --html --name=AdventOfCode2024 lib/*.ts", "bench": "deno bench -A day.ts -- -b" diff --git a/lib/rect.ts b/lib/rect.ts index 730cac0..6cfac10 100644 --- a/lib/rect.ts +++ b/lib/rect.ts @@ -358,7 +358,7 @@ export class Rect { with(xp: PointLike | number, yp: number | T, val?: T): Rect { const [x, y, v] = (typeof xp === 'number') ? [xp, yp as number, val as T] - : [xp.x, xp.y, val!]; + : [xp.x, xp.y, yp as T]; const r = this.copy(); r.set(x, y, v); return r; @@ -443,6 +443,10 @@ export class Rect { } } +/** + * Rectangle that wraps around so that the top is below the bottom and right + * column is left of 0. + */ export class InfiniteRect extends Rect { max: Point; min: Point; @@ -471,10 +475,10 @@ export class InfiniteRect extends Rect { const col = mod(x, this.width); const line = mod(y, this.height); - this.min.x = Math.min(this.min.x, col); - this.min.y = Math.min(this.min.y, line); - this.max.x = Math.max(this.max.x, col); - this.max.y = Math.max(this.max.y, line); + this.min.x = Math.min(this.min.x, x); + this.min.y = Math.min(this.min.y, y); + this.max.x = Math.max(this.max.x, x); + this.max.y = Math.max(this.max.y, y); super.set(col, line, val!); } diff --git a/lib/test/counter.test.ts b/lib/test/counter.test.ts index 3dedb6f..76e3ea9 100644 --- a/lib/test/counter.test.ts +++ b/lib/test/counter.test.ts @@ -9,6 +9,7 @@ Deno.test('Counter', () => { c.add(1, 2); // 1 assertEquals(c.get(1, 2), 1); assertEquals(c.get(33), 0); + assertEquals(c.values(), [1]); c.add(1, 2); // 2 c.add(3, 4); // 1 assertEquals(c.keys(), ['1,2', '3,4']); diff --git a/lib/test/rect.test.ts b/lib/test/rect.test.ts index 46c3958..91a1629 100644 --- a/lib/test/rect.test.ts +++ b/lib/test/rect.test.ts @@ -1,4 +1,4 @@ -import { Point, Rect } from '../rect.ts'; +import { Dir, InfiniteRect, Point, Rect } from '../rect.ts'; import { assert, @@ -17,6 +17,10 @@ Deno.test('Point', async (t) => { assert(p2.equals({ x: 3, y: -1 })); const p3 = p.stretch(2); assertEquals(p3, new Point(6, 8)); + assertEquals(p.inDir(Dir.E), new Point(4, 4)); + assertEquals(p.inDir(Dir.W), new Point(2, 4)); + assertEquals(p.inDir(Dir.N), new Point(3, 3)); + assertEquals(p.inDir(Dir.S), new Point(3, 5)); }); await t.step('distances', () => { @@ -31,6 +35,29 @@ Deno.test('Point', async (t) => { assertEquals(p.toString(), '9,8'); assertEquals(Deno.inspect(p), '9,8'); }); + + await t.step('neighbors', () => { + const p = new Point(6, 8); + assertEquals(p.cardinal(), [ + new Point(7, 8), + new Point(6, 9), + new Point(5, 8), + new Point(6, 7), + ]); + assertEquals(p.cardinal(Rect.ofSize(8, 8, '')), [ + new Point(6, 7), + ]); + }); + + await t.step('sort', () => { + const points = [new Point(2, 3), new Point(2, 1), new Point(1, 2)]; + points.sort(Point.sort); + assertEquals(points, [ + new Point(1, 2), + new Point(2, 1), + new Point(2, 3), + ]); + }); }); Deno.test('Rect', async (t) => { @@ -95,6 +122,8 @@ Deno.test('Rect', async (t) => { assertEquals(s.get(p), 'p'); s.set({ x: 0, y: 0 }, 'q'); assertEquals(s.get({ x: 0, y: 0 }), 'q'); + const t = r.with(new Point(0, 0), 't'); + assertEquals(Deno.inspect(t), 'tbc\ndef'); }); await t.step('toString', () => { @@ -139,4 +168,39 @@ XdefX XXXXX`, ); }); + + await t.step('map', () => { + const s = r.map(() => 'z'); + assertEquals(Deno.inspect(s), 'zzz\nzzz'); + }); + + await t.step('indexOf', () => { + const p = r.indexOf('e'); + assertEquals(p, new Point(1, 1)); + assertEquals(r.indexOf('z'), undefined); + }); +}); + +Deno.test('InfinitRect', async (t) => { + await t.step('create', () => { + const ir = new InfiniteRect([[1, 2], [3, 4]]); + assertEquals(ir.min, new Point(0, 0)); + assertEquals(ir.max, new Point(2, 2)); + assert(ir.check(new Point(100, 1000))); + assertEquals(ir.get(new Point(3, 3)), 4); + ir.set(4, 4, 9); + assertEquals(ir.max.x, 4); + assertEquals(ir.max.y, 4); + ir.set(new Point(-1, 0), 8); + assertEquals(ir.min.x, -1); + }); + + await t.step('slice', () => { + const ir = new InfiniteRect([ + 'abc'.split(''), + 'def'.split(''), + ]); + const s = ir.slice(new Point(0, 0), new Point(1, 1)); + assertEquals(Deno.inspect(s), 'ab\nde'); + }); }); diff --git a/lib/utils.ts b/lib/utils.ts index 017791a..4a1e056 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -1,5 +1,6 @@ import { dirname, fromFileUrl, join } from '$std/path/mod.ts'; import { TextLineStream } from '$std/streams/mod.ts'; +import { assert } from '$std/assert/mod.ts'; import peggy from 'peggy'; export interface MainArgs { @@ -207,12 +208,8 @@ export function divmod(x: T, y: T): [T, T] { } return [q, r]; } - if (typeof q === 'number') { - return [Math.floor(q) as T, r]; - } - - /* c8 ignore next */ - throw new Error('Unreachable'); + assert(typeof q === 'number'); + return [Math.floor(q) as T, r]; } export function gcd(...n: T[]): T {