Skip to content

Commit a923b45

Browse files
author
Matthew Judy
committed
Add solution for 2022-07.
1 parent 258449e commit a923b45

File tree

2 files changed

+300
-0
lines changed

2 files changed

+300
-0
lines changed

Package.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ let package: Package = Package(
3030
.executable(name: "camp-cleanup", targets: ["2022-04"]),
3131
.executable(name: "supply-stacks", targets: ["2022-05"]),
3232
.executable(name: "tuning-trouble", targets: ["2022-06"]),
33+
.executable(name: "no-space-left-on-device", targets: ["2022-07"]),
3334
],
3435

3536
dependencies: [
@@ -44,5 +45,6 @@ let package: Package = Package(
4445
.executableTarget(name: "2022-04", dependencies: commonDependencies, path: "Sources/2022/04", swiftSettings: commonSettings),
4546
.executableTarget(name: "2022-05", dependencies: commonDependencies, path: "Sources/2022/05", swiftSettings: commonSettings),
4647
.executableTarget(name: "2022-06", dependencies: commonDependencies, path: "Sources/2022/06", swiftSettings: commonSettings),
48+
.executableTarget(name: "2022-07", dependencies: commonDependencies, path: "Sources/2022/07", swiftSettings: commonSettings),
4749
]
4850
)
Lines changed: 298 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
1+
//
2+
// ChallengeName.swift
3+
//
4+
// Created by Author on 2023-01-03.
5+
//
6+
7+
8+
import ArgumentParser
9+
import Foundation
10+
import Shared
11+
12+
13+
/**
14+
Day 3: No Space Left On Device
15+
16+
# Part One
17+
18+
You can hear birds chirping and raindrops hitting leaves as the expedition
19+
proceeds. Occasionally, you can even hear much louder sounds in the distance;
20+
how big do the animals get out here, anyway?
21+
22+
The device the Elves gave you has problems with more than just its
23+
communication system. You try to run a system update:
24+
25+
```
26+
$ system-update --please --pretty-please-with-sugar-on-top
27+
Error: No space left on device
28+
```
29+
30+
Perhaps you can delete some files to make space for the update?
31+
32+
You browse around the filesystem to assess the situation and save the
33+
resulting terminal output (your puzzle input). For example:
34+
35+
```
36+
$ cd /
37+
$ ls
38+
dir a
39+
14848514 b.txt
40+
8504156 c.dat
41+
dir d
42+
$ cd a
43+
$ ls
44+
dir e
45+
29116 f
46+
2557 g
47+
62596 h.lst
48+
$ cd e
49+
$ ls
50+
584 i
51+
$ cd ..
52+
$ cd ..
53+
$ cd d
54+
$ ls
55+
4060174 j
56+
8033020 d.log
57+
5626152 d.ext
58+
7214296 k
59+
```
60+
61+
The filesystem consists of a tree of files (plain data) and directories (which
62+
can contain other directories or files). The outermost directory iscalled
63+
`/`. You can navigate around the filesystem, moving into or out of
64+
directories and listing the contents of the directory you're currently in.
65+
66+
Within the terminal output, lines that begin with `$` are commands you
67+
executed, very much like some modern computers:
68+
69+
* `cd` means **change directory.** This changes which directory is the
70+
current directory, but the specific result depends on the argument:
71+
* `cd x` moves **in** one level: it looks in the current directory for the
72+
directory named `x` and makes it the current directory.
73+
* `cd ..` moves **out** one level: it finds the directory that contains the
74+
current directory, then makes that directory the current directory.
75+
* `cd /` switches the current directory to the outermost directory, `/`.
76+
* `ls` means list. It prints out all of the files and directories immediately
77+
contained by the current directory:
78+
* `123 abc` means that the current directory contains a file named
79+
`abc` with size `123`.
80+
* `dir xyz` means that the current directory contains a directory
81+
named `xyz`.
82+
83+
Given the commands and output in the example above, you can determine that the
84+
filesystem looks visually like this:
85+
86+
```
87+
- / (dir)
88+
- a (dir)
89+
- e (dir)
90+
- i (file, size=584)
91+
- f (file, size=29116)
92+
- g (file, size=2557)
93+
- h.lst (file, size=62596)
94+
- b.txt (file, size=14848514)
95+
- c.dat (file, size=8504156)
96+
- d (dir)
97+
- j (file, size=4060174)
98+
- d.log (file, size=8033020)
99+
- d.ext (file, size=5626152)
100+
- k (file, size=7214296)
101+
```
102+
103+
Here, there are four directories:
104+
105+
* `/` (the outermost directory),
106+
* `a` and `d` (which are in `/`), and
107+
* `e` (which is in a).
108+
109+
These directories also contain files of various sizes.
110+
111+
Since the disk is full, your first step should probably be to find directories
112+
that are good candidates for deletion. To do this, you need to determine
113+
the **total size** of each directory. The total size of a directory is the sum
114+
of the sizes of the files it contains, directly or indirectly.
115+
(Directories themselves do not count as having any intrinsic size.)
116+
117+
The total sizes of the directories above can be found as follows:
118+
119+
* The total size of directory `e` is `584` because it contains a single file `i`
120+
of size `584` and no other directories.
121+
* The directory `a` has total size `94853` because it contains files `f`
122+
(size `29116`), `g` (size `2557`), and `h.lst` (size `62596`), plus file `i`
123+
indirectly (`a` contains `e` which contains `i`).
124+
* Directory `d` has total size `24933642`.
125+
* As the outermost directory, `/` contains every file. Its total size is
126+
`48381165`, the sum of the size of every file.
127+
128+
To begin, find all of the directories with a total size of `at most 100000`,
129+
then calculate the sum of their total sizes. In the example above, these
130+
directories are `a` and `e`; the sum of their total sizes is
131+
`95437` (94853 + 584). (As in this example, this process can count files
132+
more than once!)
133+
134+
Find all of the directories with a total size of at most 100000.
135+
What is **the sum of the total sizes of those directories?**
136+
137+
# Part Two
138+
139+
Now, you're ready to choose a directory to delete.
140+
141+
The total disk space available to the filesystem is `70000000`. To run the
142+
update, you need unused space of at least `30000000`. You need to find a
143+
directory you can delete that will **free up enough space** to run the update.
144+
145+
In the example above, the total size of the outermost directory (and thus the
146+
total amount of used space) is `48381165`; this means that the size of the
147+
unused space must currently be `21618835`, which isn't quite the `30000000`
148+
required by the update. Therefore, the update still requires a directory with
149+
total size of at least `8381165` to be deleted before it can run.
150+
151+
To achieve this, you have the following options:
152+
153+
* Delete directory `e`, which would increase unused space by `584`.
154+
* Delete directory `a`, which would increase unused space by `94853`.
155+
* Delete directory `d`, which would increase unused space by `24933642`.
156+
* Delete directory `/`, which would increase unused space by `48381165`.
157+
158+
Directories e and a are both too small; deleting them would not free up enough space. However, directories d and / are both big enough! Between these, choose the smallest: d, increasing unused space by 24933642.
159+
160+
Find the smallest directory that, if deleted, would free up enough space on the filesystem to run the update. What is the total size of that directory?
161+
*/
162+
@main
163+
struct NoSpaceLeftOnDevice: ParsableCommand
164+
{
165+
/// Enumeration for argument which activates "Part Two" behavior
166+
enum Mode: String, ExpressibleByArgument, CaseIterable
167+
{
168+
case sumOf100kOrLess
169+
case sizeOfSmallestBigEnough
170+
}
171+
172+
@Option(help: "'sumOf100kOrLess' or 'sizeOfSmallestBigEnough'")
173+
var mode: Mode
174+
}
175+
176+
177+
protocol FilesystemItem
178+
{
179+
var name: String { get }
180+
var size: Int { get }
181+
}
182+
183+
184+
class Directory: FilesystemItem
185+
{
186+
class File: FilesystemItem
187+
{
188+
let name : String
189+
let size : Int
190+
191+
init(name: String, size: Int)
192+
{
193+
self.name = name
194+
self.size = size
195+
}
196+
}
197+
198+
let name : String
199+
var subdirectories : [Directory]
200+
var files : [File]
201+
202+
var size: Int
203+
{
204+
let allItems: [FilesystemItem] = (self.subdirectories + self.files)
205+
return allItems.map(\.size).sum()
206+
}
207+
208+
init(name: String)
209+
{
210+
self.name = name
211+
self.subdirectories = []
212+
self.files = []
213+
}
214+
215+
216+
func findDirectoriesOfSize(within range: any RandomAccessCollection<Int>) -> [Directory]
217+
{
218+
var results : [Directory] = []
219+
220+
if ( range.contains(self.size) )
221+
{
222+
results.append(self)
223+
}
224+
225+
for subdirectory in self.subdirectories
226+
{
227+
results.append(contentsOf: subdirectory.findDirectoriesOfSize(within: range))
228+
}
229+
230+
return results
231+
}
232+
}
233+
234+
235+
// MARK: - Command Execution
236+
237+
extension NoSpaceLeftOnDevice
238+
{
239+
mutating func run() throws
240+
{
241+
let diskCapacity = 70000000
242+
let updateSize = 30000000
243+
244+
var currentPath: [Directory] = []
245+
246+
while let inputLine = readLine()
247+
{
248+
let components = inputLine.split(separator: " ")
249+
250+
switch ( components[0], components[1] )
251+
{
252+
case ( "$", "cd" ) :
253+
switch components[2]
254+
{
255+
case "..":
256+
currentPath.removeLast()
257+
258+
default:
259+
let newDirectory = Directory(name: String(components[2]))
260+
if let currentDirectory = currentPath.last
261+
{
262+
currentDirectory.subdirectories.append(newDirectory)
263+
}
264+
currentPath.append(newDirectory)
265+
}
266+
267+
case ( let size, let name ) where (try! /\d+/.wholeMatch(in: size) != nil):
268+
let file = Directory.File(name: String(name), size: Int(size)!)
269+
let currentDirectory: Directory = currentPath.last!
270+
currentDirectory.files.append(file)
271+
272+
case ( "$", "ls" ) : break
273+
case ( "dir", _ ) : break
274+
default : fatalError()
275+
}
276+
}
277+
278+
let root = currentPath.first!
279+
280+
switch self.mode
281+
{
282+
case .sumOf100kOrLess:
283+
print(root.findDirectoriesOfSize(within: 0 ... 100000)
284+
.map(\.size)
285+
.sum())
286+
287+
case .sizeOfSmallestBigEnough:
288+
let diskUsage = root.size
289+
let minSize = (updateSize - (diskCapacity - diskUsage))
290+
291+
print(root.findDirectoriesOfSize(within: minSize ... .max)
292+
.sorted(by: { $0.size < $1.size })
293+
.first(where: { $0.size >= minSize })!
294+
.size)
295+
}
296+
}
297+
}
298+

0 commit comments

Comments
 (0)