111 lines
2.2 KiB
Go
111 lines
2.2 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
func proccessLines(path string, f func(string) (stop bool, err error)) error {
|
|
file, err := os.Open(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer file.Close()
|
|
scanner := bufio.NewScanner(file)
|
|
for scanner.Scan() {
|
|
stop, err := f(scanner.Text())
|
|
if stop || err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if err := scanner.Err(); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
var matcher = regexp.MustCompile(`([0-9]+)-([0-9]+) ([a-zA-Z]): ([a-zA-Z]+)`)
|
|
|
|
func part1() {
|
|
totalValid := 0
|
|
err := proccessLines("input.txt", func(line string) (stop bool, err error) {
|
|
results := matcher.FindStringSubmatch(line)
|
|
if results == nil {
|
|
err = fmt.Errorf("invalid line %s", line)
|
|
return
|
|
}
|
|
minCount, err := strconv.Atoi(results[1])
|
|
if err != nil {
|
|
return
|
|
}
|
|
maxCount, err := strconv.Atoi(results[2])
|
|
if err != nil {
|
|
return
|
|
}
|
|
letter := results[3]
|
|
password := results[4]
|
|
// fmt.Printf("Make sure %s is in %s between %d and %d times\n", letter, password, minCount, maxCount)
|
|
// Validate
|
|
count := strings.Count(password, letter)
|
|
if minCount <= count && count <= maxCount {
|
|
totalValid++
|
|
}
|
|
return
|
|
})
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
fmt.Printf("Total valid %d\n", totalValid)
|
|
}
|
|
|
|
func part2() {
|
|
totalValid := 0
|
|
err := proccessLines("input.txt", func(line string) (stop bool, err error) {
|
|
results := matcher.FindStringSubmatch(line)
|
|
if results == nil {
|
|
err = fmt.Errorf("invalid line %s", line)
|
|
return
|
|
}
|
|
pos1, err := strconv.Atoi(results[1])
|
|
if err != nil {
|
|
return
|
|
}
|
|
pos2, err := strconv.Atoi(results[2])
|
|
if err != nil {
|
|
return
|
|
}
|
|
// 1 vs 0 indexed
|
|
pos1--
|
|
pos2--
|
|
letter := results[3]
|
|
password := results[4]
|
|
// fmt.Printf("Make sure %s is in %s between %d and %d times\n", letter, password, minCount, maxCount)
|
|
// Validate
|
|
if pos1 >= len(password) || pos2 >= len(password) {
|
|
return
|
|
}
|
|
letter1 := string(password[pos1])
|
|
letter2 := string(password[pos2])
|
|
if (letter == letter1 || letter == letter2) && letter1 != letter2 {
|
|
totalValid++
|
|
}
|
|
return
|
|
})
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
fmt.Printf("Total valid %d\n", totalValid)
|
|
}
|
|
|
|
func main() {
|
|
part1()
|
|
part2()
|
|
}
|