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.5KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. package intcode
  2. import (
  3. "fmt"
  4. "math"
  5. )
  6. // VirtualMachine is an IntCode virtual machine.
  7. type VirtualMachine struct {
  8. ip int
  9. opcodes map[int]OpcodeFunc
  10. Memory []int
  11. Halted bool
  12. Input chan int
  13. Output chan int
  14. }
  15. // NewVirtualMachine creates a new IntCode virtual machine, initialised
  16. // to the given slice of memory.
  17. func NewVirtualMachine(memory []int) *VirtualMachine {
  18. return &VirtualMachine{
  19. ip: 0,
  20. Memory: memory,
  21. Halted: false,
  22. Input: make(chan int, 100),
  23. Output: make(chan int, 100),
  24. opcodes: map[int]OpcodeFunc{
  25. 1: AddOpcode,
  26. 2: MulOpcode,
  27. 3: ReadOpCode,
  28. 4: WriteOpCode,
  29. 5: JumpIfTrueOpCode,
  30. 6: JumpIfFalseOpCode,
  31. 7: LessThanOpCode,
  32. 8: EqualsOpCode,
  33. 99: HaltOpcode,
  34. },
  35. }
  36. }
  37. // Run repeatedly executes instructions until the VM halts.
  38. func (vm *VirtualMachine) Run() {
  39. for !vm.Halted {
  40. instruction := vm.Memory[vm.ip]
  41. opcode := instruction % 100
  42. vm.opcodes[opcode](vm, func(pos int) int {
  43. mode := (instruction / int(math.Pow10(2+pos))) % 10
  44. switch mode {
  45. case 0:
  46. return vm.Memory[vm.Memory[vm.ip+1+pos]]
  47. case 1:
  48. return vm.Memory[vm.ip+1+pos]
  49. default:
  50. panic(fmt.Sprintf("Unknown parameter mode: %d", mode))
  51. }
  52. })
  53. }
  54. close(vm.Input)
  55. close(vm.Output)
  56. }
  57. // Reset resets the memory to the given slice, and all other state back to its original value.
  58. func (vm *VirtualMachine) Reset(memory []int) {
  59. copy(vm.Memory, memory)
  60. vm.ip = 0
  61. vm.Halted = false
  62. vm.Input = make(chan int, 100)
  63. vm.Output = make(chan int, 100)
  64. }