2017 Day 20 Complete!
This commit is contained in:
parent
ef98db2967
commit
3d7ac83d3f
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
|
||||||
|
}
|
1000
2017/day20/input
Normal file
1000
2017/day20/input
Normal file
File diff suppressed because it is too large
Load Diff
121
2017/day20/problem
Normal file
121
2017/day20/problem
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
Advent of Code
|
||||||
|
|
||||||
|
--- Day 20: Particle Swarm ---
|
||||||
|
|
||||||
|
Suddenly, the GPU contacts you, asking for help. Someone has
|
||||||
|
asked it to simulate too many particles, and it won't be able
|
||||||
|
to finish them all in time to render the next frame at this
|
||||||
|
rate.
|
||||||
|
|
||||||
|
It transmits to you a buffer (your puzzle input) listing each
|
||||||
|
particle in order (starting with particle 0, then particle 1,
|
||||||
|
particle 2, and so on). For each particle, it provides the X,
|
||||||
|
Y, and Z coordinates for the particle's position (p), velocity
|
||||||
|
(v), and acceleration (a), each in the format <X,Y,Z>.
|
||||||
|
|
||||||
|
Each tick, all particles are updated simultaneously. A
|
||||||
|
particle's properties are updated in the following order:
|
||||||
|
|
||||||
|
* Increase the X velocity by the X acceleration.
|
||||||
|
* Increase the Y velocity by the Y acceleration.
|
||||||
|
* Increase the Z velocity by the Z acceleration.
|
||||||
|
* Increase the X position by the X velocity.
|
||||||
|
* Increase the Y position by the Y velocity.
|
||||||
|
* Increase the Z position by the Z velocity.
|
||||||
|
|
||||||
|
Because of seemingly tenuous rationale involving z-buffering,
|
||||||
|
the GPU would like to know which particle will stay closest to
|
||||||
|
position <0,0,0> in the long term. Measure this using the
|
||||||
|
Manhattan distance, which in this situation is simply the sum
|
||||||
|
of the absolute values of a particle's X, Y, and Z position.
|
||||||
|
|
||||||
|
For example, suppose you are only given two particles, both of
|
||||||
|
which stay entirely on the X-axis (for simplicity). Drawing
|
||||||
|
the current states of particles 0 and 1 (in that order) with
|
||||||
|
an adjacent a number line and diagram of current X positions
|
||||||
|
(marked in parenthesis), the following would take place:
|
||||||
|
|
||||||
|
p=< 3,0,0>, v=< 2,0,0>, a=<-1,0,0> -4 -3 -2 -1 0 1 2 3 4
|
||||||
|
p=< 4,0,0>, v=< 0,0,0>, a=<-2,0,0> (0)(1)
|
||||||
|
|
||||||
|
p=< 4,0,0>, v=< 1,0,0>, a=<-1,0,0> -4 -3 -2 -1 0 1 2 3 4
|
||||||
|
p=< 2,0,0>, v=<-2,0,0>, a=<-2,0,0> (1) (0)
|
||||||
|
|
||||||
|
p=< 4,0,0>, v=< 0,0,0>, a=<-1,0,0> -4 -3 -2 -1 0 1 2 3 4
|
||||||
|
p=<-2,0,0>, v=<-4,0,0>, a=<-2,0,0> (1) (0)
|
||||||
|
|
||||||
|
p=< 3,0,0>, v=<-1,0,0>, a=<-1,0,0> -4 -3 -2 -1 0 1 2 3 4
|
||||||
|
p=<-8,0,0>, v=<-6,0,0>, a=<-2,0,0> (0)
|
||||||
|
|
||||||
|
At this point, particle 1 will never be closer to <0,0,0> than
|
||||||
|
particle 0, and so, in the long run, particle 0 will stay
|
||||||
|
closest.
|
||||||
|
|
||||||
|
Which particle will stay closest to position <0,0,0> in the
|
||||||
|
long term?
|
||||||
|
|
||||||
|
Your puzzle answer was _______.
|
||||||
|
|
||||||
|
The first half of this puzzle is complete! It provides one
|
||||||
|
gold star: *
|
||||||
|
|
||||||
|
--- Part Two ---
|
||||||
|
|
||||||
|
To simplify the problem further, the GPU would like to remove
|
||||||
|
any particles that collide. Particles collide if their
|
||||||
|
positions ever exactly match. Because particles are updated
|
||||||
|
simultaneously, more than two particles can collide at the
|
||||||
|
same time and place. Once particles collide, they are removed
|
||||||
|
and cannot collide with anything else after that tick.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
p=<-6,0,0>, v=< 3,0,0>, a=< 0,0,0>
|
||||||
|
p=<-4,0,0>, v=< 2,0,0>, a=< 0,0,0> -6 -5 -4 -3 -2 -1 0 1 2 3
|
||||||
|
p=<-2,0,0>, v=< 1,0,0>, a=< 0,0,0> (0) (1) (2) (3)
|
||||||
|
p=< 3,0,0>, v=<-1,0,0>, a=< 0,0,0>
|
||||||
|
|
||||||
|
p=<-3,0,0>, v=< 3,0,0>, a=< 0,0,0>
|
||||||
|
p=<-2,0,0>, v=< 2,0,0>, a=< 0,0,0> -6 -5 -4 -3 -2 -1 0 1 2 3
|
||||||
|
p=<-1,0,0>, v=< 1,0,0>, a=< 0,0,0> (0)(1)(2) (3)
|
||||||
|
p=< 2,0,0>, v=<-1,0,0>, a=< 0,0,0>
|
||||||
|
|
||||||
|
p=< 0,0,0>, v=< 3,0,0>, a=< 0,0,0>
|
||||||
|
p=< 0,0,0>, v=< 2,0,0>, a=< 0,0,0> -6 -5 -4 -3 -2 -1 0 1 2 3
|
||||||
|
p=< 0,0,0>, v=< 1,0,0>, a=< 0,0,0> X (3)
|
||||||
|
p=< 1,0,0>, v=<-1,0,0>, a=< 0,0,0>
|
||||||
|
|
||||||
|
------destroyed by collision------
|
||||||
|
------destroyed by collision------ -6 -5 -4 -3 -2 -1 0 1 2 3
|
||||||
|
------destroyed by collision------ (3)
|
||||||
|
p=< 0,0,0>, v=<-1,0,0>, a=< 0,0,0>
|
||||||
|
|
||||||
|
In this example, particles 0, 1, and 2 are simultaneously
|
||||||
|
destroyed at the time and place marked X. On the next tick,
|
||||||
|
particle 3 passes through unharmed.
|
||||||
|
|
||||||
|
How many particles are left after all collisions are resolved?
|
||||||
|
|
||||||
|
Although it hasn't changed, you can still get your puzzle
|
||||||
|
input.
|
||||||
|
|
||||||
|
Answer: _____________________
|
||||||
|
|
||||||
|
References
|
||||||
|
|
||||||
|
Visible links
|
||||||
|
. http://adventofcode.com/
|
||||||
|
. http://adventofcode.com/2017/about
|
||||||
|
. http://adventofcode.com/2017/support
|
||||||
|
. http://adventofcode.com/2017/events
|
||||||
|
. http://adventofcode.com/2017/settings
|
||||||
|
. http://adventofcode.com/2017/auth/logout
|
||||||
|
. http://adventofcode.com/2017
|
||||||
|
. http://adventofcode.com/2017
|
||||||
|
. http://adventofcode.com/2017/leaderboard
|
||||||
|
. http://adventofcode.com/2017/stats
|
||||||
|
. http://adventofcode.com/2017/sponsors
|
||||||
|
. http://adventofcode.com/2017/sponsors
|
||||||
|
. https://en.wikipedia.org/wiki/Z-buffering
|
||||||
|
. https://en.wikipedia.org/wiki/Taxicab_geometry
|
||||||
|
. http://adventofcode.com/2017/day/20/input
|
2
2017/day20/testinput
Normal file
2
2017/day20/testinput
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
p=<3,0,0>, v=<2,0,0>, a=<-1,0,0>
|
||||||
|
p=<4,0,0>, v=<0,0,0>, a=<-2,0,0>
|
Loading…
Reference in New Issue
Block a user