130 lines
2.4 KiB
Go
130 lines
2.4 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"math"
|
|
"os"
|
|
"strconv"
|
|
)
|
|
|
|
func main() {
|
|
if len(os.Args) < 2 {
|
|
fmt.Println("Usage: day03 <target>")
|
|
os.Exit(0)
|
|
}
|
|
target := Atoi(os.Args[1])
|
|
fmt.Println("== Part 1 ==")
|
|
part1(target)
|
|
fmt.Println("== Part 2 ==")
|
|
part2(target)
|
|
}
|
|
|
|
func part1(target int) {
|
|
idx := 1
|
|
lyrSz := 1
|
|
sizeSquare := int(math.Pow(float64(lyrSz), 2))
|
|
for sizeSquare < target {
|
|
lyrSz += 2
|
|
idx += 1
|
|
sizeSquare = int(math.Pow(float64(lyrSz), 2))
|
|
}
|
|
diff := sizeSquare - target
|
|
lyrJmp := lyrSz - 1
|
|
// Find the side it's on
|
|
side := int(diff / lyrJmp)
|
|
perps := make([]int, 4)
|
|
perps[0] = sizeSquare - (lyrJmp / 2)
|
|
perps[1] = perps[0] - lyrJmp
|
|
perps[2] = perps[1] - lyrJmp
|
|
perps[3] = perps[2] - lyrJmp
|
|
fmt.Println("Distance: ", int(math.Abs(float64(perps[side]-target)))+(idx-1))
|
|
}
|
|
|
|
const (
|
|
DIR_E = iota
|
|
DIR_N
|
|
DIR_W
|
|
DIR_S
|
|
DIR_ERROR
|
|
)
|
|
|
|
var memMap map[string]int
|
|
var lastX, lastY int
|
|
var lastDir int
|
|
|
|
func part2(target int) {
|
|
lastDir = DIR_S
|
|
lastX, lastY = 0, 0
|
|
|
|
val := 1
|
|
memMap = make(map[string]int)
|
|
memMap[getMapKey(lastX, lastY)] = val
|
|
for val <= target {
|
|
// Find the coordinate for the next one
|
|
lastX, lastY, lastDir = findNextMapPos()
|
|
val = getAdjacentSum(lastX, lastY)
|
|
memMap[getMapKey(lastX, lastY)] = val
|
|
}
|
|
fmt.Println("Result:", val, "at", getMapKey(lastX, lastY))
|
|
}
|
|
|
|
func getAdjacentSum(posX, posY int) int {
|
|
res := 0
|
|
for _, x := range []int{-1, 0, 1} {
|
|
for _, y := range []int{-1, 0, 1} {
|
|
if x == 0 && y == 0 {
|
|
continue
|
|
}
|
|
if i, ok := memMap[getMapKey((posX+x), (posY+y))]; ok {
|
|
res += i
|
|
}
|
|
}
|
|
}
|
|
return res
|
|
}
|
|
|
|
func findNextMapPos() (int, int, int) {
|
|
// First check if the current pos is empty
|
|
if _, ok := memMap[getMapKey(lastX, lastY)]; !ok {
|
|
return lastX, lastY, lastDir
|
|
}
|
|
// Check if the wrapping direction is free
|
|
nextDir := (lastDir + 1) % DIR_ERROR
|
|
testX, testY := getXYInDir(nextDir)
|
|
if _, ok := memMap[getMapKey(testX, testY)]; ok {
|
|
testX, testY = getXYInDir(lastDir)
|
|
nextDir = lastDir
|
|
}
|
|
// Otherwise continue in lastDir
|
|
return testX, testY, nextDir
|
|
}
|
|
|
|
func getXYInDir(dir int) (int, int) {
|
|
testX, testY := lastX, lastY
|
|
switch dir {
|
|
case DIR_E:
|
|
testX++
|
|
case DIR_N:
|
|
testY--
|
|
case DIR_W:
|
|
testX--
|
|
case DIR_S:
|
|
testY++
|
|
}
|
|
return testX, testY
|
|
}
|
|
|
|
func getMapKey(xPos, yPos int) string {
|
|
return fmt.Sprintf("%d;%d", xPos, yPos)
|
|
}
|
|
|
|
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
|
|
}
|