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) }