Day 3 was quite something. I think that in an attempt to make it harder for AI to solve the puzzles the creators also increased the difficulty level of the base puzzles a little too much. The test was not very clear as to what should happen with negative numbers and it might trip people up. The puzzle itself is a great to exercise grid knowledge as you have to work with neighbors and you have to extend the numbers when you find them. Part 2 was just some bookkeeping on my existing implementation, so it was not too much work.

As a note; I first started out with a list of Points, keeping track of the numbers in a coordinate system. This failed miserably :).

```
package main
import (
"fmt"
"arjenwiersma.nl/aoc/internal/aoc"
)
type Point struct {
Y, X int
}
func IsDigit(b byte) bool {
return b-'0' >= 0 && b-'0' <= 9
}
func main() {
lines := aoc.AsLines("2023/Day03/input.txt")
ygrid := len(lines)
xgrid := len(lines[0])
grid := make([][]byte, ygrid)
for y, l := range lines {
grid[y] = make([]byte, xgrid)
for x := 0; x < len(l); x++ {
grid[y][x] = l[x]
}
}
neighbors := [][]int{
{-1, -1}, {0, -1}, {1, -1},
{-1, 0}, {0, 0}, {1, 0},
{-1, 1}, {0, 1}, {1, 1},
}
gears := make(map[Point][]int)
sum := 0
for y := 0; y < ygrid; y++ {
for x := 0; x < xgrid; x++ {
num := 0
hasSymbol := false
isGear := false
var gearCoord Point
for IsDigit(grid[y][x]) {
num = num*10 + int(grid[y][x]-'0')
for _, n := range neighbors {
if y+n[1] >= 0 && y+n[1] < ygrid &&
x+n[0] >= 0 && x+n[0] < xgrid {
v := grid[y+n[1]][x+n[0]]
if !IsDigit(v) && v != '.' {
if v == '*' {
isGear = true
gearCoord = Point{X: x + n[0], Y: y + n[1]}
}
hasSymbol = true
}
}
}
x += 1
if x >= xgrid {
break
}
}
if num > 0 && hasSymbol {
if isGear {
gears[gearCoord] = append(gears[gearCoord], num)
}
sum += num
}
}
}
fmt.Println("Part 1: ", sum) // 498559
sum = 0
for _, v := range gears {
if len(v) == 2 {
sum += v[0] * v[1]
}
}
fmt.Println("Part 2: ", sum) // 72246648
}
```