#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct ColumnData { std::vector numbers; char op; }; struct Diagram { std::vector data; size_t width; size_t height; using GridView = std::mdspan>; auto grid() { return GridView(data.data(), height, width); } }; auto printDiagram(Diagram &diagram) { auto grid = diagram.grid(); for (auto row = 0UZ; row != grid.extent(0); row++) { for (auto col = 0UZ; col != grid.extent(1); col++) { std::print("{}", grid[row, col]); } std::println(); } // std::println("Map: {}", diagram.data); std::println("Width: {}", diagram.width); std::println("Height: {}", diagram.height); } template auto parseLine(std::string_view line) -> std::vector { auto to_value = [](auto &&subrange) -> T { auto str = std::string_view(subrange); T value{}; if constexpr (std::is_same_v) { return str[0]; } else { std::from_chars(str.data(), str.data() + str.size(), value); return value; } }; return line | std::views::split(' ') | std::views::filter([](auto &&range) -> bool { return !range.empty(); }) | std::views::transform(to_value) | std::ranges::to>(); } static auto parseInput(const std::string &filename) -> std::expected, std::string> { std::ifstream inputF{filename}; if (!inputF) { return std::unexpected{"Some file open error."}; } std::vector puzzleInput{}; std::vector rawLines; std::string puzzleLine; while (std::getline(inputF, puzzleLine)) { if (!puzzleLine.empty()) { rawLines.push_back(std::move(puzzleLine)); } } if (rawLines.empty()) { return std::unexpected{"No lines."}; } auto operatorLine = rawLines.back(); auto num_lines = rawLines | std::views::take(rawLines.size() - 1); std::vector ops = parseLine(operatorLine); auto grid = num_lines | std::views::transform([](const std::string &string) -> std::vector { return parseLine(string); }) | std::ranges::to>>(); size_t width = ops.size(); bool consistent = std::ranges::all_of(grid, [width](const auto &row) -> bool { return row.size() == width; }); if (!consistent) { return std::unexpected{"Error: Row width mismatch."}; } auto columns = std::views::iota(0UZ, width) | std::views::transform([&](size_t col_idx) -> ColumnData { // Collect numbers for this column from the grid auto col_nums = grid | std::views::transform([col_idx](const auto &row) { return row[col_idx]; }) | std::ranges::to>(); return ColumnData{.numbers = std::move(col_nums), .op = ops[col_idx]}; }) | std::ranges::to>(); std::cout << "Parsed " << columns.size() << " columns with " << grid.size() << " operands each:\n"; for (const auto &col : columns) { std::cout << "[ "; for (int n : col.numbers) { std::cout << n << " "; } std::cout << "] Op: " << col.op << "\n"; } return std::move(columns); } static auto parseInput_p2(const std::string &filename) -> std::expected { std::ifstream inputF{filename}; if (!inputF) { return std::unexpected{"Some file open error."}; } Diagram puzzleInput{}; int maxWidth = 0; std::string puzzleLine; while (std::getline(inputF, puzzleLine)) { if (!puzzleLine.empty()) { std::ranges::reverse(puzzleLine); for (auto c : puzzleLine) { puzzleInput.data.emplace_back(c); } puzzleInput.width = puzzleLine.length(); puzzleInput.height++; } } std::println("{}", puzzleInput.data); printDiagram(puzzleInput); return puzzleInput; } auto calculate_column(const ColumnData &col) -> long long { if (col.op == '+') { return std::ranges::fold_left(col.numbers, 0LL, std::plus()); } if (col.op == '*') { return std::ranges::fold_left(col.numbers, 1LL, std::multiplies()); } return 0; // Fallback } auto cephalopodMath(const std::vector &columns) -> long long { long long grand_total = std::ranges::fold_left(columns | std::views::transform(calculate_column), 0LL, std::plus{}); return grand_total; } auto cephalopodMath_p2(Diagram &diagram) -> long long { long long grandTotal{}; long long currentNumber = 0; std::vector columnNumbers{}; auto grid = diagram.grid(); for (auto col = 0UZ; col != grid.extent(1); col++) { for (auto row = 0UZ; row != grid.extent(0); row++) { char cur = grid[row, col]; if (cur == ' ' && currentNumber == 0) { // std::print("s"); continue; } else if (cur == ' ') { columnNumbers.emplace_back(currentNumber); currentNumber = 0; std::print("_"); continue; } else if (cur == '*') { if (currentNumber != 0) { columnNumbers.emplace_back(currentNumber); } std::print("*"); auto total = std::ranges::fold_left(columnNumbers, 1LL, std::multiplies()); grandTotal += total; std::print("\nMultiplying {}: Result: {}\n", columnNumbers, total); currentNumber = 0; columnNumbers.clear(); continue; } else if (cur == '+') { if (currentNumber != 0) { columnNumbers.emplace_back(currentNumber); } std::print("+"); auto total = std::ranges::fold_left(columnNumbers, 0LL, std::plus()); grandTotal += total; std::print("\nAdding {}: Result: {}\n", columnNumbers, total); currentNumber = 0; columnNumbers.clear(); continue; } // cur must be a digit... currentNumber = (currentNumber * 10) + (cur - '0'); std::print("{}", cur); } } return grandTotal; } auto main() -> int { // auto testCase = parseInput("test_input"); // if (testCase) { // auto testResult = cephalopodMath(*testCase); // std::println("P1 Testcase result: {}", testResult); // } else { // std::print("{}\n", testCase.error()); // } auto testCase_p2 = parseInput_p2("test_input"); if (testCase_p2) { auto testResult_p2 = cephalopodMath_p2(*testCase_p2); std::println("P2 Testcase result: {}", testResult_p2); } else { std::print("{}\n", testCase_p2.error()); } auto realPuzzle = parseInput_p2("puzzle_input"); if (realPuzzle) { // auto realResult = cephalopodMath(*realPuzzle); // std::println("P1 Real result: {}", realResult); auto realResultP2 = cephalopodMath_p2(*realPuzzle); std::println("P2 Real result: {}", realResultP2); } else { std::print("{}\n", realPuzzle.error()); } return 0; }