Created
December 7, 2022 22:50
-
-
Save zoldar/e63096b30e761c22a71ca30de24bbaca to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import std/sequtils, std/strutils, std/sugar, std/strformat | |
| type | |
| NodeKind = enum File, Dir | |
| Node = object | |
| kind: NodeKind | |
| name: string | |
| size: int | |
| children: seq[Node] | |
| proc buildTree(input: seq[string]): Node = | |
| var stack: seq[ptr Node] | |
| var root = Node(kind: Dir, name: "/") | |
| for line in input: | |
| if line == "$ cd /": | |
| stack = @[addr root] | |
| elif line == "$ cd ..": | |
| stack.delete(stack.len-1) | |
| elif line.startsWith("$ cd "): | |
| let dirName = line["$ cd ".len..<line.len] | |
| var currentRoot = stack[^1] | |
| for idx in 0..<currentRoot.children.len: | |
| var node = currentRoot.children[idx] | |
| if node.name == dirName and node.kind == Dir: | |
| stack.add(addr currentRoot.children[idx]) | |
| break | |
| elif not line.startsWith("$ "): | |
| let parts = line.split(" ") | |
| let name = parts[1] | |
| if parts[0] == "dir": | |
| stack[stack.len-1].children.add( | |
| Node(kind: Dir, name: name) | |
| ) | |
| else: | |
| let size = parseInt(parts[0]) | |
| for idx in 0..<stack.len: | |
| stack[idx].size += size | |
| stack[stack.len-1].children.add( | |
| Node(kind: File, name: name, size: size) | |
| ) | |
| root | |
| proc traverseTree[T](node: Node, initial: T, procFun: (Node, T) -> T): T = | |
| result = initial | |
| var stack = @[node] | |
| var currentNode: Node | |
| while stack.len > 0: | |
| currentNode = stack.pop() | |
| result = procFun(currentNode, result) | |
| for child in currentNode.children: | |
| stack.add(child) | |
| proc sumDirsUpTo100k(node: Node, acc: int): int = | |
| if node.kind == Dir and node.size <= 100000: | |
| result = acc + node.size | |
| else: | |
| result = acc | |
| proc smallestDirSizeAbove(sizeToFreeUp: int): (Node, int) -> int = | |
| result = proc(node: Node, size: int): int = | |
| if node.kind == Dir and node.size >= sizeToFreeUp and node.size < size: | |
| node.size | |
| else: | |
| size | |
| let input = "day-7/input.txt".lines.toSeq | |
| let tree = buildTree(input) | |
| let spaceToFreeUp = 30000000 - (70000000 - tree.size) | |
| echo fmt"Sum of size of directories at or below 100k: {traverseTree(tree, 0, sumDirsUpTo100k)}" | |
| echo fmt"Smallest dir size to free up 30M of space: {traverseTree(tree, high(int), smallestDirSizeAbove(spaceToFreeUp))}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment