2017 Day 20 Complete!
This commit is contained in:
215
2017/day20/day20.go
Normal file
215
2017/day20/day20.go
Normal file
@@ -0,0 +1,215 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var particles map[int]*Particle
|
||||
var confidenceThreshold int
|
||||
|
||||
func main() {
|
||||
inp := StdinToStrings()
|
||||
particles = make(map[int]*Particle)
|
||||
for i := range inp {
|
||||
particles[i] = NewParticle(inp[i], i)
|
||||
}
|
||||
confidenceThreshold = 1000
|
||||
doPart := 2
|
||||
if len(os.Args) > 1 {
|
||||
if os.Args[1] == "-1" {
|
||||
doPart = 1
|
||||
}
|
||||
}
|
||||
switch doPart {
|
||||
case 1:
|
||||
part1(inp)
|
||||
case 2:
|
||||
part2(inp)
|
||||
}
|
||||
}
|
||||
|
||||
func part1(inp []string) {
|
||||
var ticks, confidence, last int
|
||||
cPart := -1
|
||||
for {
|
||||
cDist := 10000000000
|
||||
ticks++
|
||||
for i := range particles {
|
||||
particles[i].Tick()
|
||||
if particles[i].GetDistance() < cDist {
|
||||
cPart = i
|
||||
cDist = particles[i].GetDistance()
|
||||
}
|
||||
}
|
||||
if cPart == last {
|
||||
confidence++
|
||||
} else {
|
||||
confidence = 0
|
||||
last = cPart
|
||||
}
|
||||
if confidence >= confidenceThreshold {
|
||||
break
|
||||
}
|
||||
}
|
||||
fmt.Println("After", ticks, "the closest is", cPart)
|
||||
}
|
||||
|
||||
func part2(inp []string) {
|
||||
var ticks, lastNum, confidence int
|
||||
for {
|
||||
ticks++
|
||||
for i := range particles {
|
||||
particles[i].Tick()
|
||||
}
|
||||
var collisions []int
|
||||
for k1, v1 := range particles {
|
||||
for k2, v2 := range particles {
|
||||
if k1 == k2 {
|
||||
continue
|
||||
}
|
||||
if v1.Collides(v2) {
|
||||
collisions = AddToSlice(collisions, k1)
|
||||
collisions = AddToSlice(collisions, k2)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
for i := len(collisions) - 1; i >= 0; i-- {
|
||||
delete(particles, collisions[i])
|
||||
}
|
||||
if len(particles) == lastNum {
|
||||
confidence++
|
||||
} else {
|
||||
confidence = 0
|
||||
lastNum = len(particles)
|
||||
}
|
||||
if confidence >= confidenceThreshold {
|
||||
break
|
||||
}
|
||||
}
|
||||
fmt.Println("After", ticks, "there are", len(particles), "particles left")
|
||||
}
|
||||
|
||||
func AddToSlice(sl []int, v int) []int {
|
||||
for i := range sl {
|
||||
if sl[i] == v {
|
||||
return sl
|
||||
}
|
||||
}
|
||||
sl = append(sl, v)
|
||||
return sl
|
||||
}
|
||||
|
||||
type Coordinate struct {
|
||||
X, Y, Z int
|
||||
}
|
||||
|
||||
func NewCoordinate(inp string) Coordinate {
|
||||
inp = inp[1 : len(inp)-1]
|
||||
pts := strings.Split(inp, ",")
|
||||
px, py, pz := Atoi(pts[0]), Atoi(pts[1]), Atoi(pts[2])
|
||||
return Coordinate{X: px, Y: py, Z: pz}
|
||||
}
|
||||
|
||||
func (c *Coordinate) toString() string {
|
||||
return fmt.Sprintf("<%d,%d,%d>", c.X, c.Y, c.Z)
|
||||
}
|
||||
|
||||
type Particle struct {
|
||||
Index int
|
||||
Position Coordinate
|
||||
Velocity Coordinate
|
||||
Acceleration Coordinate
|
||||
|
||||
LastPosition Coordinate
|
||||
}
|
||||
|
||||
func NewParticle(inp string, idx int) *Particle {
|
||||
ret := new(Particle)
|
||||
ret.Index = idx
|
||||
pts := strings.Split(inp, " ")
|
||||
for i := range pts {
|
||||
keyVal := strings.Split(pts[i], "=")
|
||||
if keyVal[1][len(keyVal[1])-1] == ',' {
|
||||
keyVal[1] = keyVal[1][:len(keyVal[1])-1]
|
||||
}
|
||||
switch keyVal[0] {
|
||||
case "p":
|
||||
ret.Position = NewCoordinate(keyVal[1])
|
||||
case "v":
|
||||
ret.Velocity = NewCoordinate(keyVal[1])
|
||||
case "a":
|
||||
ret.Acceleration = NewCoordinate(keyVal[1])
|
||||
}
|
||||
}
|
||||
ret.LastPosition = NewCoordinate(ret.Position.toString())
|
||||
return ret
|
||||
}
|
||||
|
||||
func (p *Particle) Collides(tst *Particle) bool {
|
||||
if p.Position.X == tst.Position.X &&
|
||||
p.Position.Y == tst.Position.Y &&
|
||||
p.Position.Z == tst.Position.Z {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *Particle) String() string {
|
||||
return fmt.Sprintf(
|
||||
"p=<%d,%d,%d>, v=<%d,%d,%d>, a=<%d,%d,%d>",
|
||||
p.Position.X, p.Position.Y, p.Position.Z,
|
||||
p.Velocity.X, p.Velocity.Y, p.Velocity.Z,
|
||||
p.Acceleration.X, p.Acceleration.Y, p.Acceleration.Z,
|
||||
)
|
||||
}
|
||||
|
||||
func (p *Particle) Tick() {
|
||||
p.LastPosition = NewCoordinate(p.Position.toString())
|
||||
p.Velocity.X += p.Acceleration.X
|
||||
p.Velocity.Y += p.Acceleration.Y
|
||||
p.Velocity.Z += p.Acceleration.Z
|
||||
p.Position.X += p.Velocity.X
|
||||
p.Position.Y += p.Velocity.Y
|
||||
p.Position.Z += p.Velocity.Z
|
||||
}
|
||||
|
||||
func (p *Particle) IsDone() bool {
|
||||
return p.GetDistance() == p.GetLastDistance()
|
||||
}
|
||||
|
||||
func (p *Particle) GetDistance() int {
|
||||
return GetAbs(p.Position.X) + GetAbs(p.Position.Y) + GetAbs(p.Position.Z)
|
||||
}
|
||||
|
||||
func (p *Particle) GetLastDistance() int {
|
||||
return int(math.Abs(float64(p.LastPosition.X + p.LastPosition.Y + p.LastPosition.Z)))
|
||||
}
|
||||
|
||||
func StdinToStrings() []string {
|
||||
var input []string
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
for scanner.Scan() {
|
||||
input = append(input, scanner.Text())
|
||||
}
|
||||
return input
|
||||
}
|
||||
|
||||
func GetAbs(v int) int {
|
||||
return int(math.Abs(float64(v)))
|
||||
}
|
||||
|
||||
func Atoi(i string) int {
|
||||
var ret int
|
||||
var err error
|
||||
if ret, err = strconv.Atoi(i); err != nil {
|
||||
log.Fatal("Invalid Atoi")
|
||||
}
|
||||
return ret
|
||||
}
|
||||
Reference in New Issue
Block a user