From 55fa420ed3b419ec2a5288cd5bb83091f74275c1 Mon Sep 17 00:00:00 2001 From: RPJosh Date: Sun, 3 Dec 2023 09:49:00 +0100 Subject: [PATCH] 2023.03 --- internal/2023/day_03/in.go | 195 ++++++++++++++++++++++++++++++++++++- pkg/utils/utils.go | 5 + 2 files changed, 197 insertions(+), 3 deletions(-) diff --git a/internal/2023/day_03/in.go b/internal/2023/day_03/in.go index d1da985..8635e68 100644 --- a/internal/2023/day_03/in.go +++ b/internal/2023/day_03/in.go @@ -1,11 +1,200 @@ package day_03 -type Day struct{} +import ( + "fmt" + "strings" + + "git.rpjosh.de/RPJosh/go-logger" + "rpjosh.de/adventOfCode/pkg/utils" +) + +type Day struct { + engine []string + + currentRow int + currentLine int +} func (d *Day) Part1(in string) string { - return "" + + // Initialize variables + sum := 0 + d.currentLine = -1 + d.engine = strings.Split(in, "\n") + + for _, val := range d.engine { + if val == "" { + continue + } + + // Initialize variables + strVal := "" + isSymbolNear := false + d.currentRow = 0 + d.currentLine++ + + // Loop through all characters and find ints + for _, str := range val { + if utils.IsInt(string(str)) { + strVal += string(str) + if !isSymbolNear { + // Check if a symbol is near + isSymbolNear = d.isSymbolNear() + } + } else { + // It's a '.' or a symbole + if strVal != "" && isSymbolNear { + logger.Debug("Found value %q", strVal) + sum += utils.ToInt(strVal) + } + + // Reset variables + strVal = "" + isSymbolNear = false + } + + d.currentRow += 1 + } + + // End of line + if strVal != "" && isSymbolNear { + logger.Debug("Found value %q", strVal) + sum += utils.ToInt(strVal) + } + } + + return fmt.Sprintf("%d", sum) +} + +func (d *Day) isSymbolNear() bool { + + // Left and right + if d.isSymbole(d.currentRow-1, d.currentLine, ' ') || d.isSymbole(d.currentRow+1, d.currentLine, ' ') { + return true + } + + // Top and bottom + if d.isSymbole(d.currentRow, d.currentLine-1, ' ') || d.isSymbole(d.currentRow, d.currentLine+1, ' ') { + return true + } + + // Diagonale + if d.isSymbole(d.currentRow-1, d.currentLine-1, ' ') || d.isSymbole(d.currentRow-1, d.currentLine+1, ' ') { + return true + } + if d.isSymbole(d.currentRow+1, d.currentLine-1, ' ') || d.isSymbole(d.currentRow+1, d.currentLine+1, ' ') { + return true + } + + return false +} + +// isGearNear returns weather a * is near and the index of that gear +// (row,line) +func (d *Day) isGearNear() (bool, string) { + + // Left and right + if d.isSymbole(d.currentRow-1, d.currentLine, '*') { + return true, fmt.Sprintf("%d,%d", d.currentRow-1, d.currentLine) + } + if d.isSymbole(d.currentRow+1, d.currentLine, '*') { + return true, fmt.Sprintf("%d,%d", d.currentRow+1, d.currentLine) + } + + // Top and bottom + if d.isSymbole(d.currentRow, d.currentLine-1, '*') { + return true, fmt.Sprintf("%d,%d", d.currentRow, d.currentLine-1) + } + if d.isSymbole(d.currentRow, d.currentLine+1, '*') { + return true, fmt.Sprintf("%d,%d", d.currentRow, d.currentLine+1) + } + + // Diagonale + if d.isSymbole(d.currentRow-1, d.currentLine-1, '*') { + return true, fmt.Sprintf("%d,%d", d.currentRow-1, d.currentLine-1) + } + if d.isSymbole(d.currentRow-1, d.currentLine+1, '*') { + return true, fmt.Sprintf("%d,%d", d.currentRow-1, d.currentLine+1) + } + if d.isSymbole(d.currentRow+1, d.currentLine-1, '*') { + return true, fmt.Sprintf("%d,%d", d.currentRow+1, d.currentLine-1) + } + if d.isSymbole(d.currentRow+1, d.currentLine+1, '*') { + return true, fmt.Sprintf("%d,%d", d.currentRow+1, d.currentLine+1) + } + + return false, "" +} + +// isSymbole checks if the characters at the given position is a rune. +// If an invalid line or row is provided, this function returns false +func (d *Day) isSymbole(row, line int, symbole rune) bool { + // Check out of bounds + if row < 0 || line < 0 || line >= len(d.engine) || row >= len(d.engine[line]) { + return false + } + + val := d.engine[line][row] + return val != '.' && !utils.IsInt(string(val)) && (symbole == ' ' || symbole == rune(val)) } func (d *Day) Part2(in string) string { - return "" + // Initialize variables + d.currentLine = -1 + d.engine = strings.Split(in, "\n") + gears := make(map[string][]int, 0) + + for _, val := range d.engine { + if val == "" { + continue + } + + // Initialize variables + strVal := "" + isGearNear := false + isGearNearPos := "" + d.currentRow = 0 + d.currentLine++ + + // Loop through all characters and find ints + for _, str := range val { + if utils.IsInt(string(str)) { + strVal += string(str) + // Check if a symbol is near + if isNear, pos := d.isGearNear(); isNear { + isGearNear = true + isGearNearPos = pos + } + } else { + // It's a '.' or a symbole + if strVal != "" && isGearNear { + logger.Debug("Found pos %q with value %q", isGearNearPos, strVal) + gears[isGearNearPos] = append(gears[isGearNearPos], utils.ToInt(strVal)) + } + + // Reset variables + strVal = "" + isGearNear = false + isGearNearPos = "" + } + + d.currentRow += 1 + } + + // End of line + // Check if a symbol is near + if isGearNear { + logger.Debug("Found pos %q with value %q", isGearNearPos, strVal) + gears[isGearNearPos] = append(gears[isGearNearPos], utils.ToInt(strVal)) + } + } + + sum := 0 + for _, values := range gears { + if len(values) == 2 { + sum += values[0] * values[1] + } + } + + return fmt.Sprintf("%d", sum) } diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 91ad06a..8d9f5d2 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -94,3 +94,8 @@ func ToInt(val string) int { return value } + +func IsInt(val string) bool { + _, err := strconv.Atoi(val) + return err == nil +}