2018 Complete!
This commit is contained in:
parent
0044574db3
commit
056ba2d484
55
2018/day25/constellation.go
Normal file
55
2018/day25/constellation.go
Normal file
@ -0,0 +1,55 @@
|
||||
package main
|
||||
|
||||
import "math"
|
||||
|
||||
type Coordinate [4]int
|
||||
|
||||
func (c Coordinate) Distance(b Coordinate) int {
|
||||
sum := 0
|
||||
for i := 0; i < 4; i++ {
|
||||
sum += abs(c[i] - b[i])
|
||||
}
|
||||
return sum
|
||||
}
|
||||
|
||||
type Constellation map[Coordinate]struct{}
|
||||
|
||||
func (c Constellation) Distance(b Coordinate) int {
|
||||
shortestDistance := math.MaxInt64
|
||||
|
||||
for p := range c {
|
||||
if p.Distance(b) < shortestDistance {
|
||||
shortestDistance = p.Distance(b)
|
||||
}
|
||||
}
|
||||
|
||||
return shortestDistance
|
||||
}
|
||||
|
||||
func (c Constellation) CelestialDistance(b Constellation) int {
|
||||
shortestDistance := math.MaxInt64
|
||||
|
||||
for p := range c {
|
||||
if b.Distance(p) < shortestDistance {
|
||||
shortestDistance = b.Distance(p)
|
||||
}
|
||||
}
|
||||
|
||||
return shortestDistance
|
||||
}
|
||||
|
||||
func (c Constellation) Add(b Coordinate) {
|
||||
c[b] = struct{}{}
|
||||
}
|
||||
|
||||
func (c Constellation) Merge(b Constellation) {
|
||||
for p := range b {
|
||||
c[p] = struct{}{}
|
||||
delete(b, p)
|
||||
}
|
||||
}
|
||||
|
||||
func NewConstellation(b Coordinate) Constellation {
|
||||
c := Constellation{b: struct{}{}}
|
||||
return c
|
||||
}
|
@ -2,146 +2,70 @@ package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var grid *Grid
|
||||
|
||||
// Pt 1
|
||||
// 431 too high
|
||||
func main() {
|
||||
input := stdinToStringSlice()
|
||||
grid = &Grid{}
|
||||
for _, v := range input {
|
||||
grid.addPoint(v)
|
||||
inp := StdinToStringSlice()
|
||||
fmt.Println(HotChocolatePortal(inp))
|
||||
}
|
||||
|
||||
func HotChocolatePortal(input []string) int {
|
||||
var constellations []Constellation
|
||||
|
||||
for _, line := range input {
|
||||
var c Coordinate
|
||||
|
||||
if _, err := fmt.Sscanf(line, "%d,%d,%d,%d", &c[0], &c[1], &c[2], &c[3]); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
last := len(grid.constellations)
|
||||
for grid.checkMerges() {
|
||||
fmt.Println("++ merge ++ ", len(grid.constellations))
|
||||
if len(grid.constellations) == last {
|
||||
|
||||
var found bool
|
||||
for _, constellation := range constellations {
|
||||
if constellation.Distance(c) <= 3 {
|
||||
constellation.Add(c)
|
||||
found = true
|
||||
break
|
||||
}
|
||||
last = len(grid.constellations)
|
||||
}
|
||||
fmt.Println("Points:", len(grid.points))
|
||||
fmt.Println("Constellations:", len(grid.constellations))
|
||||
}
|
||||
if !found {
|
||||
constellations = append(constellations, NewConstellation(c))
|
||||
}
|
||||
}
|
||||
|
||||
type Grid struct {
|
||||
points []*Pos
|
||||
constellations []*Constellation
|
||||
}
|
||||
var nc []Constellation
|
||||
for i, a := range constellations {
|
||||
merged := false
|
||||
|
||||
func (g *Grid) checkMerges() bool {
|
||||
for ci, c := range g.constellations {
|
||||
for _, p := range c.points {
|
||||
for wrki, wrk := range g.constellations {
|
||||
if wrki == ci {
|
||||
for j, b := range constellations {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
if wrk.should(p) {
|
||||
g.merge(ci, wrki)
|
||||
g.remove(wrki)
|
||||
return true
|
||||
|
||||
if b.CelestialDistance(a) <= 3 {
|
||||
b.Merge(a)
|
||||
merged = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !merged {
|
||||
nc = append(nc, a)
|
||||
}
|
||||
}
|
||||
fmt.Println("Nothing merged")
|
||||
return false
|
||||
|
||||
return len(nc)
|
||||
}
|
||||
|
||||
func (g *Grid) addPoint(inp string) {
|
||||
pts := strings.Split(inp, ",")
|
||||
pt := &Pos{
|
||||
x: atoi(pts[0]),
|
||||
y: atoi(pts[1]),
|
||||
z: atoi(pts[2]),
|
||||
t: atoi(pts[3]),
|
||||
}
|
||||
g.points = append(g.points, pt)
|
||||
|
||||
// Check if this point is within 3 from any other points
|
||||
cIdx := -1
|
||||
var mergedIdx []int
|
||||
for i, v := range g.constellations {
|
||||
if v.should(pt) {
|
||||
if cIdx >= 0 {
|
||||
g.merge(cIdx, i)
|
||||
mergedIdx = append(mergedIdx, i)
|
||||
} else {
|
||||
cIdx = i
|
||||
g.constellations[cIdx].add(pt)
|
||||
}
|
||||
}
|
||||
}
|
||||
for i := range mergedIdx {
|
||||
g.remove(i)
|
||||
}
|
||||
if cIdx == -1 {
|
||||
c := &Constellation{}
|
||||
c.add(pt)
|
||||
g.constellations = append(g.constellations, c)
|
||||
func abs(num int) int {
|
||||
if num < 0 {
|
||||
return num * -1
|
||||
}
|
||||
return num
|
||||
}
|
||||
|
||||
func (g *Grid) merge(c1Idx, c2Idx int) error {
|
||||
fmt.Println(" Merging", c1Idx, c2Idx)
|
||||
if c1Idx >= len(g.constellations) || c2Idx >= len(g.constellations) {
|
||||
return errors.New("Invalid Constellation Index")
|
||||
}
|
||||
for _, v := range g.constellations[c2Idx].points {
|
||||
g.constellations[c1Idx].add(v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *Grid) remove(remIdx int) error {
|
||||
if remIdx >= len(g.constellations) {
|
||||
return errors.New("Invalid Constellation Index")
|
||||
}
|
||||
g.constellations = append(g.constellations[:remIdx], g.constellations[remIdx+1:]...)
|
||||
return nil
|
||||
}
|
||||
|
||||
type Constellation struct {
|
||||
points []*Pos
|
||||
}
|
||||
|
||||
func (c *Constellation) should(p *Pos) bool {
|
||||
for _, v := range c.points {
|
||||
if v.to(p) <= 3 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *Constellation) add(p *Pos) {
|
||||
p.constellation = c
|
||||
c.points = append(c.points, p)
|
||||
}
|
||||
|
||||
type Pos struct {
|
||||
x, y, z, t int
|
||||
constellation *Constellation
|
||||
}
|
||||
|
||||
func (p *Pos) to(p2 *Pos) int {
|
||||
xs := math.Abs(float64(p.x) - float64(p2.x))
|
||||
ys := math.Abs(float64(p.y) - float64(p2.y))
|
||||
zs := math.Abs(float64(p.z) - float64(p2.z))
|
||||
ts := math.Abs(float64(p.t) - float64(p2.t))
|
||||
return int(xs + ys + zs + ts)
|
||||
}
|
||||
|
||||
func stdinToStringSlice() []string {
|
||||
func StdinToStringSlice() []string {
|
||||
var input []string
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
for scanner.Scan() {
|
||||
@ -149,12 +73,3 @@ func stdinToStringSlice() []string {
|
||||
}
|
||||
return input
|
||||
}
|
||||
|
||||
func atoi(i string) int {
|
||||
var ret int
|
||||
var err error
|
||||
if ret, err = strconv.Atoi(i); err != nil {
|
||||
log.Fatal("Invalid Atoi: " + i)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user