AdventOfCode2022/07/main.go

163 lines
3.8 KiB
Go

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
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,
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(sum)
}
func partTwo() {
scanner := makeScanner(false)
root := Folder{
name: "/",
files: map[string]int{},
folders: map[string]*Folder{},
}
spaceToFree := 30000000 - (70000000 - 49192532) // size of all files, precomputed
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,
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
}
if curr.size > spaceToFree && curr.size < toDelete {
toDelete = curr.size
}
stack = stack[0 : len(stack)-1]
}
fmt.Println(toDelete)
}