-
Notifications
You must be signed in to change notification settings - Fork 0
/
day07_2.nim
148 lines (123 loc) · 3.83 KB
/
day07_2.nim
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
146
147
148
import os
if paramCount() != 1:
echo "Usage: ./dayXX <input file>"
quit(1)
let filename = paramStr(1)
if not fileExists(filename):
echo "File not found: ", filename
quit(1)
## RUN: TEST
# RUN: FULL
import std/strutils
import std/algorithm
type
File = tuple
name: string
size: int64
Directory = object
name: string
size: int64
parent: ptr Directory
directories: seq[Directory]
files: seq[File]
proc newDirectory(name: string, parent: ptr Directory): Directory =
result = Directory(
name: name,
size: 0,
parent: parent,
directories: @[],
files: @[],
)
proc addToSize(dir: var Directory, size: int64) =
dir.size += size
if dir.parent != nil:
dir.parent[].addToSize(size)
proc addFile(dir: var Directory, name: string, size: int64) =
dir.files.add((name: name, size: size))
dir.addToSize(size)
proc `in`(name: string, dir: Directory): bool =
result = false
for subdir in dir.directories:
if subdir.name == name:
result = true
break
# for filename in dir.files:
# if filename.name == name:
# result = true
# break
proc `notin`(name: string, dir: Directory): bool =
result = not (name in dir)
let root = newDirectory("/", nil)
var cd: ptr Directory = unsafeAddr(root)
var i = 0
for line in lines(filename):
# echo line
let split_line = line.split(" ")
if i == 0:
assert(split_line[0] == "$")
assert(split_line[1] == "cd")
assert(split_line[2] == "/")
i += 1
continue
if split_line[0] == "$":
assert(split_line.len > 1)
if split_line[1] == "cd":
assert(split_line.len == 3)
let name = split_line[2]
if name == "..":
cd = cd[].parent
elif name notin cd[]:
let new_dir = newDirectory(name, cd)
cd[].directories.add(new_dir)
cd = unsafeAddr(new_dir)
else:
var found = false
for child in cd.directories:
if child.name == name:
cd = unsafeAddr(child)
found = true
break
assert(found)
elif split_line[1] == "ls":
assert(split_line.len == 2)
else:
raise newException(ValueError, "Unknown command: " & split_line[1])
else:
assert(split_line.len == 2)
if split_line[0] == "dir":
let name = split_line[1]
if name notin cd[]:
cd[].directories.add(newDirectory(name, cd))
else:
let size = split_line[0].parseInt
let name = split_line[1]
cd[].addFile(name, size)
i += 1
proc print(dir: Directory, indent: int = 0) =
echo ' '.repeat(indent) & "- " & dir.name & " (dir, size=" & $dir.size & ")"
for child in dir.directories:
print(child, indent + 2)
for file in dir.files:
echo ' '.repeat(indent + 2) & "- " & file.name & " (file, size=" & $file.size & ")"
# root.print()
const DISK_SPACE = 70000000
const REQUIRED_SPACE = 30000000
let free_space = DISK_SPACE - root.size
# echo "Free space: " & $free_space
let needs_to_delete = REQUIRED_SPACE - free_space
# echo "Needs to delete: " & $needs_to_delete
proc toSeq(dir: Directory): seq[Directory] =
result = @[]
result.add(dir)
for child in dir.directories:
result.add(child.toSeq())
proc sorted(dir: Directory): seq[Directory] =
result = dir.toSeq().sortedByIt(it.size)
var to_delete_size: int64 = -1
for dir in root.sorted():
if dir.size > needs_to_delete:
to_delete_size = dir.size
# echo dir.name & " " & $dir.size
break
assert(to_delete_size != -1)
echo to_delete_size