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() }