AdventOfCode2023/03/main.go

209 lines
4.5 KiB
Go

package main
import (
"bufio"
"fmt"
"os"
"strconv"
"time"
)
func mustAtoi(line string) int {
i, _ := strconv.Atoi(line)
return i
}
func main() {
start := time.Now()
partOne()
duration := time.Since(start)
partTwo()
duration2 := time.Since(start)
fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration)
}
func makeScanner(test bool) *bufio.Scanner {
var f *os.File
if test {
f, _ = os.Open("inputs/testinput")
} else {
f, _ = os.Open("inputs/input")
}
reader := bufio.NewReader(f)
return bufio.NewScanner(reader)
}
type schematic map[string]entry
type entry struct {
num string
symb string
}
func key(row, col int) string {
return fmt.Sprintf("%d.%d", row, col)
}
func isSymbol(s schematic, row, col int) bool {
if c, ok := s[key(row, col)]; ok {
return c.symb != ""
}
return false
}
func partOne() {
scanner := makeScanner(false)
row := 0
schematic := schematic{}
// read the whole thing in
for scanner.Scan() {
line := scanner.Text()
i := struct {
tmp []rune
col int
}{}
for col, c := range line {
switch c {
case '.':
if len(i.tmp) != 0 {
schematic[key(row, i.col)] = entry{num: string(i.tmp)}
i.tmp = []rune{}
}
continue
case '1', '2', '3', '4', '5', '6', '7', '8', '9', '0':
if len(i.tmp) == 0 {
i.tmp = append(i.tmp, c)
i.col = col
} else {
i.tmp = append(i.tmp, c)
}
continue
default:
if len(i.tmp) != 0 {
schematic[key(row, i.col)] = entry{num: string(i.tmp)}
i.tmp = []rune{}
}
schematic[key(row, col)] = entry{symb: string(c)}
continue
}
}
// check if we have a number still to save but ran out of line
if len(i.tmp) != 0 {
schematic[key(row, i.col)] = entry{num: string(i.tmp)}
i.tmp = []rune{}
}
row++
}
sum := 0
// now, map back over the schematics and find the parts
for row := 0; row <= 139; row++ {
for col := 0; col <= 139; col++ {
if num, ok := schematic[key(row, col)]; ok && num.num != "" {
part := mustAtoi(num.num)
if isSymbol(schematic, row, col-1) {
// look behind
sum += part
} else if isSymbol(schematic, row, col+len(num.num)) {
// look ahead
sum += part
} else {
for i := -1; i < len(num.num)+1; i++ {
// check row above and below
if isSymbol(schematic, row-1, col+i) {
sum += part
break
} else if isSymbol(schematic, row+1, col+i) {
sum += part
break
}
}
}
}
}
}
fmt.Println(sum)
}
func partTwo() {
scanner := makeScanner(false)
row := 0
schematic := schematic{}
// read the whole thing in
for scanner.Scan() {
line := scanner.Text()
i := struct {
tmp []rune
col int
}{}
for col, c := range line {
switch c {
case '1', '2', '3', '4', '5', '6', '7', '8', '9', '0':
if len(i.tmp) == 0 {
i.tmp = append(i.tmp, c)
i.col = col
} else {
i.tmp = append(i.tmp, c)
}
continue
default:
if len(i.tmp) != 0 {
schematic[key(row, i.col)] = entry{num: string(i.tmp)}
i.tmp = []rune{}
}
if c == '*' { // no longer care about other symbols
schematic[key(row, col)] = entry{symb: string(c)}
}
continue
}
}
// check if we have a number still to save but ran out of line
if len(i.tmp) != 0 {
schematic[key(row, i.col)] = entry{num: string(i.tmp)}
i.tmp = []rune{}
}
row++
}
gears := map[string][]int{}
// map back over the schematics and find the gears
for row := 0; row <= 139; row++ {
for col := 0; col <= 139; col++ {
if num, ok := schematic[key(row, col)]; ok && num.num != "" {
part := mustAtoi(num.num)
if isSymbol(schematic, row, col-1) {
if schematic[key(row, col-1)].symb == "*" {
gears[key(row, col-1)] = append(gears[key(row, col-1)], part)
}
} else if isSymbol(schematic, row, col+len(num.num)) {
if schematic[key(row, col+len(num.num))].symb == "*" {
gears[key(row, col+len(num.num))] = append(gears[key(row, col+len(num.num))], part)
}
} else {
for i := -1; i < len(num.num)+1; i++ {
// check row above and below
if isSymbol(schematic, row-1, col+i) {
if schematic[key(row-1, col+i)].symb == "*" {
gears[key(row-1, col+i)] = append(gears[key(row-1, col+i)], part)
}
break
} else if isSymbol(schematic, row+1, col+i) {
if schematic[key(row+1, col+i)].symb == "*" {
gears[key(row+1, col+i)] = append(gears[key(row+1, col+i)], part)
}
break
}
}
}
}
}
}
sum := 0
for _, g := range gears {
if len(g) == 2 {
sum += g[0] * g[1]
}
}
fmt.Println(sum)
}