mirror of
https://github.com/Threnklyn/advent-of-code-go.git
synced 2026-06-07 04:33:31 +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