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