aoc2023/day-3/one.go
2023-12-03 23:57:05 +00:00

118 lines
2.4 KiB
Go

package main
import (
"fmt"
"strconv"
"unicode"
)
var symbols = [][]bool{}
// enginePart represents a single engine part
type enginePart struct {
digits []digit
}
// realValue returns the numeric value of all digits combined
func (e *enginePart) realValue() (int, error) {
var numStr string
for _, digit := range e.digits {
numStr += fmt.Sprintf("%d", digit.raw)
}
n, err := strconv.Atoi(numStr)
if err != nil {
return 0, err
}
return n, nil
}
// digit represents a single digit in an engine part
type digit struct {
row int
col int
raw int
pass bool
}
// checkDigit checks if any neighbouring characters are true (in symbol matrix)
func checkDigit(d digit) digit {
i := d.col - 1
for ; i < len(symbols[d.row]) && i <= d.col+1; i += 1 {
if i < 0 {
continue
}
if d.row != 0 {
if symbols[d.row-1][i] {
d.pass = true
break
}
}
if symbols[d.row][i] {
d.pass = true
break
}
if d.row != len(symbols)-1 {
if symbols[d.row+1][i] {
d.pass = true
break
}
}
}
return d
}
// checkDigits runs each digit in an engine part through checkDigit()
func checkDigits(i, j int, line string) (int, int, error) {
enginePart := enginePart{}
for ; j < len(line); j += 1 {
if !unicode.IsNumber(rune(line[j])) {
break
}
enginePart.digits = append(enginePart.digits, checkDigit(digit{row: i, col: j, raw: int(line[j]) - '0', pass: false}))
}
if anyTrue(enginePart.digits) {
engineParts[i] = append(engineParts[i], enginePart)
n, err := enginePart.realValue()
if err != nil {
return 0, 0, err
}
return j, n, nil
}
return j, 0, nil
}
// symbolToBool generates a boolean matrix that represents the placement of symbols
func symbolToBool(line string) []bool {
bool_arr := []bool{}
for _, c := range line {
bool_arr = append(bool_arr, !(unicode.IsNumber(c) || c == '.'))
}
return bool_arr
}
// one deciphers which numbers represent engine parts
// it returns the sum of all engine parts
func one(lines []string) (int, error) {
for _, line := range lines {
symbols = append(symbols, symbolToBool(line))
}
engineParts = make([][]enginePart, len(lines))
sum := 0
for i, line := range lines {
for j := 0; j < len(line); j += 1 {
if unicode.IsNumber(rune(line[j])) {
next, n, err := checkDigits(i, j, line)
if err != nil {
return 0, err
}
sum += n
j = next
}
}
}
return sum, nil
}