Skip to content

Commit

Permalink
feat: initial solution for 2023 day 10
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexAegis committed Dec 10, 2023
1 parent e25868a commit 51ebb73
Show file tree
Hide file tree
Showing 17 changed files with 610 additions and 47 deletions.
5 changes: 5 additions & 0 deletions resources/2023/10/example.1.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
7-F7-
.FJ|7
SJLL7
|F--J
LJ.LJ
9 changes: 9 additions & 0 deletions resources/2023/10/example.2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
...........
.S-------7.
.|F-----7|.
.||.....||.
.||.....||.
.|L-7.F-J|.
.|..|.|..|.
.L--J.L--J.
...........
9 changes: 9 additions & 0 deletions resources/2023/10/example.2b.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
..........
.S------7.
.|F----7|.
.||....||.
.||....||.
.|L-7F-J|.
.|..||..|.
.L--JL--J.
..........
9 changes: 9 additions & 0 deletions resources/2023/10/example.3.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
..........
.S------7.
.|F----7|.
.||....||.
.||....||.
.|L-7F-J|.
.|..||..|.
.L--JL--J.
..........
10 changes: 10 additions & 0 deletions resources/2023/10/example.4.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FF7FSF7F7F7F7F7F---7
L|LJ||||||||||||F--J
FL-7LJLJ||||||LJL-77
F--JF--7||LJLJ7F7FJ-
L---JF-JLJ.||-FJLJJ7
|F|F-JF---7F7-L7L|7|
|FFJF7L7F-JF7|JL---7
7-L-JL7||F7|L7F-7F7|
L.L7LFJ|||||FJL7||LJ
L7JLJL-JLJLJL--JLJ.L
140 changes: 140 additions & 0 deletions resources/2023/10/input.txt

Large diffs are not rendered by default.

