diff --git a/18/main.go b/18/main.go new file mode 100644 index 0000000..0a56f73 --- /dev/null +++ b/18/main.go @@ -0,0 +1,182 @@ +package main + +import ( + "bufio" + "fmt" + "os" + "strconv" + "time" +) + +func mustAtoi(line rune) int { + i, _ := strconv.Atoi(string(line)) + return i +} + +func main() { + start := time.Now() + partOne() + duration := time.Since(start) + partTwo() + duration2 := time.Since(start) + fmt.Printf("p1: %s, p2: %s\n", duration, duration2-duration) +} + +func makeScanner(test bool) *bufio.Scanner { + var f *os.File + if test { + f, _ = os.Open("inputs/testinput") + } else { + f, _ = os.Open("inputs/input") + } + reader := bufio.NewReader(f) + return bufio.NewScanner(reader) +} + +type pair struct { + parent *pair + leftp *pair + left int + rightp *pair + right int +} + +func Parse(raw string) *pair { + root := &pair{} + var current *pair + left := true + for _, v := range raw { + switch v { + case '[': + if current == nil { + current = root + } else { + p := &pair{parent: current} + if left { + current.leftp = p + } else { + current.rightp = p + } + current = p + } + left = true + case ']': + current = current.parent + case ',': + left = false + case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': + if left { + current.left = mustAtoi(v) + } else { + current.right = mustAtoi(v) + } + case ' ': + continue + default: + panic("what the: " + string(v)) + } + } + return root +} + +func (p *pair) String() string { + var left, right string + if p.leftp == nil { + left = fmt.Sprintf("%d", p.left) + } else { + left = p.leftp.String() + } + if p.rightp == nil { + right = fmt.Sprintf("%d", p.right) + } else { + right = p.rightp.String() + } + return fmt.Sprintf("[%s,%s]", left, right) +} + +func (p *pair) Magnitude() int { + left := 0 + right := 0 + if p.leftp == nil { + left = p.left + } else { + left = p.leftp.Magnitude() + } + if p.rightp == nil { + right = p.right + } else { + right = p.rightp.Magnitude() + } + return left*3 + right*2 +} + +func Add(left, right *pair) *pair { + return &pair{ + leftp: left, + rightp: right, + } +} + +func Reduce(p *pair) *pair { + return &pair{} // ??? +} + +func Split(p *pair) *pair { + if p.left > 9 { + p.leftp = &pair{ + left: p.left / 2, + right: (p.left / 2) + (p.left % 2), + } + p.left = 0 + return p + } + if p.right > 9 { + p.rightp = &pair{ + left: p.right / 2, + right: (p.right / 2) + (p.right % 2), + } + p.right = 0 + return p + } + return p +} + +func MustExplode(depth int, p *pair) bool { + if depth >= 4 { + return true + } + if p.leftp != nil { + m := MustExplode(depth+1, p.leftp) + if m { + return true + } + } + if p.rightp != nil { + m := MustExplode(depth+1, p.rightp) + if m { + return true + } + } + return false +} + +func partOne() { + scanner := makeScanner(false) + + scanner.Scan() + line := scanner.Text() + total := Parse(line) + for scanner.Scan() { + line := scanner.Text() + total = Add(total, Parse(line)) + } + fmt.Println(total) +} + +func partTwo() { + scanner := makeScanner(false) + + for scanner.Scan() { + // line := scanner.Text() + } +} diff --git a/18/main_test.go b/18/main_test.go new file mode 100644 index 0000000..61eb6f5 --- /dev/null +++ b/18/main_test.go @@ -0,0 +1,82 @@ +package main + +import ( + "fmt" + "testing" +) + +func TestParse(t *testing.T) { + cases := []string{ + "[1,2]", + "[[3,2],1]", + "[[3,2],[4,5]]", + "[[3,2],[[7,8],5]]", + "[[1,2],3]", + "[9,[8,7]]", + "[[1,9],[8,5]]", + "[[[[1,2],[3,4]],[[5,6],[7,8]]],9]", + "[[[9,[3,8]],[[0,9],6]],[[[3,7],[4,9]],3]]", + "[[[[1,3],[5,3]],[[1,3],[8,7]]],[[[4,9],[6,9]],[[8,2],[7,3]]]]", + } + for _, input := range cases { + p := Parse(input) + if input != p.String() { + t.Log(p.String()) + t.Fail() + } + } +} + +func TestMustExplode(t *testing.T) { + cases := map[string]bool{ + "[1,2]": false, + "[[[[2,4],4],[2,3]],1]": false, + "[[[[[4,3],4],4],1],3]": true, + "[2,[1,[4,[3,[4,3]]]]]": true, + "[[[[0,7],4],[7,[[8,4],9]]],[1,1]]": true, + } + for input, output := range cases { + if MustExplode(0, Parse(input)) != output { + t.Log(input) + t.Fail() + } + } +} + +func TestAdd(t *testing.T) { + cases := map[string][]*pair{ + "[[1,2],[[3,4],5]]": { + &pair{left: 1, right: 2}, + &pair{leftp: &pair{left: 3, right: 4}, right: 5}, + }, + } + for answer, pairs := range cases { + r := Add(pairs[0], pairs[1]) + if r.String() != answer { + fmt.Printf("%s %s", r, answer) + t.Fail() + } + } +} + +func TestMagnitude(t *testing.T) { + cases := map[int]*pair{ + 29: {left: 9, right: 1}, + 21: {left: 1, right: 9}, + 129: { + leftp: &pair{left: 9, right: 1}, + rightp: &pair{left: 1, right: 9}, + }, + 143: { + leftp: &pair{left: 1, right: 2}, + rightp: &pair{leftp: &pair{left: 3, right: 4}, right: 5}, + }, + } + for answer, pair := range cases { + r := pair.Magnitude() + if r != answer { + fmt.Printf("%d %d", r, answer) + t.Fail() + } + } +}