From 9e681141696b41e703bdd538ad15e79bc6a6efd2 Mon Sep 17 00:00:00 2001 From: mnerv <24420859+mnerv@users.noreply.github.com> Date: Tue, 3 Dec 2024 20:56:46 +0100 Subject: [PATCH] aoc24: day03a complete --- CMakeLists.txt | 18 +- sol/24/01/CMakeLists.txt | 15 -- sol/24/01/entry.cpp | 61 ------ sol/24/02/CMakeLists.txt | 15 -- sol/24/02/entry.cpp | 7 - sol/24/03/CMakeLists.txt | 15 -- sol/24/03/entry.cpp | 186 ------------------ sol/24/CMakeLists.txt | 3 - sol/24/day01.cpp | 0 sol/24/day02.cpp | 0 sol/24/day03.cpp | 405 +++++++++++++++++++++++++++++++++++++++ 11 files changed, 421 insertions(+), 304 deletions(-) delete mode 100644 sol/24/01/CMakeLists.txt delete mode 100644 sol/24/01/entry.cpp delete mode 100644 sol/24/02/CMakeLists.txt delete mode 100644 sol/24/02/entry.cpp delete mode 100644 sol/24/03/CMakeLists.txt delete mode 100644 sol/24/03/entry.cpp delete mode 100644 sol/24/CMakeLists.txt create mode 100644 sol/24/day01.cpp create mode 100644 sol/24/day02.cpp create mode 100644 sol/24/day03.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 69eef59..907ee41 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,7 +76,7 @@ if (NOT MSVC) # fmt warnings "-Wno-unknown-attributes" # ctre warning - "-Wno-missing-template-arg-list-after-template-kw" + # "-Wno-missing-template-arg-list-after-template-kw" ) else() set(BASE_OPTIONS @@ -115,4 +115,18 @@ target_link_libraries(aoc ) source_group(TREE "${CMAKE_CURRENT_LIST_DIR}" FILES ${HEADERS} ${SOURCES}) -add_subdirectory(sol/24) +set(HEADERS "") +set(SOURCES sol/24/day03.cpp) +add_executable(app ${HEADERS} ${SOURCES}) +target_include_directories(app PRIVATE ${PROJECT_SOURCE_DIR}) +target_compile_features(app PRIVATE cxx_std_23) +target_compile_options(app PRIVATE ${BASE_OPTIONS}) +target_compile_definitions(app PRIVATE ${BASE_DEFINITIONS}) +target_link_libraries(app + PRIVATE + aoc +) +set_target_properties(app PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" +) +source_group(TREE "${CMAKE_CURRENT_LIST_DIR}" FILES ${HEADERS} ${SOURCES}) diff --git a/sol/24/01/CMakeLists.txt b/sol/24/01/CMakeLists.txt deleted file mode 100644 index 7a845d9..0000000 --- a/sol/24/01/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -set(HEADERS "") -set(SOURCES entry.cpp) -add_executable(sol2401 ${HEADERS} ${SOURCES}) -target_include_directories(sol2401 PRIVATE ${PROJECT_SOURCE_DIR}) -target_compile_features(sol2401 PRIVATE cxx_std_23) -target_compile_options(sol2401 PRIVATE ${BASE_OPTIONS}) -target_compile_definitions(sol2401 PRIVATE ${BASE_DEFINITIONS}) -target_link_libraries(sol2401 - PRIVATE - aoc -) -set_target_properties(sol2401 PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" -) -source_group(TREE "${CMAKE_CURRENT_LIST_DIR}" FILES ${HEADERS} ${SOURCES}) diff --git a/sol/24/01/entry.cpp b/sol/24/01/entry.cpp deleted file mode 100644 index 9636242..0000000 --- a/sol/24/01/entry.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "aoc/aoc.hpp" -#include "fmt/format.h" - -// auto aoc::entry([[maybe_unused]]std::vector const& args) -> void { -// constexpr auto filename = "./dat/24/re/01.txt"; -// std::ifstream strm{filename, std::ios::in}; -// if (!strm.is_open()) { -// fmt::print("Error opening file: {}\n", filename); -// return 1; -// } -// -// std::vector a{}; -// std::vector b{}; -// -// std::string str{}; -// while (strm) { -// auto const c = char(strm.peek()); -// if (std::isdigit(c)) { -// str += char(strm.get()); -// continue; -// } -// if (c == ' ') { -// if (!str.empty()) { -// a.emplace_back(std::stoi(str)); -// str.clear(); -// } -// } -// if (c == '\n') { -// if (!str.empty()) { -// b.emplace_back(std::stoi(str)); -// str.clear(); -// } -// } -// [[discard]]strm.get(); -// } -// -// fmt::print("a: {}, b: {}\n", a.size(), b.size()); -// -// std::sort(std::begin(a), std::end(a)); -// std::sort(std::begin(b), std::end(b)); -// -// auto diff_view = std::views::zip(a, b) | std::views::transform([](auto const& p) { -// auto const [x, y] = p; -// return x > y ? x - y : y - x; -// }); -// auto const sum = std::accumulate(std::begin(diff_view), std::end(diff_view), 0); -// -// fmt::print("Part A: {}\n", std::abs(sum)); -// -// auto values = a | std::views::transform([&b](auto v) { -// return std::pair{v, b | std::views::filter([v](auto c) { -// return v == c; // Filter elements in `b` equal to `v` -// }) | std::ranges::to()}; -// }) | std::ranges::to(); -// -// auto const meow = std::accumulate(std::begin(values), std::end(values), 0, [](auto const acc, auto const& pair) { -// return acc + std::int32_t(pair.first * pair.second.size()); -// }); -// -// fmt::print("Part B: {}\n", meow); -// } diff --git a/sol/24/02/CMakeLists.txt b/sol/24/02/CMakeLists.txt deleted file mode 100644 index dc03b67..0000000 --- a/sol/24/02/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -set(HEADERS "") -set(SOURCES entry.cpp) -add_executable(sol2402 ${HEADERS} ${SOURCES}) -target_include_directories(sol2402 PRIVATE ${PROJECT_SOURCE_DIR}) -target_compile_features(sol2402 PRIVATE cxx_std_23) -target_compile_options(sol2402 PRIVATE ${BASE_OPTIONS}) -target_compile_definitions(sol2402 PRIVATE ${BASE_DEFINITIONS}) -target_link_libraries(sol2402 - PRIVATE - aoc -) -set_target_properties(sol2402 PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" -) -source_group(TREE "${CMAKE_CURRENT_LIST_DIR}" FILES ${HEADERS} ${SOURCES}) diff --git a/sol/24/02/entry.cpp b/sol/24/02/entry.cpp deleted file mode 100644 index 4cc1e53..0000000 --- a/sol/24/02/entry.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "aoc/aoc.hpp" -#include "fmt/format.h" - -auto aoc::entry([[maybe_unused]]std::vector const& args) -> void { - fmt::print("Hello, World!\n"); -} - diff --git a/sol/24/03/CMakeLists.txt b/sol/24/03/CMakeLists.txt deleted file mode 100644 index 78b6b5f..0000000 --- a/sol/24/03/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -set(HEADERS "") -set(SOURCES entry.cpp) -add_executable(sol2403 ${HEADERS} ${SOURCES}) -target_include_directories(sol2403 PRIVATE ${PROJECT_SOURCE_DIR}) -target_compile_features(sol2403 PRIVATE cxx_std_23) -target_compile_options(sol2403 PRIVATE ${BASE_OPTIONS}) -target_compile_definitions(sol2403 PRIVATE ${BASE_DEFINITIONS}) -target_link_libraries(sol2403 - PRIVATE - aoc -) -set_target_properties(sol2403 PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" -) -source_group(TREE "${CMAKE_CURRENT_LIST_DIR}" FILES ${HEADERS} ${SOURCES}) diff --git a/sol/24/03/entry.cpp b/sol/24/03/entry.cpp deleted file mode 100644 index 3f85a7f..0000000 --- a/sol/24/03/entry.cpp +++ /dev/null @@ -1,186 +0,0 @@ -#include -#include -#include - -#include "aoc/aoc.hpp" -#include "fmt/format.h" -#include "ctre.hpp" - -#define ENUMERATOR_AOC_TOKENS \ - ENUMERATOR_AOC_TOKEN(mul , operator_ ) \ - ENUMERATOR_AOC_TOKEN(invalid , invalid ) \ - ENUMERATOR_AOC_TOKEN(numeric_literal, number ) \ - ENUMERATOR_AOC_TOKEN(newline , punctuation) \ - ENUMERATOR_AOC_TOKEN(paren_open , punctuation) \ - ENUMERATOR_AOC_TOKEN(paren_close , punctuation) \ - ENUMERATOR_AOC_TOKEN(comma , punctuation) \ - ENUMERATOR_AOC_TOKEN(identifier , identifier ) - -enum class token_type : std::uint32_t { -#define ENUMERATOR_AOC_TOKEN(type, category) type, - ENUMERATOR_AOC_TOKENS -#undef ENUMERATOR_AOC_TOKEN - _count -}; - -enum class token_category : std::uint32_t { - operator_, - invalid, - number, - punctuation, - identifier, - _count -}; - -auto token_type_str(token_type type) -> char const* { - switch (type) { - using enum token_type; -#define ENUMERATOR_AOC_TOKEN(type, category) case type: return #type; - ENUMERATOR_AOC_TOKENS -#undef ENUMERATOR_AOC_TOKEN - default: return "invalid"; - } -} - -auto token_type_category(token_type type) -> token_category { - switch (type) { - using enum token_category; -#define ENUMERATOR_AOC_TOKEN(type, category) case token_type::type: return category; - ENUMERATOR_AOC_TOKENS -#undef ENUMERATOR_AOC_TOKEN - default: return token_category::invalid; - } -} - -class token { -public: - token(std::string const& str, token_type type, token_category category, std::size_t row, std::size_t col) - : m_type(type) - , m_category(category) - , m_value(str) - , m_row(row) - , m_column(col) { } - - auto type() const -> token_type { return m_type; } - auto category() const -> token_category { return m_category; } - auto value() const -> std::string const& { return m_value; } - - auto row() const -> std::size_t { return m_row; } - auto col() const -> std::size_t { return m_column; } - - auto str() const -> std::string { - using namespace std::string_literals; - std::string str{"token {"}; - str += " type: "s + token_type_str(m_type) + ","s; - str += " value: \""s + m_value + "\","s; - str += " row: "s + std::to_string(m_row) + ","s; - str += " col: "s + std::to_string(m_column); - str += " }"; - return str; - } - -public: - inline static auto is_identifier(std::string_view const& str) -> bool { - return ctre::match<"^[a-z]+$">(str); - } - -private: - token_type m_type; - token_category m_category; - std::string m_value; - std::size_t m_row; - std::size_t m_column; -}; - -enum class lexer_error { - eof, - unknown -}; - -class lexer { -public: - lexer(std::filesystem::path const& source) - : m_strm(source, std::ios::in | std::ios::binary) - , m_line(1), m_col(1) { - } - - auto tokenize() -> std::vector { - std::vector tokens{}; - auto tk = next_token(); - while (tk) { - tokens.emplace_back(std::move(tk.value())); - tk = next_token(); - } - return tokens; - } - -private: - auto next_token() -> std::optional { - if (!has_next()) return {}; - if (peek() == '\n') { - peek_consume(); - m_line = m_line + 1; - m_col = 0; - } - - std::string str{}; - if (peek() == 'm') { - auto const col = m_col; - auto const is_valid_identifier_char = [](auto const c) { - return c >= 'a' && c <= 'z'; - }; - while (is_valid_identifier_char(peek())) str += peek_consume(); - auto const& type = token::is_identifier(str) ? token_type::identifier : token_type::invalid; - return token(str, type, token_type_category(type), m_line, col); - } - - if (peek() == '(') { - auto const col = m_col; - str += peek_consume(); - return token(str, token_type::paren_open, token_type_category(token_type::paren_open), m_line, col); - } - - if (peek() == ')') { - auto const col = m_col; - str += peek_consume(); - return token(str, token_type::paren_close, token_type_category(token_type::paren_close), m_line, col); - } - - if (peek() == ',') { - auto const col = m_col; - str += peek_consume(); - return token(str, token_type::comma, token_type_category(token_type::comma), m_line, col); - } - - auto const col = m_col; - str += peek_consume(); - return token(str, token_type::invalid, token_type_category(token_type::invalid), m_line, col); - } - - auto peek() -> char { - return static_cast(m_strm.peek()); - } - auto peek_consume() -> char { - ++m_col; - return static_cast(m_strm.get()); - } - auto has_next() const -> bool { - return !m_strm.eof(); - } - -private: - std::fstream m_strm; - std::size_t m_line; - std::size_t m_col; -}; - -auto aoc::entry([[maybe_unused]]std::vector const& args) -> void { - lexer lexer{"./dat/24/ex/03.txt"}; - - auto const tokens = lexer.tokenize(); - - for (auto const& tk : tokens) { - fmt::print("{}\n", tk.str()); - } -} - diff --git a/sol/24/CMakeLists.txt b/sol/24/CMakeLists.txt deleted file mode 100644 index 9f95ab8..0000000 --- a/sol/24/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -# add_subdirectory(01) -# add_subdirectory(02) -add_subdirectory(03) diff --git a/sol/24/day01.cpp b/sol/24/day01.cpp new file mode 100644 index 0000000..e69de29 diff --git a/sol/24/day02.cpp b/sol/24/day02.cpp new file mode 100644 index 0000000..e69de29 diff --git a/sol/24/day03.cpp b/sol/24/day03.cpp new file mode 100644 index 0000000..7978a7e --- /dev/null +++ b/sol/24/day03.cpp @@ -0,0 +1,405 @@ +#include +#include +#include +#include +#include + +#include "aoc/aoc.hpp" +#include "fmt/format.h" +#include "ctre.hpp" + +namespace npr { +#define ENUMERATOR_AOC_TOKENS \ + ENUMERATOR_AOC_TOKEN(mul , operator_ ) \ + ENUMERATOR_AOC_TOKEN(invalid , invalid ) \ + ENUMERATOR_AOC_TOKEN(numeric_literal, number ) \ + ENUMERATOR_AOC_TOKEN(newline , punctuation) \ + ENUMERATOR_AOC_TOKEN(paren_open , punctuation) \ + ENUMERATOR_AOC_TOKEN(paren_close , punctuation) \ + ENUMERATOR_AOC_TOKEN(comma , punctuation) \ + ENUMERATOR_AOC_TOKEN(identifier , identifier ) + +#define ENUMERATOR_AOC_CATEGORIES \ + ENUMERATOR_AOC_CATEGORY(operator_) \ + ENUMERATOR_AOC_CATEGORY(invalid) \ + ENUMERATOR_AOC_CATEGORY(number) \ + ENUMERATOR_AOC_CATEGORY(punctuation) \ + ENUMERATOR_AOC_CATEGORY(identifier) + +#define ENUMERATOR_AOC_NODE_TYPES \ + ENUMERATOR_AOC_NODE_TYPE(numeric_literal) \ + ENUMERATOR_AOC_NODE_TYPE(call_expression) \ + ENUMERATOR_AOC_NODE_TYPE(binary_expression) + +enum class token_type : std::uint32_t { +#define ENUMERATOR_AOC_TOKEN(type, category) type, + ENUMERATOR_AOC_TOKENS +#undef ENUMERATOR_AOC_TOKEN + _count +}; + +enum class token_category : std::uint32_t { +#define ENUMERATOR_AOC_CATEGORY(type) type, + ENUMERATOR_AOC_CATEGORIES +#undef ENUMERATOR_AOC_CATEGORY + _count +}; + +enum class node_type : std::uint32_t { +#define ENUMERATOR_AOC_NODE_TYPE(type) type, + ENUMERATOR_AOC_NODE_TYPES +#undef ENUMERATOR_AOC_NODE_TYPE + _count +}; + +auto token_type_str(token_type type) -> char const* { + switch (type) { + using enum token_type; +#define ENUMERATOR_AOC_TOKEN(type, category) case type: return #type; + ENUMERATOR_AOC_TOKENS +#undef ENUMERATOR_AOC_TOKEN + default: return "invalid"; + } +} + +auto token_type_category(token_type type) -> token_category { + switch (type) { + using enum token_category; +#define ENUMERATOR_AOC_TOKEN(type, category) case token_type::type: return category; + ENUMERATOR_AOC_TOKENS +#undef ENUMERATOR_AOC_TOKEN + default: return token_category::invalid; + } +} + +auto node_type_str(node_type type) -> char const* { + switch (type) { + using enum node_type; +#define ENUMERATOR_AOC_NODE_TYPE(type) case type: return #type; + ENUMERATOR_AOC_NODE_TYPES +#undef ENUMERATOR_AOC_NODE_TYPE + default: return "invalid"; + } +} + +class token { +public: + token(std::string const& str, token_type type, token_category category, std::size_t row, std::size_t col) + : m_type(type) + , m_category(category) + , m_value(str) + , m_row(row) + , m_column(col) { } + + auto type() const -> token_type { return m_type; } + auto category() const -> token_category { return m_category; } + auto value() const -> std::string const& { return m_value; } + + auto row() const -> std::size_t { return m_row; } + auto col() const -> std::size_t { return m_column; } + + auto str() const -> std::string { + using namespace std::string_literals; + std::string str{"token {"}; + str += " value: \""s + m_value + "\","s; + str += " type: "s + token_type_str(m_type) + ","s; + str += " row: "s + std::to_string(m_row) + ","s; + str += " col: "s + std::to_string(m_column); + str += " }"; + return str; + } + +public: + inline static auto is_identifier(std::string_view const& str) -> bool { + return ctre::match<"^[a-z]+$">(str); + } + + inline static auto is_numeric_literal(std::string_view const& str) -> bool { + return ctre::match<"^[0-9]+$">(str); + } + +private: + token_type m_type; + token_category m_category; + std::string m_value; + std::size_t m_row; + std::size_t m_column; +}; + +enum class lexer_error { + eof, + unknown +}; + +class lexer { +public: + lexer(std::string const& source) + : m_strm(source, std::ios::in | std::ios::binary) + , m_line(1), m_col(1) { + } + + auto tokenize() -> std::vector { + std::vector tokens{}; + auto tk = next_token(); + while (tk) { + tokens.emplace_back(std::move(tk.value())); + tk = next_token(); + } + return tokens; + } + +private: + auto next_token() -> std::optional { + if (!has_next()) return {}; + std::string str{}; + auto const col = m_col; + + if (peek() == '\n') { + peek_consume(); + m_line = m_line + 1; + m_col = 1; + str += "\\n"; + auto const& type = token_type::invalid; + return token(str, type, token_type_category(type), m_line, col); + } + + if (peek() == 'm') { + auto const is_valid_identifier_char = [](auto const c) { + return c >= 'a' && c <= 'z'; + }; + while (is_valid_identifier_char(peek())) str += peek_consume(); + auto const check_type = [](auto const str) { + if (!token::is_identifier(str)) return token_type::invalid; + if (str == "mul") return token_type::identifier; + return token_type::invalid; + }; + auto const& type = check_type(str); + return token(str, type, token_type_category(type), m_line, col); + } + + if (peek() == '(') { + str += peek_consume(); + return token{ + str, + token_type::paren_open, + token_type_category(token_type::paren_open), + m_line, + col + }; + } + + if (peek() == ')') { + str += peek_consume(); + return token{ + str, + token_type::paren_close, + token_type_category(token_type::paren_close), + m_line, + col + }; + } + + if (peek() == ',') { + str += peek_consume(); + return token{ + str, + token_type::comma, + token_type_category(token_type::comma), + m_line, + col + }; + } + + if (std::isdigit(peek())) { + while(std::isdigit(peek())) str += peek_consume(); + auto const& type = token::is_numeric_literal(str) ? token_type::numeric_literal : token_type::invalid; + return token(str, type, token_type_category(type), m_line, col); + } + + if (!has_next()) return {}; + + str += peek_consume(); + return token{ + str, + token_type::invalid, + token_type_category(token_type::invalid), + m_line, + col + }; + } + + auto peek() -> char { + return static_cast(m_strm.peek()); + } + auto peek_consume() -> char { + ++m_col; + return static_cast(m_strm.get()); + } + auto has_next() const -> bool { + return !m_strm.eof(); + } + +private: + std::fstream m_strm; + std::size_t m_line; + std::size_t m_col; +}; + +class node { +public: + node(node_type type, + token const& token, + std::vector const& nodes = {}) + : m_type(type) + , m_token(token) + , m_nodes(nodes) { } + + auto type() const -> node_type { return m_type; } + auto token() const -> npr::token const& { return m_token; } + auto nodes() const -> std::vector const& { return m_nodes; } + auto value() const -> std::string const& { return m_token.value(); } + + auto add_node(npr::node const& node) -> void { + m_nodes.push_back(node); + } + + auto str() const -> std::string { + using namespace std::string_literals; + std::string str{node_type_str(m_type) + " {"s}; + str += " value: "s + m_token.value(); + switch (m_type) { + case node_type::call_expression: + str += call_expression_str(); + break; + default: break; + } + str += " }"; + return str; + } + +private: + auto call_expression_str() const -> std::string { + using namespace std::string_literals; + std::string str{", ["}; + for (std::size_t i = 0; i < m_nodes.size(); ++i) { + str += " "s + std::to_string(i) + ": "s + m_nodes[i].str(); + if (i < m_nodes.size() - 1) str += ","; + } + str += " ]"; + return str; + } + +private: + node_type m_type; + npr::token m_token; + std::vector m_nodes; +}; + +class parser { +public: + parser() : m_cursor(0), m_tokens() { } + + auto parse(std::vector const& tokens) -> std::vector { + m_cursor = 0; + m_tokens = tokens; + + std::vector nodes{}; + do { + auto n = parse_statement(); + if (n.has_value()) nodes.push_back(n.value()); + } while(has_next()); + + return nodes; + } + +private: + auto parse_statement() -> std::optional { + auto const type = peek().type(); + + switch (type) { + case token_type::identifier: { + if (!has_next()) return {}; + auto next = peek_next(); + if (next.type() == token_type::paren_open) { + return parse_call_expression(); + } + } + default: + break; + } + + consume(); + return {}; + } + + auto parse_call_expression() -> std::optional { + auto const& token_callee = peek(); + node callee{node_type::call_expression, token_callee}; + consume(); + return parse_args(callee); + } + + auto parse_args(npr::node callee) -> std::optional { + if (peek().type() != token_type::paren_open) return {}; + consume(); + while (has_next()) { + auto const& arg_token = peek(); + if (arg_token.type() == token_type::numeric_literal) { + callee.add_node({node_type::numeric_literal, arg_token}); + consume(); + continue; + } + if (arg_token.type() == token_type::comma) { + consume(); + continue; + } + if (arg_token.type() == token_type::paren_close) { + consume(); + break; + } + return {}; + } + return callee; + } + +private: + auto peek() const -> token const& { + return m_tokens[m_cursor]; + } + + auto peek_next() const -> token const& { + return m_tokens[m_cursor + 1]; + } + + auto consume() -> void { + if (m_cursor >= m_tokens.size()) return; + ++m_cursor; + } + + auto has_next(std::size_t i = 0) const -> bool { + return m_cursor + i < m_tokens.size(); + } + +private: + std::size_t m_cursor; + std::vector m_tokens; +}; +} + +auto aoc::entry([[maybe_unused]]std::vector const& args) -> void { + npr::lexer lexer{"./dat/24/re/03.txt"}; + npr::parser parser{}; + auto const tokens = lexer.tokenize(); + auto const nodes = parser.parse(tokens); + + auto op = nodes | std::views::transform([](auto const& node) { + auto const a = std::stoi(node.nodes()[0].value()); + auto const b = std::stoi(node.nodes()[1].value()); + return a * b; + }); + + auto const sum = std::accumulate(std::begin(op), std::end(op), 0); + + fmt::print("Part A: {}\n", sum); +} +