Tweak day 7 solution somewhat and start writing

This commit is contained in:
Danila Fedorin 2022-12-07 00:02:53 -08:00
parent 6029164067
commit 6ba1b3f326

View File

@ -1,17 +1,53 @@
// Advent of Code 2022, Day 7: Traversing Directories
// authors: ["Daniel Fedorin"]
// summary: "A solution to day seven of AoC 2022, introducing classes and memory management."
// tags: ["Advent of Code 2022"]
// date: 2022-12-07
/*
Welcome to day 7 of Chapel's Advent of Code 2022 series. We're over halway
through the twelve days of Chapel AoC! In case you haven't been following
the series, check out the introductory [Advent of Code 2022: Twelve
Days of Chapel](../aoc2022-day00-intro/) article for more context.
*/
/*
### The Task at Hand and My Approach
In today's puzzle, we are given a list of terminal-like commands (
[`ls`](https://man7.org/linux/man-pages/man1/ls.1.html) and [`cd`](https://man7.org/linux/man-pages/man1/cd.1p.html)
), as well as output corresponding to running these commands. The commands
explore a fictional file system, which can have files (objects with size)
as well as directories that group files and other (sub-)directories. The
problem then asks to compute the sizes of each folder, and to total up the
sizes of all folders that are smaller than a particular threshold.
The tree-like nature of the file system does not make it amenable to
representations based on arrays, lists, and maps alone. The trouble with
these data types is that they're flat. Our input could -- and will -- have arbitrary
levels of nested directories. However, arrays, lists, and maps cannot have
such arbitrary nesting -- we'd need something like a list of lists of lists...
We could, of course, use the `map` and `list` data types to represent the
file system with some sort of [adjacency list](https://en.wikipedia.org/wiki/Adjacency_list).
However, such an implementation would be somewhat clunky and hard to use.
Instead, we'll use a different tool from the repertoire of Chapel language
features, one we haven't seen so far: classes. Much like in most languages,
classes are a way to group together related pieces of data. up until now,
we've used tuples for this purpose.
*/
use IO, Map, List; use IO, Map, List;
class TreeNode { class TreeNode {
var name: string; var name: string;
var parent: borrowed TreeNode?;
var files = new map(string, int); var files = new map(string, int);
var dirs = new list(owned TreeNode); var dirs = new list(owned TreeNode);
var size = -1; proc init(name: string) {
proc init(name: string, parent: borrowed TreeNode?) {
this.name = name; this.name = name;
this.parent = parent;
} }
/* /*
@ -32,43 +68,43 @@ class TreeNode {
*/ */
iter these(): (string, int) { iter dirSizes(ref parentSize = 0): (string, int) {
var size = + reduce files.values(); var size = + reduce files.values();
for dir in dirs { for dir in dirs {
// Yield directory sizes from the dir. // Yield directory sizes from the dir.
for subSize in dir.these() do yield subSize; for subSize in dir.dirSizes(size) do yield subSize;
// Count its size for our size.
size += dir.size;
} }
yield (name, size); yield (name, size);
this.size = size; parentSize += size;
} }
}
var rootFolder: owned TreeNode = new owned TreeNode("", nil); proc type fromInput(name: string, readFrom): owned TreeNode {
var currentFolder: borrowed TreeNode = rootFolder.borrow(); var line: string;
var newDir = new TreeNode(name);
for line in stdin.lines() { while readFrom.readLine(line, stripNewline = true) {
const strippedLine = line.strip(); if line == "$ cd .." {
if strippedLine == "$ cd .." { break;
if const parent = currentFolder.parent then } else if line.startsWith("$ cd ") {
currentFolder = parent; const dirName = line["$ cd ".size..];
} else if strippedLine.startsWith("$ cd ") { newDir.dirs.append(TreeNode.fromInput(dirName, readFrom));
const dirName = strippedLine["$ cd ".size..]; } else if !line.startsWith("$ ls") {
var newFolder = new owned TreeNode(dirName, currentFolder); const (sizeOrDir, _, name) = line.partition(" ");
currentFolder.dirs.append(newFolder);
currentFolder = currentFolder.dirs.last().borrow();
} else if !strippedLine.startsWith("$ ls") {
const (sizeOrDir, _, name) = strippedLine.partition(" ");
if sizeOrDir == "dir" { if sizeOrDir == "dir" {
// Ignore directories, we'll CD into them. // Ignore directories, we'll `cd` into them.
} else { } else {
currentFolder.files[name] = sizeOrDir : int; newDir.files[name] = sizeOrDir : int;
} }
} }
}
return newDir;
}
} }
writeln(+ reduce [(_, size) in rootFolder] if size < 100000 then size); var rootFolder = TreeNode.fromInput("", stdin);
const toDelete = rootFolder.size - 40000000; var rootSize = 0;
writeln(min reduce [(_, size) in rootFolder] if size >= toDelete then size); writeln(+ reduce [(_, size) in rootFolder.dirSizes(rootSize)] if size < 100000 then size);
const toDelete = rootSize - 40000000;
writeln(min reduce [(_, size) in rootFolder.dirSizes()] if size >= toDelete then size);