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