Skip to content

Instantly share code, notes, and snippets.

@PatrickVienne
Created December 3, 2023 06:21
Show Gist options
  • Save PatrickVienne/8c4dd899fb4d2e974786e7dd3b029623 to your computer and use it in GitHub Desktop.
Save PatrickVienne/8c4dd899fb4d2e974786e7dd3b029623 to your computer and use it in GitHub Desktop.
Advent of Code 2023 - Day 3
package d3
import (
"bufio"
"io"
"regexp"
"strconv"
)
func Must(err error) {
if err != nil {
panic(err)
}
}
func getSum(numbers []int) int {
total := 0
for _, num := range numbers {
total += num
}
return total
}
// idea:
// find all numbers and their index ranges
// look for symbol around their index ranges
func d3_1(r io.Reader) int {
numberLinesStartTopIdx := map[int][][3]int{}
symbolLinesStartTopIdx := map[int]map[int]bool{}
reNums := regexp.MustCompile(`\d+`)
fileScanner := bufio.NewScanner(r)
fileScanner.Split(bufio.ScanLines)
lineNo := 0
for fileScanner.Scan() {
numberLinesStartTopIdx[lineNo] = [][3]int{}
lineBytes := fileScanner.Bytes()
for i, c := range lineBytes {
if (c >= '0' && c <= '9') || c == '.' {
continue
} else {
if val, ok := symbolLinesStartTopIdx[lineNo]; !ok {
symbolLinesStartTopIdx[lineNo] = map[int]bool{i: true}
} else {
val[i] = true
}
}
}
nums := reNums.FindAllIndex(lineBytes, -1)
for _, numGroup := range nums {
num, err := strconv.Atoi(string(lineBytes[numGroup[0]:numGroup[1]]))
Must(err)
numberLinesStartTopIdx[lineNo] = append(numberLinesStartTopIdx[lineNo], [3]int{numGroup[0], numGroup[1], num})
}
lineNo++
}
validNumbers := []int{}
for lineNo, numGroups := range numberLinesStartTopIdx {
for _, numGroup := range numGroups {
// start or end of number
if symbolLine, ok := symbolLinesStartTopIdx[lineNo]; !ok {
// nothing on the same line
} else if symbolLine[numGroup[0]-1] || symbolLine[numGroup[1]] {
validNumbers = append(validNumbers, numGroup[2])
continue
}
// line on top or under
for i := numGroup[0] - 1; i <= numGroup[1]; i++ {
if symbolLine, ok := symbolLinesStartTopIdx[lineNo-1]; !ok {
// nothing on the same line
} else if symbolLine[i] {
validNumbers = append(validNumbers, numGroup[2])
break
}
if symbolLine, ok := symbolLinesStartTopIdx[lineNo+1]; !ok {
// nothing on the same line
} else if symbolLine[i] {
validNumbers = append(validNumbers, numGroup[2])
break
}
}
}
}
return getSum(validNumbers)
}
func d3_2(r io.Reader) int {
numberLinesStartTopIdx := map[int][][3]int{}
symbolLinesStartTopIdx := map[int]map[int]bool{}
reNums := regexp.MustCompile(`\d+`)
fileScanner := bufio.NewScanner(r)
fileScanner.Split(bufio.ScanLines)
lineNo := 0
for fileScanner.Scan() {
numberLinesStartTopIdx[lineNo] = [][3]int{}
lineBytes := fileScanner.Bytes()
for i, c := range lineBytes {
if c == '*' {
if val, ok := symbolLinesStartTopIdx[lineNo]; !ok {
symbolLinesStartTopIdx[lineNo] = map[int]bool{i: true}
} else {
val[i] = true
}
}
}
nums := reNums.FindAllIndex(lineBytes, -1)
for _, numGroup := range nums {
num, err := strconv.Atoi(string(lineBytes[numGroup[0]:numGroup[1]]))
Must(err)
numberLinesStartTopIdx[lineNo] = append(numberLinesStartTopIdx[lineNo], [3]int{numGroup[0], numGroup[1], num})
}
lineNo++
}
totalSum := 0
for lineNo, startStops := range symbolLinesStartTopIdx {
for gearIdx := range startStops {
neighborNumsCount := 0
neighborNums := []int{}
for _, numGroup := range numberLinesStartTopIdx[lineNo-1] {
if gearIdx >= numGroup[0]-1 && gearIdx <= numGroup[1] {
neighborNumsCount++
neighborNums = append(neighborNums, numGroup[2])
}
}
for _, numGroup := range numberLinesStartTopIdx[lineNo] {
if gearIdx >= numGroup[0]-1 && gearIdx <= numGroup[1] {
neighborNumsCount++
neighborNums = append(neighborNums, numGroup[2])
}
}
for _, numGroup := range numberLinesStartTopIdx[lineNo+1] {
if gearIdx >= numGroup[0]-1 && gearIdx <= numGroup[1] {
neighborNumsCount++
neighborNums = append(neighborNums, numGroup[2])
}
}
if neighborNumsCount == 2 {
totalSum += neighborNums[0] * neighborNums[1]
}
}
}
return totalSum
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment