-
Notifications
You must be signed in to change notification settings - Fork 5
/
day07.mjs
145 lines (121 loc) · 3.42 KB
/
day07.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import { readFileSync } from "node:fs";
const lines = readFileSync("day07.txt", { encoding: "utf-8" }) // read day??.txt content
.replace(/\r/g, "") // remove all \r characters to avoid issues on Windows
.trim() // Remove starting/ending whitespace
.split("\n"); // Split on newline
function createTree(lines) {
const tree = {
name: "/",
isDirectory: true,
children: [],
}; // node: name, isDirectory, size, children, parent
let currentNode = tree;
let currentCommand = null;
for (const line of lines) {
if (line[0] === "$") {
// command
const match = /^\$ (?<command>\w+)(?: (?<arg>.+))?$/.exec(line);
currentCommand = match.groups.command;
if (currentCommand === "cd") {
const target = match.groups.arg;
switch (target) {
case "/":
currentNode = tree;
break;
case "..":
currentNode = currentNode.parent;
break;
default:
currentNode = currentNode.children.find(
(folder) => folder.isDirectory && folder.name === target
);
}
}
} else {
if (currentCommand === "ls") {
// For now, it's a file/directory from a 'ls' command
const fileMatch = /^(?<size>\d+) (?<name>.+)$/.exec(line);
if (fileMatch) {
const node = {
name: fileMatch.groups.name,
size: parseInt(fileMatch.groups.size),
isDirectory: false,
parent: currentNode,
};
currentNode.children.push(node);
}
const dirMatch = /^dir (?<name>.+)$/.exec(line);
if (dirMatch) {
const node = {
name: dirMatch.groups.name,
isDirectory: true,
children: [],
parent: currentNode,
};
currentNode.children.push(node);
}
} else {
throw new Error("unkown state");
}
}
}
return tree;
}
function printTree(node, depth = 0) {
console.log(
`${" ".repeat(depth * 2)}- ${node.name} (${
node.isDirectory ? "dir" : `file, size=${node.size}`
})`
);
if (node.isDirectory) {
for (const child of node.children) {
printTree(child, depth + 1);
}
}
}
function getSize(node, directoryCallback = () => {}) {
if (!node.isDirectory) {
return node.size;
}
const directorySize = node.children
.map((child) => getSize(child, directoryCallback))
.reduce((a, b) => a + b, 0);
directoryCallback(node.name, directorySize);
return directorySize;
}
function part1() {
const thresholdSize = 100000;
const tree = createTree(lines);
// printTree(tree);
let sumSmallFolder = 0;
getSize(tree, (name, size) => {
if (size < thresholdSize) {
sumSmallFolder += size;
}
});
console.log(sumSmallFolder);
}
function part2() {
const totalDiskSpace = 70000000;
const requiredSpace = 30000000;
const tree = createTree(lines);
const usedSpace = getSize(tree);
const availableSpace = totalDiskSpace - usedSpace;
if (availableSpace > requiredSpace) {
throw new Error("There is already enough space");
}
const minimumFolderSize = requiredSpace - availableSpace;
const candidates = [];
getSize(tree, (name, size) => {
if (size >= minimumFolderSize) {
candidates.push({
name,
size,
});
}
});
candidates.sort((a, b) => a.size - b.size);
console.log(candidates[0].size);
}
part1();
part2();