You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

vm.go 1.7KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. package intcode
  2. // VirtualMachine is an IntCode virtual machine.
  3. type VirtualMachine struct {
  4. ip int
  5. modes uint8
  6. opcodes [100]interface{}
  7. Memory []int
  8. Halted bool
  9. Input chan int
  10. Output chan int
  11. }
  12. // NewVirtualMachine creates a new IntCode virtual machine, initialised
  13. // to the given slice of memory.
  14. func NewVirtualMachine(memory []int, hasIO bool) *VirtualMachine {
  15. vm := &VirtualMachine{
  16. ip: 0,
  17. Memory: memory,
  18. Halted: false,
  19. opcodes: [100]interface{}{
  20. 1: AddOpcode,
  21. 2: MulOpcode,
  22. 3: ReadOpCode,
  23. 4: WriteOpCode,
  24. 5: JumpIfTrueOpCode,
  25. 6: JumpIfFalseOpCode,
  26. 7: LessThanOpCode,
  27. 8: EqualsOpCode,
  28. 99: HaltOpcode,
  29. },
  30. }
  31. if hasIO {
  32. vm.Input = make(chan int, 1)
  33. vm.Output = make(chan int, 1)
  34. }
  35. return vm
  36. }
  37. func (vm *VirtualMachine) arg(pos int) int {
  38. mask := uint8(1) << uint8(pos)
  39. if vm.modes&mask == mask {
  40. return vm.Memory[vm.ip+1+pos]
  41. } else {
  42. return vm.Memory[vm.Memory[vm.ip+1+pos]]
  43. }
  44. }
  45. // Run repeatedly executes instructions until the VM halts.
  46. func (vm *VirtualMachine) Run() {
  47. for !vm.Halted {
  48. instruction := vm.Memory[vm.ip]
  49. opcode := instruction % 100
  50. vm.modes = 0
  51. mask := uint8(1)
  52. for i := instruction / 100; i > 0; i /= 10 {
  53. if i%10 == 1 {
  54. vm.modes = vm.modes | mask
  55. }
  56. mask = mask << 1
  57. }
  58. vm.opcodes[opcode].(OpcodeFunc)(vm)
  59. }
  60. if vm.Input != nil {
  61. close(vm.Input)
  62. close(vm.Output)
  63. }
  64. }
  65. // Reset resets the memory to the given slice, and all other state back to its original value.
  66. func (vm *VirtualMachine) Reset(memory []int) {
  67. copy(vm.Memory, memory)
  68. vm.ip = 0
  69. vm.Halted = false
  70. if vm.Input != nil {
  71. vm.Input = make(chan int, 1)
  72. vm.Output = make(chan int, 1)
  73. }
  74. }