github.com/agrigoryan/aoc_2023_go@v0.0.0-20231216221323-4ace361ec685/day3/d3p2.go (about)

     1  package day3
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  	"strings"
     7  	"unicode"
     8  )
     9  
    10  func d3p2(input string) int {
    11  	lines := strings.Split(input, "\n")
    12  
    13  	const empty = '.'
    14  
    15  	hasSymbol := func(parts []string) bool {
    16  		for _, p := range parts {
    17  			for _, r := range p {
    18  				if !unicode.IsDigit(r) && r != empty {
    19  					return true
    20  				}
    21  			}
    22  		}
    23  		return false
    24  	}
    25  
    26  	type partNumber struct {
    27  		numLine int
    28  		value   int
    29  		start   int
    30  		end     int
    31  	}
    32  
    33  	parts := []partNumber{}
    34  
    35  	digitFound := func(numLine int, line string, start int, end int) {
    36  		pStart := max(start-1, 0)
    37  		pEnd := min(end+1, len(line))
    38  		partsToCheck := []string{line[pStart:pEnd]}
    39  
    40  		if numLine > 0 {
    41  			partsToCheck = append(partsToCheck, lines[numLine-1][pStart:pEnd])
    42  		}
    43  		if numLine < len(lines)-1 {
    44  			partsToCheck = append(partsToCheck, lines[numLine+1][pStart:pEnd])
    45  		}
    46  
    47  		if hasSymbol(partsToCheck) {
    48  			if num, err := strconv.Atoi(line[start:end]); err == nil {
    49  				parts = append(parts, partNumber{
    50  					numLine: numLine,
    51  					value:   num,
    52  					start:   start,
    53  					end:     end,
    54  				})
    55  			}
    56  		}
    57  	}
    58  
    59  	for i, line := range lines {
    60  		digitStart := -1
    61  		for j, r := range line {
    62  			if unicode.IsDigit(r) {
    63  				if digitStart == -1 {
    64  					digitStart = j
    65  				}
    66  			} else if digitStart != -1 {
    67  				digitFound(i, line, digitStart, j)
    68  				digitStart = -1
    69  			}
    70  		}
    71  		if digitStart != -1 {
    72  			digitFound(i, line, digitStart, len(line))
    73  		}
    74  	}
    75  
    76  	sum := 0
    77  	for i, line := range lines {
    78  		for j, r := range line {
    79  			if r == '*' {
    80  				adjacentPartNumbers := []int{}
    81  				for _, p := range parts {
    82  					if p.numLine < i+2 && p.numLine > i-2 && j > p.start-2 && j < p.end+1 {
    83  						adjacentPartNumbers = append(adjacentPartNumbers, p.value)
    84  					}
    85  				}
    86  				if len(adjacentPartNumbers) == 2 {
    87  					sum += adjacentPartNumbers[0] * adjacentPartNumbers[1]
    88  				}
    89  			}
    90  		}
    91  	}
    92  	fmt.Println(sum)
    93  	return sum
    94  }