aoc2025/day4/main.go

120 lines
2.5 KiB
Go
Raw Normal View History

2025-12-06 13:17:34 -05:00
package main
import (
"fmt"
"os"
"strings"
"github.com/kelindar/bitmap"
)
func readLines(filename string) []string {
raw, err := os.ReadFile(filename)
if err != nil {
panic(err)
}
return strings.Split(string(raw), "\n")
}
type warehouse struct {
2025-12-06 19:41:51 -05:00
boxes *bitmap.Bitmap
2025-12-06 13:17:34 -05:00
width uint32
height uint32
}
func buildWarehouse(lines []string) warehouse {
2025-12-06 19:41:51 -05:00
wh := warehouse{
boxes: &bitmap.Bitmap{},
}
2025-12-06 13:17:34 -05:00
wh.height = uint32(len(lines))
if wh.height == 0 {
return wh
}
wh.width = uint32(len(lines[0]))
if wh.width == 0 {
return wh
}
for y, line := range lines {
for x, char := range line {
if char == '@' {
2025-12-06 19:41:51 -05:00
set(wh.boxes, wh.width, wh.height, uint32(x), uint32(y))
2025-12-06 13:17:34 -05:00
}
}
}
return wh
}
func set(area *bitmap.Bitmap, width uint32, height uint32, x uint32, y uint32) {
if x >= width || y >= height {
return
}
area.Set(y*width + x)
}
func debug(area *bitmap.Bitmap, width uint32) {
area.Range(func(offset uint32) {
fmt.Printf("(%d, %d)\n", offset%width, offset/width)
})
}
2025-12-06 19:41:51 -05:00
func buildNeighbors(width uint32, height uint32, offset uint32) *bitmap.Bitmap {
y := offset / width
x := offset % width
2025-12-06 13:17:34 -05:00
var neighbors bitmap.Bitmap
set(&neighbors, width, height, x+1, y)
set(&neighbors, width, height, x-1, y)
set(&neighbors, width, height, x+1, y+1)
set(&neighbors, width, height, x-1, y+1)
set(&neighbors, width, height, x+1, y-1)
set(&neighbors, width, height, x-1, y-1)
set(&neighbors, width, height, x, y+1)
set(&neighbors, width, height, x, y-1)
return &neighbors
}
func (wh warehouse) countAccessibleBoxes() uint32 {
boxes := wh.boxes.Clone(nil)
boxes.Filter(func(offset uint32) bool {
2025-12-06 19:41:51 -05:00
neighbors := buildNeighbors(wh.width, wh.height, offset)
neighbors.And(*wh.boxes)
2025-12-06 13:17:34 -05:00
accessible := neighbors.Count() < 4
return accessible
})
return uint32(boxes.Count())
}
2025-12-06 19:41:51 -05:00
func (wh *warehouse) removeAccessibleBoxes() uint32 {
boxes := wh.boxes.Clone(nil)
removed := uint32(0)
boxes.Filter(func(offset uint32) bool {
neighbors := buildNeighbors(wh.width, wh.height, offset)
neighbors.And(*wh.boxes)
accessible := neighbors.Count() < 4
if accessible {
removed++
}
return !accessible
})
wh.boxes = &boxes
return removed
}
2025-12-06 13:17:34 -05:00
func main() {
filename := "input0.txt"
if len(os.Args) > 1 {
filename = os.Args[1]
}
lines := readLines(filename)
wh := buildWarehouse(lines)
fmt.Printf("%v\n", wh.countAccessibleBoxes())
2025-12-06 19:41:51 -05:00
total := uint32(0)
for {
count := wh.removeAccessibleBoxes()
if count == 0 {
break
}
total += count
}
fmt.Printf("%v\n", total)
2025-12-06 13:17:34 -05:00
}