AdventOfCode2023/03/main.go

206 lines
4.1 KiB
Go
Raw Normal View History

2023-12-03 11:34:49 +00:00
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"time"
)
2023-12-03 22:35:24 +00:00
func mustAtoi(line []rune) int {
i, _ := strconv.Atoi(string(line))
2023-12-03 11:34:49 +00:00
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)
}
2023-12-04 01:33:05 +00:00
type schematic map[coord]entry
2023-12-03 22:15:50 +00:00
type entry struct {
2023-12-03 22:35:24 +00:00
num []rune
symb rune
}
type tmp struct {
tmp []rune
col int
2023-12-03 22:15:50 +00:00
}
2023-12-04 01:33:05 +00:00
type coord struct {
row int
col int
2023-12-03 22:15:50 +00:00
}
func isSymbol(s schematic, row, col int) bool {
2023-12-04 01:33:05 +00:00
if c, ok := s[coord{row, col}]; ok {
2023-12-03 22:35:24 +00:00
return c.symb != 0
2023-12-03 22:15:50 +00:00
}
return false
}
2023-12-03 11:34:49 +00:00
func partOne() {
scanner := makeScanner(false)
2023-12-03 22:15:50 +00:00
row := 0
schematic := schematic{}
// read the whole thing in
2023-12-03 11:34:49 +00:00
for scanner.Scan() {
2023-12-03 22:15:50 +00:00
line := scanner.Text()
2023-12-03 22:35:24 +00:00
i := tmp{}
2023-12-03 22:15:50 +00:00
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)
}
default:
if len(i.tmp) != 0 {
2023-12-04 01:33:05 +00:00
schematic[coord{row, i.col}] = entry{num: i.tmp}
2023-12-03 22:15:50 +00:00
i.tmp = []rune{}
}
2023-12-03 22:35:24 +00:00
if c != '.' {
2023-12-04 01:33:05 +00:00
schematic[coord{row, col}] = entry{symb: c}
2023-12-03 22:35:24 +00:00
}
2023-12-03 22:15:50 +00:00
}
}
// check if we have a number still to save but ran out of line
if len(i.tmp) != 0 {
2023-12-04 01:33:05 +00:00
schematic[coord{row, i.col}] = entry{num: i.tmp}
2023-12-03 22:15:50 +00:00
}
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++ {
2023-12-04 01:33:05 +00:00
if entry, ok := schematic[coord{row, col}]; ok && entry.symb == 0 {
2023-12-03 22:35:24 +00:00
part := mustAtoi(entry.num)
2023-12-03 22:15:50 +00:00
if isSymbol(schematic, row, col-1) {
// look behind
sum += part
2023-12-03 22:35:24 +00:00
}
if isSymbol(schematic, row, col+len(entry.num)) {
2023-12-03 22:15:50 +00:00
// look ahead
sum += part
2023-12-03 22:35:24 +00:00
}
for i := -1; i < len(entry.num)+1; i++ {
// check row above and below
if isSymbol(schematic, row-1, col+i) {
sum += part
}
if isSymbol(schematic, row+1, col+i) {
sum += part
2023-12-03 22:15:50 +00:00
}
}
}
}
2023-12-03 11:34:49 +00:00
}
2023-12-03 22:15:50 +00:00
fmt.Println(sum)
2023-12-03 11:34:49 +00:00
}
func partTwo() {
scanner := makeScanner(false)
2023-12-03 22:15:50 +00:00
row := 0
schematic := schematic{}
// read the whole thing in
2023-12-03 11:34:49 +00:00
for scanner.Scan() {
2023-12-03 22:15:50 +00:00
line := scanner.Text()
2023-12-03 22:35:24 +00:00
i := tmp{}
2023-12-03 22:15:50 +00:00
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)
}
default:
if len(i.tmp) != 0 {
2023-12-04 01:33:05 +00:00
schematic[coord{row, i.col}] = entry{num: i.tmp}
2023-12-03 22:15:50 +00:00
i.tmp = []rune{}
}
if c == '*' { // no longer care about other symbols
2023-12-04 01:33:05 +00:00
schematic[coord{row, col}] = entry{symb: c}
2023-12-03 22:15:50 +00:00
}
}
}
// check if we have a number still to save but ran out of line
if len(i.tmp) != 0 {
2023-12-04 01:33:05 +00:00
schematic[coord{row, i.col}] = entry{num: i.tmp}
2023-12-03 22:15:50 +00:00
}
row++
}
2023-12-03 22:35:24 +00:00
2023-12-04 01:33:05 +00:00
gears := map[coord]int{}
2023-12-03 22:35:24 +00:00
sum := 0
// map back over the schematics and find the gears.
// there are only ever 1 or 2 parts attached to a gear.
2023-12-03 22:15:50 +00:00
for row := 0; row <= 139; row++ {
for col := 0; col <= 139; col++ {
2023-12-04 01:33:05 +00:00
if entry, ok := schematic[coord{row, col}]; ok && entry.symb == 0 {
2023-12-03 22:35:24 +00:00
offset := len(entry.num)
part := mustAtoi(entry.num)
2023-12-03 22:15:50 +00:00
if isSymbol(schematic, row, col-1) {
2023-12-04 01:33:05 +00:00
k := coord{row, col - 1}
2023-12-03 22:35:24 +00:00
if gears[k] != 0 {
sum += gears[k] * part
} else {
gears[k] = part
2023-12-03 22:15:50 +00:00
}
2023-12-03 22:35:24 +00:00
}
if isSymbol(schematic, row, col+offset) {
2023-12-04 01:33:05 +00:00
k := coord{row, col + offset}
2023-12-03 22:35:24 +00:00
if gears[k] != 0 {
sum += gears[k] * part
} else {
gears[k] = part
2023-12-03 22:15:50 +00:00
}
2023-12-03 22:35:24 +00:00
}
for i := -1; i < offset+1; i++ {
if isSymbol(schematic, row-1, col+i) {
2023-12-04 01:33:05 +00:00
k := coord{row - 1, col + i}
2023-12-03 22:35:24 +00:00
if gears[k] != 0 {
sum += gears[k] * part
} else {
gears[k] = part
}
}
if isSymbol(schematic, row+1, col+i) {
2023-12-04 01:33:05 +00:00
k := coord{row + 1, col + i}
2023-12-03 22:35:24 +00:00
if gears[k] != 0 {
sum += gears[k] * part
} else {
gears[k] = part
2023-12-03 22:15:50 +00:00
}
}
}
}
}
}
fmt.Println(sum)
2023-12-03 11:34:49 +00:00
}