235 lines
3.7 KiB
Go
235 lines
3.7 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
_ "embed"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
|
|
aoc "go.sour.is/advent-of-code"
|
|
"golang.org/x/exp/maps"
|
|
)
|
|
|
|
// var log = aoc.Log
|
|
|
|
func main() { aoc.MustResult(aoc.Runner(run)) }
|
|
|
|
type result struct {
|
|
valuePT1 int
|
|
valuePT2 int
|
|
}
|
|
|
|
func (r result) String() string { return fmt.Sprintf("%#v", r) }
|
|
|
|
func run(scan *bufio.Scanner) (*result, error) {
|
|
|
|
var vecs []vec
|
|
var vecs2 []vec
|
|
|
|
for scan.Scan() {
|
|
text := scan.Text()
|
|
|
|
if len(text) == 0 {
|
|
continue
|
|
}
|
|
|
|
var s string
|
|
v := vec{}
|
|
s, text, _ = strings.Cut(text, " ")
|
|
v.Direction = direction(s[0])
|
|
s, text, _ = strings.Cut(text, " ")
|
|
v.Steps = aoc.Atoi(s)
|
|
_, text, _ = strings.Cut(text, "#")
|
|
s, _, _ = strings.Cut(text, ")")
|
|
b, _ := hex.DecodeString(s)
|
|
copy(v.Color[:], b)
|
|
vecs = append(vecs, v)
|
|
vecs2 = append(vecs2, fromColor(s))
|
|
}
|
|
return &result{
|
|
valuePT1: findArea(vecs),
|
|
valuePT2: skip("AOC_DAY18P2", func() int { return findArea(vecs2) }),
|
|
}, nil
|
|
}
|
|
|
|
func findArea(vecs []vec) int {
|
|
var points []point
|
|
|
|
var x, y int
|
|
var minX, minY int
|
|
last := direction('S')
|
|
for _, v := range vecs {
|
|
// fmt.Println("pt ", i, v)
|
|
for i := 0; i < v.Steps; i++ {
|
|
switch v.Direction {
|
|
case 'U':
|
|
y++
|
|
case 'D':
|
|
y--
|
|
case 'R':
|
|
x++
|
|
case 'L':
|
|
x--
|
|
}
|
|
// fmt.Println("pt ", i, y, x)
|
|
|
|
minX = min(minX, x)
|
|
minY = min(minY, y)
|
|
if len(points) > 0 {
|
|
points[len(points)-1].d = v.Direction
|
|
}
|
|
points = append(points, point{d: v.Direction, w: opposite(v.Direction), x: x, y: y, color: v.Color})
|
|
last = v.Direction
|
|
}
|
|
}
|
|
_ = last
|
|
// points[0].w = last
|
|
points[len(points)-1].d = points[0].w
|
|
|
|
adjX := aoc.ABS(min(0, minX))
|
|
adjY := aoc.ABS(min(0, minY))
|
|
fmt.Println("minX", minX, "minY", minY)
|
|
fmt.Println("adjX", adjX, "adjY", adjY)
|
|
|
|
trace := make(map[int]map[int]point)
|
|
|
|
minX, minY = 0, 0
|
|
maxX, maxY := 0, 0
|
|
|
|
for i, p := range points {
|
|
|
|
p.x += adjX
|
|
p.y += adjY
|
|
// fmt.Println("raw", i, p.x, p.y, string(p.w), string(p.d))
|
|
|
|
maxX = max(maxX, p.x)
|
|
maxY = max(maxY, p.y)
|
|
|
|
points[i] = p
|
|
|
|
if row, ok := trace[p.y]; true {
|
|
if !ok {
|
|
row = make(map[int]point)
|
|
}
|
|
row[p.x] = p
|
|
trace[p.y] = row
|
|
}
|
|
}
|
|
fmt.Println("maxX", maxX, "maxY", maxY)
|
|
|
|
area := 0
|
|
|
|
for y := maxY; y >= 0; y-- {
|
|
row, ok := trace[y]
|
|
if !ok {
|
|
continue
|
|
}
|
|
|
|
var last direction
|
|
p := row[0]
|
|
last = p.d
|
|
inLoop := false
|
|
|
|
for x := 0; x <= maxX; x++ {
|
|
if p, ok := row[x]; ok {
|
|
// fmt.Println("vec", string(p.w), string(p.d))
|
|
switch string([]rune{rune(p.w), rune(p.d)}) {
|
|
case "LD", "DL", "UD", "DU", "RD", "UU", "DR":
|
|
inLoop = !inLoop
|
|
}
|
|
if last != p.d {
|
|
last = p.d
|
|
}
|
|
|
|
// fmt.Print(string(p.w)+string(p.d))
|
|
|
|
// On loop
|
|
area++
|
|
|
|
continue // 203338
|
|
}
|
|
last = direction('0')
|
|
|
|
if inLoop {
|
|
area++
|
|
// fmt.Print("XX")
|
|
// } else {
|
|
// fmt.Print("..")
|
|
}
|
|
|
|
}
|
|
// fmt.Println("")
|
|
fmt.Println(y, area)
|
|
}
|
|
return area
|
|
}
|
|
|
|
type direction rune
|
|
|
|
const (
|
|
U direction = 'U'
|
|
D direction = 'D'
|
|
L direction = 'L'
|
|
R direction = 'R'
|
|
)
|
|
|
|
func opposite(d direction) direction {
|
|
switch d {
|
|
case U:
|
|
return D
|
|
case D:
|
|
return U
|
|
case L:
|
|
return R
|
|
case R:
|
|
return L
|
|
}
|
|
return '0'
|
|
}
|
|
|
|
type vec struct {
|
|
Direction direction
|
|
Steps int
|
|
Color [3]byte
|
|
}
|
|
|
|
type point struct {
|
|
w direction
|
|
d direction
|
|
x, y int
|
|
color [3]byte
|
|
}
|
|
|
|
func fromColor(c string) vec {
|
|
steps, _ := strconv.ParseInt(c[:5], 16, 64)
|
|
|
|
d := '_'
|
|
switch c[5] {
|
|
case '0':
|
|
d = 'R'
|
|
case '1':
|
|
d = 'D'
|
|
case '2':
|
|
d = 'L'
|
|
case '3':
|
|
d = 'U'
|
|
}
|
|
|
|
return vec{
|
|
Direction: direction(d),
|
|
Steps: int(steps),
|
|
}
|
|
}
|
|
|
|
func skip[T any](env string, fn func() T) T {
|
|
var zero T
|
|
if e, err := strconv.ParseBool(os.Getenv(env)); err == nil && e {
|
|
return zero
|
|
}
|
|
|
|
return fn()
|
|
}
|