Skip to content

Commit 5169808

Browse files
authored
2022:07: Solve parts 1, 2 [js]
1 parent 8412200 commit 5169808

File tree

1 file changed

+168
-0
lines changed

1 file changed

+168
-0
lines changed

2022/day07/solution.js

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
const { readFileSync } = require("fs");
2+
const { join: path } = require("path");
3+
4+
class FSNode {
5+
type = "raw"
6+
name = null
7+
size = null
8+
parent = null
9+
10+
constructor(name) {
11+
this.name = name
12+
}
13+
14+
getSize = () => this.size
15+
16+
setParent = (parentNode) => {
17+
this.parent = parentNode
18+
}
19+
20+
static fromDataLine = (dataLine) => {
21+
const data = dataLine.split(" ");
22+
if (data[0] == "dir") {
23+
return new Directory(data[1], []);
24+
} else {
25+
return new File(dataLine)
26+
}
27+
}
28+
}
29+
30+
class Directory extends FSNode {
31+
type = "dir"
32+
children = null
33+
34+
constructor(name, children = []) {
35+
super(name);
36+
this.children = children;
37+
}
38+
39+
getSize = () => {
40+
let total = 0;
41+
this.children.forEach((child) => {
42+
total += child.getSize();
43+
});
44+
return total;
45+
}
46+
47+
addChild = (childNode) => {
48+
childNode.setParent(this);
49+
this.children.push(childNode);
50+
}
51+
52+
getChild = (childName) => {
53+
const child = this.children.find((child) => {
54+
return child.name === childName;
55+
});
56+
if (!child)
57+
throw new Error(`${this.name} doesn't contain ${childName}!`);
58+
else return child;
59+
}
60+
}
61+
62+
class File extends FSNode {
63+
type = "file";
64+
65+
constructor(name, size=undefined) {
66+
if (size) {
67+
super(name);
68+
this.size = size;
69+
} else {
70+
// Allow for passing the input line directly
71+
const data = name.split(" ");
72+
super(data[1]);
73+
this.size = parseInt(data[0])
74+
}
75+
}
76+
}
77+
78+
class Shell {
79+
workingDir = null;
80+
81+
constructor(startingDir) {
82+
this.workingDir = startingDir
83+
}
84+
85+
eval = (line, getNextLine) => {
86+
if (!line.startsWith("$"))
87+
throw new Error("Shell#eval received invalid command (missing $)");
88+
89+
const words = line.split(" ");
90+
words.shift(); // Remove leading $
91+
const cmd = words.shift();
92+
// `words` now contains the arguments
93+
94+
if (cmd === "cd") {
95+
const target = words.shift();
96+
if (target === "..") this.workingDir = this.workingDir.parent;
97+
else if (target === "/") {
98+
while (this.workingDir.name !== "/") {
99+
this.eval("$ cd ..");
100+
}
101+
} else {
102+
this.workingDir = this.workingDir.getChild(target);
103+
}
104+
} else if (cmd === "ls") {
105+
let nextLineOffset = 1;
106+
while (true) {
107+
const nextLine = getNextLine(nextLineOffset);
108+
109+
// Stop if the next line doesn't exist or is a new command
110+
if (!nextLine) break;
111+
if (nextLine.startsWith("$")) break;
112+
113+
const newNode = FSNode.fromDataLine(nextLine);
114+
this.workingDir.addChild(newNode);
115+
nextLineOffset += 1;
116+
}
117+
} else
118+
throw new Error(`Shell#eval received invalid command (${cmd})`);
119+
}
120+
}
121+
122+
const rootNode = new Directory("/");
123+
const shell = new Shell(rootNode);
124+
125+
const input = readFileSync(path(__dirname, "input")).toString();
126+
const inputLines = input.split("\n")
127+
for (let _inputLineInx in inputLines) {
128+
inputLineInx = parseInt(_inputLineInx)
129+
const inputLine = inputLines[inputLineInx]
130+
if (inputLine.startsWith("$")) {
131+
shell.eval(inputLine, (offset=1) => {
132+
return inputLines[inputLineInx + offset];
133+
});
134+
}
135+
}
136+
137+
const getAllDirs = (root) => {
138+
let result = [root];
139+
const subDirs = root.children.filter((child) => child.type === "dir");
140+
subDirs.forEach((subDir) => { result = [...result, ...getAllDirs(subDir)] });
141+
return result;
142+
};
143+
144+
const allSizes = getAllDirs(rootNode).map((dir) => dir.getSize());
145+
146+
// PART 1: Combine the sizes of all dirs below 100K in size
147+
const solution1 = allSizes.reduce((accumulated, nextSolutionSize) => {
148+
if (nextSolutionSize > 100000) return accumulated;
149+
else return accumulated + nextSolutionSize;
150+
}, 0);
151+
152+
153+
// PART 2: Find the size of the smallest dir that is at least 30M in size
154+
const fsSize = 70 * 1000000
155+
const updateSize = 30 * 1000000;
156+
157+
const usedSpace = rootNode.getSize();
158+
const freeSpace = fsSize - usedSpace;
159+
const neededSpace = updateSize - freeSpace;
160+
161+
const solution2Candidates = allSizes.filter((size) => size >= neededSpace);
162+
let solution2 = solution2Candidates[0];
163+
solution2Candidates.forEach((candidate) => {
164+
if (candidate < solution2) { solution2 = candidate; }
165+
});
166+
167+
console.log(solution1);
168+
console.log(solution2);

0 commit comments

Comments
 (0)