Skip to content

Commit

Permalink
refactor: optimized 2023 day 13
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexAegis committed Dec 22, 2023
1 parent 831f130 commit 488dbb0
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 77 deletions.
37 changes: 13 additions & 24 deletions solutions/typescript/2023/13/src/internal/matrix-reflection.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import type { GridGraph, GridGraphNode, Interval, ToString } from '@alexaegis/advent-of-code-lib';

export const matchingNodes = <
T extends ToString = string,
N extends GridGraphNode<T> = GridGraphNode<T>,
>(
a: N[],
b: N[],
): number => {
return a.zip(b).filter(([an, bn]) => an.value === bn.value).length;
import { Interval } from '@alexaegis/advent-of-code-lib';

export const matchingNodes = (a: string[], b: string[]): number => {
return a.zip(b).filter(([an, bn]) => an === bn).length;
};

export const findReflectivePairings = (
Expand All @@ -24,19 +18,14 @@ export const findReflectivePairings = (
});
};

export const findReflection = <
T extends ToString = string,
N extends GridGraphNode<T> = GridGraphNode<T>,
>(
gg: GridGraph<T, N>,
axis: 'row' | 'column',
export const findReflection = (
matrix: string[][],
smudges = 0,
skip?: number,
): number | undefined => {
const aabb = gg.boundingBox();
const axisInterval = axis === 'column' ? aabb.horizontal : aabb.vertical;
const otherAxistInterval = axis === 'column' ? aabb.vertical : aabb.horizontal;
const getNodesOfAxis = (n: number) => (axis === 'column' ? gg.getColumn(n) : gg.getRow(n));
const axisInterval = Interval.closed(0, matrix.length - 1);
const otherAxisInterval = Interval.closed(0, matrix[0]!.length - 1);

return axisInterval.collectValues().find((index) => {
if (skip !== undefined && index === skip) {
return false;
Expand All @@ -50,12 +39,12 @@ export const findReflection = <

const matching = pairs
.map(([left, right]) => {
const leftNodes = getNodesOfAxis(left)!;
const rightNodes = getNodesOfAxis(right)!;
return matchingNodes<T, N>(leftNodes, rightNodes);
const leftNodes = matrix[left]!;
const rightNodes = matrix[right]!;
return matchingNodes(leftNodes, rightNodes);
})
.sum();

return matching + smudges === pairs.length * otherAxistInterval.length;
return matching + smudges === pairs.length * otherAxisInterval.length;
});
};
27 changes: 14 additions & 13 deletions solutions/typescript/2023/13/src/p1.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
import { DOUBLE_NEWLINE, task } from '@alexaegis/advent-of-code-lib';
import { DOUBLE_NEWLINE, isNotNullish, task } from '@alexaegis/advent-of-code-lib';
import packageJson from '../package.json';
import { findReflection } from './internal/matrix-reflection.js';

export const p1 = (input: string): number =>
input
.split(DOUBLE_NEWLINE)
.map((m) => m.toGridGraph())
.map((graph) => {
const columnReflectionIndex = findReflection(graph, 'column');
const rowReflectionIndex = findReflection(graph, 'row');
.map((m) => m.toMatrix())
.map((matrix) => {
const rowWise = matrix;
const columnWise = matrix.rotateMatrix('r');
const rowReflectionIndex = findReflection(rowWise);
const columnReflectionIndex = findReflection(columnWise);

let value = 0;
if (columnReflectionIndex !== undefined) {
value = columnReflectionIndex + 1;
if (isNotNullish(columnReflectionIndex)) {
return columnReflectionIndex + 1;
} else if (isNotNullish(rowReflectionIndex)) {
return (rowReflectionIndex + 1) * 100;
} else {
throw new Error('Reflection not found');
}
if (rowReflectionIndex !== undefined) {
value = (rowReflectionIndex + 1) * 100;
}
return value;
})
.sum();

await task(p1, packageJson.aoc); // 37718 ~371.96ms
await task(p1, packageJson.aoc); // 37718 ~2.59ms
37 changes: 19 additions & 18 deletions solutions/typescript/2023/13/src/p2.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
import { DOUBLE_NEWLINE, task } from '@alexaegis/advent-of-code-lib';
import { DOUBLE_NEWLINE, isNotNullish, task } from '@alexaegis/advent-of-code-lib';
import packageJson from '../package.json';
import { findReflection } from './internal/matrix-reflection.js';

export const p2 = (input: string): number => {
return input
export const p2 = (input: string): number =>
input
.split(DOUBLE_NEWLINE)
.map((m) => m.toGridGraph())
.map((graph) => {
const smudgyRowIndex = findReflection(graph, 'row');
const smudgyColumnIndex = findReflection(graph, 'column');
const rowIndex = findReflection(graph, 'row', 1, smudgyRowIndex);
const columnIndex = findReflection(graph, 'column', 1, smudgyColumnIndex);
.map((m) => m.toMatrix())
.map((matrix) => {
const rowWise = matrix;
const columnWise = matrix.rotateMatrix('r');

let value = 0;
if (columnIndex !== undefined) {
value = columnIndex + 1;
}
if (rowIndex !== undefined) {
value = (rowIndex + 1) * 100;
const smudgyRowIndex = findReflection(rowWise);
const smudgyColumnIndex = findReflection(columnWise);
const rowIndex = findReflection(rowWise, 1, smudgyRowIndex);
const columnIndex = findReflection(columnWise, 1, smudgyColumnIndex);

if (isNotNullish(columnIndex)) {
return columnIndex + 1;
} else if (isNotNullish(rowIndex)) {
return (rowIndex + 1) * 100;
} else {
throw new Error('Reflection not found');
}
return value;
})
.sum();
};

await task(p2, packageJson.aoc); // 40995 ~658.23ms
await task(p2, packageJson.aoc); // 40995 ~4.95ms
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { NEWLINE } from '../regex/index.js';

export interface StringToMatrixOptions<T = string> {
valueConverter?: ((value: string) => T) | undefined;
rowSeparator?: RegExp | string;
itemSeparator?: RegExp | string;
}

/**
* Splits a string into a matrix along row and item separators. By default it
* splits along new lines and every character
Expand All @@ -8,15 +14,18 @@ import { NEWLINE } from '../regex/index.js';
* @param rowSeparator to split the rows apart with
* @param itemSeparator to split the items apart with
*/
export const stringToMatrix = (
export const stringToMatrix = <T = string>(
s: string,
rowSeparator: RegExp | string = NEWLINE,
itemSeparator: RegExp | string = '',
): string[][] => {
const lines = s.split(rowSeparator);
options?: StringToMatrixOptions<T>,
): T[][] => {
const lines = s.split(options?.rowSeparator ?? NEWLINE);
if (lines.at(-1) === '') {
lines.pop();
}
const matrix = lines.map((line) => line.split(itemSeparator));
return matrix;
const matrix = lines.map((line) => {
const values = line.split(options?.itemSeparator ?? '');

return options?.valueConverter ? values.map(options?.valueConverter) : values;
});
return matrix as T[][];
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export interface StringToVectorMapOptions<V> {
*/
ignoreValues?: (value: V) => boolean;
}

/**
* Splits a string into a matrix along row and item separators. By default it
* splits along new lines and every character
Expand All @@ -24,7 +25,7 @@ export const stringToVectorMap = <V = string>(
rawOptions?: StringToVectorMapOptions<V>,
): Map<Vec2String, V> => {
const options = normalizeStringToVectorMapOptions(rawOptions);
const matrix = stringToMatrix(s, options.rowSeparator, options.itemSeparator);
const matrix = stringToMatrix(s, options);

const map = new Map<Vec2String, V>();
for (let y = 0; y < matrix.length; y++) {
Expand All @@ -33,11 +34,8 @@ export const stringToVectorMap = <V = string>(
for (let x = 0; x < row.length; x++) {
const coord = new Vec2(x, y);
const value = row[x];
if (value !== undefined) {
const convertedValue = options.valueConverter?.(value) ?? (value as V);
if (!options.ignoreValues(convertedValue)) {
map.set(coord.toString(), convertedValue);
}
if (value !== undefined && !options.ignoreValues(value)) {
map.set(coord.toString(), value);
}
}
}
Expand Down
12 changes: 4 additions & 8 deletions solutions/typescript/libs/lib/src/string/string.polyfill.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ import { GridGraph, type GridGraphOptions } from '../model/graph/grid-graph.clas
import type { ToString } from '../model/to-string.interface.js';
import type { Vec2 } from '../model/vector/vec2.class.js';
import type { Vec2String } from '../model/vector/vec2.class.types.js';
import { NEWLINE } from '../regex/whitespace.regex.js';
import { alphabeticalOrder } from './alphabetical-order.function.js';
import { rightSplit } from './right-split.function.js';
import { splitIntoStringPair } from './split-into-tuple.function.js';
import { stringToMatrix } from './string-to-matrix.function.js';
import { stringToMatrix, type StringToMatrixOptions } from './string-to-matrix.function.js';
import { stringToVectorMap } from './string-to-vectormap.function.js';
import { vectorsInStringTile } from './vectors-in-string-tile.function.js';
export * from '../array/array.polyfill.js'; // `toInt` is used in `splitToInt`
Expand All @@ -15,7 +14,7 @@ declare global {
interface String {
alphabeticalOrder(): number;
toInt(radix?: number): number;
toMatrix(): string[][];
toMatrix<T = string>(options?: StringToMatrixOptions<T>): T[][];
toGridGraph<T extends ToString = string>(
gridOptions?: GridGraphOptions<T> & {
valueConverter?: (value: string) => T;
Expand Down Expand Up @@ -131,11 +130,8 @@ String.prototype.splitToInt = function (options?: {
});
};

String.prototype.toMatrix = function (
rowSeparator: RegExp | string = NEWLINE,
itemSeparator: RegExp | string = '',
): string[][] {
return stringToMatrix(this as string, rowSeparator, itemSeparator);
String.prototype.toMatrix = function <T = string>(options?: StringToMatrixOptions<T>): T[][] {
return stringToMatrix<T>(this as string, options);
};

String.prototype.vectorsOf = function (character: string, fromBottom = false): Vec2[] {
Expand Down
2 changes: 1 addition & 1 deletion solutions/typescript/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
| [Day 10](/solutions/typescript/2023/10/) | [68.44ms](/solutions/typescript/2023/10/src/p1.ts) | [1.4s](/solutions/typescript/2023/10/src/p2.ts) |
| [Day 11](/solutions/typescript/2023/11/) | [104.54ms](/solutions/typescript/2023/11/src/p1.ts) | [104.48ms](/solutions/typescript/2023/11/src/p2.ts) |
| [Day 12](/solutions/typescript/2023/12/) | [30.83ms](/solutions/typescript/2023/12/src/p1.ts) | [539.06ms](/solutions/typescript/2023/12/src/p2.ts) |
| [Day 13](/solutions/typescript/2023/13/) | [371.96ms](/solutions/typescript/2023/13/src/p1.ts) | [658.23ms](/solutions/typescript/2023/13/src/p2.ts) |
| [Day 13](/solutions/typescript/2023/13/) | [2.59ms](/solutions/typescript/2023/13/src/p1.ts) | [4.95ms](/solutions/typescript/2023/13/src/p2.ts) |
| [Day 14](/solutions/typescript/2023/14/) | [?ms](/solutions/typescript/2023/14/src/p1.ts) | [?ms](/solutions/typescript/2023/14/src/p2.ts) |
| [Day 15](/solutions/typescript/2023/15/) | [0.19ms](/solutions/typescript/2023/15/src/p1.ts) | [0.65ms](/solutions/typescript/2023/15/src/p2.ts) |
| [Day 16](/solutions/typescript/2023/16/) | [31.37ms](/solutions/typescript/2023/16/src/p1.ts) | [\~1s](/solutions/typescript/2023/16/src/p2.ts) |
Expand Down

0 comments on commit 488dbb0

Please sign in to comment.