Browse Source

Day 5

master
Chris Smith 4 years ago
parent
commit
c65781d961
Signed by: Chris Smith <chris@chameth.com> GPG Key ID: 3A2D4BBDC4A3C9A9
6 changed files with 175 additions and 11 deletions
  1. 2
    0
      05/answers.txt
  2. 1
    0
      05/input.txt
  3. 34
    0
      05/main.go
  4. 65
    10
      intcode/ops.go
  5. 33
    1
      intcode/vm.go
  6. 40
    0
      intcode/vm_test.go

+ 2
- 0
05/answers.txt View File

@@ -0,0 +1,2 @@
1
+6745903
2
+9168267

+ 1
- 0
05/input.txt View File

@@ -0,0 +1 @@
1
+3,225,1,225,6,6,1100,1,238,225,104,0,1102,40,93,224,1001,224,-3720,224,4,224,102,8,223,223,101,3,224,224,1,224,223,223,1101,56,23,225,1102,64,78,225,1102,14,11,225,1101,84,27,225,1101,7,82,224,1001,224,-89,224,4,224,1002,223,8,223,1001,224,1,224,1,224,223,223,1,35,47,224,1001,224,-140,224,4,224,1002,223,8,223,101,5,224,224,1,224,223,223,1101,75,90,225,101,9,122,224,101,-72,224,224,4,224,1002,223,8,223,101,6,224,224,1,224,223,223,1102,36,63,225,1002,192,29,224,1001,224,-1218,224,4,224,1002,223,8,223,1001,224,7,224,1,223,224,223,102,31,218,224,101,-2046,224,224,4,224,102,8,223,223,101,4,224,224,1,224,223,223,1001,43,38,224,101,-52,224,224,4,224,1002,223,8,223,101,5,224,224,1,223,224,223,1102,33,42,225,2,95,40,224,101,-5850,224,224,4,224,1002,223,8,223,1001,224,7,224,1,224,223,223,1102,37,66,225,4,223,99,0,0,0,677,0,0,0,0,0,0,0,0,0,0,0,1105,0,99999,1105,227,247,1105,1,99999,1005,227,99999,1005,0,256,1105,1,99999,1106,227,99999,1106,0,265,1105,1,99999,1006,0,99999,1006,227,274,1105,1,99999,1105,1,280,1105,1,99999,1,225,225,225,1101,294,0,0,105,1,0,1105,1,99999,1106,0,300,1105,1,99999,1,225,225,225,1101,314,0,0,106,0,0,1105,1,99999,1007,226,677,224,1002,223,2,223,1005,224,329,1001,223,1,223,1007,226,226,224,1002,223,2,223,1006,224,344,101,1,223,223,1107,677,226,224,102,2,223,223,1006,224,359,1001,223,1,223,108,677,677,224,1002,223,2,223,1006,224,374,1001,223,1,223,107,677,677,224,1002,223,2,223,1005,224,389,101,1,223,223,8,677,677,224,1002,223,2,223,1005,224,404,1001,223,1,223,108,226,226,224,1002,223,2,223,1005,224,419,101,1,223,223,1008,677,677,224,1002,223,2,223,1005,224,434,101,1,223,223,1008,226,226,224,1002,223,2,223,1005,224,449,101,1,223,223,7,677,226,224,1002,223,2,223,1006,224,464,1001,223,1,223,7,226,226,224,1002,223,2,223,1005,224,479,1001,223,1,223,1007,677,677,224,102,2,223,223,1005,224,494,101,1,223,223,1108,677,226,224,102,2,223,223,1006,224,509,1001,223,1,223,8,677,226,224,102,2,223,223,1005,224,524,1001,223,1,223,1107,226,226,224,102,2,223,223,1006,224,539,1001,223,1,223,1008,226,677,224,1002,223,2,223,1006,224,554,1001,223,1,223,1107,226,677,224,1002,223,2,223,1006,224,569,1001,223,1,223,1108,677,677,224,102,2,223,223,1005,224,584,101,1,223,223,7,226,677,224,102,2,223,223,1006,224,599,1001,223,1,223,1108,226,677,224,102,2,223,223,1006,224,614,101,1,223,223,107,226,677,224,1002,223,2,223,1005,224,629,101,1,223,223,108,226,677,224,1002,223,2,223,1005,224,644,101,1,223,223,8,226,677,224,1002,223,2,223,1005,224,659,1001,223,1,223,107,226,226,224,1002,223,2,223,1006,224,674,101,1,223,223,4,223,99,226

