You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

233 lines
3.5 KiB
Go

package day3
import (
"fmt"
"strconv"
)
type Number struct {
value int
l int
js int
je int
}
type Gear struct {
l int
c int
}
var gears map[Gear]*[]*Number
func parseNumber(lineNum int, line string, start int) *Number {
js := start
// move to first digit
for ; js < len(line); js++ {
c := line[js]
if c >= '0' && c <= '9' {
break
}
}
// return nil if no digit
if js == len(line) {
return nil
}
je := js + 1
// move to last digit in sequence
for ; je < len(line); je++ {
c := line[je]
if c < '0' || c > '9' {
break
}
}
//fmt.Println("-->", js, je)
num, err := strconv.Atoi(line[js:je])
if err != nil {
fmt.Println(err)
}
return &Number{
value: num,
l: lineNum,
js: js,
je: je - 1,
}
}
func hasGearInRange(lineNum int, line string, start int, end int) *Gear {
i := start - 1
if i < 1 {
i = 0
}
for ; i < len(line) && i <= end+1; i++ {
c := line[i]
if (c < '0' || c > '9') && c != '.' {
return &Gear{
l: lineNum,
c: i,
}
}
}
return nil
}
func hasAdjacentSymbol(n *Number, before string, line string, after string) *Gear {
if before != "" {
g := hasGearInRange(n.l-1, before, n.js, n.je)
if g != nil {
return g
}
}
g := hasGearInRange(n.l, line, n.js, n.je)
if g != nil {
return g
}
if after != "" {
g := hasGearInRange(n.l+1, after, n.js, n.je)
if g != nil {
return g
}
}
return nil
}
func PartNumberSum(lines []string) int {
result := 0
for i, line := range lines {
for j := 0; j < len(line); {
num := parseNumber(i, line, j)
if num == nil {
break // no new number on this line
}
// number found
before := ""
after := ""
if i > 0 {
before = lines[i-1]
}
if i < len(lines)-1 {
after = lines[i+1]
}
g := hasAdjacentSymbol(num, before, line, after)
b := g != nil
fmt.Printf("%t : Found %d at line %d between col %d and col %d\n", b, num.value, i, num.js, num.je)
if b {
result += num.value
}
// move cursor to the first char following the number
j = num.je + 1
}
}
return result
}
func markGearInRange(n *Number, lineNum int, line string, start int, end int) {
i := start - 1
if i < 1 {
i = 0
}
for ; i < len(line) && i <= end+1; i++ {
c := line[i]
if (c < '0' || c > '9') && c != '.' {
key := Gear{
l: lineNum,
c: i,
}
nums, ok := gears[key]
if !ok {
newNums := make([]*Number, 0)
nums = &newNums
gears[key] = nums
}
newNums := append(*nums, n)
gears[key] = &newNums
}
}
}
func markAdjacentSymbols(n *Number, before string, line string, after string) {
if before != "" {
markGearInRange(n, n.l-1, before, n.js, n.je)
}
markGearInRange(n, n.l, line, n.js, n.je)
if after != "" {
markGearInRange(n, n.l+1, after, n.js, n.je)
}
}
func GearRatioSum(lines []string) int64 {
result := int64(0)
gears = make(map[Gear]*[]*Number)
for i, line := range lines {
for j := 0; j < len(line); {
num := parseNumber(i, line, j)
if num == nil {
break // no new number on this line
}
// number found
before := ""
after := ""
if i > 0 {
before = lines[i-1]
}
if i < len(lines)-1 {
after = lines[i+1]
}
markAdjacentSymbols(num, before, line, after)
// move cursor to the first char following the number
j = num.je + 1
}
}
for k, v := range gears {
t := *v
if len(t) == 2 {
ratio := t[0].value * t[1].value
fmt.Printf("Found gear at line %d and col %d with ratio %v\n", k.l, k.c, ratio)
result += int64(ratio)
}
}
return result
}