Files
advent2022/solutions/day7/day7.go
2022-12-23 19:45:56 -08:00

160 lines
3.3 KiB
Go

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