Skip to content
This repository has been archived by the owner on Jan 3, 2025. It is now read-only.

Commit

Permalink
feat: day 5 (#7)
Browse files Browse the repository at this point in the history
* day 5 part 1

* day 5 part 2

* reuse parsed data
  • Loading branch information
rnbguy authored Dec 5, 2024
1 parent 4b35e49 commit a83bc48
Show file tree
Hide file tree
Showing 11 changed files with 295 additions and 19 deletions.
6 changes: 3 additions & 3 deletions day1/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export function solve2(data: number[][]): number {

if (import.meta.main) {
const data_path = new URL("input.txt", import.meta.url).pathname;
const data = await Deno.readTextFile(data_path);
console.log(solve1(parse(data)));
console.log(solve2(parse(data)));
const data = parse(await Deno.readTextFile(data_path));
console.log(solve1(data));
console.log(solve2(data));
}
6 changes: 3 additions & 3 deletions day1/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { parse, solve1, solve2 } from "./mod.ts";

Deno.test(async function testExample() {
const example_data_path = new URL("example.txt", import.meta.url).pathname;
const example_data = await Deno.readTextFile(example_data_path);
assertEquals(solve1(parse(example_data)), 11);
assertEquals(solve2(parse(example_data)), 31);
const example_data = parse(await Deno.readTextFile(example_data_path));
assertEquals(solve1(example_data), 11);
assertEquals(solve2(example_data), 31);
});
6 changes: 3 additions & 3 deletions day2/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export function solve2(data: number[][]): number {

if (import.meta.main) {
const data_path = new URL("input.txt", import.meta.url).pathname;
const data = await Deno.readTextFile(data_path);
console.log(solve1(parse(data)));
console.log(solve2(parse(data)));
const data = parse(await Deno.readTextFile(data_path));
console.log(solve1(data));
console.log(solve2(data));
}
6 changes: 3 additions & 3 deletions day2/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { parse, solve1, solve2 } from "./mod.ts";

Deno.test(async function testExample() {
const example_data_path = new URL("example.txt", import.meta.url).pathname;
const example_data = await Deno.readTextFile(example_data_path);
assertEquals(solve1(parse(example_data)), 2);
assertEquals(solve2(parse(example_data)), 4);
const example_data = parse(await Deno.readTextFile(example_data_path));
assertEquals(solve1(example_data), 2);
assertEquals(solve2(example_data), 4);
});
6 changes: 3 additions & 3 deletions day4/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export function solve2(data: string[]): number {

if (import.meta.main) {
const data_path = new URL("input.txt", import.meta.url).pathname;
const data = await Deno.readTextFile(data_path);
console.log(solve1(parse(data)));
console.log(solve2(parse(data)));
const data = parse(await Deno.readTextFile(data_path));
console.log(solve1(data));
console.log(solve2(data));
}
6 changes: 3 additions & 3 deletions day4/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { parse, solve1, solve2 } from "./mod.ts";

Deno.test(async function testExample() {
const example_data_path = new URL("example.txt", import.meta.url).pathname;
const example_data = await Deno.readTextFile(example_data_path);
assertEquals(solve1(parse(example_data)), 18);
assertEquals(solve2(parse(example_data)), 9);
const example_data = parse(await Deno.readTextFile(example_data_path));
assertEquals(solve1(example_data), 18);
assertEquals(solve2(example_data), 9);
});
7 changes: 7 additions & 0 deletions day5/deno.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "@scope/day5",
"version": "0.1.0",
"exports": {
".": "./mod.ts"
}
}
28 changes: 28 additions & 0 deletions day5/example.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
47|53
97|13
97|61
97|47
75|29
61|13
75|53
29|13
97|29
53|29
61|53
97|53
61|29
47|13
75|47
97|75
47|61
75|61
47|29
75|13
53|13

75,47,61,53,29
97,61,53,29,13
75,29,13
75,97,47,61,53
61,13,29
97,13,75,29,47
231 changes: 231 additions & 0 deletions day5/mod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
class DirectedGraph {
edges: Map<number, Set<number>>;
tempEdges: Map<number, Set<number>>;

constructor() {
this.edges = new Map();
this.tempEdges = new Map();
}

addEdge(from: number, to: number) {
if (this.edges.get(from) === undefined) {
this.edges.set(from, new Set());
}
this.edges.get(from)!.add(to);
}

hasEdge(from: number, to: number): boolean {
return (this.edges.get(from) ?? new Set()).has(to);
}

restrict(nodes: Set<number>): DirectedGraph {
const result = new DirectedGraph();

for (const [from, tos] of this.edges) {
if (nodes.has(from)) {
for (const to of tos) {
if (nodes.has(to)) {
result.addEdge(from, to);
}
}
}
}

return result;
}

hasCycleFrom(
node: number,
visited: Set<number>,
stack: Set<number>,
): boolean {
if (stack.has(node)) {
return true;
}

if (visited.has(node)) {
return false;
}

visited.add(node);
stack.add(node);

for (const neighbor of this.edges.get(node) ?? new Set()) {
if (this.hasCycleFrom(neighbor, visited, stack)) {
return true;
}
}

for (const neighbor of this.tempEdges.get(node) ?? new Set()) {
if (this.hasCycleFrom(neighbor, visited, stack)) {
return true;
}
}

stack.delete(node);
return false;
}

hasCycle(): boolean {
const visited = new Set<number>();
const stack = new Set<number>();

for (const node of Object.keys(this.edges).map(Number)) {
if (stack.size > 0) {
alert("stack not empty");
}
if (this.hasCycleFrom(node, visited, stack)) {
return true;
}
}

for (const node of Object.keys(this.tempEdges).map(Number)) {
if (stack.size > 0) {
alert("stack not empty");
}
if (this.hasCycleFrom(node, visited, stack)) {
return true;
}
}

return false;
}

topological_sort(): number[] {
const nodes: Set<number> = new Set();

for (const [from, tos] of this.edges) {
nodes.add(from);
for (const to of tos) {
nodes.add(to);
}
}

for (const [from, tos] of this.tempEdges) {
nodes.add(from);
for (const to of tos) {
nodes.add(to);
}
}

const parents = new Map<number, Set<number>>();

for (const node of nodes) {
parents.set(node, new Set());
}

for (const [from, tos] of this.edges) {
for (const to of tos) {
parents.get(to)!.add(from);
}
}

for (const [from, tos] of this.tempEdges) {
for (const to of tos) {
parents.get(to)!.add(from);
}
}

const result = [];

while (parents.size > 0) {
const next_nodes = [...parents.entries()].find(([node, parent]) => {
return parent.size === 0;
});
if (next_nodes === undefined) {
return [];
}

const node = next_nodes[0];

result.push(node);
parents.delete(node);

for (const parent of parents.values()) {
parent.delete(node);
}
}

if (result.length === nodes.size) {
return result;
} else {
return [];
}
}
}

export function parse(data_r: string): [number[][], number[][]] {
const data = data_r.trim();
const [rules_s, pages_s, _] = data.split("\n\n");
const rules = rules_s.split("\n").map((rule) =>
rule.split("|").map((r) => Number(r))
);

const pages = pages_s.split("\n").map((page) => page.split(",").map(Number));

return [rules, pages];
}

export function solve1(data: [number[][], number[][]]): number {
const [rules, pages] = data;

const dirGraph = new DirectedGraph();

rules.forEach(([from, to]) => {
dirGraph.addEdge(from, to);
});

return pages.map((page) => {
const pageGraph = dirGraph.restrict(new Set(page));

for (let i = 0; i < page.length - 1; i++) {
pageGraph.addEdge(page[i], page[i + 1]);
}
const top_sort = pageGraph.topological_sort();
if (top_sort.length === 0) {
return 0;
} else {
return page[(page.length - 1) / 2];
}
}).reduce((a, b) => a + b, 0);
}

export function solve2(data: [number[][], number[][]]): number {
const [rules, pages] = data;

const dirGraph = new DirectedGraph();

rules.forEach(([from, to]) => {
dirGraph.addEdge(from, to);
});

const topological_sort = dirGraph.topological_sort();

const topological_index = new Map<number, number>();
topological_sort.forEach((node, index) => {
topological_index.set(node, index);
});

return pages.map((page) => {
const pageGraph = dirGraph.restrict(new Set(page));

const fixed = pageGraph.topological_sort();

for (let i = 0; i < page.length - 1; i++) {
pageGraph.addEdge(page[i], page[i + 1]);
}
const top_sort = pageGraph.topological_sort();
if (top_sort.length === 0) {
return fixed[(fixed.length - 1) / 2];
} else {
return 0;
}
}).reduce((a, b) => a + b, 0);
}

if (import.meta.main) {
const data_path = new URL("input.txt", import.meta.url).pathname;
const data = parse(await Deno.readTextFile(data_path));
console.log(solve1(data));
console.log(solve2(data));
}
9 changes: 9 additions & 0 deletions day5/test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { assertEquals } from "@std/assert";
import { parse, solve1, solve2 } from "./mod.ts";

Deno.test(async function testExample() {
const example_data_path = new URL("example.txt", import.meta.url).pathname;
const example_data = parse(await Deno.readTextFile(example_data_path));
assertEquals(solve1(example_data), 143);
assertEquals(solve2(example_data), 123);
});
3 changes: 2 additions & 1 deletion deno.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"./day1",
"./day2",
"./day3",
"./day4"
"./day4",
"./day5"
]
},
"imports": {
Expand Down

0 comments on commit a83bc48

Please sign in to comment.