111 lines
2.3 KiB
Go
111 lines
2.3 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
|
||
|
h "git.bullercodeworks.com/brian/adventofcode/helpers"
|
||
|
)
|
||
|
|
||
|
func main() {
|
||
|
inp := h.StdinToStringSlice()
|
||
|
part1(inp)
|
||
|
part2(inp)
|
||
|
}
|
||
|
|
||
|
func part1(input []string) {
|
||
|
bm := h.StringSliceToCoordByteMap(input)
|
||
|
symbols := bm.FindAllNot('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.')
|
||
|
// Gather a list of numbers that are adjacent to the symbols
|
||
|
nums := make(map[h.Coordinate]int)
|
||
|
for k, _ := range symbols {
|
||
|
wrk := findPartNumsFrom(bm, k)
|
||
|
for coord, val := range wrk {
|
||
|
nums[coord] = val
|
||
|
}
|
||
|
}
|
||
|
var sum int
|
||
|
for _, v := range nums {
|
||
|
sum += v
|
||
|
}
|
||
|
fmt.Println("# Part 1")
|
||
|
fmt.Println(sum)
|
||
|
}
|
||
|
|
||
|
func part2(input []string) {
|
||
|
bm := h.StringSliceToCoordByteMap(input)
|
||
|
maybeGears := bm.FindAll('*')
|
||
|
var ratioSum int
|
||
|
for _, k := range maybeGears {
|
||
|
wrk := findPartNumsFrom(bm, k)
|
||
|
if len(wrk) != 2 {
|
||
|
// It's not a gear
|
||
|
continue
|
||
|
}
|
||
|
var second bool
|
||
|
var ratio int
|
||
|
for _, v := range wrk {
|
||
|
if !second {
|
||
|
ratio += v
|
||
|
second = true
|
||
|
} else {
|
||
|
ratio *= v
|
||
|
}
|
||
|
}
|
||
|
ratioSum += ratio
|
||
|
}
|
||
|
fmt.Println("# Part 2")
|
||
|
fmt.Println(ratioSum)
|
||
|
}
|
||
|
|
||
|
func findPartNumsFrom(m h.CoordByteMap, c h.Coordinate) map[h.Coordinate]int {
|
||
|
partNums := make(map[h.Coordinate]int)
|
||
|
for _, chk := range []h.Coordinate{
|
||
|
c.North(),
|
||
|
c.NE(),
|
||
|
c.East(),
|
||
|
c.SE(),
|
||
|
c.South(),
|
||
|
c.SW(),
|
||
|
c.West(),
|
||
|
c.NW(),
|
||
|
} {
|
||
|
if m.Get(chk) >= '0' && m.Get(chk) <= '9' {
|
||
|
v, pos := parseNumAt(m, chk)
|
||
|
partNums[pos] = v
|
||
|
}
|
||
|
}
|
||
|
return partNums
|
||
|
}
|
||
|
|
||
|
// parseNumAt returns the number at c and the Coordinate
|
||
|
// that the first digit of that number is at
|
||
|
func parseNumAt(m h.CoordByteMap, c h.Coordinate) (int, h.Coordinate) {
|
||
|
var resStr string
|
||
|
startCoord := c
|
||
|
// From 'c' move left until we find the first digit
|
||
|
chk := m.Get(startCoord)
|
||
|
for coordIsNum(m, startCoord) {
|
||
|
startCoord = startCoord.West()
|
||
|
chk = m.Get(startCoord)
|
||
|
}
|
||
|
startCoord = startCoord.East()
|
||
|
|
||
|
// Now put the number at 'startCoord' together
|
||
|
parseNum := startCoord
|
||
|
chk = m.Get(startCoord)
|
||
|
for coordIsNum(m, parseNum) {
|
||
|
resStr = fmt.Sprintf("%s%s", resStr, string(chk))
|
||
|
parseNum = parseNum.East()
|
||
|
chk = m.Get(parseNum)
|
||
|
}
|
||
|
if resStr == "" {
|
||
|
return -1, h.Coordinate{X: -1, Y: -1}
|
||
|
}
|
||
|
return h.Atoi(resStr), startCoord
|
||
|
}
|
||
|
|
||
|
func coordIsNum(m h.CoordByteMap, c h.Coordinate) bool {
|
||
|
wrk := m.Get(c)
|
||
|
return wrk >= '0' && wrk <= '9'
|
||
|
}
|