mirror of
https://github.com/Crocmagnon/advent-of-code.git
synced 2024-11-21 14:08:11 +01:00
135 lines
3 KiB
Go
135 lines
3 KiB
Go
package _023
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"io"
|
|
"regexp"
|
|
"slices"
|
|
"strconv"
|
|
)
|
|
|
|
type Day03Number struct {
|
|
lineNo int
|
|
start int
|
|
end int
|
|
value int
|
|
}
|
|
|
|
type Day03Symbol struct {
|
|
row, col int
|
|
}
|
|
|
|
func Day03Part1(input io.Reader) (int, error) {
|
|
numberReg := regexp.MustCompile(`\d+`)
|
|
symbolReg := regexp.MustCompile(`[^\d.]`)
|
|
scanner := bufio.NewScanner(input)
|
|
var symbols []Day03Symbol
|
|
var numbers []Day03Number
|
|
|
|
lineNo := 0
|
|
width := 0
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
width = len(line)
|
|
lineNumbers := numberReg.FindAllStringIndex(line, -1)
|
|
lineSymbols := symbolReg.FindAllStringIndex(line, -1)
|
|
for _, symbol := range lineSymbols {
|
|
symbols = append(symbols, Day03Symbol{lineNo, symbol[0]})
|
|
}
|
|
for _, number := range lineNumbers {
|
|
value, err := strconv.Atoi(line[number[0]:number[1]])
|
|
if err != nil {
|
|
return 0, fmt.Errorf("parsing number: %w", err)
|
|
}
|
|
numbers = append(numbers, Day03Number{lineNo, number[0], number[1], value})
|
|
}
|
|
lineNo++
|
|
}
|
|
|
|
sum := 0
|
|
for _, number := range numbers {
|
|
if isAdjacent(number, symbols, lineNo, width) {
|
|
sum += number.value
|
|
}
|
|
}
|
|
|
|
return sum, nil
|
|
}
|
|
|
|
func isAdjacent(number Day03Number, symbols []Day03Symbol, height, width int) bool {
|
|
minRow := max(number.lineNo-1, 0)
|
|
maxRow := min(number.lineNo+1, height)
|
|
minCol := max(number.start-1, 0)
|
|
maxCol := min(number.end, width)
|
|
|
|
for row := minRow; row <= maxRow; row++ {
|
|
for col := minCol; col <= maxCol; col++ {
|
|
if slices.Contains(symbols, Day03Symbol{row, col}) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func Day03Part2(input io.Reader) (int, error) {
|
|
numberReg := regexp.MustCompile(`\d+`)
|
|
symbolReg := regexp.MustCompile(`\*`)
|
|
scanner := bufio.NewScanner(input)
|
|
|
|
var (
|
|
potentialGears []Day03Symbol
|
|
numbers []Day03Number
|
|
)
|
|
|
|
lineNo := 0
|
|
width := 0
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
width = len(line)
|
|
lineNumbers := numberReg.FindAllStringIndex(line, -1)
|
|
lineSymbols := symbolReg.FindAllStringIndex(line, -1)
|
|
for _, symbol := range lineSymbols {
|
|
potentialGears = append(potentialGears, Day03Symbol{lineNo, symbol[0]})
|
|
}
|
|
for _, number := range lineNumbers {
|
|
value, err := strconv.Atoi(line[number[0]:number[1]])
|
|
if err != nil {
|
|
return 0, fmt.Errorf("parsing number: %w", err)
|
|
}
|
|
numbers = append(numbers, Day03Number{lineNo, number[0], number[1], value})
|
|
}
|
|
lineNo++
|
|
}
|
|
|
|
sum := 0
|
|
for _, potentialGear := range potentialGears {
|
|
sum += gearRatio(potentialGear, numbers, lineNo, width)
|
|
}
|
|
|
|
return sum, nil
|
|
}
|
|
|
|
func gearRatio(gear Day03Symbol, numbers []Day03Number, height int, width int) int {
|
|
minRow := max(gear.row-1, 0)
|
|
maxRow := min(gear.row+1, height)
|
|
minCol := max(gear.col-1, 0)
|
|
maxCol := min(gear.col+1, width)
|
|
|
|
var ratio []int
|
|
for row := minRow; row <= maxRow; row++ {
|
|
for col := minCol; col <= maxCol; col++ {
|
|
for _, number := range numbers {
|
|
if row == number.lineNo && col >= number.start && col < number.end {
|
|
ratio = append(ratio, number.value)
|
|
col = number.end
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if len(ratio) != 2 {
|
|
return 0
|
|
}
|
|
return ratio[0] * ratio[1]
|
|
}
|