package day07 import ( "strings" "adventofcode2022/utils" ) type dir struct { name string files map[string]int subdir map[string]*dir parent *dir size int } func Part1(input string) int { root := dir{name: "/", files: map[string]int{}, subdir: map[string]*dir{}, parent: nil} root.parse(input) sum := 0 find_dirs_part1(&root, 100000, &sum) return sum } func Part2(input string) int { root := dir{name: "/", files: map[string]int{}, subdir: map[string]*dir{}, parent: nil} root.parse(input) unused := 70000000 - root.size need := 30000000 - unused dir_size := 0 find_dirs_part2(&root, need, &dir_size) return dir_size } func find_dirs_part1(d *dir, size int, sum *int) { // recurse into subdir for _, subdir := range d.subdir { if (subdir.size) <= size { *sum += subdir.size } find_dirs_part1(subdir, size, sum) } } func find_dirs_part2(d *dir, size int, sum *int) { // recurse into subdir for _, subdir := range d.subdir { if (subdir.size) >= size && (*sum == 0 || (subdir.size) < *sum) { *sum = subdir.size } find_dirs_part2(subdir, size, sum) } } func (root *dir) parse(input string) { c := root for _, line := range strings.Split(input, "\n") { pieces := strings.Split(line, " ") if pieces[0] == "$" { if pieces[1] == "cd" { if pieces[2] == ".." { c = c.parent } else if pieces[2] == "/" { c = root } else { c = c.addDirectoryIfMissing(pieces[2]) } } else if pieces[1] == "ls" { // no need to do anything } else { panic("oops") } } else if pieces[0] == "dir" { c.addDirectoryIfMissing(pieces[1]) } else { c.addFileIfMissing(pieces[1], utils.MustAtoi(pieces[0])) } } } func (d *dir) addDirectoryIfMissing(name string) *dir { t, ok := d.subdir[name] if !ok { t = &dir{ name: name, files: map[string]int{}, subdir: map[string]*dir{}, parent: d, } d.subdir[name] = t } return t } func (d *dir) addFileIfMissing(name string, size int) { t, ok := d.files[name] if ok { if t != size { panic("oops") } } else { current := d d.files[name] = size for current.name != "/" { current.size += size current = current.parent } current.size += size } }