-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday07_1.nim
130 lines (110 loc) · 3.44 KB
/
day07_1.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
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/sequtils
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 SIZE_LIMIT = 100000
proc findSmall(dir: Directory): seq[Directory] =
result = @[]
if dir.size < SIZE_LIMIT:
result.add(dir)
for child in dir.directories:
result = result.concat(findSmall(child))
echo root.findSmall().map(proc (dir: Directory): int64 = dir.size).foldl(a + b)