135 lines
2.1 KiB
Go
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]
|
|
}
|