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 }