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