advent_of_code_2024/day_09/solution.go

136 lines
2.5 KiB
Go
Raw Permalink Normal View History

2024-12-09 22:53:46 +00:00
package day_09
const Empty = -1
type State int
type Chunk struct {
start, length int
}
const (
ReadingValue = iota
ReadingSpace = iota
)
// task:https://adventofcode.com/2024/day/9
func SolveBasic(input string) int {
diagram := loadDiagram(input)
diagram = compress(diagram)
return hashSum(diagram)
}
// task:https://adventofcode.com/2024/day/9#part2
func SolveComplex(input string) int {
diagram := loadDiagram(input)
diagram = safeCompress(diagram)
return hashSum(diagram)
}
func hashSum(diagram []int) int {
sum := 0
for i, val := range diagram {
if val != Empty {
sum += i * val
}
}
return sum
}
func compress(diagram []int) []int {
startingCursor := 0
endingCursor := len(diagram) - 1
for {
for diagram[startingCursor] != Empty && startingCursor < endingCursor {
startingCursor++
}
for diagram[endingCursor] == Empty && startingCursor < endingCursor {
endingCursor--
}
if startingCursor >= endingCursor {
break
}
diagram[startingCursor] = diagram[endingCursor]
diagram[endingCursor] = Empty
}
return diagram
}
func safeCompress(diagram []int) []int {
value := diagram[len(diagram)-1]
for value >= 0 {
file := locateFile(diagram, value)
if hole, found := findHole(diagram, file.start, file.length); found {
copyFile(diagram, file, value, hole)
}
value--
}
return diagram
}
func copyFile(diagram []int, file Chunk, value int, hole Chunk) {
for i := 0; i < file.length; i++ {
diagram[hole.start+i] = value
diagram[file.start+i] = Empty
}
}
func findHole(diagram []int, end int, length int) (Chunk, bool) {
for i := 0; i < end; i++ {
if diagram[i] == Empty {
size := 0
for i+size < end && diagram[i+size] == Empty {
size++
}
if size >= length {
return Chunk{i, size}, true
}
}
}
return Chunk{}, false
}
func locateFile(diagram []int, value int) Chunk {
length := 0
for i := 0; i < len(diagram); i++ {
if diagram[i] == value {
start := i
for i+length < len(diagram) && diagram[i+length] == value {
length++
}
return Chunk{start, length}
}
}
panic("couldn't find the value")
}
func loadDiagram(input string) []int {
diagram := make([]int, 0, len(input)*5) // we reserve about the average we need
state := ReadingValue
currentValue := 0
for _, r := range input {
lenght := int(r - '0')
if state == ReadingValue {
for i := 0; i < lenght; i++ {
diagram = append(diagram, currentValue)
}
currentValue++
} else {
for i := 0; i < lenght; i++ {
diagram = append(diagram, Empty)
}
}
state = (state + 1) % 2
}
return diagram
}