Skip to content

Commit 048f461

Browse files
committed
Add 2019 days 15-21 cpp
1 parent 874c9e5 commit 048f461

24 files changed

+3708
-0
lines changed

2019/cpp/day_15a.cpp

+378
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,378 @@
1+
#include <algorithm>
2+
#include <fstream>
3+
#include <iostream>
4+
#include <string>
5+
#include <unordered_set>
6+
#include <unordered_map>
7+
#include <vector>
8+
#include <queue>
9+
#include <stack>
10+
11+
constexpr long long pow(const int base, const int raised_to) {
12+
long long ans = 1;
13+
for (int i = 1; i <= raised_to; i++) {
14+
ans *= base;
15+
}
16+
return ans;
17+
}
18+
19+
struct hash_pair {
20+
template <class T1, class T2>
21+
size_t operator()(const std::pair<T1, T2>& p) const {
22+
auto hash1 = std::hash<T1>{}(p.first);
23+
auto hash2 = std::hash<T2>{}(p.second);
24+
return hash1 ^ hash2;
25+
}
26+
};
27+
28+
class Program {
29+
public:
30+
Program(const std::vector<long long>& program) : init_program_state(program) {
31+
for (long long i = 0; i < program.size(); i++) {
32+
memory[i] = program[i];
33+
}
34+
}
35+
36+
void InitIfNotInited(const long long key) {
37+
if (memory.find(key) == memory.end()) {
38+
memory[key] = 0;
39+
}
40+
}
41+
42+
void reset() {
43+
for (long long i = 0; i < init_program_state.size(); i++) {
44+
memory[i] = init_program_state[i];
45+
}
46+
complete = false;
47+
inst_ptr = 0;
48+
relative_base = 0;
49+
}
50+
51+
std::vector<long long> getNOps(const size_t n, const size_t inst_ptr,
52+
long long modes) {
53+
std::vector<long long> ops;
54+
for (size_t i = 1; i <= n; ++i) {
55+
size_t rem = modes % 10;
56+
modes = modes / 10;
57+
if (rem == 0) {
58+
InitIfNotInited(inst_ptr + i);
59+
InitIfNotInited(memory[inst_ptr + i]);
60+
ops.push_back(memory[memory[inst_ptr + i]]);
61+
} else if (rem == 1) {
62+
InitIfNotInited(inst_ptr + i);
63+
InitIfNotInited(memory[inst_ptr + i]);
64+
ops.push_back(memory[inst_ptr + i]);
65+
} else if (rem == 2) {
66+
InitIfNotInited(inst_ptr + i);
67+
InitIfNotInited(relative_base + memory[inst_ptr + i]);
68+
InitIfNotInited(memory[relative_base + memory[inst_ptr + i]]);
69+
ops.push_back(memory[relative_base + memory[inst_ptr + i]]);
70+
} else {
71+
std::cout << "Error" << '\n';
72+
exit(0);
73+
}
74+
}
75+
return ops;
76+
}
77+
78+
long long getAddress(const size_t increment, long long modes) {
79+
long long address;
80+
const size_t rem = modes;
81+
if (rem == 0) {
82+
InitIfNotInited(inst_ptr + increment);
83+
address = memory[inst_ptr + increment];
84+
} else if (rem == 2) {
85+
InitIfNotInited(inst_ptr + increment);
86+
InitIfNotInited(relative_base + memory[inst_ptr + increment]);
87+
address = relative_base + memory[inst_ptr + increment];
88+
} else {
89+
std::cout << "Error" << '\n';
90+
exit(0);
91+
}
92+
return address;
93+
}
94+
95+
long long compute(const std::vector<long long>& input) {
96+
long long output = -1;
97+
size_t input_ptr = 0;
98+
while (memory[inst_ptr] != 99) {
99+
const long long instr = memory[inst_ptr];
100+
const long long opcode = instr % 100;
101+
const long long modes = instr / 100;
102+
if (opcode == 1) {
103+
constexpr int n_ops = 2;
104+
const auto ops = getNOps(n_ops, inst_ptr, modes);
105+
memory[getAddress(3, modes / pow(10, n_ops))] = ops[0] + ops[1];
106+
inst_ptr += 4;
107+
} else if (opcode == 2) {
108+
constexpr int n_ops = 2;
109+
const auto ops = getNOps(n_ops, inst_ptr, modes);
110+
memory[getAddress(3, modes / pow(10, n_ops))] = ops[0] * ops[1];
111+
inst_ptr += 4;
112+
} else if (opcode == 3) {
113+
memory[getAddress(1, modes)] = input[input_ptr];
114+
inst_ptr += 2;
115+
input_ptr += 1;
116+
} else if (opcode == 4) {
117+
const auto ops = getNOps(1, inst_ptr, modes);
118+
output = ops[0];
119+
inst_ptr += 2;
120+
// std::cout << output << '\n';
121+
return output;
122+
} else if (opcode == 5) {
123+
const auto ops = getNOps(2, inst_ptr, modes);
124+
if (ops[0] != 0) {
125+
inst_ptr = ops[1];
126+
} else {
127+
inst_ptr += 3;
128+
}
129+
} else if (opcode == 6) {
130+
const auto ops = getNOps(2, inst_ptr, modes);
131+
if (ops[0] == 0) {
132+
inst_ptr = ops[1];
133+
} else {
134+
inst_ptr += 3;
135+
}
136+
} else if (opcode == 7) {
137+
constexpr int n_ops = 2;
138+
const auto ops = getNOps(n_ops, inst_ptr, modes);
139+
if (ops[0] < ops[1]) {
140+
memory[getAddress(3, modes / pow(10, n_ops))] = 1;
141+
} else {
142+
memory[getAddress(3, modes / pow(10, n_ops))] = 0;
143+
}
144+
inst_ptr += 4;
145+
} else if (opcode == 8) {
146+
constexpr int n_ops = 2;
147+
const auto ops = getNOps(n_ops, inst_ptr, modes);
148+
if (ops[0] == ops[1]) {
149+
memory[getAddress(3, modes / pow(10, n_ops))] = 1;
150+
} else {
151+
memory[getAddress(3, modes / pow(10, n_ops))] = 0;
152+
}
153+
inst_ptr += 4;
154+
} else if (opcode == 9) {
155+
const auto ops = getNOps(1, inst_ptr, modes);
156+
relative_base += ops[0];
157+
inst_ptr += 2;
158+
}
159+
}
160+
complete = true;
161+
return output;
162+
}
163+
164+
bool isComplete() { return complete; }
165+
166+
private:
167+
const std::vector<long long> init_program_state;
168+
std::unordered_map<long long, long long> memory;
169+
bool complete = false;
170+
size_t inst_ptr = 0;
171+
size_t relative_base = 0;
172+
};
173+
174+
class IntcodeComputer {
175+
public:
176+
void addProgram(const std::vector<long long>& program) {
177+
programs.emplace_back(program);
178+
}
179+
180+
long long runProgram(const size_t index,
181+
const std::vector<long long>& input) {
182+
return programs[index].compute(input);
183+
}
184+
185+
void resetProgram(const size_t index) { programs[index].reset(); }
186+
187+
bool isLastComplete() { return programs.back().isComplete(); }
188+
189+
bool isComplete(size_t index) { return programs[index].isComplete(); }
190+
191+
void reset() { programs.clear(); }
192+
193+
private:
194+
std::vector<Program> programs;
195+
};
196+
197+
// TODO(vss): Refactor to remoe extra functions
198+
struct Point2D {
199+
int x, y;
200+
Point2D(const int x = 0, const int y = 0) : x(x), y(y){}
201+
Point2D operator+ (const Point2D& p) {
202+
return Point2D(this->x + p.x, this->y + p.y);
203+
}
204+
Point2D operator- (const Point2D& p) {
205+
return Point2D(this->x - p.x, this->y - p.y);
206+
}
207+
bool operator== (const Point2D& p) const {
208+
return (this->x == p.x && this->y == p.y);
209+
}
210+
};
211+
212+
bool ComparePts(const Point2D& p1, const Point2D& p2) {
213+
return (p1.x == p2.x && p1.y == p2.y);
214+
}
215+
216+
Point2D AddPoints(const Point2D& p1, const Point2D& p2) {
217+
return Point2D(p1.x + p2.x, p1.y + p2.y);
218+
}
219+
Point2D SubtractPoints(const Point2D& p1, const Point2D& p2) {
220+
return Point2D(p1.x - p2.x, p1.y - p2.y);
221+
}
222+
223+
struct hashp2d {
224+
size_t operator()(const Point2D& p) const {
225+
return std::hash<int>{}(p.x) ^ std::hash<int>{}(p.y);
226+
}
227+
};
228+
229+
std::vector<Point2D> getNeighbours(const Point2D& p) {
230+
std::vector<Point2D> deltas;
231+
deltas.emplace_back(AddPoints(p, Point2D(0, 1)));
232+
deltas.emplace_back(AddPoints(p, Point2D(0, -1)));
233+
deltas.emplace_back(AddPoints(p, Point2D(1, 0)));
234+
deltas.emplace_back(AddPoints(p, Point2D(-1, 0)));
235+
return deltas;
236+
}
237+
238+
int convertMoveToInstruction (const Point2D& p) {
239+
if( ComparePts(p, Point2D(0, 1))) {
240+
return 1;
241+
}
242+
if (ComparePts(p, Point2D(1, 0))) {
243+
return 4;
244+
}
245+
if (ComparePts(p, Point2D(-1, 0))) {
246+
return 3;
247+
}
248+
if (ComparePts(p, Point2D(0, -1))) {
249+
return 2;
250+
}
251+
return 0;
252+
}
253+
254+
void print(const std::vector<Point2D>& v) {
255+
for(const auto& ele : v) {
256+
std::cout << "(" << ele.x << ", " << ele.y << ")" << ' ';
257+
}
258+
std::cout << '\n';
259+
}
260+
261+
void print(const Point2D& ele) {
262+
std::cout << "(" << ele.x << ", " << ele.y << ")" << ' ';
263+
std::cout << '\n';
264+
}
265+
266+
void CallError(const std::string& err) {
267+
std::cout << err << '\n';
268+
exit(0);
269+
}
270+
271+
std::vector<Point2D> dijkstra(std::unordered_map<Point2D, int, hashp2d>& grid,
272+
const Point2D& start,
273+
const Point2D& dest) {
274+
std::vector<Point2D> moves;
275+
std::queue<Point2D> points;
276+
std::unordered_set <Point2D, hashp2d> visited;
277+
std::unordered_map <Point2D, Point2D, hashp2d> parent;
278+
points.push(start);
279+
// if (grid.find(start) != grid.end() && grid[start] == 0) CallError("Start is obstacle"); // Obstacle
280+
while (!points.empty() && !ComparePts(points.front(), dest)) {
281+
const auto current = points.front();
282+
points.pop();
283+
visited.insert(current);
284+
bool found = false; // Early break condition
285+
for (auto& neighbour : getNeighbours(current)) {
286+
if (visited.find(neighbour) != visited.end()) continue; // Already popped
287+
if (grid.find(neighbour) != grid.end() && grid[neighbour] == 0) continue; // Obstacle
288+
if (grid.find(neighbour) == grid.end() && !ComparePts(neighbour, dest)) continue; // Unknown point. Search shoudl be restricted to known points
289+
parent[neighbour] = current;
290+
if (ComparePts(neighbour, dest)) {
291+
found = true;
292+
points.push(neighbour);
293+
break;
294+
}
295+
points.push(neighbour);
296+
}
297+
if (found) break;
298+
}
299+
if (points.empty()) CallError("Failed to find a path");
300+
auto current = dest;
301+
while(!ComparePts(current, start)) {
302+
moves.push_back(SubtractPoints(current, parent[current]));
303+
current = parent[current];
304+
}
305+
std::reverse(std::begin(moves), std::end(moves));
306+
return moves;
307+
}
308+
309+
template<typename T>
310+
void print(const std::vector<T>& v) {
311+
for(const auto& ele : v) {
312+
std::cout << ele << ' ';
313+
}
314+
std::cout << '\n';
315+
}
316+
317+
void explore(IntcodeComputer& computer) {
318+
int output = 1;
319+
Point2D current(0, 0);
320+
std::stack<Point2D> unknown;
321+
std::unordered_set <Point2D, hashp2d> visited;
322+
323+
for (const auto& neighbour : getNeighbours(current)) {
324+
unknown.push(neighbour);
325+
}
326+
std::unordered_map<Point2D, int, hashp2d> grid;
327+
grid[current] = 1;
328+
329+
while (output != 2) {
330+
const auto nearest_unknown_pt = unknown.top();
331+
unknown.pop();
332+
if(grid.find(nearest_unknown_pt) != grid.end() && grid[nearest_unknown_pt] == 0) continue;
333+
if(current == nearest_unknown_pt) continue;
334+
if (grid.find(current) != grid.end() && grid[current] == 0) continue;
335+
// Search will never go through an obstacle, only the dest pount can be an obstacle, but is at yet unknow
336+
const auto moves = dijkstra(grid, current, nearest_unknown_pt);
337+
for (const auto& move : moves) {
338+
current = AddPoints(current, move);
339+
output = computer.runProgram(0, {convertMoveToInstruction(move)});
340+
}
341+
grid[nearest_unknown_pt] = output;
342+
if (output == 0) {
343+
current = SubtractPoints(current, moves.back());
344+
} else if (output == 1) {
345+
for (const auto& neighbour : getNeighbours(current)) {
346+
if(grid.find(neighbour) == grid.end()) unknown.push(neighbour);
347+
}
348+
}
349+
}
350+
std::cout << dijkstra(grid, Point2D(0,0), current).size() << '\n';
351+
}
352+
353+
int main(int argc, char* argv[]) {
354+
// Get input
355+
std::string input = "../input/day_15_input";
356+
if (argc > 1) {
357+
input = argv[1];
358+
}
359+
std::ifstream file(input);
360+
std::string input_str;
361+
std::getline(file, input_str);
362+
const std::string delimiter = ",";
363+
364+
std::size_t start = 0;
365+
std::size_t end = input_str.find(delimiter);
366+
std::vector<long long> program;
367+
while (end != std::string::npos) {
368+
program.emplace_back(std::stoll(input_str.substr(start, end - start)));
369+
start = end + delimiter.size();
370+
end = input_str.find(delimiter, start);
371+
}
372+
program.emplace_back(std::stoll(input_str.substr(start, end - start)));
373+
374+
// Solve
375+
IntcodeComputer computer;
376+
computer.addProgram(program);
377+
explore(computer);
378+
}

0 commit comments

Comments
 (0)