Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

vm.go 2.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. package intcode
  2. type parameterMode int
  3. const (
  4. position parameterMode = 0
  5. immediate parameterMode = 1
  6. relative parameterMode = 2
  7. )
  8. // VirtualMachine is an IntCode virtual machine.
  9. type VirtualMachine struct {
  10. ip int
  11. rb int
  12. Memory []int
  13. Halted bool
  14. Input chan int
  15. Output chan int
  16. }
  17. // NewVirtualMachine creates a new IntCode virtual machine, initialised to the given slice of memory.
  18. // The caller is responsible for initialising the VM's I/O channels if required.
  19. func NewVirtualMachine(memory []int) *VirtualMachine {
  20. vm := &VirtualMachine{
  21. ip: 0,
  22. Memory: memory,
  23. Halted: false,
  24. }
  25. return vm
  26. }
  27. // Clone returns a deep copy of this VM, with newly allocated memory and I/O channels.
  28. func (vm *VirtualMachine) Clone() *VirtualMachine {
  29. memory := make([]int, len(vm.Memory))
  30. copy(memory, vm.Memory)
  31. return &VirtualMachine{
  32. ip: vm.ip,
  33. rb: vm.rb,
  34. Memory: memory,
  35. Halted: vm.Halted,
  36. Input: make(chan int, 1),
  37. Output: make(chan int, 1),
  38. }
  39. }
  40. // Run repeatedly executes instructions until the VM halts.
  41. func (vm *VirtualMachine) Run() {
  42. var args [3]*int
  43. for !vm.Halted {
  44. instruction := vm.Memory[vm.ip]
  45. opcode := instruction % 100
  46. param := instruction / 100
  47. for i := 0; i < opcodeArity[opcode]; i++ {
  48. switch parameterMode(param % 10) {
  49. // The argument is the actual value
  50. case immediate:
  51. args[i] = &vm.Memory[vm.ip+1+i]
  52. // The argument is a memory reference
  53. case position:
  54. for vm.Memory[vm.ip+1+i] >= len(vm.Memory) {
  55. vm.Memory = append(vm.Memory, make([]int, 128)...)
  56. }
  57. args[i] = &vm.Memory[vm.Memory[vm.ip+1+i]]
  58. // The argument is a memory reference offset by the relative base
  59. case relative:
  60. for vm.rb+vm.Memory[vm.ip+1+i] >= len(vm.Memory) {
  61. vm.Memory = append(vm.Memory, make([]int, 128)...)
  62. }
  63. args[i] = &vm.Memory[vm.rb+vm.Memory[vm.ip+1+i]]
  64. }
  65. param /= 10
  66. }
  67. opcodes[opcode](vm, args[0], args[1], args[2])
  68. }
  69. if vm.Output != nil {
  70. close(vm.Output)
  71. }
  72. }
  73. // Reset resets the memory to the given slice, and all other state back to its original value.
  74. func (vm *VirtualMachine) Reset(memory []int) {
  75. copy(vm.Memory, memory)
  76. // We may previously have expanded our own memory, reset that to zero.
  77. for i := len(memory); i < len(vm.Memory)-1; i++ {
  78. vm.Memory[i] = 0
  79. }
  80. vm.ip = 0
  81. vm.rb = 0
  82. vm.Halted = false
  83. }