mirror of
https://github.com/Threnklyn/advent-of-code-go.git
synced 2026-05-18 19:13:27 +02:00
2016-day23: easiest assembly manual understanding so far
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/alexchao26/advent-of-code-go/cast"
|
||||
"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)
|
||||
|
||||
ans := assemblyComputer(util.ReadFile("./input.txt"), part)
|
||||
fmt.Println("Output:", ans)
|
||||
}
|
||||
|
||||
func assemblyComputer(input string, part int) int {
|
||||
instructions := strings.Split(input, "\n")
|
||||
registers := map[string]int{}
|
||||
var instIndex int
|
||||
|
||||
registers["a"] = 7
|
||||
if part == 2 {
|
||||
registers["a"] = 12
|
||||
}
|
||||
|
||||
for instIndex < len(instructions) {
|
||||
// uncomment this to print out the instruction set and see how it's changed
|
||||
// fmt.Println(instIndex)
|
||||
// for in, i := range instructions {
|
||||
// fmt.Println(in, i)
|
||||
// }
|
||||
// fmt.Println()
|
||||
|
||||
inst := instructions[instIndex]
|
||||
parts := strings.Split(inst, " ")
|
||||
|
||||
// My instruction list gets transformed into this
|
||||
// all jump instructions can be optimized, in particular the ones
|
||||
// tagged here b/c they jump over another jump instruction
|
||||
// effectively becoming multiplication steps
|
||||
// 0 cpy a b
|
||||
// 1 dec b
|
||||
// 2 cpy a d
|
||||
// 3 cpy 0 a
|
||||
// 4 cpy b c
|
||||
// 5 inc a
|
||||
// 6 dec c
|
||||
// 7 jnz c -2
|
||||
// 8 dec d
|
||||
// 9 jnz d -5 // <-
|
||||
// 10 dec b
|
||||
// 11 cpy b c
|
||||
// 12 cpy c d
|
||||
// 13 dec d
|
||||
// 14 inc c
|
||||
// 15 jnz d
|
||||
// 16 tgl c
|
||||
// 17 cpy -16 c
|
||||
// 18 cpy 1 c
|
||||
// 19 cpy 89 c
|
||||
// 20 cpy 77 d
|
||||
// 21 inc a
|
||||
// 22 dec d
|
||||
// 23 jnz d
|
||||
// 24 dec c
|
||||
// 25 jnz c -5 // <-
|
||||
|
||||
// Hard coded multiplication skippers
|
||||
if inst == "jnz d -5" && instructions[instIndex-1] == "dec d" &&
|
||||
instructions[instIndex-2] == "jnz c -2" {
|
||||
registers["a"] += registers["b"] * registers["d"]
|
||||
registers["c"] = 0
|
||||
registers["d"] = 0
|
||||
}
|
||||
|
||||
if inst == "jnz c -5" && instructions[instIndex-1] == "dec c" {
|
||||
registers["a"] += 77 * registers["c"]
|
||||
registers["c"] = 0
|
||||
registers["d"] = 0
|
||||
}
|
||||
|
||||
switch parts[0] {
|
||||
case "cpy":
|
||||
valX := parseValueOrRegister(registers, parts[1])
|
||||
registers[parts[2]] = valX
|
||||
instIndex++
|
||||
case "inc":
|
||||
registers[parts[1]]++
|
||||
instIndex++
|
||||
case "dec":
|
||||
registers[parts[1]]--
|
||||
instIndex++
|
||||
case "jnz":
|
||||
valX := parseValueOrRegister(registers, parts[1])
|
||||
if valX != 0 {
|
||||
valY := parseValueOrRegister(registers, parts[2])
|
||||
instIndex += valY
|
||||
} else {
|
||||
instIndex++
|
||||
}
|
||||
case "tgl":
|
||||
// valX is an offset
|
||||
valX := parseValueOrRegister(registers, parts[1])
|
||||
indexToMod := instIndex + valX
|
||||
if indexToMod < len(instructions) {
|
||||
instToModParts := strings.Split(instructions[indexToMod], " ")
|
||||
var newType string
|
||||
if len(instToModParts) == 2 {
|
||||
newType = "inc"
|
||||
if instToModParts[0] == "inc" {
|
||||
newType = "dec"
|
||||
}
|
||||
} else if len(instToModParts) == 3 {
|
||||
newType = "jnz"
|
||||
if instToModParts[0] == "jnz" {
|
||||
newType = "cpy"
|
||||
}
|
||||
}
|
||||
instToModParts[0] = newType
|
||||
instructions[indexToMod] = strings.Join(instToModParts, " ")
|
||||
}
|
||||
instIndex++
|
||||
default:
|
||||
panic("unhanded instruction type " + parts[0])
|
||||
}
|
||||
}
|
||||
|
||||
return registers["a"]
|
||||
}
|
||||
|
||||
func parseValueOrRegister(registers map[string]int, part string) int {
|
||||
if regexp.MustCompile("[0-9]").MatchString(part) {
|
||||
return cast.ToInt(part)
|
||||
}
|
||||
return registers[part]
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/alexchao26/advent-of-code-go/util"
|
||||
)
|
||||
|
||||
var example = `cpy 2 a
|
||||
tgl a
|
||||
tgl a
|
||||
tgl a
|
||||
cpy 1 a
|
||||
dec a
|
||||
dec a`
|
||||
|
||||
func Test_part1(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
part int
|
||||
want int
|
||||
}{
|
||||
{"example", example, 1, 3},
|
||||
{"actual", util.ReadFile("input.txt"), 1, 11893},
|
||||
{"actual", util.ReadFile("input.txt"), 2, 479008453},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := assemblyComputer(tt.input, tt.part); got != tt.want {
|
||||
t.Errorf("assemblyComputer() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user