diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index f585909..0000000 --- a/.travis.yml +++ /dev/null @@ -1,24 +0,0 @@ -language: rust -rust: - - stable - - beta - - nightly - - 1.28.0 # Ubuntu Bionic and Xenial - -matrix: - allow_failures: - - rust: nightly - - rust: 1.28.0 - fast_finish: true - -cache: cargo - -# Custom directory, for the correct year -before_script: - - cd 2018 - -# After success on stable, run benchmark -after_success: - - if [ "$TRAVIS_RUST_VERSION" == "stable" ]; then - cargo bench; - fi diff --git a/2019/.gitignore b/2019/.gitignore new file mode 100644 index 0000000..8eee68f --- /dev/null +++ b/2019/.gitignore @@ -0,0 +1 @@ +cmake-build-* diff --git a/2019/CMakeLists.txt b/2019/CMakeLists.txt new file mode 100644 index 0000000..1ee4f27 --- /dev/null +++ b/2019/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.12) + +project(aoc2019) + +find_package(GTest REQUIRED) + +file(GLOB DAYS_FILES src/day*.cpp) +add_library(AoCSolutions src/implementations.cpp "${DAYS_FILES}") +target_compile_features(AoCSolutions PUBLIC cxx_std_17) + +add_executable(runner src/runner.cpp) +target_compile_features(runner PUBLIC cxx_std_17) +target_link_libraries(runner AoCSolutions) + +add_executable(unit_tests tests/test_solutions.cpp) +target_compile_features(unit_tests PUBLIC cxx_std_17) +target_link_libraries(unit_tests AoCSolutions GTest::GTest GTest::Main) +target_compile_definitions(unit_tests PRIVATE "TEST_SAMPLES_DIR=\"${CMAKE_SOURCE_DIR}/tests/samples\"") +target_include_directories(unit_tests PRIVATE "${CMAKE_SOURCE_DIR}/src") + +enable_testing() +gtest_discover_tests(unit_tests NO_PRETTY_VALUES) diff --git a/2019/README.md b/2019/README.md new file mode 100644 index 0000000..f857611 --- /dev/null +++ b/2019/README.md @@ -0,0 +1,31 @@ +# Advent of Code 2019 + +This project contains my implementations for Advent of Code 2019. The +goal is to create reasonably fast C++ implementations in readable and +ergonomic C++. At the end of the contest, I will probably do a write- +up of some sorts. + + +## How to compile + +Install the dependencies: + +- [GTest](https://github.com/google/googletest) **Note:** this project + by default tries to dynamically link GTest, and the Ubuntu packages + only provide a statically linked archive. You may need to compile it + for yourself. + +``` +mkdir build && cd build +cmake .. +make +``` + +You can then use the generated executable `runner`. + +## Running tests + +Tests can be executed with `make test`. The `tests` folder contains a +`samples` folder. This folder contains pairs of `XX-Y-something.in` and +`XX-Y-something.out`, which will be taken as the expected input and +output of the implementations. You can add your own samples to this mix. diff --git a/2019/src/day01.cpp b/2019/src/day01.cpp new file mode 100644 index 0000000..c4ff5e4 --- /dev/null +++ b/2019/src/day01.cpp @@ -0,0 +1,10 @@ +#include +#include "days.hpp" + +void aoc2019::day01_part1(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} + +void aoc2019::day01_part2(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} diff --git a/2019/src/day02.cpp b/2019/src/day02.cpp new file mode 100644 index 0000000..5bb6abf --- /dev/null +++ b/2019/src/day02.cpp @@ -0,0 +1,10 @@ +#include +#include "days.hpp" + +void aoc2019::day02_part1(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} + +void aoc2019::day02_part2(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} diff --git a/2019/src/day03.cpp b/2019/src/day03.cpp new file mode 100644 index 0000000..dfc74de --- /dev/null +++ b/2019/src/day03.cpp @@ -0,0 +1,10 @@ +#include +#include "days.hpp" + +void aoc2019::day03_part1(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} + +void aoc2019::day03_part2(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} diff --git a/2019/src/day04.cpp b/2019/src/day04.cpp new file mode 100644 index 0000000..c9f113f --- /dev/null +++ b/2019/src/day04.cpp @@ -0,0 +1,10 @@ +#include +#include "days.hpp" + +void aoc2019::day04_part1(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} + +void aoc2019::day04_part2(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} diff --git a/2019/src/day05.cpp b/2019/src/day05.cpp new file mode 100644 index 0000000..af62105 --- /dev/null +++ b/2019/src/day05.cpp @@ -0,0 +1,10 @@ +#include +#include "days.hpp" + +void aoc2019::day05_part1(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} + +void aoc2019::day05_part2(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} diff --git a/2019/src/day06.cpp b/2019/src/day06.cpp new file mode 100644 index 0000000..52421fd --- /dev/null +++ b/2019/src/day06.cpp @@ -0,0 +1,10 @@ +#include +#include "days.hpp" + +void aoc2019::day06_part1(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} + +void aoc2019::day06_part2(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} diff --git a/2019/src/day07.cpp b/2019/src/day07.cpp new file mode 100644 index 0000000..603b222 --- /dev/null +++ b/2019/src/day07.cpp @@ -0,0 +1,10 @@ +#include +#include "days.hpp" + +void aoc2019::day07_part1(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} + +void aoc2019::day07_part2(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} diff --git a/2019/src/day08.cpp b/2019/src/day08.cpp new file mode 100644 index 0000000..03855f3 --- /dev/null +++ b/2019/src/day08.cpp @@ -0,0 +1,10 @@ +#include +#include "days.hpp" + +void aoc2019::day08_part1(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} + +void aoc2019::day08_part2(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} diff --git a/2019/src/day09.cpp b/2019/src/day09.cpp new file mode 100644 index 0000000..28f8285 --- /dev/null +++ b/2019/src/day09.cpp @@ -0,0 +1,10 @@ +#include +#include "days.hpp" + +void aoc2019::day09_part1(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} + +void aoc2019::day09_part2(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} diff --git a/2019/src/day10.cpp b/2019/src/day10.cpp new file mode 100644 index 0000000..391e112 --- /dev/null +++ b/2019/src/day10.cpp @@ -0,0 +1,10 @@ +#include +#include "days.hpp" + +void aoc2019::day10_part1(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} + +void aoc2019::day10_part2(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} diff --git a/2019/src/day11.cpp b/2019/src/day11.cpp new file mode 100644 index 0000000..508ed43 --- /dev/null +++ b/2019/src/day11.cpp @@ -0,0 +1,10 @@ +#include +#include "days.hpp" + +void aoc2019::day11_part1(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} + +void aoc2019::day11_part2(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} diff --git a/2019/src/day12.cpp b/2019/src/day12.cpp new file mode 100644 index 0000000..16cb2a8 --- /dev/null +++ b/2019/src/day12.cpp @@ -0,0 +1,10 @@ +#include +#include "days.hpp" + +void aoc2019::day12_part1(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} + +void aoc2019::day12_part2(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} diff --git a/2019/src/day13.cpp b/2019/src/day13.cpp new file mode 100644 index 0000000..39dd64c --- /dev/null +++ b/2019/src/day13.cpp @@ -0,0 +1,10 @@ +#include +#include "days.hpp" + +void aoc2019::day13_part1(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} + +void aoc2019::day13_part2(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} diff --git a/2019/src/day14.cpp b/2019/src/day14.cpp new file mode 100644 index 0000000..b0441a4 --- /dev/null +++ b/2019/src/day14.cpp @@ -0,0 +1,10 @@ +#include +#include "days.hpp" + +void aoc2019::day14_part1(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} + +void aoc2019::day14_part2(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} diff --git a/2019/src/day15.cpp b/2019/src/day15.cpp new file mode 100644 index 0000000..6fa383f --- /dev/null +++ b/2019/src/day15.cpp @@ -0,0 +1,10 @@ +#include +#include "days.hpp" + +void aoc2019::day15_part1(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} + +void aoc2019::day15_part2(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} diff --git a/2019/src/day16.cpp b/2019/src/day16.cpp new file mode 100644 index 0000000..61765e5 --- /dev/null +++ b/2019/src/day16.cpp @@ -0,0 +1,10 @@ +#include +#include "days.hpp" + +void aoc2019::day16_part1(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} + +void aoc2019::day16_part2(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} diff --git a/2019/src/day17.cpp b/2019/src/day17.cpp new file mode 100644 index 0000000..a979207 --- /dev/null +++ b/2019/src/day17.cpp @@ -0,0 +1,10 @@ +#include +#include "days.hpp" + +void aoc2019::day17_part1(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} + +void aoc2019::day17_part2(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} diff --git a/2019/src/day18.cpp b/2019/src/day18.cpp new file mode 100644 index 0000000..4783ee1 --- /dev/null +++ b/2019/src/day18.cpp @@ -0,0 +1,10 @@ +#include +#include "days.hpp" + +void aoc2019::day18_part1(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} + +void aoc2019::day18_part2(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} diff --git a/2019/src/day19.cpp b/2019/src/day19.cpp new file mode 100644 index 0000000..aa2248c --- /dev/null +++ b/2019/src/day19.cpp @@ -0,0 +1,10 @@ +#include +#include "days.hpp" + +void aoc2019::day19_part1(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} + +void aoc2019::day19_part2(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} diff --git a/2019/src/day20.cpp b/2019/src/day20.cpp new file mode 100644 index 0000000..bb8a3a7 --- /dev/null +++ b/2019/src/day20.cpp @@ -0,0 +1,10 @@ +#include +#include "days.hpp" + +void aoc2019::day20_part1(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} + +void aoc2019::day20_part2(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} diff --git a/2019/src/day21.cpp b/2019/src/day21.cpp new file mode 100644 index 0000000..89decc1 --- /dev/null +++ b/2019/src/day21.cpp @@ -0,0 +1,10 @@ +#include +#include "days.hpp" + +void aoc2019::day21_part1(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} + +void aoc2019::day21_part2(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} diff --git a/2019/src/day22.cpp b/2019/src/day22.cpp new file mode 100644 index 0000000..70e3852 --- /dev/null +++ b/2019/src/day22.cpp @@ -0,0 +1,10 @@ +#include +#include "days.hpp" + +void aoc2019::day22_part1(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} + +void aoc2019::day22_part2(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} diff --git a/2019/src/day23.cpp b/2019/src/day23.cpp new file mode 100644 index 0000000..383e9f5 --- /dev/null +++ b/2019/src/day23.cpp @@ -0,0 +1,10 @@ +#include +#include "days.hpp" + +void aoc2019::day23_part1(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} + +void aoc2019::day23_part2(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} diff --git a/2019/src/day24.cpp b/2019/src/day24.cpp new file mode 100644 index 0000000..632ed30 --- /dev/null +++ b/2019/src/day24.cpp @@ -0,0 +1,10 @@ +#include +#include "days.hpp" + +void aoc2019::day24_part1(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} + +void aoc2019::day24_part2(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} diff --git a/2019/src/day25.cpp b/2019/src/day25.cpp new file mode 100644 index 0000000..0eb6ade --- /dev/null +++ b/2019/src/day25.cpp @@ -0,0 +1,10 @@ +#include +#include "days.hpp" + +void aoc2019::day25_part1(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} + +void aoc2019::day25_part2(std::istream &input, std::ostream &output) { + output << "Not implemented\n"; +} diff --git a/2019/src/days.hpp b/2019/src/days.hpp new file mode 100644 index 0000000..f34ed64 --- /dev/null +++ b/2019/src/days.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include + +namespace aoc2019 { + // Declarations of all implemented days. + void day01_part1(std::istream &input, std::ostream &output); + void day01_part2(std::istream &input, std::ostream &output); + void day02_part1(std::istream &input, std::ostream &output); + void day02_part2(std::istream &input, std::ostream &output); + void day03_part1(std::istream &input, std::ostream &output); + void day03_part2(std::istream &input, std::ostream &output); + void day04_part1(std::istream &input, std::ostream &output); + void day04_part2(std::istream &input, std::ostream &output); + void day05_part1(std::istream &input, std::ostream &output); + void day05_part2(std::istream &input, std::ostream &output); + void day06_part1(std::istream &input, std::ostream &output); + void day06_part2(std::istream &input, std::ostream &output); + void day07_part1(std::istream &input, std::ostream &output); + void day07_part2(std::istream &input, std::ostream &output); + void day08_part1(std::istream &input, std::ostream &output); + void day08_part2(std::istream &input, std::ostream &output); + void day09_part1(std::istream &input, std::ostream &output); + void day09_part2(std::istream &input, std::ostream &output); + void day10_part1(std::istream &input, std::ostream &output); + void day10_part2(std::istream &input, std::ostream &output); + void day11_part1(std::istream &input, std::ostream &output); + void day11_part2(std::istream &input, std::ostream &output); + void day12_part1(std::istream &input, std::ostream &output); + void day12_part2(std::istream &input, std::ostream &output); + void day13_part1(std::istream &input, std::ostream &output); + void day13_part2(std::istream &input, std::ostream &output); + void day14_part1(std::istream &input, std::ostream &output); + void day14_part2(std::istream &input, std::ostream &output); + void day15_part1(std::istream &input, std::ostream &output); + void day15_part2(std::istream &input, std::ostream &output); + void day16_part1(std::istream &input, std::ostream &output); + void day16_part2(std::istream &input, std::ostream &output); + void day17_part1(std::istream &input, std::ostream &output); + void day17_part2(std::istream &input, std::ostream &output); + void day18_part1(std::istream &input, std::ostream &output); + void day18_part2(std::istream &input, std::ostream &output); + void day19_part1(std::istream &input, std::ostream &output); + void day19_part2(std::istream &input, std::ostream &output); + void day20_part1(std::istream &input, std::ostream &output); + void day20_part2(std::istream &input, std::ostream &output); + void day21_part1(std::istream &input, std::ostream &output); + void day21_part2(std::istream &input, std::ostream &output); + void day22_part1(std::istream &input, std::ostream &output); + void day22_part2(std::istream &input, std::ostream &output); + void day23_part1(std::istream &input, std::ostream &output); + void day23_part2(std::istream &input, std::ostream &output); + void day24_part1(std::istream &input, std::ostream &output); + void day24_part2(std::istream &input, std::ostream &output); + void day25_part1(std::istream &input, std::ostream &output); + void day25_part2(std::istream &input, std::ostream &output); +} diff --git a/2019/src/implementations.cpp b/2019/src/implementations.cpp new file mode 100644 index 0000000..9111331 --- /dev/null +++ b/2019/src/implementations.cpp @@ -0,0 +1,35 @@ +#include +#include "days.hpp" +#include "implementations.hpp" + +constexpr const std::array, 25> SOLUTIONS = {{ + {aoc2019::day01_part1, aoc2019::day01_part2}, + {aoc2019::day02_part1, aoc2019::day02_part2}, + {aoc2019::day03_part1, aoc2019::day03_part2}, + {aoc2019::day04_part1, aoc2019::day04_part2}, + {aoc2019::day05_part1, aoc2019::day05_part2}, + {aoc2019::day06_part1, aoc2019::day06_part2}, + {aoc2019::day07_part1, aoc2019::day07_part2}, + {aoc2019::day08_part1, aoc2019::day08_part2}, + {aoc2019::day09_part1, aoc2019::day09_part2}, + {aoc2019::day10_part1, aoc2019::day10_part2}, + {aoc2019::day11_part1, aoc2019::day11_part2}, + {aoc2019::day12_part1, aoc2019::day12_part2}, + {aoc2019::day13_part1, aoc2019::day13_part2}, + {aoc2019::day14_part1, aoc2019::day14_part2}, + {aoc2019::day15_part1, aoc2019::day15_part2}, + {aoc2019::day16_part1, aoc2019::day16_part2}, + {aoc2019::day17_part1, aoc2019::day17_part2}, + {aoc2019::day18_part1, aoc2019::day18_part2}, + {aoc2019::day19_part1, aoc2019::day19_part2}, + {aoc2019::day20_part1, aoc2019::day20_part2}, + {aoc2019::day21_part1, aoc2019::day21_part2}, + {aoc2019::day22_part1, aoc2019::day22_part2}, + {aoc2019::day23_part1, aoc2019::day23_part2}, + {aoc2019::day24_part1, aoc2019::day24_part2}, + {aoc2019::day25_part1, aoc2019::day25_part2}, +}}; + +aoc2019::solution_t aoc2019::get_implementation(int day, bool part2) { + return SOLUTIONS.at(day - 1).at((int) part2); +} diff --git a/2019/src/implementations.hpp b/2019/src/implementations.hpp new file mode 100644 index 0000000..24e9820 --- /dev/null +++ b/2019/src/implementations.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include + +namespace aoc2019 { + typedef void (*solution_t)(std::istream &, std::ostream &); + + solution_t get_implementation(int day, bool part2 = false); +} diff --git a/2019/src/runner.cpp b/2019/src/runner.cpp new file mode 100644 index 0000000..c3f6b5a --- /dev/null +++ b/2019/src/runner.cpp @@ -0,0 +1,107 @@ +#include "implementations.hpp" +#include +#include +#include + +struct AoCOptions { + aoc2019::solution_t implementation; + bool run_timer; +}; + +static AoCOptions parse_options(const int argc, const char* argv[]) { + using namespace std::string_view_literals; + AoCOptions options{}; + + auto show_help = [argv] (int exit_status = 0) { + std::cerr << "Usage: " << argv[0] << " [--timer|-t] [--part2|-2] [--help|-h] DAY\n" + << "\t--timer|-t: print execution time\n" + << "\t--part2|-2: run part 2\n" + << "\t --help|-h: show this message\n"; + std::exit(exit_status); + }; + + int day = -1; + bool part2 = false; + + // Here follows a manual implementation of getopt, since getopt doesn't work on windows… + for (int i = 1; i < argc; ++i) { + std::string_view arg(argv[i]); + if (arg[0] == '-') { + // Handle flag arguments + if (arg[1] != '-') { + // Shorthand flags + for (char c : arg.substr(1)) { + switch (c) { + case '2': + part2 = true; + break; + + case 't': + options.run_timer = true; + break; + + case 'h': + show_help(); + break; + + default: + std::cerr << "Unknown flag '" << c << "'.\n\n"; + show_help(1); + } + } + } else { + // Handle long form versions + if (arg == "--timer"sv) { + part2 = true; + } else if (arg == "--timer"sv) { + options.run_timer = true; + } else if (arg == "--help"sv) { + show_help(); + } else { + show_help(1); + } + } + } else { + if (day != -1) { + // Double date specification, bail. + show_help(1); + } + + // Try to parse the date number + if (auto res = std::from_chars(arg.data(), arg.data() + arg.size(), day); res.ec != std::errc()) { + auto error_code = std::make_error_code(res.ec); + std::cerr << error_code.message() << "\n\n"; + show_help(1); + } + } + } + + if (day == -1) { + std::cerr << "Argument DAY is required.\n\n"; + show_help(1); + } else if (day < 1 || day > 25) { + std::cerr << "Invalid day. Valid range: [1, 25]\n"; + show_help(1); + } + + options.implementation = aoc2019::get_implementation(day, part2); + + return options; +} + +int main(int argc, const char *argv[]) { + const auto options = parse_options(argc, argv); + + if (options.implementation != nullptr) { + const auto start = std::chrono::high_resolution_clock::now(); + options.implementation(std::cin, std::cout); + if (options.run_timer) { + const std::chrono::duration duration = std::chrono::high_resolution_clock::now() - start; + std::cerr << "Time taken: " << duration.count() << "s\n"; + } + return 0; + } else { + std::cerr << "Unimplemented.\n"; + return 1; + } +} diff --git a/2019/tests/samples/.gitkeep b/2019/tests/samples/.gitkeep new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/2019/tests/samples/.gitkeep @@ -0,0 +1 @@ + diff --git a/2019/tests/test_solutions.cpp b/2019/tests/test_solutions.cpp new file mode 100644 index 0000000..ea870bc --- /dev/null +++ b/2019/tests/test_solutions.cpp @@ -0,0 +1,110 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "implementations.hpp" + +class SolutionsTest : public testing::TestWithParam { +public: + static std::string nameInstantiatedTest(const testing::TestParamInfo ¶mInfo); + +protected: + std::string input_data = ""; + std::string output_data = ""; + aoc2019::solution_t implementation = nullptr; + + // Read input data + void SetUp() override; + +private: + static void readToString(const std::string &name, std::string &target); + + static std::tuple parseInputName(const std::string &name); +}; + +void SolutionsTest::SetUp() { + const auto input_name = GetParam(); + const auto output_name = input_name.substr(0, input_name.length() - 3) + ".out"; + + int day; + bool part2; + std::tie(day, part2, std::ignore) = parseInputName(input_name); + implementation = aoc2019::get_implementation(day, part2); + + readToString(input_name, input_data); + readToString(output_name, output_data); +} + +void SolutionsTest::readToString(const std::string &name, std::string &target) { + std::ifstream source(name); + + target.assign(std::istreambuf_iterator(source), + std::istreambuf_iterator()); +} + +std::tuple SolutionsTest::parseInputName(const std::string &name) { + const char *base_name = name.c_str(); + if (const auto last_slash = name.rfind('/'); last_slash != std::string::npos) { + base_name += last_slash + 1; + } + int day, part; + auto res = std::from_chars(base_name, base_name + 2, day); + assert(res.ec == std::errc()); + res = std::from_chars(base_name + 3, base_name + 4, part); + assert(res.ec == std::errc()); + + return {day, part == 2, std::string(base_name + 5, (const char*) std::strchr(base_name, '.'))}; +} + +std::string SolutionsTest::nameInstantiatedTest(const testing::TestParamInfo ¶mInfo) { + int day; + bool part2; + std::string sampleName; + + std::tie(day, part2, sampleName) = parseInputName(paramInfo.param); + + std::stringstream nameBuilder; + + nameBuilder << "Day" << day << "Part" << (part2 ? 2 : 1) << "Sample"; + + std::copy_if(sampleName.cbegin(), sampleName.cend(), std::ostream_iterator(nameBuilder), [](char c) { + return std::isalnum(c); + }); + + return nameBuilder.str(); +} + +TEST_P(SolutionsTest, TestExpectedOutcome) { + std::stringstream input_buffer, output_buffer; + + // Sanity check, don't call null implementation + ASSERT_NE(implementation, nullptr); + + input_buffer.str(input_data); + + implementation(input_buffer, output_buffer); + + ASSERT_EQ(output_data, output_buffer.str()); +} + +static std::vector get_samples() { + std::vector samples; + for (const auto &entry : std::filesystem::directory_iterator(TEST_SAMPLES_DIR)) { + if (entry.path().filename().extension() == ".in") { + samples.push_back(entry.path().string()); + } + } + + // Ensure a consistent order. + std::sort(samples.begin(), samples.end()); + + return samples; +} + +INSTANTIATE_TEST_CASE_P(DaysTest, SolutionsTest, + testing::ValuesIn(get_samples()), + SolutionsTest::nameInstantiatedTest); diff --git a/README.md b/README.md index 01b3570..f469c8c 100644 --- a/README.md +++ b/README.md @@ -8,3 +8,4 @@ This repository contains my solutions for Advent of Code. See: - [2016 edition](./2016) - [2017 edition](./2017) - [2018 edition](./2018) +- [2019 edition](./2019)