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 { boxes *bitmap.Bitmap width uint32 height uint32 } func buildWarehouse(lines []string) warehouse { wh := warehouse{ boxes: &bitmap.Bitmap{}, } 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 == '@' { set(wh.boxes, wh.width, wh.height, uint32(x), uint32(y)) } } } 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) }) } func buildNeighbors(width uint32, height uint32, offset uint32) *bitmap.Bitmap { y := offset / width x := offset % width 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 { neighbors := buildNeighbors(wh.width, wh.height, offset) neighbors.And(*wh.boxes) accessible := neighbors.Count() < 4 return accessible }) return uint32(boxes.Count()) } 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 } 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()) total := uint32(0) for { count := wh.removeAccessibleBoxes() if count == 0 { break } total += count } fmt.Printf("%v\n", total) }