105 lines
2.5 KiB
Go
105 lines
2.5 KiB
Go
package day09
|
|
|
|
func Part1(input string) int {
|
|
files, gaps, lengthOfFinalFile := parseInput(input)
|
|
checksum := compactFiles(files, gaps, lengthOfFinalFile)
|
|
return checksum
|
|
}
|
|
|
|
func Part2(input string) int {
|
|
files, freeSpaces := parseInputPart2(input)
|
|
checksum := calculateChecksum(files, freeSpaces)
|
|
return checksum
|
|
}
|
|
|
|
func parseInput(input string) ([]int, []int, int) {
|
|
var files []int
|
|
var gaps []int
|
|
lengthOfFinalFile := 0
|
|
for i, char := range input {
|
|
if i%2 == 0 {
|
|
files = append(files, int(char-'0'))
|
|
lengthOfFinalFile += int(char - '0')
|
|
} else {
|
|
gaps = append(gaps, int(char-'0'))
|
|
}
|
|
}
|
|
return files, gaps, lengthOfFinalFile
|
|
}
|
|
|
|
func parseInputPart2(input string) ([][]int, [][]int) {
|
|
files, freeSpaces, position := [][]int{}, [][]int{}, 0
|
|
for index, char := range input {
|
|
length := int(char - '0')
|
|
if index%2 == 0 {
|
|
files = append(files, generateRange(position, position+length))
|
|
} else {
|
|
freeSpaces = append(freeSpaces, generateRange(position, position+length))
|
|
}
|
|
position += length
|
|
}
|
|
return files, freeSpaces
|
|
}
|
|
|
|
func compactFiles(files []int, gaps []int, lengthOfFinalFile int) int {
|
|
fileIndex := len(files) - 1
|
|
gapIndex := 0
|
|
position := files[0]
|
|
checksum := 0
|
|
fileID := files[0]
|
|
|
|
for lengthOfFinalFile != position {
|
|
// If there's a gap and a file to move then move the file
|
|
if gaps[gapIndex] > 0 && files[fileIndex] > 0 {
|
|
files[fileIndex]--
|
|
gaps[gapIndex]--
|
|
checksum += fileIndex * position
|
|
position++
|
|
}
|
|
|
|
// If this file is fully moved go to next file
|
|
if files[fileIndex] == 0 {
|
|
fileIndex--
|
|
fileID++
|
|
}
|
|
|
|
// Update gapIndex if this gap is filled
|
|
if gaps[gapIndex] == 0 {
|
|
gapIndex++
|
|
for f := 0; f < files[gapIndex]; f++ {
|
|
checksum += gapIndex * position
|
|
position++
|
|
}
|
|
}
|
|
}
|
|
|
|
return checksum
|
|
}
|
|
|
|
func generateRange(start, end int) []int {
|
|
rangeList := make([]int, end-start)
|
|
for i := range rangeList {
|
|
rangeList[i] = start + i
|
|
}
|
|
return rangeList
|
|
}
|
|
|
|
func calculateChecksum(files, freeSpaces [][]int) int {
|
|
checksum := 0
|
|
for fileIndex := len(files) - 1; fileIndex >= 0; fileIndex-- {
|
|
for spaceIndex := 0; spaceIndex < len(freeSpaces); spaceIndex++ {
|
|
if len(freeSpaces[spaceIndex]) >= len(files[fileIndex]) && files[fileIndex][0] > freeSpaces[spaceIndex][0] {
|
|
files[fileIndex] = freeSpaces[spaceIndex][:len(files[fileIndex])]
|
|
freeSpaces[spaceIndex] = freeSpaces[spaceIndex][len(files[fileIndex]):]
|
|
}
|
|
}
|
|
}
|
|
|
|
for fileID, file := range files {
|
|
for _, block := range file {
|
|
checksum += fileID * block
|
|
}
|
|
}
|
|
return checksum
|
|
}
|