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
|
|
|
}
|