Advent-of-Code-2023/day3/day-three.go

164 lines
3.4 KiB
Go

package day3
import (
"fmt"
"os"
"strings"
"unicode"
)
func Run() int {
filename := "day3/input"
bytes, err := os.ReadFile(filename)
if err != nil {
panic(fmt.Sprint(err, filename))
}
text := string(bytes)
matrix := ReadMatrix(text)
fmt.Println(matrix.String())
numbers := ReadNumbers(&matrix)
for _, num := range numbers {
fmt.Println(num)
}
// partNumbersSum := 0
// for _, num := range numbers {
// if len(num.Specials) > 0 {
// partNumbersSum += num.Num
// }
// }
gearRatiosSum := partTwo(numbers)
return gearRatiosSum
}
type Matrix [][]rune
func ReadMatrix(text string) Matrix {
text = strings.TrimSpace(text)
lines := strings.Split(text, "\n")
matrix := make([][]rune, len(lines))
for i, lineStr := range strings.Split(text, "\n") {
for _, r := range lineStr {
matrix[i] = append(matrix[i], r)
}
}
return matrix
}
func (m *Matrix)String() string {
res := make([]string, len(*m))
for _, row := range *m {
res = append(res, string(row) + "\n")
}
return strings.Join(res, "")
}
// and now from matrix, i want to scan top-down, left-right
// when encountering digit - start new number, read it in
// and when finished reading : scan around for the special symbols
type SpecialSymbol struct {
Symb rune
X, Y int
}
func (s SpecialSymbol) String() string {
return fmt.Sprintf("('%s' at x:%d,y:%d)", string(s.Symb), s.X, s.Y)
}
func (s SpecialSymbol) Equal() bool {
return false
}
type MatrixNumber struct {
Num int
Specials map[SpecialSymbol]any
}
func ReadNumbers(m *Matrix) []MatrixNumber {
res := make([]MatrixNumber, 0)
var curNum *MatrixNumber
for x, row := range *m {
for y, symb := range row {
if unicode.IsDigit(symb) {
digit := int(symb - '0')
// seing digit
if curNum == nil {
curNum = &MatrixNumber{
Num: digit,
Specials: make(map[SpecialSymbol]any),
}
} else {
curNum.Num = curNum.Num*10 + digit
}
// on each digit - scan around for special symbols
for i := x-1; i <= x+1; i++ {
for j := y-1; j <= y+1; j++ {
if isValidCoord(i, j, m) {
checkingForSpecial := (*m)[i][j]
if checkingForSpecial != '.' && !unicode.IsDigit(checkingForSpecial) {
special := SpecialSymbol{
Symb: checkingForSpecial,
X: i,
Y: j,
}
curNum.Specials[special] = struct{}{}
}
}
}
}
// now let's check for special symbols around and save them
}
if !unicode.IsDigit(symb) {
if curNum != nil {
res = append(res, *curNum)
curNum = nil
}
}
}
}
return res
}
// x is row, y is column. from top-left to bottom-right
func isValidCoord(x, y int, m *Matrix) bool {
if x < 0 || y < 0 || x >= len(*m) || y >= len((*m)[x]) {
return false
}
return true
}
// part 2 - find all gears '*' that connect exactly two numbers
// multiply the numbers and calculate total sum
// i guess i could do full scan of my numbers?
// every time i encounter '*' in special symbols, could put that into map, hopefully?
// with value for the number
func partTwo(numbers []MatrixNumber) int {
res := 0
specialsMap := make(map[SpecialSymbol][]MatrixNumber)
for _, num := range numbers {
for special, _ := range num.Specials {
specialsMap[special] = append(specialsMap[special], num)
}
}
for special, nums := range specialsMap {
if special.Symb == '*' && len(nums) == 2 {
res += nums[0].Num * nums[1].Num
}
}
return res
}