package main
import (
"bufio"
"log"
"os"
"regexp"
"strconv"
"strings"
)
type cuboid struct {
state string
xmin, xmax int
ymin, ymax int
zmin, zmax int
}
func main() {
if err := myMain(); err != nil {
log.Println(err)
}
}
func myMain() error {
cbs, err := parseInput("input.txt")
if err != nil {
return err
}
log.Println(solveFirst(cbs))
log.Println(solveSecond(cbs))
return nil
}
type point struct {
x, y, z int
}
func solveFirst(cbs []cuboid) int {
const (
rangeMin = -50
rangeMax = 50
)
m := map[point]struct{}{}
for _, cb := range cbs {
for x := max(cb.xmin, rangeMin); x <= min(cb.xmax, rangeMax); x++ {
for y := max(cb.ymin, rangeMin); y <= min(cb.ymax, rangeMax); y++ {
for z := max(cb.zmin, rangeMin); z <= min(cb.zmax, rangeMax); z++ {
switch cb.state {
case "on":
m[point{x, y, z}] = struct{}{}
case "off":
delete(m, point{x, y, z})
default:
log.Panicln("no such state")
}
}
}
}
}
return len(m)
}
type subcubes map[cuboid]int
func solveSecond(cbs []cuboid) int {
m := subcubes{}
for _, cube := range cbs {
subMap := subcubes{}
for orig := range m {
ovrlp := overlap(cube, orig)
if ovrlp.state == "noop" {
continue
}
subMap[ovrlp] -= m[orig]
}
if cube.state == "on" {
subMap[cube] += 1
}
for c := range subMap {
m[c] += subMap[c]
}
}
var sum int
for cube, v := range m {
sum += cube.size() * v
}
return sum
}
func (c cuboid) size() int {
return (c.xmax - c.xmin + 1) * (c.ymax - c.ymin + 1) * (c.zmax - c.zmin + 1)
}
func overlap(first, second cuboid) cuboid {
if first.xmax < second.xmin || second.xmax < first.xmin ||
first.ymax < second.ymin || second.ymax < first.ymin ||
first.zmax < second.zmin || second.zmax < first.zmin {
return cuboid{state: "noop"}
}
return cuboid{"",
max(first.xmin, second.xmin), min(first.xmax, second.xmax),
max(first.ymin, second.ymin), min(first.ymax, second.ymax),
max(first.zmin, second.zmin), min(first.zmax, second.zmax),
}
}
func min(x, y int) int {
if x < y {
return x
}
return y
}
func max(x, y int) int {
if x > y {
return x
}
return y
}
func parseInput(fileName string) ([]cuboid, error) {
ret := []cuboid{}
fd, err := os.Open(fileName)
if err != nil {
return ret, err
}
defer fd.Close()
re := regexp.MustCompile(`[-]*\d+`)
buf := bufio.NewScanner(fd)
for buf.Scan() {
line := cuboid{}
state := strings.Split(buf.Text(), " ")
line.state = state[0]
tmp := re.FindAllString(buf.Text(), -1)
line.xmin, err = strconv.Atoi(tmp[0])
if err != nil {
return ret, err
}
line.xmax, err = strconv.Atoi(tmp[1])
if err != nil {
return ret, err
}
line.ymin, err = strconv.Atoi(tmp[2])
if err != nil {
return ret, err
}
line.ymax, err = strconv.Atoi(tmp[3])
if err != nil {
return ret, err
}
line.zmin, err = strconv.Atoi(tmp[4])
if err != nil {
return ret, err
}
line.zmax, err = strconv.Atoi(tmp[5])
if err != nil {
return ret, err
}
ret = append(ret, line)
}
return ret, nil
}