package main import ( "fmt" h "git.bullercodeworks.com/brian/adventofcode/helpers" ) func main() { inp := h.StdinToStringSlice() part1(inp) fmt.Println() part2(inp) } func part1(input []string) { var maps []*h.CoordByteMap var wrkInput []string bld := func() { m := h.StringSliceToCoordByteMap(wrkInput) maps = append(maps, &m) wrkInput = []string{} } for i := range input { if len(input[i]) == 0 { bld() } else { wrkInput = append(wrkInput, input[i]) } } if len(wrkInput) > 0 { bld() } var result int for _, m := range maps { result += findMirror(m, -1) } fmt.Println("# Part 1") fmt.Println(result) } func part2(input []string) { var maps []*h.CoordByteMap var wrkInput []string bld := func() { m := h.StringSliceToCoordByteMap(wrkInput) maps = append(maps, &m) wrkInput = []string{} } for i := range input { if len(input[i]) == 0 { bld() } else { wrkInput = append(wrkInput, input[i]) } } if len(wrkInput) > 0 { bld() } var result int for _, m := range maps { result += checkForSmudge(m) } fmt.Println("# Part 2") fmt.Println(result) } func checkForSmudge(m *h.CoordByteMap) int { origMirror := findMirror(m, -1) for y := m.TLY; y <= m.BRY; y++ { for x := m.TLX; x <= m.BRX; x++ { orig := m.Get(c(x, y)) switch orig { case '#': m.Put(c(x, y), '.') case '.': m.Put(c(x, y), '#') } res := findMirror(m, origMirror) if res > 0 && res != origMirror { return res } m.Put(c(x, y), orig) } } return 0 } // findMirror finds a mirror in the map // returning the value of that mirror (vertical (x+1), horizontal (y+1)* 100) func findMirror(m *h.CoordByteMap, exclude int) int { var found bool for x := m.TLX; x <= m.BRX; x++ { val := (x + 1) if found = checkForVerticalMirror(m, x, x+1); found && val != exclude { return x + 1 } } for y := m.TLY; y <= m.BRY; y++ { val := (y + 1) * 100 if found = checkForHorizontalMirror(m, y, y+1); found && val != exclude { return (y + 1) * 100 } } return 0 } func c(x, y int) h.Coordinate { return h.Coordinate{X: x, Y: y} } func checkForVerticalMirror(m *h.CoordByteMap, x1, x2 int) bool { var wrkX1, wrkX2 int for y := m.TLY; y <= m.BRY; y++ { wrkX1, wrkX2 = x1, x2 var match, cont bool for wrkX1 >= m.TLX || wrkX2 <= m.BRX { if match, cont = hPointsMatch(m, y, wrkX1, wrkX2); match { if cont { break } wrkX1-- wrkX2++ } else { return false } } if cont { continue } if wrkX1 < m.TLX || wrkX2 > m.BRX { return false } } // Mirrors _shouldn't_ be at the very edge (or else what are we even doing here) if wrkX1 == m.BRX || wrkX2 == m.TLX { return false } return true } func hPointsMatch(m *h.CoordByteMap, y, x1, x2 int) (bool, bool) { c1, c2 := c(x1, y), c(x2, y) // If either is off the map, it could be if m.Opt(c1, byte(0)) == 0 || m.Opt(c2, byte(0)) == 0 { return true, true } // Check if (x1, y) == (x2, y) v1, v2 := m.Get(c1), m.Get(c2) return v1 == v2, false } func checkForHorizontalMirror(m *h.CoordByteMap, y1, y2 int) bool { var wrkY1, wrkY2 int for x := m.TLX; x <= m.BRX; x++ { wrkY1, wrkY2 = y1, y2 var match, cont bool for wrkY1 >= m.TLY || wrkY2 <= m.BRY { if match, cont = vPointsMatch(m, x, wrkY1, wrkY2); match { if cont { break } wrkY1-- wrkY2++ } else { return false } } if cont { continue } if wrkY1 > m.TLY && wrkY2 < m.BRY { return false } } // Mirrors _shouldn't_ be at the very edge (or else what are we even doing here) if wrkY1 == m.BRY || wrkY2 == m.TLY { return false } return true } func vPointsMatch(m *h.CoordByteMap, x, y1, y2 int) (bool, bool) { c1, c2 := c(x, y1), c(x, y2) // If either is off the map, it could be if m.Opt(c1, byte(0)) == 0 || m.Opt(c2, byte(0)) == 0 { return true, true } // Check if (x, y1) == (x, y2) v1, v2 := m.Get(c1), m.Get(c2) return v1 == v2, false }