advent-of-code/day18/main.go

235 lines
3.7 KiB
Go
Raw Normal View History

2023-12-20 11:27:20 -07:00
package main
import (
"bufio"
_ "embed"
"encoding/hex"
"fmt"
2023-12-27 13:18:49 -07:00
"os"
"strconv"
2023-12-20 11:27:20 -07:00
"strings"
aoc "go.sour.is/advent-of-code"
2023-12-27 13:18:49 -07:00
"golang.org/x/exp/maps"
2023-12-20 11:27:20 -07:00
)
// 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
2023-12-27 13:18:49 -07:00
var vecs2 []vec
2023-12-20 11:27:20 -07:00
for scan.Scan() {
text := scan.Text()
if len(text) == 0 {
continue
}
var s string
v := vec{}
s, text, _ = strings.Cut(text, " ")
2023-12-27 13:18:49 -07:00
v.Direction = direction(s[0])
2023-12-20 11:27:20 -07:00
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)
2023-12-27 13:18:49 -07:00
vecs2 = append(vecs2, fromColor(s))
2023-12-20 11:27:20 -07:00
}
2023-12-27 13:18:49 -07:00
return &result{
valuePT1: findArea(vecs),
valuePT2: skip("AOC_DAY18P2", func() int { return findArea(vecs2) }),
}, nil
}
2023-12-20 11:27:20 -07:00
2023-12-27 13:18:49 -07:00
func findArea(vecs []vec) int {
2023-12-20 11:27:20 -07:00
var points []point
var x, y int
var minX, minY int
2023-12-27 13:18:49 -07:00
last := direction('S')
for _, v := range vecs {
// fmt.Println("pt ", i, v)
2023-12-20 11:27:20 -07:00
for i := 0; i < v.Steps; i++ {
switch v.Direction {
2023-12-27 13:18:49 -07:00
case 'U':
2023-12-20 11:27:20 -07:00
y++
2023-12-27 13:18:49 -07:00
case 'D':
2023-12-20 11:27:20 -07:00
y--
2023-12-27 13:18:49 -07:00
case 'R':
2023-12-20 11:27:20 -07:00
x++
2023-12-27 13:18:49 -07:00
case 'L':
2023-12-20 11:27:20 -07:00
x--
}
2023-12-27 13:18:49 -07:00
// fmt.Println("pt ", i, y, x)
2023-12-20 11:27:20 -07:00
minX = min(minX, x)
minY = min(minY, y)
2023-12-27 13:18:49 -07:00
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
2023-12-20 11:27:20 -07:00
}
}
2023-12-27 13:18:49 -07:00
_ = last
// points[0].w = last
points[len(points)-1].d = points[0].w
2023-12-20 11:27:20 -07:00
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 {
2023-12-27 13:18:49 -07:00
2023-12-20 11:27:20 -07:00
p.x += adjX
p.y += adjY
2023-12-27 13:18:49 -07:00
// fmt.Println("raw", i, p.x, p.y, string(p.w), string(p.d))
2023-12-20 11:27:20 -07:00
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
}
}
2023-12-27 13:18:49 -07:00
fmt.Println("maxX", maxX, "maxY", maxY)
2023-12-20 11:27:20 -07:00
area := 0
2023-12-27 13:18:49 -07:00
for y := maxY; y >= 0; y-- {
2023-12-20 11:27:20 -07:00
row, ok := trace[y]
if !ok {
continue
}
var last direction
2023-12-27 13:18:49 -07:00
p := row[0]
2023-12-20 11:27:20 -07:00
last = p.d
2023-12-27 13:18:49 -07:00
inLoop := false
2023-12-20 11:27:20 -07:00
for x := 0; x <= maxX; x++ {
if p, ok := row[x]; ok {
2023-12-27 13:18:49 -07:00
// 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":
2023-12-20 11:27:20 -07:00
inLoop = !inLoop
}
if last != p.d {
last = p.d
}
2023-12-27 13:18:49 -07:00
// fmt.Print(string(p.w)+string(p.d))
// On loop
area++
continue // 203338
2023-12-20 11:27:20 -07:00
}
2023-12-27 13:18:49 -07:00
last = direction('0')
2023-12-20 11:27:20 -07:00
if inLoop {
area++
2023-12-27 13:18:49 -07:00
// fmt.Print("XX")
// } else {
// fmt.Print("..")
2023-12-20 11:27:20 -07:00
}
}
2023-12-27 13:18:49 -07:00
// fmt.Println("")
fmt.Println(y, area)
2023-12-20 11:27:20 -07:00
}
2023-12-27 13:18:49 -07:00
return area
2023-12-20 11:27:20 -07:00
}
2023-12-27 13:18:49 -07:00
type direction rune
2023-12-20 11:27:20 -07:00
const (
2023-12-27 13:18:49 -07:00
U direction = 'U'
D direction = 'D'
L direction = 'L'
R direction = 'R'
2023-12-20 11:27:20 -07:00
)
2023-12-27 13:18:49 -07:00
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'
}
2023-12-20 11:27:20 -07:00
type vec struct {
Direction direction
Steps int
Color [3]byte
}
type point struct {
w direction
d direction
x, y int
color [3]byte
}
2023-12-27 13:18:49 -07:00
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'
2023-12-20 11:27:20 -07:00
}
2023-12-27 13:18:49 -07:00
return vec{
Direction: direction(d),
Steps: int(steps),
2023-12-20 11:27:20 -07:00
}
2023-12-27 13:18:49 -07:00
}
2023-12-20 11:27:20 -07:00
2023-12-27 13:18:49 -07:00
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
2023-12-20 11:27:20 -07:00
}
2023-12-27 13:18:49 -07:00
return fn()
2023-12-20 11:27:20 -07:00
}