2023-12-10 16:26:21 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
h "git.bullercodeworks.com/brian/adventofcode/helpers"
|
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
inp := h.StdinToStringSlice()
|
|
|
|
m, l := part1(inp)
|
|
|
|
fmt.Println()
|
|
|
|
part2(m, l)
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
|
|
|
NS = '|'
|
|
|
|
EW = '-'
|
|
|
|
NE = 'L'
|
|
|
|
NW = 'J'
|
|
|
|
SW = '7'
|
|
|
|
SE = 'F'
|
|
|
|
|
|
|
|
START = 'S'
|
|
|
|
)
|
|
|
|
|
|
|
|
var pipes = []byte{NS, EW, NE, NW, SW, SE}
|
|
|
|
|
|
|
|
func part1(input []string) (h.CoordByteMap, []h.Coordinate) {
|
|
|
|
m := h.StringSliceToCoordByteMap(input)
|
|
|
|
_, loop := findLoop(&m)
|
|
|
|
fmt.Println("# Part 1")
|
|
|
|
fmt.Println(len(loop) / 2)
|
|
|
|
return m, loop
|
|
|
|
}
|
|
|
|
|
|
|
|
func part2(m h.CoordByteMap, loop []h.Coordinate) {
|
|
|
|
var insideCoords []h.Coordinate
|
|
|
|
var inside bool
|
|
|
|
var enclosed int
|
|
|
|
for y := m.TLY; y <= m.BRY; y++ {
|
|
|
|
inside = false
|
|
|
|
var rowPathStart byte
|
|
|
|
for x := m.TLX; x <= m.BRX; x++ {
|
|
|
|
wrk := h.Coordinate{X: x, Y: y}
|
|
|
|
wrkV := m.Get(wrk)
|
2023-12-18 12:54:10 +00:00
|
|
|
if h.CoordListContains(wrk, loop) {
|
2023-12-10 16:26:21 +00:00
|
|
|
// This coordinate is part of the loop, so it can change the 'inside' flag
|
|
|
|
// A corner _only_ changes the flag if the 'exiting' corner continues in the same direction
|
|
|
|
// i.e.: L--J doesn't change the flag, L--7 does change the flag
|
|
|
|
switch wrkV {
|
|
|
|
case NE, SE:
|
|
|
|
rowPathStart = wrkV
|
|
|
|
case NW, SW:
|
|
|
|
if continues(rowPathStart, wrkV) {
|
|
|
|
inside = !inside
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if wrkV == NS {
|
|
|
|
// a | always changes the flag
|
|
|
|
inside = !inside
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if inside {
|
|
|
|
enclosed++
|
|
|
|
insideCoords = append(insideCoords, wrk)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fmt.Println("# Part 2")
|
|
|
|
fmt.Println(enclosed)
|
|
|
|
for _, insides := range insideCoords {
|
|
|
|
m.Put(insides, 'I')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// continues checks if two _corner_ pieces continue the flow in the same direction
|
|
|
|
func continues(p1, p2 byte) bool {
|
|
|
|
switch p1 {
|
|
|
|
case NE:
|
|
|
|
return p2 == SW
|
|
|
|
case NW:
|
|
|
|
return p2 == SE
|
|
|
|
case SW:
|
|
|
|
return p2 == NE
|
|
|
|
case SE:
|
|
|
|
return p2 == NW
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func connectsNorth(v byte) bool {
|
|
|
|
return v == START || v == NS || v == NE || v == NW
|
|
|
|
}
|
|
|
|
func connectsSouth(v byte) bool {
|
|
|
|
return v == START || v == NS || v == SE || v == SW
|
|
|
|
}
|
|
|
|
func connectsEast(v byte) bool {
|
|
|
|
return v == START || v == EW || v == NE || v == SE
|
|
|
|
}
|
|
|
|
func connectsWest(v byte) bool {
|
|
|
|
return v == START || v == EW || v == NW || v == SW
|
|
|
|
}
|
|
|
|
|
|
|
|
func connects(m *h.CoordByteMap, p1, p2 h.Coordinate) bool {
|
|
|
|
p1v, p2v := m.Get(p1), m.Get(p2)
|
|
|
|
switch {
|
|
|
|
case p1.North().Equals(p2):
|
|
|
|
return connectsNorth(p1v) && connectsSouth(p2v)
|
|
|
|
case p1.East().Equals(p2):
|
|
|
|
return connectsEast(p1v) && connectsWest(p2v)
|
|
|
|
case p1.South().Equals(p2):
|
|
|
|
return connectsSouth(p1v) && connectsNorth(p2v)
|
|
|
|
case p1.West().Equals(p2):
|
|
|
|
return connectsWest(p1v) && connectsEast(p2v)
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func countConnections(m *h.CoordByteMap, p h.Coordinate) int {
|
|
|
|
var res int
|
|
|
|
for _, tst := range []h.Coordinate{p.North(), p.East(), p.South(), p.West()} {
|
|
|
|
if connects(m, p, tst) {
|
|
|
|
res++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find loop finds all coordinates on the loop and returns:
|
|
|
|
// 1. The starting coordinate
|
|
|
|
// 2. All coordinates on the loop
|
|
|
|
// It also replaces the 'S' for the starting coordinate with the appropriate
|
|
|
|
// pipe byte
|
|
|
|
func findLoop(m *h.CoordByteMap) (h.Coordinate, []h.Coordinate) {
|
|
|
|
start, _ := m.FindFirst(START)
|
|
|
|
next := start
|
|
|
|
path := []h.Coordinate{start}
|
|
|
|
|
|
|
|
// Figure out the starting pipe byte
|
|
|
|
for _, v := range pipes {
|
|
|
|
m.Put(start, v)
|
|
|
|
if countConnections(m, start) == 2 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for {
|
|
|
|
for _, tst := range []h.Coordinate{
|
|
|
|
next.North(),
|
|
|
|
next.East(),
|
|
|
|
next.South(),
|
|
|
|
next.West(),
|
|
|
|
} {
|
|
|
|
if !connects(m, next, tst) || (!tst.Equals(start) && h.CoordListContains(tst, path)) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
next = tst
|
|
|
|
}
|
|
|
|
if next.Equals(start) {
|
|
|
|
// We're done
|
|
|
|
return start, path
|
|
|
|
} else {
|
|
|
|
path = append(path, next)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|