Implement day 13 part 2.

This commit is contained in:
2019-12-13 22:34:45 +01:00
parent 98f790242c
commit b79c4c9fd1
2 changed files with 123 additions and 13 deletions

View File

@@ -4,10 +4,16 @@ project(aoc2019)
find_package(GTest REQUIRED)
option(ANIMATE_DAY13 "Animate the Arkanoid game in day 13." Off)
file(GLOB DAYS_FILES src/day*.cpp)
add_library(AoCSolutions src/implementations.cpp "${DAYS_FILES}" src/point.hpp src/utils.cpp src/utils.hpp)
target_compile_features(AoCSolutions PUBLIC cxx_std_17)
if (ANIMATE_DAY13)
target_compile_definitions(AoCSolutions ANIMATE_DAY13)
endif ()
add_executable(runner src/runner.cpp)
target_compile_features(runner PUBLIC cxx_std_17)
target_link_libraries(runner AoCSolutions)

View File

@@ -1,4 +1,8 @@
#include <iostream>
#ifdef ANIMATE_DAY13
#include <chrono>
#include <thread>
#endif
#include "days.hpp"
#include "utils.hpp"
#include "point.hpp"
@@ -13,28 +17,128 @@ namespace {
PADDLE,
BALL,
};
typedef std::unordered_map<point_t, Tile> Screen;
std::optional<std::int64_t> update_screen(std::deque<std::int64_t> &output_buffer, Screen &screen) {
std::optional<std::int64_t> score;
while (!output_buffer.empty()) {
auto x = output_buffer.front(); output_buffer.pop_front();
auto y = output_buffer.front(); output_buffer.pop_front();
auto type = output_buffer.front(); output_buffer.pop_front();
if (x == -1 && y == 0) {
score = type;
continue;
}
screen[{x, y}] = static_cast<Tile>(type);
}
return score;
}
void draw_screen(const Screen &screen, std::ostream& output) {
// Determine bounding box
using limits = std::numeric_limits<int>;
std::int64_t left_edge = limits::max(), right_edge = limits::min(), top_edge = limits::max(), bottom_edge = limits::min();
for (auto& entry : screen) {
left_edge = std::min(entry.first[0], left_edge);
right_edge = std::max(entry.first[0], right_edge);
top_edge = std::min(entry.first[1], top_edge);
bottom_edge = std::max(entry.first[1], bottom_edge);
}
for (auto y = top_edge; y <= bottom_edge; ++y) {
for (auto x = left_edge; x <= right_edge; ++x) {
char c = ' ';
if (auto it = screen.find({x, y}); it != screen.end()) {
switch (it->second) {
case Tile::EMPTY:
c = ' ';
break;
case Tile::BALL:
c = '*';
break;
case Tile::BLOCK:
c = '=';
break;
case Tile::PADDLE:
c = '_';
break;
case Tile::WALL:
c = '#';
break;
}
}
output << c;
}
output << '\n';
}
}
auto find_pos(const Screen &screen, Tile to_find) {
return std::find_if(screen.begin(), screen.end(), [to_find](const auto& x) {
return x.second == to_find;
});
}
}
void aoc2019::day13_part1(std::istream &input, std::ostream &output) {
Screen screen;
aoc2019::IntCodeComputer computer(aoc2019::IntCodeComputer::read_intcode(input));
std::deque<std::int64_t> output_buffer;
computer.connectOutput(output_buffer);
computer.run();
update_screen(output_buffer, screen);
std::unordered_map<point_t, Tile> drawn;
while (!output_buffer.empty()) {
auto x = output_buffer.front(); output_buffer.pop_front();
auto y = output_buffer.front(); output_buffer.pop_front();
auto type = output_buffer.front(); output_buffer.pop_front();
drawn[{x, y}] = static_cast<Tile>(type);
}
output << std::count_if(drawn.begin(), drawn.end(), [](const auto& x) { return x.second == Tile::BLOCK; })<< std::endl;
output << std::count_if(screen.begin(), screen.end(), [](const auto &x) { return x.second == Tile::BLOCK; })
<< std::endl;
}
void aoc2019::day13_part2(std::istream &input, std::ostream &output) {
output << "Not implemented\n";
auto program = aoc2019::IntCodeComputer::read_intcode(input);
program[0] = 2;
aoc2019::IntCodeComputer computer(std::move(program));
std::deque<std::int64_t> output_buffer;
computer.connectOutput(output_buffer);
computer.run();
Screen screen;
std::int64_t score = 0;
while (!computer.isTerminated()) {
computer.run();
auto new_score = update_screen(output_buffer, screen);
if (new_score) {
score = *new_score;
}
#ifdef ANIMATE_DAY13
output << "Score: " << score << std::endl;
draw_screen(screen, output);
std::this_thread::sleep_for(std::chrono::milliseconds(40));
#endif
auto ball_pos = find_pos(screen, Tile::BALL)->first;
auto paddle_pos = find_pos(screen, Tile::PADDLE)->first;
if (ball_pos[0] < paddle_pos[0]) {
computer.sendInput(-1);
} else if (ball_pos[0] > paddle_pos[0]) {
computer.sendInput(1);
} else {
computer.sendInput(0);
}
}
output << score << std::endl;
}