Day 3a
This commit is contained in:
parent
7403ce8e72
commit
27b95e6717
3 changed files with 148 additions and 0 deletions
113
day03/day03.go
Normal file
113
day03/day03.go
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
const DIGITS = "0123456789"
|
||||||
|
const SPACE = '.'
|
||||||
|
|
||||||
|
type Number struct {
|
||||||
|
number int
|
||||||
|
index int
|
||||||
|
width int
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func isDigit(in rune) bool {
|
||||||
|
return strings.ContainsRune(DIGITS, in)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNotDigit(in rune) bool {
|
||||||
|
return !isDigit(in)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isSpace(in rune) bool {
|
||||||
|
return in == SPACE
|
||||||
|
}
|
||||||
|
|
||||||
|
func isPart(in rune) bool {
|
||||||
|
return !isDigit(in) && !isSpace(in)
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasPartAtPos(line string, at int) bool {
|
||||||
|
return at >= 0 && at < len(line) && isPart(rune(line[at]))
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasPartInRange(line string, from int, to int) bool {
|
||||||
|
return len(line) > from && strings.ContainsFunc(line[max(from, 0):min(to, len(line))], isPart)
|
||||||
|
}
|
||||||
|
|
||||||
|
func findNumbers(line string) (numbers []Number) {
|
||||||
|
offset, index := 0, 0
|
||||||
|
for {
|
||||||
|
index = strings.IndexFunc(line[offset:], isDigit)
|
||||||
|
if index == -1 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
width := strings.IndexFunc(line[offset+index:], isNotDigit)
|
||||||
|
if width == -1 {
|
||||||
|
width = len(line) - offset - index
|
||||||
|
}
|
||||||
|
|
||||||
|
numberA := line[offset+index:offset+index+width]
|
||||||
|
numberI, err := strconv.Atoi(numberA)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf(`day03: could not parse number: "%s"`, numberA))
|
||||||
|
}
|
||||||
|
|
||||||
|
numbers = append(numbers, Number{numberI, offset+index, width})
|
||||||
|
offset += index + width
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func ScanFile(file *os.File) (int, error) {
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
var sum int
|
||||||
|
|
||||||
|
var prevLine string
|
||||||
|
var prevNumbers []Number
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
numbers := findNumbers(line)
|
||||||
|
|
||||||
|
var unmatchedNumbers []Number
|
||||||
|
for _, v := range numbers {
|
||||||
|
number, index, width := v.number, v.index, v.width
|
||||||
|
if hasPartAtPos(line, index - 1) || hasPartAtPos(line, index + width) || hasPartInRange(prevLine, index - 1, index + width + 1) {
|
||||||
|
sum += number
|
||||||
|
} else {
|
||||||
|
unmatchedNumbers = append(unmatchedNumbers, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, v := range prevNumbers {
|
||||||
|
number, index, width := v.number, v.index, v.width
|
||||||
|
if hasPartInRange(line, index - 1, index + width + 1) {
|
||||||
|
sum += number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prevLine = line
|
||||||
|
prevNumbers = unmatchedNumbers
|
||||||
|
}
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return sum, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
sum, err := ScanFile(os.Stdin)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Invalid input: %s\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Println(sum)
|
||||||
|
}
|
25
day03/day03_test.go
Normal file
25
day03/day03_test.go
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestScanFile(t *testing.T) {
|
||||||
|
inFile := "input.txt"
|
||||||
|
want := 4361
|
||||||
|
|
||||||
|
f, err := os.Open(inFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
got, err := ScanFile(f)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got != want {
|
||||||
|
t.Errorf("ScanFile(%q) == %d, want %d", inFile, got, want)
|
||||||
|
}
|
||||||
|
}
|
10
day03/input.txt
Normal file
10
day03/input.txt
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
467..114..
|
||||||
|
...*......
|
||||||
|
..35..633.
|
||||||
|
......#...
|
||||||
|
617*......
|
||||||
|
.....+.58.
|
||||||
|
..592.....
|
||||||
|
......755.
|
||||||
|
...$.*....
|
||||||
|
.664.598..
|
Loading…
Add table
Add a link
Reference in a new issue