-
-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: initial solution for 2023 day 10
- Loading branch information
Showing
17 changed files
with
610 additions
and
47 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
7-F7- | ||
.FJ|7 | ||
SJLL7 | ||
|F--J | ||
LJ.LJ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. | ||
........... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
.......... | ||
.S------7. | ||
.|F----7|. | ||
.||....||. | ||
.||....||. | ||
.|L-7F-J|. | ||
.|..||..|. | ||
.L--JL--J. | ||
.......... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
.......... | ||
.S------7. | ||
.|F----7|. | ||
.||....||. | ||
.||....||. | ||
.|L-7F-J|. | ||
.|..||..|. | ||
.L--JL--J. | ||
.......... |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.