code.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. package main
  2. import (
  3. "fmt"
  4. "log"
  5. "os"
  6. )
  7. func getDiskMap(data []byte) []int {
  8. diskMap := make([]int, len(data))
  9. for i, block := range data {
  10. if block < 48 || block > 57 {
  11. continue
  12. }
  13. diskMap[i] = int(block) - 48
  14. }
  15. return diskMap
  16. }
  17. func getDisk(diskMap []int) (int, []int) {
  18. var disk []int
  19. file := true
  20. var fileID int
  21. for _, number := range diskMap {
  22. if file {
  23. file = false
  24. for j := 0; j < number; j++ {
  25. disk = append(disk, fileID)
  26. }
  27. fileID++
  28. } else {
  29. file = true
  30. for j := 0; j < number; j++ {
  31. disk = append(disk, -1)
  32. }
  33. }
  34. }
  35. return diskMap[0], disk
  36. }
  37. func compact(disk []int, free int) []int {
  38. end := len(disk) - 1
  39. for free < end {
  40. if disk[free] != -1 {
  41. free++
  42. continue
  43. }
  44. if disk[end] == -1 {
  45. end--
  46. continue
  47. }
  48. disk[free], disk[end] = disk[end], disk[free]
  49. free++
  50. end--
  51. }
  52. return disk
  53. }
  54. func calculateChecksum(disk []int) int64 {
  55. var checksum int64
  56. for i := range disk {
  57. if disk[i] != -1 {
  58. checksum += int64(disk[i] * i)
  59. }
  60. }
  61. return checksum
  62. }
  63. func part1(diskMap []int) int64 {
  64. free, disk := getDisk(diskMap)
  65. compacted := compact(disk, free)
  66. return calculateChecksum(compacted)
  67. }
  68. func findFile(disk []int, id, end int) int {
  69. for i := end; i > 0; i-- {
  70. if disk[i] != id {
  71. return i + 1
  72. }
  73. }
  74. return -1
  75. }
  76. func findFree(disk []int, start, end, goal int) (int, int) {
  77. var freeStart, freeEnd int
  78. for i := start; i < end; i++ {
  79. if disk[i] == -1 {
  80. if freeStart <= 0 {
  81. freeStart = i
  82. for j := freeStart + 1; j < freeStart+goal; j++ {
  83. if disk[j] != -1 {
  84. freeStart = -1
  85. i = j
  86. break
  87. }
  88. }
  89. if freeStart > 0 {
  90. return freeStart, freeStart + goal
  91. }
  92. }
  93. }
  94. }
  95. return freeStart, freeEnd
  96. }
  97. func defrag(diskMap []int) []int {
  98. free, disk := getDisk(diskMap)
  99. end := len(disk) - 1
  100. for i := end; i > free; i-- {
  101. if disk[i] > 0 {
  102. fileStart := findFile(disk, disk[i], i)
  103. if fileStart > 0 {
  104. freeStart, freeEnd := findFree(disk, free, fileStart, i-fileStart+1)
  105. if freeStart > 0 && freeEnd > 0 && freeStart < freeEnd {
  106. for k := freeStart; k < freeEnd; k++ {
  107. disk[k] = disk[i]
  108. }
  109. for k := fileStart; k <= i; k++ {
  110. disk[k] = -1
  111. }
  112. }
  113. i = fileStart
  114. }
  115. }
  116. }
  117. return disk
  118. }
  119. func part2(diskMap []int) int64 {
  120. defragmented := defrag(diskMap)
  121. return calculateChecksum(defragmented)
  122. }
  123. func main() {
  124. if len(os.Args) < 2 {
  125. log.Fatal("You need to specify a file!")
  126. }
  127. data, err := os.ReadFile(os.Args[1])
  128. if err != nil {
  129. log.Fatal(err)
  130. }
  131. diskMap := getDiskMap(data)
  132. fmt.Println("Part1:", part1(diskMap))
  133. fmt.Println("Part2:", part2(diskMap))
  134. }