aoc/2021/24/old/precomp.go
2021-12-25 20:49:47 +01:00

364 lines
7.6 KiB
Go

package main
// import "fmt"
type RegisterState struct {
value int
last int
known bool
}
// @TODO Apply DRY
// The function will go through all the instruction and precompute as much as possible
func (p Program) precomp() Program {
var np Program
var r [4]RegisterState
// Initalize the registers
for i := range r {
r[i].known = true
}
for _, i := range p {
// fmt.Println(i)
switch i.op {
case INP:
r[i.a].known = false
np = append(np, i)
// fmt.Printf("- \t%v\n", np[len(np)-1])
case ADD:
if r[i.a].known {
r[i.a].value += i.b
// fmt.Printf("- \t%v\n", r)
continue
}
np = append(np, i)
// fmt.Printf("- \t%v\n", np[len(np)-1])
case ADDR:
if r[i.a].known && r[i.b].known {
r[i.a].value += r[i.b].value
// fmt.Printf("- \t%v\n", r)
continue
}
if r[i.a].known {
if r[i.a].value - r[i.a].last != 0 {
np = append(np, Instruction{ADD, i.a, r[i.a].value - r[i.a].last})
r[i.a].last = r[i.a].value
// fmt.Printf("- \t%v\n", np[len(np)-1])
}
}
if r[i.b].known {
if r[i.b].value - r[i.b].last != 0 {
np = append(np, Instruction{ADD, i.b, r[i.b].value - r[i.b].last})
r[i.b].last = r[i.b].value
// fmt.Printf("- \t%v\n", np[len(np)-1])
}
}
r[i.a].known = false
// fmt.Printf("- \t%v\n", r)
np = append(np, i)
// fmt.Printf("- \t%v\n", np[len(np)-1])
case MUL:
if i.b == 0 {
r[i.a].value = 0
if !r[i.a].known {
r[i.a].value = 0
r[i.a].last = 0
r[i.a].known = true
np = append(np, Instruction{MUL, i.a, 0})
// fmt.Printf("- \t%v\n", np[len(np)-1])
}
// fmt.Printf("- \t%v\n", r)
continue
}
if i.b == 1 {
continue
}
if r[i.a].known {
r[i.a].value *= i.b
// fmt.Printf("- \t%v\n", r)
continue
}
np = append(np, i)
// fmt.Printf("- \t%v\n", np[len(np)-1])
case MULR:
if r[i.a].known && r[i.a].value == 0 {
r[i.a].value = 0
// fmt.Printf("- \t%v\n", r)
continue
}
if r[i.b].known && r[i.b].value == 0 {
r[i.a].value = 0
if !r[i.a].known {
r[i.a].value = 0
r[i.a].last = 0
r[i.a].known = true
np = append(np, Instruction{MUL, i.a, 0})
// fmt.Printf("- \t%v\n", np[len(np)-1])
}
// fmt.Printf("- \t%v\n", r)
continue
}
if r[i.b].known && r[i.b].value == 1 {
continue
}
if r[i.a].known && r[i.b].known {
r[i.a].value *= r[i.b].value
// fmt.Printf("- \t%v\n", r)
continue
}
if r[i.a].known {
if r[i.a].value - r[i.a].last != 0 {
np = append(np, Instruction{ADD, i.a, r[i.a].value - r[i.a].last})
r[i.a].last = r[i.a].value
// fmt.Printf("- \t%v\n", np[len(np)-1])
}
}
if r[i.b].known {
if r[i.b].value - r[i.b].last != 0 {
np = append(np, Instruction{ADD, i.b, r[i.b].value - r[i.b].last})
r[i.b].last = r[i.b].value
// fmt.Printf("- \t%v\n", np[len(np)-1])
}
}
r[i.a].known = false
// fmt.Printf("- \t%v\n", r)
np = append(np, i)
// fmt.Printf("- \t%v\n", np[len(np)-1])
case DIV:
if i.b == 1 {
continue
}
if r[i.a].known {
r[i.a].value /= i.b
// fmt.Printf("- \t%v\n", r)
continue
}
np = append(np, i)
// fmt.Printf("- \t%v\n", np[len(np)-1])
case DIVR:
if r[i.a].known && r[i.a].value == 0 {
r[i.a].value = 0
// fmt.Printf("- \t%v\n", r)
continue
}
if r[i.b].known && r[i.b].value == 1 {
continue
}
if r[i.a].known && r[i.b].known {
r[i.a].value /= r[i.b].value
// fmt.Printf("- \t%v\n", r)
continue
}
if r[i.a].known {
if r[i.a].value - r[i.a].last != 0 {
np = append(np, Instruction{ADD, i.a, r[i.a].value - r[i.a].last})
r[i.a].last = r[i.a].value
// fmt.Printf("- \t%v\n", np[len(np)-1])
}
}
if r[i.b].known {
if r[i.b].value - r[i.b].last != 0 {
np = append(np, Instruction{ADD, i.b, r[i.b].value - r[i.b].last})
r[i.b].last = r[i.b].value
// fmt.Printf("- \t%v\n", np[len(np)-1])
}
}
r[i.a].known = false
// fmt.Printf("- \t%v\n", r)
np = append(np, i)
// fmt.Printf("- \t%v\n", np[len(np)-1])
case MOD:
if i.b == -1 {
r[i.a].value = 0
if !r[i.a].known {
r[i.a].value = 0
r[i.a].last = 0
r[i.a].known = true
np = append(np, Instruction{MUL, i.a, 0})
// fmt.Printf("- \t%v\n", np[len(np)-1])
}
// fmt.Printf("- \t%v\n", r)
continue
}
if i.b == 1 {
r[i.a].value = 0
if !r[i.a].known {
r[i.a].value = 0
r[i.a].last = 0
r[i.a].known = true
np = append(np, Instruction{MUL, i.a, 0})
// fmt.Printf("- \t%v\n", np[len(np)-1])
}
// fmt.Printf("- \t%v\n", r)
continue
}
if r[i.a].known {
r[i.a].value %= i.b
// fmt.Printf("- \t%v\n", r)
continue
}
np = append(np, i)
// fmt.Printf("- \t%v\n", np[len(np)-1])
case MODR:
if r[i.a].known && r[i.a].value == 0 {
r[i.a].value = 0
// fmt.Printf("- \t%v\n", r)
continue
}
if r[i.b].known && r[i.b].value == -1 {
r[i.a].value = 0
if !r[i.a].known {
r[i.a].value = 0
r[i.a].last = 0
r[i.a].known = true
np = append(np, Instruction{MUL, i.a, 0})
// fmt.Printf("- \t%v\n", np[len(np)-1])
}
// fmt.Printf("- \t%v\n", r)
continue
}
if r[i.b].known && r[i.b].value == 1 {
r[i.a].value = 0
if !r[i.a].known {
r[i.a].value = 0
r[i.a].last = 0
r[i.a].known = true
np = append(np, Instruction{MUL, i.a, 0})
// fmt.Printf("- \t%v\n", np[len(np)-1])
}
// fmt.Printf("- \t%v\n", r)
continue
}
if r[i.a].known && r[i.b].known {
r[i.a].value %= r[i.b].value
// fmt.Printf("- \t%v\n", r)
continue
}
if r[i.a].known {
if r[i.a].value - r[i.a].last != 0 {
np = append(np, Instruction{ADD, i.a, r[i.a].value - r[i.a].last})
r[i.a].last = r[i.a].value
// fmt.Printf("- \t%v\n", np[len(np)-1])
}
}
if r[i.b].known {
if r[i.b].value - r[i.b].last != 0 {
np = append(np, Instruction{ADD, i.b, r[i.b].value - r[i.b].last})
r[i.b].last = r[i.b].value
// fmt.Printf("- \t%v\n", np[len(np)-1])
}
}
r[i.a].known = false
// fmt.Printf("- \t%v\n", r)
np = append(np, i)
// fmt.Printf("- \t%v\n", np[len(np)-1])
case EQL:
if r[i.a].known {
val := 0
if r[i.a].value == i.b {
val = 1
}
r[i.a].value = val
// fmt.Printf("- \t%v\n", r)
continue
}
np = append(np, i)
// fmt.Printf("- \t%v\n", np[len(np)-1])
case EQLR:
if i.a == i.b {
r[i.a].value = 1
if !r[i.a].known {
r[i.a].value = 0
r[i.a].last = 0
r[i.a].known = true
np = append(np, Instruction{MUL, i.a, 0})
// fmt.Printf("- \t%v\n", np[len(np)-1])
}
// fmt.Printf("- \t%v\n", r)
continue
}
if r[i.a].known && r[i.b].known {
val := 0
if r[i.a].value == r[i.b].value {
val = 1
}
r[i.a].value = val
// fmt.Printf("- \t%v\n", r)
continue
}
if r[i.a].known {
if r[i.a].value - r[i.a].last != 0 {
np = append(np, Instruction{ADD, i.a, r[i.a].value - r[i.a].last})
r[i.a].last = r[i.a].value
// fmt.Printf("- \t%v\n", np[len(np)-1])
}
}
if r[i.b].known {
if r[i.b].value - r[i.b].last != 0 {
np = append(np, Instruction{ADD, i.b, r[i.b].value - r[i.b].last})
r[i.b].last = r[i.b].value
// fmt.Printf("- \t%v\n", np[len(np)-1])
}
}
r[i.a].known = false
// fmt.Printf("- \t%v\n", r)
np = append(np, i)
// fmt.Printf("- \t%v\n", np[len(np)-1])
}
}
// Emit all the non-zero known registers
for i := range r {
if r[i].known && r[i].value != 0 {
np = append(np, Instruction{ADD, i, r[i].value})
}
}
return np
}