code.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. package main
  2. import (
  3. "bufio"
  4. "fmt"
  5. "log"
  6. "os"
  7. "sort"
  8. "strings"
  9. )
  10. type item struct {
  11. name string
  12. size int
  13. }
  14. type dir struct {
  15. name string
  16. parent *dir
  17. dirs []*dir
  18. files []*item
  19. }
  20. func parentHasDir(parent *dir, name string) *dir {
  21. for i := range parent.dirs {
  22. if parent.dirs[i].name == name {
  23. return parent.dirs[i]
  24. }
  25. }
  26. return nil
  27. }
  28. func cd(line string, current *dir, root *dir) *dir {
  29. var name string
  30. n, err := fmt.Sscanf(line, "$ cd %s", &name)
  31. if n != 1 || err != nil {
  32. log.Fatal("Can't parse cd:", err)
  33. }
  34. if name == "/" {
  35. current = root
  36. } else if name == ".." {
  37. current = current.parent
  38. } else {
  39. parent := current
  40. current = parentHasDir(parent, name)
  41. if current == nil {
  42. newDir := dir{name: name, parent: parent}
  43. parent.dirs = append(parent.dirs, &newDir)
  44. current = &newDir
  45. }
  46. }
  47. return current
  48. }
  49. func readInput(file *os.File) dir {
  50. scanner := bufio.NewScanner(file)
  51. root := dir{name: "/"}
  52. var current *dir
  53. read := false
  54. for scanner.Scan() {
  55. line := scanner.Text()
  56. if line == "" {
  57. continue
  58. }
  59. if strings.HasPrefix(line, "$ cd") {
  60. read = false
  61. current = cd(line, current, &root)
  62. } else if strings.HasPrefix(line, "$ ls") {
  63. read = true
  64. continue
  65. }
  66. if read {
  67. if strings.HasPrefix(line, "dir ") {
  68. continue
  69. } else {
  70. var newFile item
  71. n, err := fmt.Sscanf(line, "%d %s", &newFile.size, &newFile.name)
  72. if n != 2 || err != nil {
  73. log.Fatal("Can't parse cd:", err)
  74. }
  75. current.files = append(current.files, &newFile)
  76. }
  77. }
  78. }
  79. return root
  80. }
  81. func getSizes(root dir, sizes []int) (int, []int) {
  82. size := 0
  83. for i := range root.files {
  84. size += root.files[i].size
  85. }
  86. for i := range root.dirs {
  87. var c int
  88. c, sizes = getSizes(*root.dirs[i], sizes)
  89. size += c
  90. }
  91. sizes = append(sizes, size)
  92. return size, sizes
  93. }
  94. func part1(sizes []int) int {
  95. sum := 0
  96. for i := range sizes {
  97. if sizes[i] < 100000 {
  98. sum += sizes[i]
  99. }
  100. }
  101. return sum
  102. }
  103. func part2(sizes []int, total int, fsSize int, needed int) int {
  104. unused := fsSize - total
  105. needed -= unused
  106. sort.Ints(sizes)
  107. for i := range sizes {
  108. if sizes[i] >= needed {
  109. return sizes[i]
  110. }
  111. }
  112. return 0
  113. }
  114. func main() {
  115. if len(os.Args) < 2 {
  116. log.Fatal("You need to specify a file!")
  117. }
  118. filePath := os.Args[1]
  119. file, err := os.Open(filePath)
  120. if err != nil {
  121. log.Fatalf("Failed to open %s!\n", filePath)
  122. }
  123. root := readInput(file)
  124. total, sizes := getSizes(root, []int{})
  125. fmt.Println("Part1:", part1(sizes))
  126. fmt.Println("Part2:", part2(sizes, total, 70000000, 30000000))
  127. }