Line data Source code
1 : #include "Intcode.h"
2 :
3 : #include "IntegerCast.h"
4 : #include "Parsing.h"
5 :
6 : namespace {
7 : static constexpr std::array<int64_t, 10u> paramFactor = {
8 : -1, 100, 1000, 10000, 1000000, 10000000, 100000000, 1000000000, 10000000000, 100000000000};
9 : }
10 :
11 : Computer::Computer(std::string_view const programString)
12 23 : : _memory(parseIntegerRange<int64_t>(programString)) {}
13 :
14 30286 : Computer::Status Computer::run() {
15 1426826 : while (performOp())
16 1396540 : ;
17 30286 : return _status;
18 30286 : }
19 :
20 5313 : void Computer::reset() {
21 5313 : _ip = 0;
22 5313 : _rb = 0;
23 5432 : while (!_inputs.empty())
24 119 : _inputs.pop();
25 5313 : }
26 :
27 27489 : void Computer::queueInput(int64_t value) { _inputs.push(value); }
28 :
29 5313 : void Computer::reset(std::vector<int64_t> const &memory) {
30 5313 : reset();
31 5313 : setMemory(memory);
32 5313 : }
33 :
34 1426826 : int64_t Computer::opcode(Address address) { return readMemory(address) % 100; }
35 :
36 3274708 : int64_t Computer::parameterMode(Address address, size_t param) {
37 3274708 : return readMemory(address) / paramFactor[param] % 10;
38 3274708 : }
39 :
40 853624 : void Computer::writeMemory(Address address, int64_t value) {
41 853624 : if (address >= _memory.size())
42 1841 : _memory.resize(address + 1, 0);
43 853624 : _memory[address] = value;
44 853624 : }
45 :
46 9288759 : int64_t Computer::readMemory(Address address) {
47 9288759 : if (address >= _memory.size())
48 5 : _memory.resize(address + 1, 0);
49 9288759 : return _memory[address];
50 9288759 : }
51 :
52 1426826 : bool Computer::performOp() {
53 1426826 : int64_t value = 0;
54 1426826 : switch (opcode()) {
55 500848 : case 1: // add
56 500848 : writeParam(3, readParam(1) + readParam(2));
57 500848 : _ip += 4u;
58 500848 : break;
59 208992 : case 2: // multiply
60 208992 : writeParam(3, readParam(1) * readParam(2));
61 208992 : _ip += 4u;
62 208992 : break;
63 52332 : case 3: // input
64 52332 : if (_inputs.empty()) {
65 24963 : _status = PAUSED;
66 24963 : return false;
67 24963 : }
68 27369 : writeParam(1, _inputs.front());
69 27369 : _inputs.pop();
70 27369 : _ip += 2u;
71 27369 : break;
72 89641 : case 4: // output
73 89641 : value = readParam(1);
74 89641 : for (auto const &f : _output)
75 90841 : f(value);
76 89641 : _ip += 2u;
77 89641 : break;
78 203778 : case 5: // jump if true
79 203778 : if (readParam(1) != 0)
80 155858 : _ip = readParam(2);
81 47920 : else
82 47920 : _ip += 3;
83 203778 : break;
84 117631 : case 6: // jump if false
85 117631 : if (readParam(1) == 0)
86 86258 : _ip = readParam(2);
87 31373 : else
88 31373 : _ip += 3;
89 117631 : break;
90 60070 : case 7: // less than
91 60070 : writeParam(3, readParam(1) < readParam(2) ? 1 : 0);
92 60070 : _ip += 4u;
93 60070 : break;
94 48116 : case 8: // equals
95 48116 : writeParam(3, readParam(1) == readParam(2) ? 1 : 0);
96 48116 : _ip += 4u;
97 48116 : break;
98 140095 : case 9: // adjust relative base
99 140095 : _rb += readParam(1);
100 140095 : _ip += 2u;
101 140095 : break;
102 5323 : case 99:
103 5323 : _status = HALTED;
104 5323 : return false;
105 0 : default:
106 0 : ASSERT(false, "Invalid OP code", opcode());
107 1426826 : };
108 1396540 : return true;
109 1426826 : }
110 :
111 2429313 : int64_t Computer::readParam(size_t param) {
112 2429313 : DEBUG_ASSERT(_ip + param < _memory.size());
113 :
114 2429313 : int64_t const mode = parameterMode(param);
115 2429313 : switch (mode) {
116 903302 : case 0: // position mode
117 903302 : return readMemory(readMemory(_ip + param));
118 1120953 : case 1: // immediate mode
119 1120953 : return readMemory(_ip + param);
120 405058 : case 2: // relative mode
121 405058 : return readMemory(_rb + readMemory(_ip + param));
122 0 : default:
123 0 : ASSERT(false, "Invalid parameter mode", mode);
124 0 : return 0;
125 2429313 : }
126 2429313 : }
127 :
128 845395 : void Computer::writeParam(size_t param, int64_t value) {
129 845395 : int64_t const mode = parameterMode(param);
130 845395 : switch (mode) {
131 565669 : case 0: // position mode
132 565669 : writeMemory(readMemory(_ip + param), value);
133 565669 : break;
134 279726 : case 2: // relative mode
135 279726 : writeMemory(_rb + readMemory(_ip + param), value);
136 279726 : break;
137 0 : default:
138 : ASSERT(false, "Invalid parameter mode", mode);
139 845395 : }
140 845395 : }
|