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
1 changed files with 68 additions and 32 deletions

100
day7.chpl
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;
class TreeNode {
var name: string;
var parent: borrowed TreeNode?;
var files = new map(string, int);
var dirs = new list(owned TreeNode);
var size = -1;
proc init(name: string, parent: borrowed TreeNode?) {
proc init(name: string) {
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();
for dir in dirs {
// Yield directory sizes from the dir.
for subSize in dir.these() do yield subSize;
// Count its size for our size.
size += dir.size;
for subSize in dir.dirSizes(size) do yield subSize;
}
yield (name, size);
this.size = size;
parentSize += size;
}
}
var rootFolder: owned TreeNode = new owned TreeNode("", nil);
var currentFolder: borrowed TreeNode = rootFolder.borrow();
proc type fromInput(name: string, readFrom): owned TreeNode {
var line: string;
var newDir = new TreeNode(name);
for line in stdin.lines() {
const strippedLine = line.strip();
if strippedLine == "$ cd .." {
if const parent = currentFolder.parent then
currentFolder = parent;
} else if strippedLine.startsWith("$ cd ") {
const dirName = strippedLine["$ cd ".size..];
var newFolder = new owned TreeNode(dirName, currentFolder);
currentFolder.dirs.append(newFolder);
currentFolder = currentFolder.dirs.last().borrow();
} else if !strippedLine.startsWith("$ ls") {
const (sizeOrDir, _, name) = strippedLine.partition(" ");
if sizeOrDir == "dir" {
// Ignore directories, we'll CD into them.
} else {
currentFolder.files[name] = sizeOrDir : int;
while readFrom.readLine(line, stripNewline = true) {
if line == "$ cd .." {
break;
} else if line.startsWith("$ cd ") {
const dirName = line["$ cd ".size..];
newDir.dirs.append(TreeNode.fromInput(dirName, readFrom));
} else if !line.startsWith("$ ls") {
const (sizeOrDir, _, name) = line.partition(" ");
if sizeOrDir == "dir" {
// Ignore directories, we'll `cd` into them.
} else {
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;
writeln(min reduce [(_, size) in rootFolder] if size >= toDelete then size);
var rootSize = 0;
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);