day 7. gave up on fighting the borrow checker after three hours and wrote the go version in 45 minutes.

This commit is contained in:
David 2022-12-07 20:03:26 -05:00
parent 10eca9d419
commit 82a1ecab7d
3 changed files with 262 additions and 1 deletions

158
07/main.go Normal file
View File

@ -0,0 +1,158 @@
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
"time"
)
func mustAtoi(line string) int {
i, _ := strconv.Atoi(line)
return i
}
func main() {
start := time.Now()
partOne()
duration := time.Since(start)
partTwo()
duration2 := time.Since(start)
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
}
func makeScanner(test bool) *bufio.Scanner {
var f *os.File
if test {
f, _ = os.Open("inputs/testinput")
} else {
f, _ = os.Open("inputs/input")
}
reader := bufio.NewReader(f)
return bufio.NewScanner(reader)
}
type Folder struct {
name string
parent *Folder
files map[string]int
folders map[string]*Folder
size int
}
func partOne() {
scanner := makeScanner(false)
root := Folder{
name: "/",
files: map[string]int{},
folders: map[string]*Folder{},
}
sum := 0
stack := []*Folder{&root}
for scanner.Scan() {
line := scanner.Text()
switch {
case line == "$ cd /": // don't care
continue
case line == "$ ls": // definitely don't care
continue
case line == "$ cd ..":
// since we're done in that child, compute it's size.
curr := stack[len(stack)-1]
for _, size := range curr.files {
curr.size += size
}
for _, f := range curr.folders {
curr.size += f.size
}
if curr.size <= 100000 {
sum += curr.size
}
// pop off stack
stack = stack[0 : len(stack)-1]
case strings.HasPrefix(line, "$ cd "): // descend into folder
stack = append(stack, stack[len(stack)-1].folders[strings.Split(line, " ")[2]])
case strings.HasPrefix(line, "dir "): // add directory to current folder
name := strings.Split(line, " ")[1]
stack[len(stack)-1].folders[name] = &Folder{
name: name,
parent: stack[len(stack)-1],
files: map[string]int{},
folders: map[string]*Folder{},
}
default: // add file to current folder
stack[len(stack)-1].files[strings.Split(line, " ")[1]] = mustAtoi(strings.Split(line, " ")[0])
}
}
// compute root size
for _, size := range root.files {
root.size += size
}
for _, f := range root.folders {
root.size += f.size
}
fmt.Println(sum)
}
func partTwo() {
scanner := makeScanner(false)
root := Folder{
name: "/",
files: map[string]int{},
folders: map[string]*Folder{},
}
spaceToFree := 30000000 - (70000000 - 49192532)
toDelete := 70000000
stack := []*Folder{&root}
for scanner.Scan() {
line := scanner.Text()
switch {
case line == "$ cd /": // don't care
continue
case line == "$ ls": // definitely don't care
continue
case line == "$ cd ..":
// since we're done in that child, compute it's size.
curr := stack[len(stack)-1]
for _, size := range curr.files {
curr.size += size
}
for _, f := range curr.folders {
curr.size += f.size
}
if curr.size > spaceToFree && curr.size < toDelete {
toDelete = curr.size
}
// pop off stack
stack = stack[0 : len(stack)-1]
case strings.HasPrefix(line, "$ cd "): // descend into folder
stack = append(stack, stack[len(stack)-1].folders[strings.Split(line, " ")[2]])
case strings.HasPrefix(line, "dir "): // add directory to current folder
name := strings.Split(line, " ")[1]
stack[len(stack)-1].folders[name] = &Folder{
name: name,
parent: stack[len(stack)-1],
files: map[string]int{},
folders: map[string]*Folder{},
}
default: // add file to current folder
stack[len(stack)-1].files[strings.Split(line, " ")[1]] = mustAtoi(strings.Split(line, " ")[0])
}
}
// finish computing directory sizes
for len(stack) > 0 {
curr := stack[len(stack)-1]
for _, size := range curr.files {
curr.size += size
}
for _, f := range curr.folders {
curr.size += f.size
}
stack = stack[0 : len(stack)-1]
}
fmt.Println(toDelete)
}

99
07/main.rs Normal file
View File

@ -0,0 +1,99 @@
#![allow(dead_code)]
use std::collections::HashMap;
use std::fs::File;
use std::io;
use std::io::BufRead;
use std::path::Path;
use std::time::Instant;
#[derive(Debug, Clone)]
struct ElfFile {
name: String,
size: u32,
}
#[derive(Debug, Clone)]
struct Folder<'a> {
name: String,
files: HashMap<String, ElfFile>,
folders: HashMap<String, &'a Folder<'a>>,
}
fn main() {
let now = Instant::now();
part_one();
let part_one_duration = now.elapsed();
part_two();
let part_two_duration = now.elapsed();
println!(
"p1: {}ms, p2: {}ms",
part_one_duration.as_millis(),
(part_two_duration - part_one_duration).as_millis()
);
}
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
where
P: AsRef<Path>,
{
// note that this discards a final newline
let file = File::open(filename)?;
Ok(io::BufReader::new(file).lines())
}
fn ElfFile_FromStr(s: &str) -> ElfFile {
let mut f = s.split(" ");
return ElfFile {
size: f.next().unwrap().parse::<u32>().unwrap(),
name: f.next().unwrap().to_string(),
};
}
fn newFolder(s: &str) -> Folder {
return Folder {
name: s.to_string(),
files: HashMap::new(),
folders: HashMap::new(),
};
}
fn part_one() {
if let Ok(lines) = read_lines("./inputs/input") {
let mut tree = Folder {
name: "/".to_string(),
files: HashMap::new(),
folders: HashMap::new(),
};
let mut stack: Vec<&mut Folder> = vec![&mut tree];
for line in lines {
if let Ok(command) = line {
match command.as_str() {
"$ cd /" => continue, // skip start
"$ ls" => continue, // we can assume this if we're not moving between directories
"$ cd .." => {
// stack.pop();
}
s if s.starts_with("$ cd ") => {
println!("push {}\n", s.split(" ").nth(2).unwrap())
}
s if s.starts_with("dir ") => {
let f = stack.pop().unwrap();
let ef = newFolder(s.split(" ").nth(1).unwrap());
f.folders.insert(ef.name.clone(), &ef);
stack.push(f);
}
s => {
// otherwise it must be a file
let f = stack.pop().unwrap();
let ef = ElfFile_FromStr(s);
f.files.insert(ef.name.clone(), ef);
stack.push(f);
}
};
}
}
println!("{:?}", tree);
}
}
fn part_two() {}

4
run.sh
View File

@ -3,6 +3,10 @@
if [ "${1}" != "" ]; then
padded=$(printf "%02g" ${1})
cd ${padded}
if [ "${2}" == "go" ]; then
go run main.go
else
rustc main.rs && ./main && rm main
fi
cd - > /dev/null
fi