206 lines
4.6 KiB
Go
206 lines
4.6 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
h "git.bullercodeworks.com/brian/adventofcode/helpers"
|
|
)
|
|
|
|
var part = -1
|
|
var testRow = 2000000
|
|
var watch bool
|
|
var watchRows = 1
|
|
|
|
func main() {
|
|
inp := h.StdinToStringSlice()
|
|
if len(os.Args) > 1 {
|
|
for _, arg := range os.Args[1:] {
|
|
if strings.HasPrefix(arg, "--part") || strings.HasPrefix(arg, "-p") {
|
|
if strings.Contains(arg, "=") {
|
|
pts := strings.Split(arg, "=")
|
|
part = h.Atoi(pts[1])
|
|
}
|
|
} else if strings.HasPrefix(arg, "--row") || strings.HasPrefix(arg, "-r") {
|
|
if strings.Contains(arg, "=") {
|
|
pts := strings.Split(arg, "=")
|
|
testRow = h.Atoi(pts[1])
|
|
}
|
|
} else if strings.HasPrefix(arg, "--watch") || strings.HasPrefix(arg, "-w") {
|
|
watch = true
|
|
if strings.Contains(arg, "=") {
|
|
pts := strings.Split(arg, "=")
|
|
if pts[1] == "full" {
|
|
watchRows = -1
|
|
} else {
|
|
watchRows = h.Atoi(pts[1])
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if part == 1 || part == -1 {
|
|
part1(inp)
|
|
}
|
|
if part == 2 || part == -1 {
|
|
part2(inp)
|
|
}
|
|
}
|
|
|
|
func part1(inp []string) {
|
|
min_x, max_x := math.MaxInt, math.MinInt
|
|
var spots [][]int
|
|
for i := range inp {
|
|
s, b := strToCoords(inp[i])
|
|
xs, ys, xb, yb := s.X, s.Y, b.X, b.Y
|
|
dist := s.Distance(b)
|
|
l, r := xs-dist, xs+dist
|
|
min_x = h.Min(min_x, l)
|
|
max_x = h.Max(max_x, r)
|
|
spots = append(spots, []int{xs, ys, xb, yb, dist})
|
|
}
|
|
var nopeCount int
|
|
for x := min_x; x <= max_x; x++ {
|
|
for _, c := range spots {
|
|
if x == c[2] && testRow == c[3] {
|
|
break
|
|
}
|
|
if h.ManhattanDistance(x, testRow, c[0], c[1]) <= c[4] {
|
|
nopeCount++
|
|
break
|
|
}
|
|
}
|
|
}
|
|
fmt.Println("# Part 1")
|
|
fmt.Println(nopeCount)
|
|
}
|
|
|
|
type Sensor struct {
|
|
c h.Coordinate // Sensor Position
|
|
b h.Coordinate // Beacon Position
|
|
d int // Distance
|
|
}
|
|
|
|
func (s Sensor) isInRange(c h.Coordinate) bool { return s.c.Distance(c) <= s.d }
|
|
|
|
func (s Sensor) String() string { return s.c.String() }
|
|
|
|
func part2(inp []string) {
|
|
var sensors []Sensor
|
|
for i := range inp {
|
|
s := Sensor{}
|
|
s.c, s.b = strToCoords(inp[i])
|
|
s.d = s.c.Distance(s.b)
|
|
sensors = append(sensors, s)
|
|
}
|
|
|
|
max := testRow * 2
|
|
found := []h.Coordinate{}
|
|
// Check around each sensor, the beacon must be it's distance + 1
|
|
for _, sensor := range sensors {
|
|
d := sensor.d + 1
|
|
testEnds := []h.Coordinate{
|
|
{X: sensor.c.X, Y: sensor.c.Y - d},
|
|
{X: sensor.c.X + d, Y: sensor.c.Y},
|
|
{X: sensor.c.X, Y: sensor.c.Y + d},
|
|
{X: sensor.c.X - d, Y: sensor.c.Y},
|
|
}
|
|
printMap(sensors, max, max, h.Coordinate{X: math.MinInt, Y: math.MinInt})
|
|
var tstX, tstY int
|
|
for i := 0; i < 3; i++ {
|
|
// Test all spots between testEnds[i] & testEnds[i+1]
|
|
for tstX != testEnds[i+1].X && tstY != testEnds[i+1].Y {
|
|
if testEnds[i].X < testEnds[i+1].X {
|
|
tstX++
|
|
if testEnds[i].Y < testEnds[i+1].Y {
|
|
tstY++
|
|
} else {
|
|
tstY--
|
|
}
|
|
} else {
|
|
tstX--
|
|
if testEnds[i].Y < testEnds[i+1].Y {
|
|
tstY++
|
|
} else {
|
|
tstY--
|
|
}
|
|
}
|
|
}
|
|
if tstX <= max && tstY <= max {
|
|
fmt.Print(h.CLEAR_SCREEN)
|
|
printMap(sensors, max, max, h.Coordinate{X: tstX, Y: tstY})
|
|
fmt.Println("Testing", tstX, ",", tstY)
|
|
time.Sleep(time.Second / 10)
|
|
if testSpot(tstX, tstY, sensors) {
|
|
found = append(found, h.Coordinate{X: tstX, Y: tstY})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fmt.Println("# Part 2")
|
|
fmt.Println(found)
|
|
//fmt.Println((found.X * 4000000) + found.Y)
|
|
}
|
|
|
|
func testSpot(x, y int, sensors []Sensor) bool {
|
|
var wasInRange bool
|
|
for i := range sensors {
|
|
if sensors[i].isInRange(h.Coordinate{X: x, Y: y}) {
|
|
wasInRange = true
|
|
break
|
|
}
|
|
}
|
|
return !wasInRange
|
|
}
|
|
|
|
func printMap(sensors []Sensor, ceilX, ceilY int, tstPos h.Coordinate) {
|
|
minX, maxX, minY, maxY := math.MaxInt, math.MinInt, math.MaxInt, math.MinInt
|
|
for i := range sensors {
|
|
minX = h.Min(sensors[i].b.X, minX)
|
|
maxX = h.Max(sensors[i].b.X, maxX)
|
|
minY = h.Min(sensors[i].b.Y, minY)
|
|
maxY = h.Max(sensors[i].b.Y, maxY)
|
|
}
|
|
for y := minY; y <= maxY; y++ {
|
|
for x := minX; x <= maxX; x++ {
|
|
wrk := h.Coordinate{X: x, Y: y}
|
|
var found bool
|
|
for _, sensor := range sensors {
|
|
if sensor.c.Equals(wrk) {
|
|
fmt.Print("S")
|
|
found = true
|
|
break
|
|
} else if sensor.b.Equals(wrk) {
|
|
fmt.Print("B")
|
|
found = true
|
|
break
|
|
} else if sensor.isInRange(wrk) {
|
|
fmt.Print("#")
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
if wrk.Equals(tstPos) {
|
|
fmt.Print(h.FILL_CHAR)
|
|
} else {
|
|
fmt.Print(".")
|
|
}
|
|
}
|
|
}
|
|
fmt.Println()
|
|
}
|
|
}
|
|
|
|
func strToCoords(s string) (h.Coordinate, h.Coordinate) {
|
|
var sensor, beacon h.Coordinate
|
|
r := strings.NewReader(s)
|
|
fmt.Fscanf(r, "Sensor at x=%d, y=%d: closest beacon is at x=%d, y=%d", &sensor.X, &sensor.Y, &beacon.X, &beacon.Y)
|
|
return sensor, beacon
|
|
}
|