package main
import (
"bufio"
"log"
"os"
"regexp"
"strconv"
"strings"
)
const (
coords = 3
overlap = 12
rotation = 24
)
type scanLine struct {
x, y, z int
}
type scanData struct {
sPos scanLine beacons []scanLine
}
type scanDatas []scanData
func main() {
if err := myMain(); err != nil {
log.Println(err)
}
}
func myMain() error {
sds, err := parseInput("input.txt")
if err != nil {
return err
}
log.Println(solveFirst(sds))
return nil
}
func solveFirst(sds scanDatas) int {
absolutes := map[scanLine]struct{}{}
sds[0].sPos = scanLine{0, 0, 0}
for _, s := range sds[0].beacons {
absolutes[s] = struct{}{}
}
skip := make([]bool, len(sds))
skip[0] = true
for !allTrue(skip) {
start:
for scanNo := range sds {
if skip[scanNo] {
continue
}
for rot := 0; rot < rotation; rot++ {
offsets := map[scanLine]int{}
for _, sl := range sds[scanNo].beacons {
for abs := range absolutes {
tmp := sl.rotate(rot).sub(abs)
offsets[tmp]++
if offsets[tmp] >= overlap {
sds[scanNo].sPos = scanLine{-tmp.x, -tmp.y, -tmp.z}
for _, line := range sds[scanNo].beacons {
absolutes[line.rotate(rot).sub(tmp)] = struct{}{}
}
skip[scanNo] = true
continue start
}
}
}
}
}
}
var max int
for _, first := range sds {
for _, second := range sds {
if d := distance(first.sPos, second.sPos); d > max {
max = d
}
}
}
log.Println(max)
return len(absolutes)
}
func distance(first, second scanLine) int {
return abs(first.x-second.x) + abs(first.y-second.y) + abs(first.z-second.z)
}
func abs(in int) int {
if in < 0 {
return -in
}
return in
}
func allTrue(in []bool) bool {
for _, v := range in {
if v != true {
return false
}
}
return true
}
func (s scanLine) sub(in scanLine) scanLine {
return scanLine{s.x - in.x, s.y - in.y, s.z - in.z}
}
func (v scanLine) rotate(r int) scanLine {
switch r {
case 0:
return scanLine{v.x, v.y, v.z}
case 1:
return scanLine{v.x, -v.z, v.y}
case 2:
return scanLine{v.x, -v.y, -v.z}
case 3:
return scanLine{v.x, v.z, -v.y}
case 4:
return scanLine{-v.x, -v.y, v.z}
case 5:
return scanLine{-v.x, -v.z, -v.y}
case 6:
return scanLine{-v.x, v.y, -v.z}
case 7:
return scanLine{-v.x, v.z, v.y}
case 8:
return scanLine{v.y, v.x, -v.z}
case 9:
return scanLine{v.y, -v.x, v.z}
case 10:
return scanLine{v.y, v.z, v.x}
case 11:
return scanLine{v.y, -v.z, -v.x}
case 12:
return scanLine{-v.y, v.x, v.z}
case 13:
return scanLine{-v.y, -v.x, -v.z}
case 14:
return scanLine{-v.y, -v.z, v.x}
case 15:
return scanLine{-v.y, v.z, -v.x}
case 16:
return scanLine{v.z, v.x, v.y}
case 17:
return scanLine{v.z, -v.x, -v.y}
case 18:
return scanLine{v.z, -v.y, v.x}
case 19:
return scanLine{v.z, v.y, -v.x}
case 20:
return scanLine{-v.z, v.x, -v.y}
case 21:
return scanLine{-v.z, -v.x, v.y}
case 22:
return scanLine{-v.z, v.y, v.x}
case 23:
return scanLine{-v.z, -v.y, -v.x}
default:
log.Panicln("no such rotation:", r)
return scanLine{}
}
}
func parseInput(fileName string) ([]scanData, error) {
ret := []scanData{}
fd, err := os.Open(fileName)
if err != nil {
return ret, err
}
defer fd.Close()
re := regexp.MustCompile(`[-]*\d+`)
buf := bufio.NewScanner(fd)
sd := scanData{}
for buf.Scan() {
if buf.Text() == "" {
ret = append(ret, sd)
sd = scanData{}
continue
}
if strings.HasPrefix(buf.Text(), "---") {
continue
}
tmp := re.FindAllString(buf.Text(), -1)
line := scanLine{}
line.x, err = strconv.Atoi(tmp[0])
if err != nil {
return ret, err
}
line.y, err = strconv.Atoi(tmp[1])
if err != nil {
return ret, err
}
line.z, err = strconv.Atoi(tmp[2])
if err != nil {
return ret, err
}
sd.beacons = append(sd.beacons, line)
}
if len(sd.beacons) != 0 {
ret = append(ret, sd)
}
return ret, nil
}