195 lines
3.9 KiB
Go
195 lines
3.9 KiB
Go
|
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
|
||
|
}
|