From eb24a4e54813276a41c8b168d224b4907f6b5f80 Mon Sep 17 00:00:00 2001 From: alexchao26 Date: Sun, 20 Dec 2020 19:04:39 -0500 Subject: [PATCH] 2020-day23: ugh manually optimizing assembly --- 2017/day23/main.go | 122 ++++++++++++++++++++++++++++++++++++++++ 2017/day23/main_test.go | 41 ++++++++++++++ 2 files changed, 163 insertions(+) create mode 100644 2017/day23/main.go create mode 100644 2017/day23/main_test.go diff --git a/2017/day23/main.go b/2017/day23/main.go new file mode 100644 index 0000000..a9ab286 --- /dev/null +++ b/2017/day23/main.go @@ -0,0 +1,122 @@ +package main + +import ( + "flag" + "fmt" + "strconv" + "strings" + + "github.com/alexchao26/advent-of-code-go/util" +) + +func main() { + var part int + flag.IntVar(&part, "part", 1, "part 1 or 2") + flag.Parse() + fmt.Println("Running part", part) + + var ans int + if part == 1 { + ans = part1(util.ReadFile("./input.txt")) + } else { + ans = part2(util.ReadFile("./input.txt")) + } + fmt.Println("Output:", ans) +} + +// literal implementation for part 1 +func part1(input string) int { + comp := newComputerFromInput(input) + // prime until it gets a valid receive command, then return last outputted num + return comp.countMulsRun() +} + +// referenced this heavily: https://www.reddit.com/r/adventofcode/comments/7lms6p/2017_day_23_solutions/drnh5sx?utm_source=share&utm_medium=web2x&context=3 +func part2(input string) int { + b := 81 + c := 81 + + b = b*100 + 100000 + c = b + 17000 + var h int + for { + f := 1 + // effectively a prime number checker. + for d := 2; d*d <= b; d++ { + if b%d == 0 { + f = 0 + break + } + } + + if f == 0 { + h++ + } + if b == c { + break + } + b += 17 + } + + return h +} + +type computer struct { + instructions [][]string + pointer int + registers map[string]int + output []int +} + +func newComputerFromInput(input string) *computer { + comp := &computer{registers: map[string]int{}} + for _, line := range strings.Split(input, "\n") { + comp.instructions = append(comp.instructions, strings.Split(line, " ")) + } + + return comp +} + +func (c *computer) countMulsRun() (mulsRun int) { + for c.pointer < len(c.instructions) { + inst := c.instructions[c.pointer] + valX := inst[1] + var valFromY int + if val, err := strconv.Atoi(inst[2]); err != nil { + // if there is an error parsing to an integer, value at index 1 is a register + valFromY = c.registers[inst[2]] + } else { + valFromY = val + } + + switch inst[0] { + case "set": + c.registers[valX] = valFromY + c.pointer++ + case "sub": + c.registers[valX] -= valFromY + c.pointer++ + case "mul": + c.registers[valX] *= valFromY + c.pointer++ + mulsRun++ + case "jnz": + var parsedX int + if num, err := strconv.Atoi(valX); err != nil { + // err converting, not a number + parsedX = c.registers[valX] + } else { + // no error then a number was parsed + parsedX = num + } + if parsedX != 0 { + c.pointer += valFromY + } else { + c.pointer++ + } + default: + panic("unhandled operator " + inst[0]) + } + } + return mulsRun +} diff --git a/2017/day23/main_test.go b/2017/day23/main_test.go new file mode 100644 index 0000000..edaa849 --- /dev/null +++ b/2017/day23/main_test.go @@ -0,0 +1,41 @@ +package main + +import ( + "testing" + + "github.com/alexchao26/advent-of-code-go/util" +) + +func Test_part1(t *testing.T) { + tests := []struct { + name string + input string + want int + }{ + {"actual", util.ReadFile("input.txt"), 6241}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := part1(tt.input); got != tt.want { + t.Errorf("part1() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_part2(t *testing.T) { + tests := []struct { + name string + input string + want int + }{ + {"actual", util.ReadFile("input.txt"), 909}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := part2(tt.input); got != tt.want { + t.Errorf("part2() = %v, want %v", got, tt.want) + } + }) + } +}