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] }