package day13 import ( "bufio" "fmt" "os" "sort" "strings" ) type Element struct { isNumber bool number int sublist []Element } func parseElement(line string) (retval Element, remainder string, err error) { line = strings.TrimSpace(line) //fmt.Printf("Working on line: '%s'\n", line) if line[0] == '[' { sublist := []Element{} if line[1] == ']' { retval = Element{false, 0, sublist} remainder = line[2:] return } work := line[1:] for { element, rest, suberr := parseElement(work) //fmt.Println("Back from subcall with element", element, "rest", rest, "suberr", suberr) if suberr != nil { err = fmt.Errorf("suberror: %s", suberr) return } sublist = append(sublist, element) if rest[0] == ',' { work = rest[1:] } else if rest[0] == ']' { work = rest[1:] break } else { err = fmt.Errorf("don't know how to deal with list that ends with '%s'", rest) return } } retval = Element{false, 0, sublist} remainder = work return } else if line[0] >= '0' && line[0] <= '9' { var computed int for computed = 0; line[0] >= '0' && line[0] <= '9'; line = line[1:] { computed = (computed * 10) + int(line[0]-'0') } retval = Element{true, computed, nil} remainder = line return } else { err = fmt.Errorf("panic: Don't know how to parse line element '%s'", line) return } } func renderElement(element Element) string { if element.isNumber { return fmt.Sprintf("%d", element.number) } else { retval := "[" if len(element.sublist) > 0 { retval += renderElement(element.sublist[0]) } for i := 1; i < len(element.sublist); i++ { retval += fmt.Sprintf(",%s", renderElement(element.sublist[i])) } retval += "]" return retval } } type OrderResult int const ( ProperlyOrdered OrderResult = iota ImproperlyOrdered Unknown ) func compareElements(a Element, b Element) OrderResult { if a.isNumber && b.isNumber { return compareNumbers(a.number, b.number) } else if a.isNumber && !b.isNumber { return compareLists([]Element{{true, a.number, nil}}, b.sublist) } else if !a.isNumber && b.isNumber { return compareLists(a.sublist, []Element{{true, b.number, nil}}) } else { return compareLists(a.sublist, b.sublist) } } func compareNumbers(a int, b int) OrderResult { if a < b { return ProperlyOrdered } if a > b { return ImproperlyOrdered } return Unknown } func compareLists(a []Element, b []Element) OrderResult { if len(a) > 0 && len(b) > 0 { headResult := compareElements(a[0], b[0]) if headResult != Unknown { return headResult } return compareLists(a[1:], b[1:]) } if len(a) == 0 && len(b) == 0 { return Unknown } if len(a) == 0 { return ProperlyOrdered } return ImproperlyOrdered } func Run(filename string) { file, err := os.Open(filename) if err != nil { fmt.Println("Error opening file:", err) return } scanner := bufio.NewScanner(file) scanner.Split(bufio.ScanLines) elements := []Element{} for scanner.Scan() { line := scanner.Text() if len(line) == 0 { continue } element, remainder, err := parseElement(line) if err != nil { fmt.Println(err) return } if len(remainder) > 0 { fmt.Printf("Unexpected remainder in line: '%s'\n", remainder) return } fmt.Println("Parsed element", renderElement(element)) elements = append(elements, element) } total := 0 for i := 0; i < len(elements); i += 2 { index := i/2 + 1 switch compareElements(elements[i], elements[i+1]) { case ProperlyOrdered: fmt.Printf("Pair #%d is properly ordered\n", index) total += index case ImproperlyOrdered: fmt.Printf("Pair #%d is NOT properly ordered\n", index) case Unknown: fmt.Printf("Pair #%d is UNKNOWN\n", index) default: fmt.Printf("PANIC PANIC PANIC: Unknown ordering?!\n") } } fmt.Println("\nTotal proper index value is", total) divider2, _, _ := parseElement("[[2]]") divider6, _, _ := parseElement("[[6]]") elements = append(elements, divider2, divider6) sort.SliceStable(elements, func(i, j int) bool { return compareElements(elements[i], elements[j]) == ProperlyOrdered }) fmt.Println() fmt.Println("Sorted order:") decoderKey := 1 for i := 0; i < len(elements); i++ { fmt.Println(renderElement(elements[i])) if compareElements(elements[i], divider2) == Unknown || compareElements(elements[i], divider6) == Unknown { decoderKey *= i + 1 } } fmt.Println("Decoder key is", decoderKey) file.Close() }