aoc25/day6/main.cpp
2025-12-06 23:01:27 +00:00

244 lines
7.7 KiB
C++

#include <algorithm>
#include <array>
#include <charconv>
#include <cstddef>
#include <expected>
#include <format>
#include <fstream>
#include <functional>
#include <iostream>
#include <iterator>
#include <list>
#include <map>
#include <mdspan>
#include <numeric>
#include <print>
#include <ranges>
#include <set>
#include <sstream>
#include <string>
#include <string_view>
#include <unordered_set>
#include <utility>
#include <vector>
struct ColumnData {
std::vector<int> numbers;
char op;
};
struct Diagram {
std::vector<char> data;
size_t width;
size_t height;
using GridView = std::mdspan<char, std::dextents<size_t, 2>>;
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 <typename T> auto parseLine(std::string_view line) -> std::vector<T> {
auto to_value = [](auto &&subrange) -> T {
auto str = std::string_view(subrange);
T value{};
if constexpr (std::is_same_v<T, char>) {
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<std::vector<T>>();
}
static auto parseInput(const std::string &filename) -> std::expected<std::vector<ColumnData>, std::string> {
std::ifstream inputF{filename};
if (!inputF) {
return std::unexpected{"Some file open error."};
}
std::vector<ColumnData> puzzleInput{};
std::vector<std::string> 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<char> ops = parseLine<char>(operatorLine);
auto grid =
num_lines |
std::views::transform([](const std::string &string) -> std::vector<int> { return parseLine<int>(string); }) |
std::ranges::to<std::vector<std::vector<int>>>();
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<std::vector<int>>();
return ColumnData{.numbers = std::move(col_nums), .op = ops[col_idx]};
}) |
std::ranges::to<std::vector<ColumnData>>();
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<Diagram, std::string> {
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<ColumnData> &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<long long> 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;
}