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