160 lines
3.3 KiB
Go
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))
|
|
|
|
}
|