Compare commits

...

5 commits

Author SHA1 Message Date
495d50ba10 🐛 Account for file ids > 9 2024-12-09 14:34:01 -06:00
a495a2ef1a Implement Blocks function 2024-12-09 12:49:56 -06:00
ac16a3f167 🚸 Fill out cmd 2024-12-09 12:35:54 -06:00
932e8e2f11 🚧 Add Defrag function 2024-12-09 12:30:41 -06:00
2f165369cc 📝 Add instructions 2024-12-09 08:47:11 -06:00
9 changed files with 231 additions and 1 deletions

1
.gitignore vendored
View file

@ -23,3 +23,4 @@ go.work.sum
# env file # env file
.env .env
defrag

View file

@ -1,3 +1,66 @@
# Day 9: Disk Defragmenter # Day 9: Disk Defragmenter
[Link](https://adventofcode.com/2024/day/9) [Link](https://adventofcode.com/2024/day/9)
## Day 9: Disk Fragmenter
Another push of the button leaves you in the familiar hallways of some friendly [amphipods](https://adventofcode.com/2021/day/23)! Good thing you each somehow got your own personal mini submarine. The Historians jet away in search of the Chief, mostly by driving directly into walls.
While The Historians quickly figure out how to pilot these things, you notice an amphipod in the corner struggling with his computer. He's trying to make more contiguous free space by compacting all of the files, but his program isn't working; you offer to help.
He shows you the **disk map** (your puzzle input) he's already generated. For example:
```
2333133121414131402
```
The disk map uses a dense format to represent the layout of **files** and **free space** on the disk. The digits alternate between indicating the length of a file and the length of free space.
So, a disk map like `12345` would represent a one-block file, two blocks of free space, a three-block file, four blocks of free space, and then a five-block file. A disk map like `90909` would represent three nine-block files in a row (with no free space between them).
Each file on disk also has an **ID number** based on the order of the files as they appear **before** they are rearranged, starting with ID 0. So, the disk map 12345 has three files: a one-block file with ID 0, a three-block file with ID 1, and a five-block file with ID 2. Using one character for each block where digits are the file ID and . is free space, the disk map 12345 represents these individual blocks:
```
0..111....22222
```
The first example above, `2333133121414131402`, represents these individual blocks:
```
00...111...2...333.44.5555.6666.777.888899
```
The amphipod would like to **move file blocks one at a time** from the end of the disk to the leftmost free space block (until there are no gaps remaining between file blocks). For the disk map 12345, the process looks like this:
```
0..111....22222
02.111....2222.
022111....222..
0221112...22...
02211122..2....
022111222......
```
The first example requires a few more steps:
```
00...111...2...333.44.5555.6666.777.888899
009..111...2...333.44.5555.6666.777.88889.
0099.111...2...333.44.5555.6666.777.8888..
00998111...2...333.44.5555.6666.777.888...
009981118..2...333.44.5555.6666.777.88....
0099811188.2...333.44.5555.6666.777.8.....
009981118882...333.44.5555.6666.777.......
0099811188827..333.44.5555.6666.77........
00998111888277.333.44.5555.6666.7.........
009981118882777333.44.5555.6666...........
009981118882777333644.5555.666............
00998111888277733364465555.66.............
0099811188827773336446555566..............
```
The final step of this file-compacting process is to update the **filesystem checksum**. To calculate the checksum, add up the result of multiplying each of these blocks' position with the file ID number it contains. The leftmost block is in position 0. If a block contains free space, skip it instead.
Continuing the first example, the first few blocks' position multiplied by its file ID number are `0 * 0 = 0`, `1 * 0 = 0`, `2 * 9 = 18`, `3 * 9 = 27`, `4 * 8 = 32`, and so on. In this example, the checksum is the sum of these, **1928**.
Compact the amphipod's hard drive using the process he requested. What is the resulting filesystem checksum?

31
blocks.go Normal file
View file

@ -0,0 +1,31 @@
package defrag
import (
"strconv"
)
func Blocks(diskMap []byte) ([]int, error) {
current := 0
onFile := false
out := []int{}
for _, by := range diskMap {
count, err := strconv.Atoi(string(by))
if err != nil {
return nil, err
}
onFile = !onFile
if count == 0 {
continue
}
val := -1
if onFile {
val = current
current++
}
for idx := 0; idx < count; idx++ {
out = append(out, val)
}
}
return out, nil
}

30
blocks_test.go Normal file
View file

@ -0,0 +1,30 @@
package defrag
import (
"testing"
"github.com/stretchr/testify/require"
)
type tt struct {
name string
diskMap []byte
blocks []int
}
func sampleTests() []tt {
return []tt{
{"short", []byte("12345"), []int{0, -1, -1, 1, 1, 1, -1, -1, -1, -1, 2, 2, 2, 2, 2}},
{"longer", []byte("2333133121414131402"), []int{0, 0, -1, -1, -1, 1, 1, 1, -1, -1, -1, 2, -1, -1, -1, 3, 3, 3, -1, 4, 4, -1, 5, 5, 5, 5, -1, 6, 6, 6, 6, -1, 7, 7, 7, -1, 8, 8, 8, 8, 9, 9}},
}
}
func TestBlocks(t *testing.T) {
for _, testcase := range sampleTests() {
t.Run(testcase.name, func(sub *testing.T) {
blocks, err := Blocks(testcase.diskMap)
require.NoError(sub, err)
require.Equal(sub, testcase.blocks, blocks)
})
}
}

14
checksum.go Normal file
View file

@ -0,0 +1,14 @@
package defrag
// import "strconv"
func Checksum(blocks []int) (sum int, err error) {
for idx, fileByte := range blocks {
if fileByte == -1 {
break
}
sum += idx * fileByte
}
return
}

47
cmd/defrag/main.go Normal file
View file

@ -0,0 +1,47 @@
package main
import (
"bytes"
"fmt"
"io"
"os"
"codeberg.org/danjones000/advent-of-code/2024-09/defrag"
)
func handleErr(err error) {
if err == nil {
return
}
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
func main() {
name := os.Args[0]
input, err := io.ReadAll(os.Stdin)
handleErr(err)
fmt.Fprintln(os.Stderr, "Welcome to ", name)
input = bytes.TrimSpace(input)
blocks, err := defrag.Blocks(input)
handleErr(err)
err = defrag.Defrag(blocks)
handleErr(err)
fmt.Println("From this")
fmt.Printf("%s\n", input)
fmt.Println("Got this")
fmt.Printf("%v\n", blocks)
sum, err := defrag.Checksum(blocks)
handleErr(err)
fmt.Println("Checksum:")
fmt.Printf("%d\n", sum)
}

26
defrag.go Normal file
View file

@ -0,0 +1,26 @@
package defrag
// Defrag performs an in-place sort of blocks.
// If an error occurs during processing, it will be returned. The slice may have been partially sorted.
func Defrag(blocks []int) error {
lastPulled := len(blocks)
lastPushed := -1
for block := 0; block < len(blocks); block++ {
if blocks[block] != -1 {
continue
}
if lastPulled <= block {
break
}
for swap := lastPulled - 1; swap > lastPushed; swap-- {
if blocks[swap] == -1 {
continue
}
blocks[block], blocks[swap] = blocks[swap], blocks[block]
lastPulled = swap
lastPushed = block
break
}
}
return nil
}

10
go.mod
View file

@ -1,3 +1,11 @@
module codeberg.org/danjones000/advent-of-code-2024-09 module codeberg.org/danjones000/advent-of-code/2024-09/defrag
go 1.23.1 go 1.23.1
require github.com/stretchr/testify v1.10.0
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

10
go.sum Normal file
View file

@ -0,0 +1,10 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=