165 lines
3.1 KiB
Go
165 lines
3.1 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"math"
|
||
|
|
||
|
h "git.bullercodeworks.com/brian/adventofcode/helpers"
|
||
|
)
|
||
|
|
||
|
func main() {
|
||
|
inp := h.StdinToStringSlice()
|
||
|
part1(inp)
|
||
|
fmt.Println()
|
||
|
part2(inp)
|
||
|
}
|
||
|
|
||
|
func part1(inp []string) {
|
||
|
fmt.Println("# Part 1")
|
||
|
// Main Input size
|
||
|
sizeX, sizeY := 101, 103
|
||
|
bots := parseInput(inp, sizeX, sizeY)
|
||
|
for i := 0; i < 100; i++ {
|
||
|
for j := range bots {
|
||
|
bots[j].Move()
|
||
|
}
|
||
|
}
|
||
|
for i := range bots {
|
||
|
fmt.Println(bots[i])
|
||
|
}
|
||
|
qCnt := make([]int, 4)
|
||
|
for y := 0; y < sizeY; y++ {
|
||
|
for x := 0; x < sizeX; x++ {
|
||
|
if x == sizeX/2 || y == sizeY/2 {
|
||
|
fmt.Print(" ")
|
||
|
continue
|
||
|
}
|
||
|
bCnt := 0
|
||
|
for i := range bots {
|
||
|
if x == bots[i].X && y == bots[i].Y {
|
||
|
bCnt++
|
||
|
if x < sizeX/2 {
|
||
|
if y < sizeY/2 {
|
||
|
qCnt[0]++
|
||
|
} else {
|
||
|
qCnt[2]++
|
||
|
}
|
||
|
} else {
|
||
|
if y < sizeY/2 {
|
||
|
qCnt[1]++
|
||
|
} else {
|
||
|
qCnt[3]++
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if bCnt > 0 {
|
||
|
fmt.Print(bCnt)
|
||
|
} else {
|
||
|
fmt.Print(".")
|
||
|
}
|
||
|
}
|
||
|
fmt.Println()
|
||
|
}
|
||
|
fmt.Println("Safety Factor:", (qCnt[0] * qCnt[1] * qCnt[2] * qCnt[3]))
|
||
|
}
|
||
|
|
||
|
func part2(inp []string) {
|
||
|
fmt.Println("# Part 2")
|
||
|
// Main Input size
|
||
|
sizeX, sizeY := 101, 103
|
||
|
bots := parseInput(inp, sizeX, sizeY)
|
||
|
printState := func() {
|
||
|
for y := 0; y < sizeY; y++ {
|
||
|
for x := 0; x < sizeX; x++ {
|
||
|
btCnt := 0
|
||
|
for _, b := range bots {
|
||
|
if b.X == x && b.Y == y {
|
||
|
btCnt++
|
||
|
}
|
||
|
}
|
||
|
if btCnt == 0 {
|
||
|
fmt.Print(".")
|
||
|
} else if btCnt < 10 {
|
||
|
fmt.Print(btCnt)
|
||
|
} else {
|
||
|
fmt.Print("#")
|
||
|
}
|
||
|
}
|
||
|
fmt.Println()
|
||
|
}
|
||
|
}
|
||
|
// My hypothesis: most bots will be close to each other for the answer
|
||
|
lowest := h.MAX_INT
|
||
|
var lowStdX, lowStdY float64
|
||
|
for steps := 0; steps < 10000000; steps++ {
|
||
|
xs := make([]int, 0, len(bots))
|
||
|
ys := make([]int, 0, len(bots))
|
||
|
for j := range bots {
|
||
|
bots[j].Move()
|
||
|
xs = append(xs, bots[j].X)
|
||
|
ys = append(ys, bots[j].Y)
|
||
|
}
|
||
|
// After finding it, I added this to print it out :D
|
||
|
if steps == 7036 {
|
||
|
printState()
|
||
|
}
|
||
|
wrkX, wrkY := stdev(xs), stdev(ys)
|
||
|
if lowest == h.MAX_INT || (wrkX < lowStdX && wrkY < lowStdY) {
|
||
|
fmt.Println(lowest, ":", lowStdX, lowStdY)
|
||
|
lowStdX, lowStdY, lowest = wrkX, wrkY, steps
|
||
|
}
|
||
|
}
|
||
|
fmt.Println("Steps to Easter Egg:", lowest)
|
||
|
}
|
||
|
|
||
|
func stdev(vals []int) float64 {
|
||
|
m := 0.0
|
||
|
for _, w := range vals {
|
||
|
m += float64(w)
|
||
|
}
|
||
|
m /= float64(len(vals))
|
||
|
v := 0.0
|
||
|
for _, w := range vals {
|
||
|
diff := float64(w) - m
|
||
|
v += diff * diff
|
||
|
}
|
||
|
return math.Sqrt(v / float64(len(vals)))
|
||
|
}
|
||
|
|
||
|
var botRaw = "p=%d,%d v=%d,%d"
|
||
|
|
||
|
type Bot struct {
|
||
|
X, Y, Vx, Vy int
|
||
|
mX, mY int
|
||
|
}
|
||
|
|
||
|
func NewBot(inp string) *Bot {
|
||
|
b := Bot{}
|
||
|
fmt.Sscanf(inp, botRaw, &b.X, &b.Y, &b.Vx, &b.Vy)
|
||
|
return &b
|
||
|
}
|
||
|
|
||
|
func (b *Bot) Move() {
|
||
|
b.X = (b.X + b.Vx + b.mX) % b.mX
|
||
|
b.Y = (b.Y + b.Vy + b.mY) % b.mY
|
||
|
}
|
||
|
|
||
|
func (b *Bot) Overlaps(bt *Bot) bool {
|
||
|
return b.X == bt.X && b.Y == bt.Y
|
||
|
}
|
||
|
|
||
|
func (b Bot) String() string {
|
||
|
return fmt.Sprintf(botRaw, b.X, b.Y, b.Vx, b.Vy)
|
||
|
}
|
||
|
|
||
|
func parseInput(inp []string, mX, mY int) []*Bot {
|
||
|
var ret []*Bot
|
||
|
for i := range inp {
|
||
|
b := NewBot(inp[i])
|
||
|
b.mX, b.mY = mX, mY
|
||
|
ret = append(ret, b)
|
||
|
}
|
||
|
return ret
|
||
|
}
|