Files
aoc2021/ten/navigation.go
2021-12-10 15:07:12 +00:00

135 lines
2.1 KiB
Go

package ten
import (
"bufio"
"os"
"sort"
)
var syntaxScores = map[rune]int{
')': 3,
']': 57,
'}': 1197,
'>': 25137,
}
var autoCompleteScores = map[rune]int{
'(': 1,
'[': 2,
'{': 3,
'<': 4,
}
var pairs = map[rune]rune{
')': '(',
'}': '{',
']': '[',
'>': '<',
}
type errorType string
const (
corrupted errorType = "corrupted"
incomplete errorType = "incomplete"
)
type syntaxError struct {
line string
symbol rune
violation errorType
stack []rune
}
type navigation struct {
input []string
validInput []string
errors []syntaxError
}
func (n *navigation) load(filename string) error {
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
n.input = append(n.input, scanner.Text())
}
return nil
}
func (n *navigation) parse() {
for _, input := range n.input {
stack := []rune{}
var e *syntaxError
for _, r := range input {
switch r {
case '(', '{', '[', '<':
stack = append(stack, r)
continue
case ')', '}', ']', '>':
if len(stack) < 1 || stack[len(stack)-1] != pairs[r] {
e = &syntaxError{
line: input,
symbol: r,
violation: corrupted,
}
} else {
stack = stack[:len(stack)-1]
}
}
if e != nil {
break
}
}
if e == nil && len(stack) > 0 {
e = &syntaxError{
line: input,
symbol: stack[0],
violation: incomplete,
}
}
if e != nil {
e.stack = stack
n.errors = append(n.errors, *e)
} else {
n.validInput = append(n.validInput, input)
}
}
}
func (n *navigation) syntaxScore() (score int) {
for _, e := range n.errors {
if e.violation == corrupted {
score += syntaxScores[e.symbol]
}
}
return score
}
func (n *navigation) autoCompleteScore() int {
scores := []int{}
for _, e := range n.errors {
if e.violation == incomplete {
total := 0
for i := len(e.stack) - 1; i >= 0; i-- {
total = (total * 5) + autoCompleteScores[e.stack[i]]
}
scores = append(scores, total)
}
}
// Find the middle value
sort.Ints(scores)
medianIndex := int(len(scores)/2) + 1
return scores[medianIndex-1]
}