93 lines
1.9 KiB
Go
93 lines
1.9 KiB
Go
|
|
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{}
|
||
|
|
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, x uint32, y uint32) *bitmap.Bitmap {
|
||
|
|
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 {
|
||
|
|
y := offset / wh.width
|
||
|
|
x := offset % wh.width
|
||
|
|
neighbors := buildNeighbors(wh.width, wh.height, x, y)
|
||
|
|
neighbors.And(wh.boxes)
|
||
|
|
accessible := neighbors.Count() < 4
|
||
|
|
return accessible
|
||
|
|
})
|
||
|
|
return uint32(boxes.Count())
|
||
|
|
}
|
||
|
|
|
||
|
|
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())
|
||
|
|
}
|