Add coordinate utils
This commit is contained in:
@@ -1,5 +1,11 @@
|
|||||||
import { describe, expect, it } from 'bun:test';
|
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', () => {
|
describe('coordinates utils', () => {
|
||||||
it('inBounds', () => {
|
it('inBounds', () => {
|
||||||
@@ -30,4 +36,69 @@ describe('coordinates utils', () => {
|
|||||||
expect(isCoordinateEqual(b, b)).toBeTrue();
|
expect(isCoordinateEqual(b, b)).toBeTrue();
|
||||||
expect(isCoordinateEqual(a, 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]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -24,3 +24,57 @@ export function isCoordinateEqual(
|
|||||||
): boolean {
|
): boolean {
|
||||||
return b[0] === a[0] && b[1] === a[1];
|
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<DirectNeighbours | DiagonalNeighbours, string | undefined> {
|
||||||
|
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<Coordinates>(
|
||||||
|
(coords, row, y) =>
|
||||||
|
row
|
||||||
|
.matchAll(typeof digit === 'string' ? new RegExp(digit, 'g') : digit)
|
||||||
|
.reduce(
|
||||||
|
(coordinates, m) => [...coordinates, [m.index, y] as Coordinate],
|
||||||
|
coords
|
||||||
|
),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user