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