Task 9 completed
No bruteforce necessary, lets go
This commit is contained in:
parent
3108a6f90c
commit
c22cfbe185
3 changed files with 185 additions and 0 deletions
1
day9/input
Normal file
1
day9/input
Normal file
File diff suppressed because one or more lines are too long
183
day9/main.go
Normal file
183
day9/main.go
Normal file
|
@ -0,0 +1,183 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
"strconv"
|
||||
"unicode"
|
||||
|
||||
"git.mstar.dev/mstar/aoc24/util"
|
||||
"git.mstar.dev/mstar/goutils/other"
|
||||
"git.mstar.dev/mstar/goutils/sliceutils"
|
||||
)
|
||||
|
||||
const EmptyBlockId = -1
|
||||
|
||||
func findFirstEmptyIndex(list []int) (int, bool) {
|
||||
for i, v := range list {
|
||||
if v == EmptyBlockId {
|
||||
return i, true
|
||||
}
|
||||
}
|
||||
return -1, false
|
||||
}
|
||||
|
||||
func findLastUsedIndex(list []int) (int, bool) {
|
||||
for i := len(list) - 1; i >= 0; i-- {
|
||||
if list[i] != EmptyBlockId {
|
||||
return i, true
|
||||
}
|
||||
}
|
||||
return -1, false
|
||||
}
|
||||
|
||||
func indicesToBlocks(indices []int) []int {
|
||||
blocks := []int{}
|
||||
// indices are len of block, len of empty, len of block, len of empty
|
||||
isFile := true
|
||||
// block id increments each time a block with a file completes
|
||||
i := 0
|
||||
for _, size := range indices {
|
||||
// Write the full block
|
||||
for range size {
|
||||
if isFile {
|
||||
blocks = append(blocks, i)
|
||||
} else {
|
||||
blocks = append(blocks, EmptyBlockId)
|
||||
}
|
||||
}
|
||||
// If current block is a file, increment id counter
|
||||
if isFile {
|
||||
i++
|
||||
}
|
||||
// Swap state
|
||||
isFile = !isFile
|
||||
}
|
||||
return blocks
|
||||
}
|
||||
|
||||
func compactBlocks1(blocks []int) (compacted []int) {
|
||||
compacted = slices.Clone(blocks)
|
||||
|
||||
firstEmpty, _ := findFirstEmptyIndex(compacted)
|
||||
lastUsed, _ := findLastUsedIndex(compacted)
|
||||
for firstEmpty < lastUsed {
|
||||
util.SliceSwap(compacted, firstEmpty, lastUsed)
|
||||
firstEmpty, _ = findFirstEmptyIndex(compacted)
|
||||
lastUsed, _ = findLastUsedIndex(compacted)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func checksumBlocks(blocks []int) uint64 {
|
||||
var total uint64 = 0
|
||||
for i, v := range blocks {
|
||||
if v == EmptyBlockId {
|
||||
continue
|
||||
}
|
||||
total += uint64(i * v)
|
||||
}
|
||||
return total
|
||||
}
|
||||
|
||||
func findFirstEmptyBlockOfLength(list []int, length int) (int, bool) {
|
||||
lenCounter := 0
|
||||
for i, v := range list {
|
||||
if v == EmptyBlockId {
|
||||
lenCounter++
|
||||
} else {
|
||||
lenCounter = 0
|
||||
}
|
||||
if lenCounter == length {
|
||||
// Start of empty block with (at least) target length is at i - (lenCounter-1), since lenCounter starts at 0
|
||||
return i - lenCounter + 1, true
|
||||
}
|
||||
}
|
||||
return -1, false
|
||||
}
|
||||
|
||||
func findBlockById(list []int, blockId int) (start, length int, found bool) {
|
||||
length = 0
|
||||
for i := len(list) - 1; i >= 0; i-- {
|
||||
if list[i] == blockId {
|
||||
length++
|
||||
} else {
|
||||
if length != 0 {
|
||||
return i + 1, length, true
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1, -1, false
|
||||
}
|
||||
|
||||
func compactBlocks2(list []int) (compacted []int) {
|
||||
compacted = slices.Clone(list)
|
||||
lastBlockIndex, _ := findLastUsedIndex(compacted)
|
||||
lastBlockId := compacted[lastBlockIndex]
|
||||
// fmt.Printf("i1 Checking block id %d\n", lastBlockId)
|
||||
lastUsedStart, length, _ := findBlockById(compacted, lastBlockId)
|
||||
firstEmpty, found := findFirstEmptyBlockOfLength(compacted, length)
|
||||
for !found {
|
||||
lastBlockId--
|
||||
if lastBlockId < 0 {
|
||||
return
|
||||
}
|
||||
// fmt.Printf("i2 Checking block id %d\n", lastBlockId)
|
||||
lastUsedStart, length, _ = findBlockById(compacted, lastBlockId)
|
||||
firstEmpty, found = findFirstEmptyBlockOfLength(compacted, length)
|
||||
}
|
||||
for {
|
||||
// fmt.Printf(
|
||||
// "Moving block %d starting at %d with len %d to %d\n",
|
||||
// lastBlockId,
|
||||
// lastUsedStart,
|
||||
// length,
|
||||
// firstEmpty,
|
||||
// )
|
||||
for i := range length {
|
||||
util.SliceSwap(compacted, lastUsedStart+i, firstEmpty+i)
|
||||
}
|
||||
lastBlockId--
|
||||
if lastBlockId < 0 {
|
||||
return
|
||||
}
|
||||
// fmt.Printf("l1 Checking block id %d\n", lastBlockId)
|
||||
lastUsedStart, length, _ = findBlockById(compacted, lastBlockId)
|
||||
firstEmpty, found = findFirstEmptyBlockOfLength(compacted, length)
|
||||
// startLastEmpty := findStartLastEmptyBlock(compacted)
|
||||
// fmt.Printf("First empty found: %d, start last empty: %d\n", firstEmpty, startLastEmpty)
|
||||
for !found || firstEmpty > lastUsedStart {
|
||||
// fmt.Printf("No space for id %d found\n", lastBlockId)
|
||||
lastBlockId--
|
||||
if lastBlockId < 0 {
|
||||
return
|
||||
}
|
||||
// fmt.Printf("l2 Checking block id %d\n", lastBlockId)
|
||||
lastUsedStart, length, _ = findBlockById(compacted, lastBlockId)
|
||||
firstEmpty, found = findFirstEmptyBlockOfLength(compacted, length)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
rawInput := []rune(string(util.LoadFileFromArgs()))
|
||||
allNums := sliceutils.Map(
|
||||
sliceutils.Filter(rawInput, func(t rune) bool { return unicode.IsNumber(t) }),
|
||||
func(t rune) int { return other.Must(strconv.Atoi(string(t))) },
|
||||
)
|
||||
blocks := indicesToBlocks(allNums)
|
||||
// fmt.Printf("Parsed blocks: %v\n", blocks)
|
||||
compacted := compactBlocks1(blocks)
|
||||
// fmt.Printf("Compacted blocks: %v\n", compacted)
|
||||
onlySetBlocks := sliceutils.Filter(compacted, func(t int) bool { return t != EmptyBlockId })
|
||||
checksum1 := checksumBlocks(onlySetBlocks)
|
||||
fmt.Printf("Task 1: %d\n", checksum1)
|
||||
compacted2 := compactBlocks2(blocks)
|
||||
fmt.Printf(
|
||||
"Task 2: %d\n",
|
||||
checksumBlocks(
|
||||
compacted2,
|
||||
),
|
||||
)
|
||||
}
|
1
day9/sample
Normal file
1
day9/sample
Normal file
|
@ -0,0 +1 @@
|
|||
2333133121414131402
|
Loading…
Reference in a new issue