mirror of
https://github.com/onyx-and-iris/aoc2023.git
synced 2024-11-22 10:20:48 +00:00
118 lines
2.4 KiB
Go
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
|
||
|
}
|