Files

126 lines
2.9 KiB
Go
Raw Permalink Normal View History

2024-12-18 09:57:43 +01:00
package main
import ("math"; "errors"; "strconv"; "strings"; "fmt"; "os")
//---------------------------------------------------------
func check(err error) { if err != nil { panic(err) } }
//---------------------------------------------------------
type Computer struct {
pc uint
ra uint
rb uint
rc uint
mem []byte
}
func NewComputer(input string) *Computer {
registers := strings.Split(input, "\n\n")[0]
memory := strings.Split(strings.Split(input, "\n\n")[1], " ")[1]
lines := strings.Split(registers, "\n")
ra, err := strconv.Atoi(strings.TrimSpace(strings.Split(lines[0], ":")[1]))
check(err)
rb, err := strconv.Atoi(strings.TrimSpace(strings.Split(lines[1], ":")[1]))
check(err)
rc, err := strconv.Atoi(strings.TrimSpace(strings.Split(lines[2], ":")[1]))
check(err)
mem := make([]byte, 0)
for _, str := range strings.Split(memory, ",") {
num, err := strconv.Atoi(str)
check(err)
mem = append(mem, byte(num))
}
return &Computer{ pc: 0, ra: uint(ra), rb: uint(rb), rc: uint(rc), mem: mem }
}
func (c *Computer) literalop() uint {
// current literal operator
return uint(c.mem[c.pc + 1])
}
func (c *Computer) comboop() uint {
// current combo operator
val := uint(c.mem[c.pc + 1])
switch {
case val == 4: val = c.ra
case val == 5: val = c.rb
case val == 6: val = c.rc
case val == 7: panic("invalid program")
}
return val
}
func (c *Computer) adv(op uint) uint {
// division
numerator := c.ra
denominator := math.Pow(2, float64(op))
return uint(float64(numerator) / float64(denominator))
}
func (c *Computer) bxl(op uint) uint {
// bitwise xor
return c.rb ^ op
}
func (c *Computer) bst(op uint) uint {
// mod 8
return op % 8
}
func (c *Computer) jnz(op uint) {
// jump if non zero
if c.ra == 0 {
return
} else {
c.pc = op - 2
return
}
}
func (c *Computer) bxc() uint {
// bitwise xor
return c.rb ^ c.rc
}
func (c *Computer) out(op uint) {
fmt.Print(op % 8, ",")
}
func (c *Computer) tick() error {
// returns an error if the program halts
if c.pc >= uint(len(c.mem)) { return errors.New("halted") }
instr := c.mem[c.pc]
switch {
case instr == 0: c.ra = c.adv(c.comboop())
case instr == 1: c.rb = c.bxl(c.literalop())
case instr == 2: c.rb = c.bst(c.comboop())
case instr == 3: c.jnz(c.literalop())
case instr == 4: c.rb = c.bxc()
case instr == 5: c.out(c.comboop())
case instr == 6: c.rb = c.adv(c.comboop())
case instr == 7: c.rc = c.adv(c.comboop())
}
c.pc += 2
return nil
}
//---------------------------------------------------------
func main() {
dat, err := os.ReadFile("data.txt")
check(err)
input := strings.TrimSpace(string(dat))
comp := NewComputer(input)
for comp.tick() == nil {}
}