diff --git a/.github/workflows/2023.yml b/.github/workflows/2023.yml new file mode 100644 index 0000000..e69de29 diff --git a/2023/.gitignore b/2023/.gitignore new file mode 100644 index 0000000..8f3791e --- /dev/null +++ b/2023/.gitignore @@ -0,0 +1,2 @@ +build/** +.cache/** \ No newline at end of file diff --git a/2023/CMakeLists.txt b/2023/CMakeLists.txt new file mode 100644 index 0000000..a26fe39 --- /dev/null +++ b/2023/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.5) + +set(CMAKE_CXX_FLAGS "-Wall -Werror -Wextra -Wpedantic -Wconversion") +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED TRUE) + +project(synacor_challenge LANGUAGES CXX) +set(CMAKE_EXPORT_COMPILE_COMMANDS 1) + +if(ENABLE_SANITIZER) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fsanitize=undefined") +endif() + +message("Compiling with: ${CMAKE_CXX_FLAGS}") + +add_subdirectory(external_libraries) +add_subdirectory(solvelib) +add_subdirectory(xmaslib) +add_subdirectory(cmd) +add_subdirectory(test) + diff --git a/2023/README.md b/2023/README.md new file mode 100644 index 0000000..ac17710 --- /dev/null +++ b/2023/README.md @@ -0,0 +1,7 @@ +# 2023 + +## How to build +I don't know yet + +## How to run +I don't know yet \ No newline at end of file diff --git a/2023/cmd/CMakeLists.txt b/2023/cmd/CMakeLists.txt new file mode 100644 index 0000000..6f610b2 --- /dev/null +++ b/2023/cmd/CMakeLists.txt @@ -0,0 +1,4 @@ +add_executable(aoc2023 main.cpp cmd.cpp) +set_target_properties(aoc2023 PROPERTIES LINKER_LANGUAGE CXX) +target_include_directories(aoc2023 INTERFACE ..) +target_link_libraries(aoc2023 PUBLIC solvelib xmaslib) \ No newline at end of file diff --git a/2023/cmd/cmd.cpp b/2023/cmd/cmd.cpp new file mode 100644 index 0000000..0b84374 --- /dev/null +++ b/2023/cmd/cmd.cpp @@ -0,0 +1,122 @@ +#include "cmd.hpp" +#include "solvelib/alldays.hpp" +#include "xmaslib/registry/registry.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +template +constexpr void log_error(std::format_string msg, Args &&...args) { + std::cerr << "\x1b[31mERROR \x1b[0m " + << std::format(msg, std::forward(args)...) << std::endl; +} + +template +constexpr void log_warning(std::format_string msg, Args &&...args) { + std::cerr << "\x1b[33mWARNING\x1b[0m " + << std::format(msg, std::forward(args)...) << std::endl; +} + +constexpr int exit_success = EXIT_SUCCESS; +constexpr int exit_bad_args = 2; +constexpr int exit_error = 1; + +int run(std::vector &args) { + if (args.size() == 0) { + usage(std::cerr); + return exit_bad_args; + } + + if (args.size() == 1 && (args[0] == "-h" || args[0] == "--help")) { + usage(std::cout); + return exit_success; + } + + try { + populate_registry(); + } catch (std::runtime_error &e) { + log_error("could not populate the registry fully: {}", e.what()); + } + const auto &solutions = xmas::registered_solutions(); + + // Run all solutions + if (args.size() == 1 && (args[0] == "-a" || args[0] == "--all")) { + std::for_each(solutions.begin(), solutions.end(), solve_day); + return exit_success; + } + + if(args[0].starts_with("-")) { + log_error("Unknown argument {}. Use --help to see possible inputs.", args[0]); + return exit_bad_args; + } + + // Parse days requested + std::vector>::const_iterator> + days; + days.reserve(args.size()); + for (auto &arg : args) { + if (arg.starts_with("-")) { + log_error("invalid mixed argument types, use --help to see valid inputs"); + return exit_bad_args; + } + + const int day = std::atoi(arg.data()); + if (day == 0) { + log_warning("{} is not a vaid day", day); + continue; + } + + auto it = solutions.find(day); + if (it == solutions.end()) { + log_warning("no solution registered for day {}", day); + continue; + } + + days.push_back(it); + } + + // No critical error: execute + const auto results = days | std::ranges::views::transform( + [](auto it) { return solve_day(*it); }); + const bool all_successful = + std::reduce(results.begin(), results.end(), true, std::logical_and{}); + + if (!all_successful) { + return exit_error; + } + + return exit_success; +} + +void usage(std::ostream &s) { + s << "Usage:\n\n" + << "aoc2023 -h\n" + << "aoc2023 --help\n" + << " Prints this message and exits\n\n" + << "aoc2023 DAYS...\n" + << " Runs the solution for the specified days\n\n" + << "aoc2023 -a\n" + << "aoc2023 --all\n" + << " Runs all solutions\n\n"; +} + +bool solve_day( + std::map>::value_type const + &solution) { + try { + solution.second.get()->run(); + return true; + } catch (std::runtime_error &e) { + log_error("day {} returned error: {}\n", solution.second.get()->day(), + e.what()); + return false; + } +} diff --git a/2023/cmd/cmd.hpp b/2023/cmd/cmd.hpp new file mode 100644 index 0000000..b7b5007 --- /dev/null +++ b/2023/cmd/cmd.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include +#include +#include +#include + +#include "xmaslib/solvebase/solvebase.hpp" + + +int run(std::vector &args); + +void usage(std::ostream &s); + +bool solve_day( + std::map>::value_type const + &solution); \ No newline at end of file diff --git a/2023/cmd/main.cpp b/2023/cmd/main.cpp new file mode 100644 index 0000000..990b08a --- /dev/null +++ b/2023/cmd/main.cpp @@ -0,0 +1,18 @@ +// #include "xmaslib/solvebase/solvebase.hpp" +#include "cmd.hpp" + +#include +#include +#include + + + +int main(int argc, char **argv) { + std::vector args; + args.reserve(static_cast(argc)); + for (auto i = 1; i < argc; ++i) { + args.emplace_back(argv[i]); + } + + return run(args); +} diff --git a/2023/compile_commands.json b/2023/compile_commands.json new file mode 100644 index 0000000..d603855 --- /dev/null +++ b/2023/compile_commands.json @@ -0,0 +1,38 @@ +[ +{ + "directory": "/home/edu/AdventOfCode/2023/build/Release/_deps/doctest-build", + "command": "/usr/bin/c++ -DDOCTEST_CONFIG_IMPLEMENT_WITH_MAIN -DENABLE_DOCTEST_IN_LIBRARY -I/home/edu/AdventOfCode/2023/build/Release/_deps/doctest-src -Wall -Werror -Wextra -Wpedantic -Wconversion -O3 -DNDEBUG -std=gnu++11 -o CMakeFiles/doctest_with_main.dir/doctest/parts/doctest.cpp.o -c /home/edu/AdventOfCode/2023/build/Release/_deps/doctest-src/doctest/parts/doctest.cpp", + "file": "/home/edu/AdventOfCode/2023/build/Release/_deps/doctest-src/doctest/parts/doctest.cpp", + "output": "_deps/doctest-build/CMakeFiles/doctest_with_main.dir/doctest/parts/doctest.cpp.o" +}, +{ + "directory": "/home/edu/AdventOfCode/2023/build/Release/solvelib", + "command": "/usr/bin/c++ -I/home/edu/AdventOfCode/2023/xmaslib/.. -I/home/edu/AdventOfCode/2023/build/Release/_deps/doctest-src -Wall -Werror -Wextra -Wpedantic -Wconversion -O3 -DNDEBUG -std=gnu++20 -o CMakeFiles/solvelib.dir/01/day01.cpp.o -c /home/edu/AdventOfCode/2023/solvelib/01/day01.cpp", + "file": "/home/edu/AdventOfCode/2023/solvelib/01/day01.cpp", + "output": "solvelib/CMakeFiles/solvelib.dir/01/day01.cpp.o" +}, +{ + "directory": "/home/edu/AdventOfCode/2023/build/Release/xmaslib", + "command": "/usr/bin/c++ -Wall -Werror -Wextra -Wpedantic -Wconversion -O3 -DNDEBUG -std=gnu++20 -o CMakeFiles/xmaslib.dir/registry/registry.cpp.o -c /home/edu/AdventOfCode/2023/xmaslib/registry/registry.cpp", + "file": "/home/edu/AdventOfCode/2023/xmaslib/registry/registry.cpp", + "output": "xmaslib/CMakeFiles/xmaslib.dir/registry/registry.cpp.o" +}, +{ + "directory": "/home/edu/AdventOfCode/2023/build/Release/cmd", + "command": "/usr/bin/c++ -I/home/edu/AdventOfCode/2023/solvelib/.. -I/home/edu/AdventOfCode/2023/xmaslib/.. -I/home/edu/AdventOfCode/2023/build/Release/_deps/doctest-src -Wall -Werror -Wextra -Wpedantic -Wconversion -O3 -DNDEBUG -std=gnu++20 -o CMakeFiles/aoc2023.dir/main.cpp.o -c /home/edu/AdventOfCode/2023/cmd/main.cpp", + "file": "/home/edu/AdventOfCode/2023/cmd/main.cpp", + "output": "cmd/CMakeFiles/aoc2023.dir/main.cpp.o" +}, +{ + "directory": "/home/edu/AdventOfCode/2023/build/Release/cmd", + "command": "/usr/bin/c++ -I/home/edu/AdventOfCode/2023/solvelib/.. -I/home/edu/AdventOfCode/2023/xmaslib/.. -I/home/edu/AdventOfCode/2023/build/Release/_deps/doctest-src -Wall -Werror -Wextra -Wpedantic -Wconversion -O3 -DNDEBUG -std=gnu++20 -o CMakeFiles/aoc2023.dir/cmd.cpp.o -c /home/edu/AdventOfCode/2023/cmd/cmd.cpp", + "file": "/home/edu/AdventOfCode/2023/cmd/cmd.cpp", + "output": "cmd/CMakeFiles/aoc2023.dir/cmd.cpp.o" +}, +{ + "directory": "/home/edu/AdventOfCode/2023/build/Release/test", + "command": "/usr/bin/c++ -I/home/edu/AdventOfCode/2023/build/Release/_deps/doctest-src -I/home/edu/AdventOfCode/2023/solvelib/.. -I/home/edu/AdventOfCode/2023/xmaslib/.. -Wall -Werror -Wextra -Wpedantic -Wconversion -O3 -DNDEBUG -std=gnu++20 -o CMakeFiles/test.dir/test.cpp.o -c /home/edu/AdventOfCode/2023/test/test.cpp", + "file": "/home/edu/AdventOfCode/2023/test/test.cpp", + "output": "test/CMakeFiles/test.dir/test.cpp.o" +} +] \ No newline at end of file diff --git a/2023/dependencies b/2023/dependencies new file mode 100755 index 0000000..24ab0e8 --- /dev/null +++ b/2023/dependencies @@ -0,0 +1,9 @@ +#!/bin/bash +set -eu + +export DEBIAN_NONINTERACTIVE=1 + +SUDO=$(which sudo) || true + +$SUDO apt update -y +$SUDO apt install -y cmake g++-13 gcc-13 \ No newline at end of file diff --git a/2023/external_libraries/CMakeLists.txt b/2023/external_libraries/CMakeLists.txt new file mode 100644 index 0000000..c99b085 --- /dev/null +++ b/2023/external_libraries/CMakeLists.txt @@ -0,0 +1,5 @@ +option(ENABLE_DOCTESTS "Include tests in the library. Setting this to OFF will remove all doctest related code. + Tests in tests/*.cpp will still be enabled." ON) + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/") +include(Doctest.cmake) \ No newline at end of file diff --git a/2023/external_libraries/CxxOpts.cmake b/2023/external_libraries/CxxOpts.cmake new file mode 100644 index 0000000..ac3380d --- /dev/null +++ b/2023/external_libraries/CxxOpts.cmake @@ -0,0 +1,9 @@ +include(FetchContent) +FetchContent_Declare( + CxxOpts + GIT_REPOSITORY "https://github.com/jarro2783/cxxopts" + GIT_TAG "v3.1.1" +) + +FetchContent_MakeAvailable(CxxOpts) +include_directories(${CXXOPTS_INCLUDE_DIR}) \ No newline at end of file diff --git a/2023/external_libraries/Doctest.cmake b/2023/external_libraries/Doctest.cmake new file mode 100644 index 0000000..0c63e29 --- /dev/null +++ b/2023/external_libraries/Doctest.cmake @@ -0,0 +1,12 @@ +if(ENABLE_DOCTESTS) + add_definitions(-DENABLE_DOCTEST_IN_LIBRARY) + include(FetchContent) + FetchContent_Declare( + DocTest + GIT_REPOSITORY "https://github.com/onqtam/doctest" + GIT_TAG "v2.4.11" + ) + + FetchContent_MakeAvailable(DocTest) + include_directories(${DOCTEST_INCLUDE_DIR}) +endif() \ No newline at end of file diff --git a/2023/make b/2023/make new file mode 100755 index 0000000..29d4cb9 --- /dev/null +++ b/2023/make @@ -0,0 +1,33 @@ +#!/bin/bash +set -eu + +export PROJECT_DIR=$(pwd) + +export BUILD_TYPE="${BUILD_TYPE:-Release}" +export ENABLE_SANITIZER="${ENABLE_SANITIZER:-""}" +export BUILD_TESTS="${BUILD_TESTS:-""}" + +export C="${C:-"gcc-13"}" +export CXX="${CXX:-"g++-13"}" + +echo "Build type: ${BUILD_TYPE}" +echo + +export BUILD_DIR="${PROJECT_DIR}/build/" +export SOURCE_DIR="${PROJECT_DIR}" + +mkdir -p "${BUILD_DIR}" +cd "${BUILD_DIR}" + +mkdir -p "${BUILD_TYPE}" +cd "${BUILD_TYPE}" + +cmake "${SOURCE_DIR}" \ + -DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \ + -DENABLE_SANITIZER="${ENABLE_SANITIZER}" \ + -DBUILD_TESTS="${BUILD_TESTS}" + +cmake --build . -- -j $(nproc) + +cd "${PROJECT_DIR}" +mv "${BUILD_DIR}/${BUILD_TYPE}/compile_commands.json" . \ No newline at end of file diff --git a/2023/solvelib/01/day01.cpp b/2023/solvelib/01/day01.cpp new file mode 100644 index 0000000..206aa81 --- /dev/null +++ b/2023/solvelib/01/day01.cpp @@ -0,0 +1,5 @@ +#include "day01.hpp" + +std::int64_t Day01::part1() { return 1; } + +std::int64_t Day01::part2() { return 2; } diff --git a/2023/solvelib/01/day01.hpp b/2023/solvelib/01/day01.hpp new file mode 100644 index 0000000..b70ba2a --- /dev/null +++ b/2023/solvelib/01/day01.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include "xmaslib/solvebase/solvebase.hpp" + +class Day01 : public xmas::solution { +public: + int day() override { return 1; } + +public: + std::int64_t part1() override; + std::int64_t part2() override; +}; diff --git a/2023/solvelib/01/day01_test.hpp b/2023/solvelib/01/day01_test.hpp new file mode 100644 index 0000000..a5d96fb --- /dev/null +++ b/2023/solvelib/01/day01_test.hpp @@ -0,0 +1,10 @@ +#include "day01.hpp" +#include + +TEST_CASE("Day 1") { + Day01 solution{}; + + REQUIRE_EQ(solution.day(), 1); + REQUIRE_EQ(solution.part1(), 1); + REQUIRE_EQ(solution.part2(), 2); +} \ No newline at end of file diff --git a/2023/solvelib/CMakeLists.txt b/2023/solvelib/CMakeLists.txt new file mode 100644 index 0000000..4957309 --- /dev/null +++ b/2023/solvelib/CMakeLists.txt @@ -0,0 +1,14 @@ +add_library(solvelib + alldays.hpp + 01/day01.hpp 01/day01.cpp 01/day01_test.hpp +) + +set_target_properties(solvelib PROPERTIES LINKER_LANGUAGE CXX) +target_include_directories(solvelib INTERFACE ..) + +target_link_libraries(solvelib PUBLIC xmaslib) + +if (BUILD_TESTS) + set(ENABLE_DOCTESTS 1) + target_link_libraries(solvelib PUBLIC doctest) +endif() \ No newline at end of file diff --git a/2023/solvelib/alldays.hpp b/2023/solvelib/alldays.hpp new file mode 100644 index 0000000..3e164e3 --- /dev/null +++ b/2023/solvelib/alldays.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "xmaslib/registry/registry.hpp" + +#include "01/day01.hpp" + +inline void populate_registry() { + xmas::register_solution<1, Day01>(); +} \ No newline at end of file diff --git a/2023/test/CMakeLists.txt b/2023/test/CMakeLists.txt new file mode 100644 index 0000000..f31734e --- /dev/null +++ b/2023/test/CMakeLists.txt @@ -0,0 +1,10 @@ +if (BUILD_TESTS) + set(ENABLE_DOCTESTS 1) + + add_executable(test test.cpp) + + set_target_properties(test PROPERTIES LINKER_LANGUAGE CXX) + target_include_directories(test INTERFACE ..) + + target_link_libraries(test PUBLIC doctest solvelib xmaslib) +endif() \ No newline at end of file diff --git a/2023/test/test.cpp b/2023/test/test.cpp new file mode 100644 index 0000000..db597b6 --- /dev/null +++ b/2023/test/test.cpp @@ -0,0 +1,4 @@ +#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN + +#include +#include "solvelib/01/day01_test.hpp" diff --git a/2023/xmaslib/CMakeLists.txt b/2023/xmaslib/CMakeLists.txt new file mode 100644 index 0000000..516c7f2 --- /dev/null +++ b/2023/xmaslib/CMakeLists.txt @@ -0,0 +1,7 @@ +add_library(xmaslib + solvebase/solvebase.hpp + registry/registry.hpp registry/registry.cpp +) + +set_target_properties(xmaslib PROPERTIES LINKER_LANGUAGE CXX) +target_include_directories(xmaslib INTERFACE ..) diff --git a/2023/xmaslib/registry/registry.cpp b/2023/xmaslib/registry/registry.cpp new file mode 100644 index 0000000..d6392df --- /dev/null +++ b/2023/xmaslib/registry/registry.cpp @@ -0,0 +1,19 @@ +#include "registry.hpp" + +namespace xmas { + +std::map> solutions{}; + +std::map> const ®istered_solutions() noexcept { + return solutions; +} + +namespace internal { + +std::map> ®istered_solutions() noexcept { + return solutions; +} + +} // namespace internal + +} // namespace xmas \ No newline at end of file diff --git a/2023/xmaslib/registry/registry.hpp b/2023/xmaslib/registry/registry.hpp new file mode 100644 index 0000000..f97d582 --- /dev/null +++ b/2023/xmaslib/registry/registry.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include +#include +#include +#include + +#include "../solvebase/solvebase.hpp" + +namespace xmas { + +std::map> const ®istered_solutions() noexcept; + +namespace internal { +std::map> ®istered_solutions() noexcept; +} + +template T> void register_solution() { + auto &m = internal::registered_solutions(); + + if (auto x = m.find(V); x != m.begin()) { + throw std::runtime_error(std::format( + "Attempting the overwrite registered solution for day {}", V)); + } + + m[V] = std::unique_ptr(new T()); +} + +} // namespace xmas \ No newline at end of file diff --git a/2023/xmaslib/solvebase/solvebase.hpp b/2023/xmaslib/solvebase/solvebase.hpp new file mode 100644 index 0000000..ea5873b --- /dev/null +++ b/2023/xmaslib/solvebase/solvebase.hpp @@ -0,0 +1,40 @@ +#pragma once + +#include +#include +#include +#include + +namespace xmas { + +class solution { +public: + virtual int day() = 0; + + virtual void run() { + std::cout << "Day 1" << std::endl; + try { + const auto p1 =this->part1(); + std::cout << " Result 1: " << p1 << '\n'; + } catch (std::runtime_error &err) { + std::cerr << "Part 1 failed with message: " << err.what() << std::endl; + } + + try { + const auto p2 = this->part2(); + std::cout << " Result 2: " << p2 << '\n'; + } catch (std::runtime_error &err) { + std::cerr << "Part 2 failed with message: " << err.what() << std::endl; + } + } + +protected: + virtual std::int64_t part1() { throw std::runtime_error("not implemented"); } + virtual std::int64_t part2() { throw std::runtime_error("not implemented"); } + +private: + std::optional p1; + std::optional p2; +}; + +} // namespace xmas \ No newline at end of file