From 9e2ef2da171d3d1d3ab88c6ef1a3ca6828494b40 Mon Sep 17 00:00:00 2001 From: Pascal Syma Date: Tue, 10 Dec 2024 14:03:18 +0100 Subject: [PATCH] Add coordinate utils --- utils/coordinates.test.ts | 73 ++++++++++++++++++++++++++++++++++++++- utils/coordinates.ts | 54 +++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+), 1 deletion(-) diff --git a/utils/coordinates.test.ts b/utils/coordinates.test.ts index 02aac22..7ac9892 100644 --- a/utils/coordinates.test.ts +++ b/utils/coordinates.test.ts @@ -1,5 +1,11 @@ import { describe, expect, it } from 'bun:test'; -import { type Coordinate, inBounds, isCoordinateEqual } from './coordinates.ts'; +import { + type Coordinate, + findCoordsOfDigit, + getAdjacent, + inBounds, + isCoordinateEqual +} from './coordinates.ts'; describe('coordinates utils', () => { it('inBounds', () => { @@ -30,4 +36,69 @@ describe('coordinates utils', () => { expect(isCoordinateEqual(b, b)).toBeTrue(); expect(isCoordinateEqual(a, b)).toBeTrue(); }); + + it('getAdjacent', () => { + const input = `0123 +1234 +8765 +9876`.split('\n'); + + const actualTopLeft = getAdjacent(input, 0, 0); + + expect(actualTopLeft).toBeObject(); + expect(Object.keys(actualTopLeft)).toHaveLength(8); + expect(actualTopLeft.top).toBeUndefined(); + expect(actualTopLeft.topRight).toBeUndefined(); + expect(actualTopLeft.right).toEqual('1'); + expect(actualTopLeft.downRight).toEqual('2'); + expect(actualTopLeft.down).toEqual('1'); + expect(actualTopLeft.downLeft).toBeUndefined(); + expect(actualTopLeft.left).toBeUndefined(); + expect(actualTopLeft.topLeft).toBeUndefined(); + + const actualFirst7 = getAdjacent(input, 1, 2); + + expect(actualFirst7).toBeObject(); + expect(Object.keys(actualFirst7)).toHaveLength(8); + expect(actualFirst7.top).toEqual('2'); + expect(actualFirst7.topRight).toEqual('3'); + expect(actualFirst7.right).toEqual('6'); + expect(actualFirst7.downRight).toEqual('7'); + expect(actualFirst7.down).toEqual('8'); + expect(actualFirst7.downLeft).toEqual('9'); + expect(actualFirst7.left).toEqual('8'); + expect(actualFirst7.topLeft).toEqual('1'); + }); + + it('findCoordsOfDigit', () => { + const input = `0123 +1234 +8765 +9876`.split('\n'); + const actualZero = findCoordsOfDigit(input, '0'); + + expect(actualZero).toBeArray(); + expect(actualZero).toHaveLength(1); + actualZero.forEach((coord) => expect(coord).toBeArray()); + actualZero.forEach((coord) => expect(coord).toBeArrayOfSize(2)); + expect(actualZero[0]).toEqual([0, 0]); + + const actualSeven = findCoordsOfDigit(input, '7'); + + expect(actualSeven).toBeArray(); + expect(actualSeven).toHaveLength(2); + actualSeven.forEach((coord) => expect(coord).toBeArray()); + actualSeven.forEach((coord) => expect(coord).toBeArrayOfSize(2)); + expect(actualSeven[0]).toEqual([1, 2]); + expect(actualSeven[1]).toEqual([2, 3]); + + const actualSevenRegex = findCoordsOfDigit(input, /7/g); + + expect(actualSevenRegex).toBeArray(); + expect(actualSevenRegex).toHaveLength(2); + actualSevenRegex.forEach((coord) => expect(coord).toBeArray()); + actualSevenRegex.forEach((coord) => expect(coord).toBeArrayOfSize(2)); + expect(actualSevenRegex[0]).toEqual([1, 2]); + expect(actualSevenRegex[1]).toEqual([2, 3]); + }); }); diff --git a/utils/coordinates.ts b/utils/coordinates.ts index 5a054e6..c13cb95 100644 --- a/utils/coordinates.ts +++ b/utils/coordinates.ts @@ -24,3 +24,57 @@ export function isCoordinateEqual( ): boolean { return b[0] === a[0] && b[1] === a[1]; } + +export type DirectNeighbours = 'top' | 'left' | 'right' | 'down'; + +export type DiagonalNeighbours = + | 'topLeft' + | 'topRight' + | 'downLeft' + | 'downRight'; + +/** + * Get all eight adjacent cells from a starting cell. + * Returns undefined, when the cell is invalid (out of bounds). + * @param rows Input xy-Matrix, string array + * @param startX Center cell x Coordinate + * @param startY Center cell y Coordinate + */ +export function getAdjacent( + rows: string[], + startX: number, + startY: number +): Record { + const top = rows[startY - 1]?.[startX]; + const right = rows[startY]?.[startX + 1]; + const down = rows[startY + 1]?.[startX]; + const left = rows[startY]?.[startX - 1]; + + const topLeft = rows[startY - 1]?.[startX - 1]; + const topRight = rows[startY - 1]?.[startX + 1]; + const downLeft = rows[startY + 1]?.[startX - 1]; + const downRight = rows[startY + 1]?.[startX + 1]; + + return { top, right, left, down, topLeft, topRight, downLeft, downRight }; +} + +/** + * Find all xy-Coordinates of a digit or custom regex match. + * @param rows Input xy-Matrix, string array + * @param digit Digit to search for, or custom regex pattern + */ +export function findCoordsOfDigit( + rows: string[], + digit: string | RegExp +): Coordinates { + return rows.reduce( + (coords, row, y) => + row + .matchAll(typeof digit === 'string' ? new RegExp(digit, 'g') : digit) + .reduce( + (coordinates, m) => [...coordinates, [m.index, y] as Coordinate], + coords + ), + [] + ); +}