package day7 import ( "bufio" "errors" "fmt" "os" "strconv" "strings" ) type FileSystem struct { name string parent *FileSystem subdirectories []*FileSystem files []FileInfo } func newFileSystem(name string, parent *FileSystem) *FileSystem { return &FileSystem{name, parent, []*FileSystem{}, []FileInfo{}} } func printFileTree(tree *FileSystem, prefix string) { fmt.Println(prefix, "-", tree.name, fmt.Sprintf("(dir size=%d)", totalSize(tree))) for _, file := range tree.files { fmt.Println(prefix, " ", "-", file.name, fmt.Sprintf("(file, size=%d)", file.size)) } for _, dir := range tree.subdirectories { printFileTree(dir, prefix+" ") } } func totalSize(tree *FileSystem) int { total := 0 for _, file := range tree.files { total += file.size } for _, dir := range tree.subdirectories { total += totalSize(dir) } return total } func computePart1(tree *FileSystem) int { result := 0 for _, dir := range tree.subdirectories { result += computePart1(dir) } currentSize := totalSize(tree) if currentSize <= 100000 { result += currentSize } return result } func computePart2(tree *FileSystem, size int) int { result := 70000000 for _, dir := range tree.subdirectories { subResult := computePart2(dir, size) if subResult < result { result = subResult } } currentSize := totalSize(tree) if currentSize > size && currentSize < result { result = currentSize } return result } type FileInfo struct { name string size int } func parseFileInfo(line string) (result FileInfo, err error) { splits := strings.Split(line, " ") if len(splits) != 2 { err = errors.New("too many values from file info split") return } size, err := strconv.Atoi(splits[0]) if err != nil { err = errors.New(fmt.Sprintf("could not parse file size: '%s'", splits[0])) return } result = FileInfo{splits[1], size} return } func Run(filename string) { file, err := os.Open(filename) if err != nil { fmt.Println("Error opening file:", err) return } scanner := bufio.NewScanner(file) scanner.Split(bufio.ScanLines) root := newFileSystem("/", nil) current := root for scanner.Scan() { line := scanner.Text() fmt.Println("line", line) if strings.HasPrefix(line, "$ cd /") { current = root } else if strings.HasPrefix(line, "$ cd ..") { current = current.parent } else if strings.HasPrefix(line, "$ cd ") { for _, subdir := range current.subdirectories { if subdir.name == line[5:] { current = subdir continue } } } else if strings.HasPrefix(line, "$ ls") { // don't do anything } else if strings.HasPrefix(line, "dir ") { newTree := newFileSystem(line[4:], current) current.subdirectories = append(current.subdirectories, newTree) } else { fileInfo, err := parseFileInfo(line) if err != nil { fmt.Println("PANIC:", err) return } current.files = append((*current).files, fileInfo) } } file.Close() printFileTree(root, "") fmt.Println("example first part", computePart1(root)) unusedSpace := 70000000 - totalSize(root) fmt.Println("unused space is currently", unusedSpace) needToGet := 30000000 - unusedSpace fmt.Println("need to find a directory at least", needToGet, "bytes big") fmt.Println("that directory has size", computePart2(root, needToGet)) }