package main
import (
"bufio"
"fmt"
"os"
"strings"
)
const (
gridX = 1000
gridY = 1000
gridSize = gridX * gridY
)
type Puzzle struct {
Collides map[int]bool
Grid [gridSize]int
}
func (p *Puzzle) Add(num, x, y, w, h int) {
if x+w > gridX || y+h > gridY {
return
}
if p.Collides == nil {
p.Collides = make(map[int]bool)
}
if _, ok := p.Collides[num]; !ok {
p.Collides[num] = false
}
for yy := y; yy < y+h; yy++ {
for xx := x; xx < x+w; xx++ {
i := (yy * gridX) + xx
if p.Grid[i] == 0 {
p.Grid[i] = num
} else {
p.Collides[num] = true
p.Collides[p.Grid[i]] = true
p.Grid[i] = -1
}
}
}
}
func (p *Puzzle) NumCollisions() int {
collisions := 0
for y := 0; y < gridY; y++ {
for x := 0; x < gridX; x++ {
i := (y * gridX) + x
if p.Grid[i] > 1 {
collisions++
}
}
}
return collisions
}
func (p *Puzzle) Spared() int {
for id, collides := range p.Collides {
if !collides {
return id
}
}
return -1
}
func (p Puzzle) String() string {
output := strings.Builder{}
output.Grow(gridSize)
for y := 0; y < gridY; y++ {
for x := 0; x < gridX; x++ {
i := (y * gridX) + x
switch p.Grid[i] {
case 0:
output.WriteByte('.')
case -1:
output.WriteByte('x')
default:
output.WriteByte('+')
}
}
output.WriteByte('\n')
}
return output.String()
}
func main() {
input, err := os.Open("input.txt")
if err != nil {
panic(err.Error())
}
defer input.Close()
scanner := bufio.NewScanner(input)
p := Puzzle{}
for scanner.Scan() {
var num, x, y, w, h int
fmt.Sscanf(scanner.Text(), "#%d @ %d,%d: %dx%d", &num, &x, &y, &w, &h)
p.Add(num, x, y, w, h)
}
if err := scanner.Err(); err != nil {
panic(err.Error())
}
fmt.Println("Collisions:", p.NumCollisions())
fmt.Println("Spared:", p.Spared())
}