Browse Source

Minor day 7 optimisations

Each VM doesn't need its own opcode array (hopefully); use a
pre-allocated memory bank for the memory of all amplifiers.
master
Chris Smith 4 years ago
parent
commit
cea1ff0bc9
Signed by: Chris Smith <chris@chameth.com> GPG Key ID: 3A2D4BBDC4A3C9A9
3 changed files with 48 additions and 51 deletions
  1. 9
    12
      07/main.go
  2. 32
    20
      intcode/ops.go
  3. 7
    19
      intcode/vm.go

+ 9
- 12
07/main.go View File

@@ -6,17 +6,13 @@ import (
6 6
 	"github.com/csmith/aoc-2019/intcode"
7 7
 )
8 8
 
9
-func copyOf(memory []int) []int {
10
-	res := make([]int, len(memory))
11
-	copy(res, memory)
12
-	return res
13
-}
14
-
15
-func runPipeline(program []int, ps []int, feedback bool) int {
9
+func runPipeline(memoryBanks []int, program []int, ps []int, feedback bool) int {
16 10
 	// Create a series of VMs for our amplifiers
17 11
 	vms := make([]*intcode.VirtualMachine, len(ps))
18 12
 	for i := 0; i < len(ps); i++ {
19
-		vms[i] = intcode.NewVirtualMachine(copyOf(program), true)
13
+		memory := memoryBanks[i*len(program) : (i+1)*len(program)]
14
+		copy(memory, program)
15
+		vms[i] = intcode.NewVirtualMachine(memory, true)
20 16
 	}
21 17
 
22 18
 	// Link all the inputs and outputs
@@ -46,10 +42,10 @@ func runPipeline(program []int, ps []int, feedback bool) int {
46 42
 	return <-vms[len(vms)-1].Output
47 43
 }
48 44
 
49
-func maxOutput(input []int, ps []int, feedback bool) int {
45
+func maxOutput(memoryBanks []int, input []int, ps []int, feedback bool) int {
50 46
 	max := 0
51 47
 	for _, p := range common.Permutations(ps) {
52
-		val := runPipeline(input, p, feedback)
48
+		val := runPipeline(memoryBanks, input, p, feedback)
53 49
 		if val > max {
54 50
 			max = val
55 51
 		}
@@ -59,6 +55,7 @@ func maxOutput(input []int, ps []int, feedback bool) int {
59 55
 
60 56
 func main() {
61 57
 	input := common.ReadCsvAsInts("07/input.txt")
62
-	fmt.Println(maxOutput(input, []int{0, 1, 2, 3, 4}, false))
63
-	fmt.Println(maxOutput(input, []int{5, 6, 7, 8, 9}, true))
58
+	memoryBanks := make([]int, len(input)*5)
59
+	fmt.Println(maxOutput(memoryBanks, input, []int{0, 1, 2, 3, 4}, false))
60
+	fmt.Println(maxOutput(memoryBanks, input, []int{5, 6, 7, 8, 9}, true))
64 61
 }

+ 32
- 20
intcode/ops.go View File

@@ -1,36 +1,48 @@
1 1
 package intcode
2 2
 
3
-// OpcodeFunc is a function that describes an opcode implemented in the VM.
4
-type OpcodeFunc = func(vm *VirtualMachine)
3
+// opcodeFunc is a function that describes an opcode implemented in the VM.
4
+type opcodeFunc = func(vm *VirtualMachine)
5 5
 
6
-// AddOpcode takes the values specified by args 1 and 2, adds them together, and stores at the memory address given
6
+var opcodes = [100]opcodeFunc{
7
+	1:  addOpcode,
8
+	2:  mulOpcode,
9
+	3:  readOpCode,
10
+	4:  writeOpCode,
11
+	5:  jumpIfTrueOpCode,
12
+	6:  jumpIfFalseOpCode,
13
+	7:  lessThanOpCode,
14
+	8:  equalsOpCode,
15
+	99: haltOpcode,
16
+}
17
+
18
+// addOpcode takes the values specified by args 1 and 2, adds them together, and stores at the memory address given
7 19
 // by arg 3.
8
-func AddOpcode(vm *VirtualMachine) {
20
+func addOpcode(vm *VirtualMachine) {
9 21
 	vm.Memory[vm.Memory[vm.ip+3]] = vm.arg(0) + vm.arg(1)
10 22
 	vm.ip += 4
11 23
 }
12 24
 
13
-// MulOpcode takes the values specified by args 1 and 2, multiplies them together, and stores at the memory address
25
+// mulOpcode takes the values specified by args 1 and 2, multiplies them together, and stores at the memory address
14 26
 // given by arg 3.
15
-func MulOpcode(vm *VirtualMachine) {
27
+func mulOpcode(vm *VirtualMachine) {
16 28
 	vm.Memory[vm.Memory[vm.ip+3]] = vm.arg(0) * vm.arg(1)
17 29
 	vm.ip += 4
18 30
 }
19 31
 
20
-// ReadOpCode reads a value from the input stream and stores it at the memory address given by arg 1.
21
-func ReadOpCode(vm *VirtualMachine) {
32
+// readOpCode reads a value from the input stream and stores it at the memory address given by arg 1.
33
+func readOpCode(vm *VirtualMachine) {
22 34
 	vm.Memory[vm.Memory[vm.ip+1]] = <-vm.Input
23 35
 	vm.ip += 2
24 36
 }
25 37
 
26
-// WriteOpCode writes the value specified by the first argument to the output stream.
27
-func WriteOpCode(vm *VirtualMachine) {
38
+// writeOpCode writes the value specified by the first argument to the output stream.
39
+func writeOpCode(vm *VirtualMachine) {
28 40
 	vm.Output <- vm.arg(0)
29 41
 	vm.ip += 2
30 42
 }
31 43
 
32
-// JumpIfTrueOpCode checks if the first argument is not zero, and if so jumps to the second argument.
33
-func JumpIfTrueOpCode(vm *VirtualMachine) {
44
+// jumpIfTrueOpCode checks if the first argument is not zero, and if so jumps to the second argument.
45
+func jumpIfTrueOpCode(vm *VirtualMachine) {
34 46
 	if vm.arg(0) != 0 {
35 47
 		vm.ip = vm.arg(1)
36 48
 	} else {
@@ -38,8 +50,8 @@ func JumpIfTrueOpCode(vm *VirtualMachine) {
38 50
 	}
39 51
 }
40 52
 
41
-// JumpIfFalseOpCode checks if the first argument is zero, and if so jumps to the second argument.
42
-func JumpIfFalseOpCode(vm *VirtualMachine) {
53
+// jumpIfFalseOpCode checks if the first argument is zero, and if so jumps to the second argument.
54
+func jumpIfFalseOpCode(vm *VirtualMachine) {
43 55
 	if vm.arg(0) == 0 {
44 56
 		vm.ip = vm.arg(1)
45 57
 	} else {
@@ -47,9 +59,9 @@ func JumpIfFalseOpCode(vm *VirtualMachine) {
47 59
 	}
48 60
 }
49 61
 
50
-// LessThanOpCode checks if the first argument is less than the second, and stores the result at the address given
62
+// lessThanOpCode checks if the first argument is less than the second, and stores the result at the address given
51 63
 // by the third argument.
52
-func LessThanOpCode(vm *VirtualMachine) {
64
+func lessThanOpCode(vm *VirtualMachine) {
53 65
 	if vm.arg(0) < vm.arg(1) {
54 66
 		vm.Memory[vm.Memory[vm.ip+3]] = 1
55 67
 	} else {
@@ -58,9 +70,9 @@ func LessThanOpCode(vm *VirtualMachine) {
58 70
 	vm.ip += 4
59 71
 }
60 72
 
61
-// EqualsOpCode checks if the first argument is equal to the second, and stores the result at the address given
73
+// equalsOpCode checks if the first argument is equal to the second, and stores the result at the address given
62 74
 // by the third argument.
63
-func EqualsOpCode(vm *VirtualMachine) {
75
+func equalsOpCode(vm *VirtualMachine) {
64 76
 	if vm.arg(0) == vm.arg(1) {
65 77
 		vm.Memory[vm.Memory[vm.ip+3]] = 1
66 78
 	} else {
@@ -69,7 +81,7 @@ func EqualsOpCode(vm *VirtualMachine) {
69 81
 	vm.ip += 4
70 82
 }
71 83
 
72
-// HaltOpcode halts the VM and takes no arguments.
73
-func HaltOpcode(vm *VirtualMachine) {
84
+// haltOpcode halts the VM and takes no arguments.
85
+func haltOpcode(vm *VirtualMachine) {
74 86
 	vm.Halted = true
75 87
 }

+ 7
- 19
intcode/vm.go View File

@@ -2,13 +2,12 @@ package intcode
2 2
 
3 3
 // VirtualMachine is an IntCode virtual machine.
4 4
 type VirtualMachine struct {
5
-	ip      int
6
-	modes   uint8
7
-	opcodes [100]interface{}
8
-	Memory  []int
9
-	Halted  bool
10
-	Input   chan int
11
-	Output  chan int
5
+	ip     int
6
+	modes  uint8
7
+	Memory []int
8
+	Halted bool
9
+	Input  chan int
10
+	Output chan int
12 11
 }
13 12
 
14 13
 // NewVirtualMachine creates a new IntCode virtual machine, initialised
@@ -18,17 +17,6 @@ func NewVirtualMachine(memory []int, hasIO bool) *VirtualMachine {
18 17
 		ip:     0,
19 18
 		Memory: memory,
20 19
 		Halted: false,
21
-		opcodes: [100]interface{}{
22
-			1:  AddOpcode,
23
-			2:  MulOpcode,
24
-			3:  ReadOpCode,
25
-			4:  WriteOpCode,
26
-			5:  JumpIfTrueOpCode,
27
-			6:  JumpIfFalseOpCode,
28
-			7:  LessThanOpCode,
29
-			8:  EqualsOpCode,
30
-			99: HaltOpcode,
31
-		},
32 20
 	}
33 21
 
34 22
 	if hasIO {
@@ -63,7 +51,7 @@ func (vm *VirtualMachine) Run() {
63 51
 			mask = mask << 1
64 52
 		}
65 53
 
66
-		vm.opcodes[opcode].(OpcodeFunc)(vm)
54
+		opcodes[opcode](vm)
67 55
 	}
68 56
 	if vm.Output != nil {
69 57
 		close(vm.Output)

Loading…
Cancel
Save