From 3b5bae794815c2e825b7a5efd4662d0a364af551 Mon Sep 17 00:00:00 2001 From: Brian Buller Date: Wed, 23 Dec 2020 09:29:58 -0600 Subject: [PATCH] 2020 Day 23 Complete! --- 2020/day23/input | 1 + 2020/day23/main.go | 228 +++++++++++++++++++++++++++++++++++++++++++ 2020/day23/testinput | 1 + 3 files changed, 230 insertions(+) create mode 100644 2020/day23/input create mode 100644 2020/day23/main.go create mode 100644 2020/day23/testinput diff --git a/2020/day23/input b/2020/day23/input new file mode 100644 index 0000000..c4108a7 --- /dev/null +++ b/2020/day23/input @@ -0,0 +1 @@ +614752839 diff --git a/2020/day23/main.go b/2020/day23/main.go new file mode 100644 index 0000000..eeceb78 --- /dev/null +++ b/2020/day23/main.go @@ -0,0 +1,228 @@ +package main + +import ( + "fmt" + + h "git.bullercodeworks.com/brian/adventofcode/helpers" +) + +var highest int +var lowest int +var AllCups map[int]*Cup + +func init() { + highest = h.MIN_INT + lowest = h.MAX_INT + AllCups = make(map[int]*Cup) +} + +func main() { + fmt.Println("# Day 22") + inp := h.StdinToString() + + solve(inp, h.Atoi(h.OptArgNumber(1, "2"))) +} + +var move int +var first *Cup + +func solve(inp string, part int) { + moves := 100 + if part == 1 { + BuildCircle(inp, -1) + } else { + BuildCircle(inp, 1000000) + moves = 10000000 + } + current := first + for i := 0; i < moves; i++ { + current = DoMove(current) + } + ans := FindLabel(1, first).next + fmt.Println("## Part", part, ":\nAnswer:") + if part == 1 { + for ans.label != 1 { + fmt.Print(ans.label) + ans = ans.next + } + } else { + fmt.Print(ans.label * ans.next.label) + } + fmt.Println() +} + +func BuildCircle(inp string, cups int) *Cup { + var wrk *Cup + for k := range inp { + next := &Cup{label: int(inp[k] - '0')} + next.next = next + next.prev = next + if first == nil { + first = next + first.next = next + first.prev = next + } else { + wrk.SetNext(next) + } + if next.label > highest { + highest = next.label + } + if next.label < lowest { + lowest = next.label + } + AllCups[next.label] = next + wrk = next + } + total := Count(first) + last := GetLast(first) + nextLabel := highest + 1 + for cups > 0 && total < cups { + next := &Cup{label: nextLabel} + nextLabel++ + next.next = next + next.prev = next + last.SetNext(next) + last = next + if next.label > highest { + highest = next.label + } + if next.label < lowest { + lowest = next.label + } + AllCups[next.label] = next + total++ + } + return first +} + +func DoMove(curr *Cup) *Cup { + move++ + hold := curr.RemoveNext(3) + target := curr.label - 1 + if target < lowest { + target = highest + } + // Check the removed cups + for FindLabel(target, hold) != nil { + target = target - 1 + if target < lowest { + target = highest + } + } + //dest := FindLabel(target, curr) + dest := AllCups[target] + dest.SetNext(hold) + return curr.next +} + +func FindLabel(num int, first *Cup) *Cup { + if first.label == num { + return first + } + c := first.next + for c != first { + if c.label == num { + return c + } + c = c.next + } + return nil +} + +func StringifyCircle(first *Cup, current *Cup) string { + c := first + stringify := func(c *Cup) string { + if c == nil { + return "ERR" + } + if c == current { + return fmt.Sprintf("(%d)", c.label) + } else { + return fmt.Sprintf(" %d ", c.label) + } + } + ret := stringify(c) + c = c.next + for c != first { + ret = ret + stringify(c) + if c == nil { + ret = ret + " ERR " + break + } + if c.next == c { + break + } + c = c.next + } + return ret +} + +func GetLast(cups *Cup) *Cup { + if cups.next == cups || cups.next == nil { + return cups + } + c := cups.next + for c.next != cups { + if c.next == nil { + break + } + c = c.next + } + return c +} + +func Count(cups *Cup) int { + start := cups + wrk := start.next + ret := 1 + for wrk != start { + wrk = wrk.next + ret++ + } + return ret +} + +var current *Cup + +type Cup struct { + label int + next *Cup + prev *Cup +} + +func (c *Cup) SetNext(next *Cup) { + if c.next == c { + c.prev = next + c.next = next + next.next = c + next.prev = c + return + } + hold := c.next + // c.p c c.n + // c.p c next... c.n + c.next = next + if hold != nil { + hold.prev = GetLast(next) + GetLast(next).next = hold + } + next.prev = c +} + +// RemoveNext removes the next cnt cups, returning a circle of the removed cups +func (c *Cup) RemoveNext(cnt int) *Cup { + if cnt == 0 { + return nil + } + hold := c.next + dest := hold + for cnt > 0 { + dest = dest.next + cnt-- + } + c.next = dest + dest.prev.next = hold + hold.prev = dest.prev + dest.prev = c + return hold +} diff --git a/2020/day23/testinput b/2020/day23/testinput new file mode 100644 index 0000000..ab40847 --- /dev/null +++ b/2020/day23/testinput @@ -0,0 +1 @@ +389125467