mirror of
https://github.com/bertptrs/adventofcode.git
synced 2025-12-26 05:10:32 +01:00
136 lines
4.6 KiB
C++
136 lines
4.6 KiB
C++
#include "implementations.hpp"
|
|
#include <charconv>
|
|
#include <chrono>
|
|
#include <iostream>
|
|
#include <string_view>
|
|
#include <optional>
|
|
#include <fstream>
|
|
|
|
struct AoCOptions {
|
|
aoc2019::solution_t implementation;
|
|
bool run_timer;
|
|
std::optional<std::ifstream> input_file;
|
|
};
|
|
|
|
static AoCOptions parse_options(const int argc, const char* argv[]) {
|
|
using namespace std::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--input ARG|-fARG: use given input file as puzzle input"
|
|
<< "\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 (int j = 1; j < arg.size(); ++j) {
|
|
switch (arg[j]) {
|
|
case '2':
|
|
part2 = true;
|
|
break;
|
|
|
|
case 't':
|
|
options.run_timer = true;
|
|
break;
|
|
|
|
case 'h':
|
|
show_help();
|
|
break;
|
|
|
|
case 'f':
|
|
if (j == arg.size() - 1) {
|
|
if (i == argc - 1) {
|
|
std::cerr << "Option -f requires an argument.";
|
|
show_help(1);
|
|
} else {
|
|
options.input_file = std::ifstream(argv[i + 1]);
|
|
++i;
|
|
}
|
|
} else {
|
|
options.input_file = std::ifstream(std::string(arg.substr(j)));
|
|
j = arg.size();
|
|
}
|
|
break;
|
|
|
|
default:
|
|
std::cerr << "Unknown flag '" << arg[j] << "'.\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 if (arg == "--input"sv) {
|
|
if (i == argc - 1) {
|
|
std::cerr << "Option -f requires an argument.";
|
|
show_help(1);
|
|
} else {
|
|
options.input_file = std::ifstream(argv[i + 1]);
|
|
++i;
|
|
}
|
|
} 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[]) {
|
|
auto options = parse_options(argc, argv);
|
|
|
|
if (options.implementation != nullptr) {
|
|
const auto start = std::chrono::high_resolution_clock::now();
|
|
options.implementation(options.input_file ? *options.input_file : std::cin, std::cout);
|
|
if (options.run_timer) {
|
|
const std::chrono::duration<double> 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;
|
|
}
|
|
}
|