2023 Day 10 Complete!
This commit is contained in:
168
2023/day10/main.go
Normal file
168
2023/day10/main.go
Normal file
@@ -0,0 +1,168 @@
|
||||
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)
|
||||
if h.CoordListContains(wrk, loop) { //&& (wrkV == NS || wrkV == NE || wrkV == NW) {
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user