136 lines
2.5 KiB
Go
136 lines
2.5 KiB
Go
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
|
|
}
|