+ 34
- 0
05/main.go View File

@@ -0,0 +1,34 @@
1
+package main
2
+
3
+import (
4
+	"fmt"
5
+	"github.com/csmith/aoc-2019/common"
6
+	"github.com/csmith/aoc-2019/intcode"
7
+)
8
+
9
+func last(channel <-chan int) (res int) {
10
+	for {
11
+		o, more := <-channel
12
+		if more {
13
+			res = o
14
+		} else {
15
+			return
16
+		}
17
+	}
18
+}
19
+
20
+func main() {
21
+	input := common.ReadCsvAsInts("05/input.txt")
22
+	memory := make([]int, len(input))
23
+	copy(memory, input)
24
+
25
+	vm := intcode.NewVirtualMachine(memory)
26
+	vm.Input <- 1
27
+	vm.Run()
28
+	fmt.Println(last(vm.Output))
29
+
30
+	vm.Reset(input)
31
+	vm.Input <- 5
32
+	vm.Run()
33
+	fmt.Println(last(vm.Output))
34
+}

+ 65
- 10
intcode/ops.go View File

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

+ 33
- 1
intcode/vm.go View File

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

+ 40
- 0
intcode/vm_test.go View File

@@ -24,3 +24,43 @@ func TestDayTwoSamples(t *testing.T) {
24 24
 		}
25 25
 	}
26 26
 }
27
+
28
+func TestDayFiveSamples(t *testing.T) {
29
+	tables := []struct {
30
+		given  []int
31
+		input  []int
32
+		output []int
33
+	}{
34
+		// Reads then outputs a number
35
+		{[]int{3, 0, 4, 0, 99}, []int{123}, []int{123}},
36
+		// Using position mode, consider whether the input is equal to 8; output 1 (if it is) or 0 (if it is not).
37
+		{[]int{3, 9, 8, 9, 10, 9, 4, 9, 99, -1, 8}, []int{8}, []int{1}},
38
+		{[]int{3, 9, 8, 9, 10, 9, 4, 9, 99, -1, 8}, []int{7}, []int{0}},
39
+		// Using position mode, consider whether the input is less than 8; output 1 (if it is) or 0 (if it is not).
40
+		{[]int{3, 9, 7, 9, 10, 9, 4, 9, 99, -1, 8}, []int{7}, []int{1}},
41
+		{[]int{3, 9, 7, 9, 10, 9, 4, 9, 99, -1, 8}, []int{8}, []int{0}},
42
+		// Using immediate mode, consider whether the input is equal to 8; output 1 (if it is) or 0 (if it is not).
43
+		{[]int{3, 3, 1108, -1, 8, 3, 4, 3, 99}, []int{8}, []int{1}},
44
+		{[]int{3, 3, 1108, -1, 8, 3, 4, 3, 99}, []int{9}, []int{0}},
45
+		// Using immediate mode, consider whether the input is less than 8; output 1 (if it is) or 0 (if it is not).
46
+		{[]int{3, 3, 1107, -1, 8, 3, 4, 3, 99}, []int{0}, []int{1}},
47
+		{[]int{3, 3, 1107, -1, 8, 3, 4, 3, 99}, []int{10}, []int{0}},
48
+	}
49
+
50
+	for _, table := range tables {
51
+		vm := NewVirtualMachine(table.given)
52
+
53
+		for _, v := range table.input {
54
+			vm.Input <- v
55
+		}
56
+
57
+		vm.Run()
58
+
59
+		for _, v := range table.output {
60
+			actual := <-vm.Output
61
+			if !reflect.DeepEqual(v, actual) {
62
+				t.Errorf("Wrong output value received for %v, got: %v, want: %v.", table.given, actual, v)
63
+			}
64
+		}
65
+	}
66
+}

Loading…
Cancel
Save