5 changes: 0 additions & 5 deletions solutions/typescript/2023/10/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,6 @@
"import": "./dist/p2.js",
"default": "./dist/p2.js"
},
"./parse": {
"types": "./src/parse.ts",
"import": "./dist/parse.js",
"default": "./dist/parse.js"
},
"./readme": "./readme.md"
},
"dependencies": {
Expand Down
49 changes: 45 additions & 4 deletions solutions/typescript/2023/10/src/p1.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,49 @@
import { task } from '@alexaegis/advent-of-code-lib';
import { Direction, descending, task } from '@alexaegis/advent-of-code-lib';
import packageJson from '../package.json';

export const p1 = (_input: string): number => {
return 0;
const pipeConnectorMap: Record<string, Direction[]> = {
'|': [Direction.NORTH, Direction.SOUTH],
'-': [Direction.WEST, Direction.EAST],
L: [Direction.NORTH, Direction.EAST],
J: [Direction.NORTH, Direction.WEST],
'7': [Direction.SOUTH, Direction.WEST],
F: [Direction.SOUTH, Direction.EAST],
'.': [],
S: [Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST],
};

await task(p1, packageJson.aoc); // 0 ~0ms
export const p1 = (input: string): number => {
const graph = input.toGridGraph({
weighter: (a, b, dir) => {
console.log(a.value, b.value, dir.toString());
const aConnectors = pipeConnectorMap[a.value.toString()];
const bConnectors = pipeConnectorMap[b.value.toString()];
const connection =
(aConnectors?.includes(dir) && bConnectors?.includes(dir.reverse())) ?? false;
return connection ? 1 : 0;
},
connectionFilter: (a, b, dir) => {
console.log(a.value, b.value, dir.toString());
const aConnectors = pipeConnectorMap[a.value.toString()];
const bConnectors = pipeConnectorMap[b.value.toString()];

return (aConnectors?.includes(dir) && bConnectors?.includes(dir.reverse())) ?? false;
},
});
graph.print();

const animalStart = graph.findNode((node) => node.value === 'S');
if (!animalStart) {
throw new Error('no starting position for the animal!');
}

const distanceMap = graph.flood(animalStart);

return distanceMap
.entryArray()
.map(([_node, distance]) => distance)
.sort(descending)
.first();
};

await task(p1, packageJson.aoc); // 6733 ~0ms
213 changes: 209 additions & 4 deletions solutions/typescript/2023/10/src/p2.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,213 @@
import { task } from '@alexaegis/advent-of-code-lib';
import {
Direction,
GridGraph,
GridGraphNode,
task,
type ToString,
type Weighter,
} from '@alexaegis/advent-of-code-lib';
import packageJson from '../package.json';

export const p2 = (_input: string): number => {
return 0;
const pipeConnectorMap: Record<string, Direction[]> = {
'|': [Direction.NORTH, Direction.SOUTH],
'-': [Direction.WEST, Direction.EAST],
L: [Direction.NORTH, Direction.EAST],
J: [Direction.NORTH, Direction.WEST],
'7': [Direction.SOUTH, Direction.WEST],
F: [Direction.SOUTH, Direction.EAST],
'.': [],
S: [Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST],
};

await task(p2, packageJson.aoc); // 0 ~0ms
export const findPartition = <
T extends ToString = string,
N extends GridGraphNode<T> = GridGraphNode<T>,
>(
partitions: Map<N, number>[],
node: N,
): Map<N, number> => {
const partition = partitions.find((p) => p.has(node));
if (!partition) {
throw new Error('No partition found for node');
}
return partition;
};

const enclosedPartitions = <
T extends ToString = string,
N extends GridGraphNode<T> = GridGraphNode<T>,
>(
partitions: Map<N, number>[],
encloser: Map<N, number>,
): Map<N, number>[] => {
const partitionsEnclosedByLoop = partitions.filter(
(partition) =>
partition !== encloser &&
partition.keyArray().every(
(pn) =>
pn.neighbours.size >= 4 && // Not an edge node
pn.neighbours
.valueArray()
.every((pnn) => encloser.has(pnn.to) || partition.has(pnn.to)),
),
);
return partitionsEnclosedByLoop;
};

export const partitionGraph = <
T extends ToString = string,
N extends GridGraphNode<T> = GridGraphNode<T>,
>(
graph: GridGraph<T, N>,
foundPartitions: Map<N, number>[],
): Map<N, number>[] => {
const nonPartitionedNodes = new Set(graph.nodes.values());
for (const foundPartition of foundPartitions) {
for (const [foundNode] of foundPartition) {
nonPartitionedNodes.delete(foundNode);
}
}
while (nonPartitionedNodes.size > 0) {
const nodeNotInTheLoop = nonPartitionedNodes.values().next().value as N;
const nextPartition = graph.flood(nodeNotInTheLoop);

for (const [foundNode] of nextPartition) {
nonPartitionedNodes.delete(foundNode);
}
foundPartitions.push(nextPartition);
}

return foundPartitions;
};

export interface GraphLoopPartitions<
T extends ToString = string,
N extends GridGraphNode<T> = GridGraphNode<T>,
> {
loop: Set<N>;
/**
* empty if the loop has no nodes inside, or the loop is not closed
*/
inside: Set<N>;
/**
* empty if the loop has no nodes outside, or the loop is not closed
*/
outside: Set<N>;
}

export const partitionIntoTwoFromLoop = <
T extends ToString = string,
N extends GridGraphNode<T> = GridGraphNode<T>,
>(
graph: GridGraph<T, N>,
loop: Map<N, number>,
): GraphLoopPartitions<T, N> => {
const nonPartitionedNodes = new Set(graph.nodes.values());

for (const [foundNode] of loop) {
nonPartitionedNodes.delete(foundNode);
}

const foundPartitions: Map<N, number>[] = [];

while (nonPartitionedNodes.size > 0) {
const nodeNotInTheLoop = nonPartitionedNodes.values().next().value as N;
const nextPartition = graph.flood(nodeNotInTheLoop, {
weighter: (a, b) => (loop.has(a) || loop.has(b) ? Number.POSITIVE_INFINITY : 1),
});

for (const [foundNode] of nextPartition) {
nonPartitionedNodes.delete(foundNode);
}
foundPartitions.push(nextPartition);
}

const insides = enclosedPartitions<T, N>(foundPartitions, loop);
const outside = foundPartitions.find((p) => !insides.includes(p));

return {
loop: new Set(loop.keys()),
inside: new Set(insides.flatMap((i) => i.keyArray())),
outside: new Set(outside?.keys()),
};
};

const weighter: Weighter<GridGraphNode> = (a, b, dir) => {
if (a.value === '.' && b.value === '.') {
return 1;
}

const aConnectors = pipeConnectorMap[a.value.toString()];
const bConnectors = pipeConnectorMap[b.value.toString()];

const connection =
(aConnectors?.includes(dir) && bConnectors?.includes(dir.reverse())) ?? false;
return connection ? 1 : Number.POSITIVE_INFINITY;
};

export const p2 = (input: string): number => {
const og = input.toGridGraph<string>({
weighter,
});

const liminalNodes = new Set<GridGraphNode>();
const gg = new GridGraph<string>();
for (const ogNode of og.nodeValues) {
for (const { from, to, weight, direction } of Direction.allDirections.map((direction) => ({
...ogNode.neighbours.get(direction),
from: ogNode,
to: og.getNode(ogNode.coordinate.add(direction)),
direction,
}))) {
if (to === undefined) {
continue;
}

let newNodeSymbol = '.';
if (from.value === '.' && to.value === '.') {
newNodeSymbol = '.';
} else if (weight && weight < Number.POSITIVE_INFINITY) {
newNodeSymbol = direction.isHorizonal() ? '-' : '|';
}

const fromDoubled = from.coordinate.add(from.coordinate);
const toDoubled = to.coordinate.add(to.coordinate);

const middle = fromDoubled.middle(toDoubled);

const newFrom = gg.nodes.getOrAdd(
fromDoubled.toString(),
(_n) => new GridGraphNode(fromDoubled, from.value),
);
const newMiddle = gg.nodes.getOrAdd(
middle.toString(),
(_n) => new GridGraphNode(middle, newNodeSymbol),
);
liminalNodes.add(newMiddle);
const newTo = gg.nodes.getOrAdd(
toDoubled.toString(),
(_n) => new GridGraphNode(toDoubled, to.value),
);

newFrom.attachNeightbours(gg, Direction.cardinalDirections, weighter);
newMiddle.attachNeightbours(gg, Direction.cardinalDirections, weighter);
newTo.attachNeightbours(gg, Direction.cardinalDirections, weighter);
}
}

const animalStart = gg.findNode((node) => node.value === 'S');

if (!animalStart) {
throw new Error('no starting position for the animal!');
}

const pathLoop = gg.flood(animalStart);

const { inside, outside } = partitionIntoTwoFromLoop(gg, pathLoop);

gg.print((n) => (inside.has(n) ? 'I' : outside.has(n) ? 'O' : n.toString()));

return inside.valueArray().filter((node) => !liminalNodes.has(node)).length ?? -1;
};

await task(p2, packageJson.aoc); // 435 ~0ms
5 changes: 4 additions & 1 deletion solutions/typescript/libs/lib/src/model/graph/edge.type.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import type { Direction } from '../index.js';

/**
* Represents an edge between two vertices
*/
export interface Edge<N, EdgeData = unknown> {
export interface Edge<N, Dir = Direction, EdgeData = unknown> {
from: N;
to: N;
direction: Dir;
data?: EdgeData;
weight?: number;
weighter?: () => number;
Expand Down
Loading

0 comments on commit 51ebb73

Please sign in to comment.