Add solution day 5
This commit is contained in:
parent
49547c9170
commit
fa4ca32939
28
day_5/example.txt
Normal file
28
day_5/example.txt
Normal file
@ -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
|
1378
day_5/input.txt
Normal file
1378
day_5/input.txt
Normal file
File diff suppressed because it is too large
Load Diff
90
day_5/solve_1.test.ts
Normal file
90
day_5/solve_1.test.ts
Normal file
@ -0,0 +1,90 @@
|
||||
import { assertArrayIncludes, assertEquals } from "jsr:@std/assert";
|
||||
import { makeTopologySortOrder, readFormat } from "./solve_1.ts";
|
||||
|
||||
Deno.test("readFormat", async () => {
|
||||
const path = new URL("example.txt", import.meta.url).pathname;
|
||||
const actual = await readFormat(path);
|
||||
const expected = {
|
||||
order: [
|
||||
{ left: 47, right: 53 },
|
||||
{ left: 97, right: 13 },
|
||||
{ left: 97, right: 61 },
|
||||
{ left: 97, right: 47 },
|
||||
{ left: 75, right: 29 },
|
||||
{ left: 61, right: 13 },
|
||||
{ left: 75, right: 53 },
|
||||
{ left: 29, right: 13 },
|
||||
{ left: 97, right: 29 },
|
||||
{ left: 53, right: 29 },
|
||||
{ left: 61, right: 53 },
|
||||
{ left: 97, right: 53 },
|
||||
{ left: 61, right: 29 },
|
||||
{ left: 47, right: 13 },
|
||||
{ left: 75, right: 47 },
|
||||
{ left: 97, right: 75 },
|
||||
{ left: 47, right: 61 },
|
||||
{ left: 75, right: 61 },
|
||||
{ left: 47, right: 29 },
|
||||
{ left: 75, right: 13 },
|
||||
{ left: 53, right: 13 },
|
||||
],
|
||||
pageNumbers: [
|
||||
[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],
|
||||
],
|
||||
};
|
||||
assertEquals(actual, expected);
|
||||
});
|
||||
|
||||
Deno.test("makeTopologySortOrder", () => {
|
||||
const orderMap = new Map<number, Set<number>>([
|
||||
[1, new Set([2, 3])],
|
||||
[2, new Set([4])],
|
||||
[3, new Set([4])],
|
||||
[4, new Set()],
|
||||
]);
|
||||
const actual = makeTopologySortOrder(orderMap);
|
||||
const expected = [[4, 2, 3, 1], [4, 3, 2, 1]];
|
||||
// 4 -> 2 -> 3 -> 1
|
||||
// 4 -> 3 -> 2 -> 1
|
||||
// multiple valid topological sort order
|
||||
assertArrayIncludes(expected, [actual]);
|
||||
});
|
||||
|
||||
Deno.test("makeTopologySortOrder with cycle", () => {
|
||||
const orderMap = new Map<number, Set<number>>([
|
||||
[1, new Set([2])],
|
||||
[2, new Set([3])],
|
||||
[3, new Set([1])],
|
||||
]);
|
||||
const actual = makeTopologySortOrder(orderMap);
|
||||
const expected = [[3, 2, 1], [2, 1, 3], [1, 3, 2]]; // or any valid topological sort order
|
||||
// 3 -> 1 -> 2 -> 3
|
||||
// 2 -> 3 -> 1 -> 2
|
||||
// 1 -> 2 -> 3 -> 1
|
||||
// multiple valid topological sort order
|
||||
|
||||
// The order of the nodes in the cycle is not guaranteed.
|
||||
assertArrayIncludes(expected, [actual]);
|
||||
});
|
||||
|
||||
Deno.test("makeTopologySortOrder with disconnected graph", () => {
|
||||
const orderMap = new Map<number, Set<number>>([
|
||||
[1, new Set([2])],
|
||||
[3, new Set([4])],
|
||||
]);
|
||||
const actual = makeTopologySortOrder(orderMap);
|
||||
const expected = [
|
||||
[2, 1, 4, 3],
|
||||
[2, 4, 1, 3],
|
||||
[2, 4, 3, 1],
|
||||
[4, 2, 1, 3],
|
||||
[4, 2, 3, 1],
|
||||
[4, 3, 2, 1],
|
||||
];
|
||||
assertArrayIncludes(expected, [actual]);
|
||||
});
|
108
day_5/solve_1.ts
Normal file
108
day_5/solve_1.ts
Normal file
@ -0,0 +1,108 @@
|
||||
export async function readFormat(path: string) {
|
||||
const data = await Deno.readTextFile(path);
|
||||
// assume LF line endings.
|
||||
// TODO: handle CRLF line endings.
|
||||
const [orderTxt, pageNumbersTxt] = data.split("\n\n");
|
||||
|
||||
const order = orderTxt.split("\n").map((line) => {
|
||||
const [left, right] = line.split("|");
|
||||
return {
|
||||
left: parseInt(left.trim()),
|
||||
right: parseInt(right.trim()),
|
||||
};
|
||||
});
|
||||
const pageNumbers = pageNumbersTxt.split("\n").map((line) => {
|
||||
const numbers = line.split(",");
|
||||
return numbers.map((num) => parseInt(num.trim()));
|
||||
});
|
||||
return { order, pageNumbers };
|
||||
}
|
||||
|
||||
// topology sort order
|
||||
export function makeTopologySortOrder(
|
||||
orderMap: Map<number, Set<number>>,
|
||||
): number[] {
|
||||
const visited = new Set<number>();
|
||||
const sorted = new Array<number>();
|
||||
for (const key of orderMap.keys()) {
|
||||
if (!visited.has(key)) {
|
||||
visit(key);
|
||||
}
|
||||
}
|
||||
function visit(node: number) {
|
||||
if (visited.has(node)) return;
|
||||
visited.add(node);
|
||||
const set = orderMap.get(node);
|
||||
if (set) {
|
||||
for (const next of set) {
|
||||
visit(next);
|
||||
}
|
||||
}
|
||||
sorted.push(node);
|
||||
}
|
||||
return sorted;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const path = new URL("input.txt", import.meta.url).pathname;
|
||||
const { order, pageNumbers } = await readFormat(path);
|
||||
|
||||
// create order map
|
||||
const orderMap = new Map<number, Set<number>>();
|
||||
for (const { left, right } of order) {
|
||||
const leftSet = orderMap.get(left) ?? new Set<number>();
|
||||
leftSet.add(right);
|
||||
orderMap.set(left, leftSet);
|
||||
}
|
||||
// it's not transitive closure...
|
||||
//
|
||||
// apply transitive closure
|
||||
// const topologySortOrder = makeTopologySortOrder(orderMap);
|
||||
// const completedSetMap = new Map<number, Set<number>>();
|
||||
// for (const num of topologySortOrder) {
|
||||
// // console.log(num, "\n===");
|
||||
// const set = orderMap.get(num) ?? new Set<number>();
|
||||
// const completedSet = completedSetMap.get(num) ?? new Set<number>();
|
||||
// set.forEach((elem) => completedSet.add(elem));
|
||||
// for (const next of set) {
|
||||
// const nextSet = completedSetMap.get(next) ?? new Set<number>();
|
||||
// nextSet.forEach((elem) => completedSet.add(elem));
|
||||
// }
|
||||
// console.log(completedSet);
|
||||
// // console.log("===");
|
||||
// completedSetMap.set(num, completedSet);
|
||||
// }
|
||||
|
||||
const completedSetMap = orderMap;
|
||||
|
||||
// check order is valid or not by comparing with pageNumbers
|
||||
function checkPageNumberOrder(pageNumbers: number[]): boolean {
|
||||
const notAllowed = new Set<number>();
|
||||
for (let i = pageNumbers.length - 1; i >= 0; i--) {
|
||||
const current = pageNumbers[i];
|
||||
if (notAllowed.has(current)) {
|
||||
return false;
|
||||
}
|
||||
notAllowed.add(current);
|
||||
const biggerThanCurrent = completedSetMap.get(current);
|
||||
biggerThanCurrent?.forEach((elem) => notAllowed.add(elem));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
let sum = 0;
|
||||
for (const pages of pageNumbers) {
|
||||
if (!checkPageNumberOrder(pages)) {
|
||||
// console.log("invalid order", pages);
|
||||
} else {
|
||||
// get middle number
|
||||
const middle = pages[pages.length >> 1];
|
||||
sum += middle;
|
||||
}
|
||||
}
|
||||
console.log(sum);
|
||||
}
|
||||
|
||||
if (import.meta.main) {
|
||||
main();
|
||||
}
|
86
day_5/solve_2.ts
Normal file
86
day_5/solve_2.ts
Normal file
@ -0,0 +1,86 @@
|
||||
import { readFormat } from "./solve_1.ts";
|
||||
|
||||
async function main() {
|
||||
const path = new URL("input.txt", import.meta.url).pathname;
|
||||
const { order, pageNumbers } = await readFormat(path);
|
||||
|
||||
// create order map
|
||||
const orderMap = new Map<number, Set<number>>();
|
||||
for (const { left, right } of order) {
|
||||
const leftSet = orderMap.get(left) ?? new Set<number>();
|
||||
leftSet.add(right);
|
||||
orderMap.set(left, leftSet);
|
||||
}
|
||||
const completedSetMap = orderMap;
|
||||
|
||||
// check order is valid or not by comparing with pageNumbers
|
||||
function checkPageNumberOrder(pageNumbers: number[]): boolean {
|
||||
const notAllowed = new Set<number>();
|
||||
for (let i = pageNumbers.length - 1; i >= 0; i--) {
|
||||
const current = pageNumbers[i];
|
||||
if (notAllowed.has(current)) {
|
||||
// console.log("not allowed", current, notAllowed );
|
||||
return false;
|
||||
}
|
||||
notAllowed.add(current);
|
||||
const biggerThanCurrent = completedSetMap.get(current);
|
||||
biggerThanCurrent?.forEach((elem) => notAllowed.add(elem));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function findErrorIndex(n: number, pages: number[]) {
|
||||
return pages.findIndex(page => {
|
||||
const biggerThanCurrent = completedSetMap.get(page);
|
||||
if (biggerThanCurrent) {
|
||||
return biggerThanCurrent.has(n);
|
||||
}
|
||||
return false;
|
||||
})
|
||||
}
|
||||
|
||||
function correctPageNumberOrder(pageNumbers: number[]): number[] {
|
||||
const result = [...pageNumbers];
|
||||
const notAllowed = new Set<number>();
|
||||
for (let i = result.length - 1; i >= 0; i--) {
|
||||
const current = result[i];
|
||||
if (notAllowed.has(current)) {
|
||||
const p = result.slice(i + 1);
|
||||
const errorIndex = findErrorIndex(current, p);
|
||||
if (errorIndex === undefined) {
|
||||
// could not happen
|
||||
throw new Error("cannot correct the order");
|
||||
}
|
||||
const ei = errorIndex + i + 1;
|
||||
result[i] = result[ei];
|
||||
result[ei] = current;
|
||||
|
||||
return correctPageNumberOrder(result);
|
||||
}
|
||||
notAllowed.add(current);
|
||||
const biggerThanCurrent = completedSetMap.get(current);
|
||||
biggerThanCurrent?.forEach((elem) => notAllowed.add(elem));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
let sum = 0;
|
||||
for (const pages of pageNumbers) {
|
||||
if (!checkPageNumberOrder(pages)) {
|
||||
// correct the order
|
||||
const corrected = correctPageNumberOrder(pages);
|
||||
if (!checkPageNumberOrder(corrected)) {
|
||||
console.log("cannot correct the order", pages);
|
||||
console.log("corrected", corrected);
|
||||
throw new Error("cannot correct the order");
|
||||
}
|
||||
const middle = corrected[corrected.length >> 1];
|
||||
sum += middle;
|
||||
}
|
||||
}
|
||||
console.log(sum);
|
||||
}
|
||||
|
||||
if (import.meta.main) {
|
||||
main();
|
||||
}
|
Loading…
Reference in New Issue
Block a user