diff --git a/day6/CMakeLists.txt b/day6/CMakeLists.txt new file mode 100644 index 0000000..ea6fa66 --- /dev/null +++ b/day6/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.10) + +# Project name and version +project(Day6 VERSION 1.0) + +# Set default build type +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Debug) +endif() + +# 1. This is the critical line for Clangd. +# It generates the file clangd reads to know where headers are. +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# Debug and Release flags +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g -O0 -Wall -Wextra") +set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3") + +# Specify C standard +set(CMAKE_CXX_STANDARD 23) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +# Add include directory +include_directories(${PROJECT_SOURCE_DIR}/include) + +# Add executable +add_executable(${PROJECT_NAME} + src/main.cpp +) diff --git a/day6/Makefile b/day6/Makefile new file mode 100644 index 0000000..d5e989b --- /dev/null +++ b/day6/Makefile @@ -0,0 +1,13 @@ + + +clear: + rm -rf build/* + +run: + cp input.txt build + cp input_test.txt build + cd build && cmake .. && make && ./Day6 input_test.txt + +release: + cp input.txt build + cd build && cmake .. -DCMAKE_BUILD_TYPE=Release && make && ./Day6 input.txt diff --git a/day6/flake.lock b/day6/flake.lock new file mode 100644 index 0000000..2b1bdda --- /dev/null +++ b/day6/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1756787288, + "narHash": "sha256-rw/PHa1cqiePdBxhF66V7R+WAP8WekQ0mCDG4CFqT8Y=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "d0fc30899600b9b3466ddb260fd83deb486c32f1", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/day6/flake.nix b/day6/flake.nix new file mode 100644 index 0000000..20aa75f --- /dev/null +++ b/day6/flake.nix @@ -0,0 +1,58 @@ +{ + description = "A Nix-flake-based C/C++ development environment"; + + inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + + outputs = + { self, nixpkgs }: + let + supportedSystems = [ + "x86_64-linux" + "aarch64-linux" + "x86_64-darwin" + "aarch64-darwin" + ]; + forEachSupportedSystem = + f: + nixpkgs.lib.genAttrs supportedSystems ( + system: + f { + pkgs = import nixpkgs { inherit system; }; + } + ); + in + { + devShells = forEachSupportedSystem ( + { pkgs }: + { + default = + pkgs.mkShell.override + { + # Override stdenv in order to change compiler: + # stdenv = pkgs.clangStdenv; + } + + { + nativeBuildInputs = with pkgs; [ + pkg-config + ]; + packages = + with pkgs; + [ + clang-tools + cmake + codespell + cppcheck + doxygen + gtest + lcov + nodejs + vscode-extensions.vadimcn.vscode-lldb + ] + ++ (if system == "aarch64-darwin" then [ ] else [ gdb ]); + CODELLDB_PATH = "${pkgs.vscode-extensions.vadimcn.vscode-lldb}/share/vscode/extensions/vadimcn.vscode-lldb/adapter/codelldb"; + }; + } + ); + }; +} diff --git a/day6/input_test.txt b/day6/input_test.txt new file mode 100644 index 0000000..337b837 --- /dev/null +++ b/day6/input_test.txt @@ -0,0 +1,4 @@ +123 328 51 64 + 45 64 387 23 + 6 98 215 314 +* + * + diff --git a/day6/src/main.cpp b/day6/src/main.cpp new file mode 100644 index 0000000..269444f --- /dev/null +++ b/day6/src/main.cpp @@ -0,0 +1,191 @@ +#include +#include +#include +#include +#include +#include + +std::vector find_operations_on_string(const std::string &line) { + std::vector results; + for (auto c : line) { + if (c != ' ' && c != '\n') { + results.emplace_back(c); + } + } + return results; +} + +std::string read_line_backwards(std::ifstream &file) { + std::string line; + char c; + do { + c = file.get(); + line.insert(line.begin(), c); + file.seekg(-2, file.cur); + } while (c != '\n' && (file.tellg() >= 0)); + return line; +} + +template +std::vector find_values_on_string(const std::string &line) { + std::vector results; + std::string token; + + for (auto c : line) { + if (c != ' ' && c != '\n') { + token.push_back(c); + } else if (!token.empty()) { + if constexpr (std::is_same_v) { + results.emplace_back(std::stoi(token)); + } else if constexpr (std::is_same_v) { + results.emplace_back(token); + } + token.clear(); + } + } + + if (!token.empty()) { + if constexpr (std::is_same_v) { + results.emplace_back(std::stoi(token)); + } else if constexpr (std::is_same_v) { + results.emplace_back(token); + } + } + + return results; +} + +u_int64_t do_operation(char op, u_int64_t n1, u_int64_t n2) { + switch (op) { + case '*': + return n1 * n2; + break; + case '+': + return n1 + n2; + break; + default: + std::cerr << "Unknown operation: " << op << std::endl; + return -1; + } +} + +u_int64_t do_part_1(std::ifstream &file, const std::vector &operations) { + std::string line; + std::vector results(operations.size(), 0); + while (file.tellg() >= 0) { + line = read_line_backwards(file); + auto ints = find_values_on_string(line); + if (ints.size() != operations.size()) { + std::cerr << "Error: number of operations and ints do not match!\n" + << "Operations: \n" + << operations.size() << ", Ints: " << ints.size() << std::endl; + return -1; + } + for (size_t i = 0; i < ints.size(); i++) { + if (results[i] == 0) { + results[i] = ints[i]; + } else { + results[i] = do_operation(operations[i], ints[i], results[i]); + } + } + } + + return std::accumulate(results.begin(), results.end(), 0ULL); +} + +int extract_ints_from_column(const std::vector> &parsed_lines, + int column) { + std::string num; + for (const auto &vec : parsed_lines) { + char c = vec[column]; + if (std::isdigit(c)) { + num += c; + } + } + if (!num.empty()) + return std::stoi(num); + return -1; +} + +u_int64_t do_part_2(std::ifstream &file, const std::vector &operations) { + std::vector results(operations.size(), 0); + std::string line; + std::vector> parsed_lines; + std::vector> nums; + + while (std::getline(file, line)) { + std::vector row; + for (char c : line) { + row.emplace_back(c); + } + parsed_lines.emplace_back(row); + } + + std::vector col; + for (size_t i = 0; i < parsed_lines[0].size(); i++) { + int num = extract_ints_from_column(parsed_lines, i); + if (num != -1) { + col.emplace_back(num); + } else { + nums.emplace_back(col); + col.clear(); + } + } + + if (!col.empty()) + nums.emplace_back(col); + + if (nums.size() != operations.size()) { + std::cerr << "Error: number of operations and nums do not match!\n" + << "Operations: \n" + << operations.size() << ", Nums: " << nums.size() << std::endl; + return -1; + } + for (int i = 0; i < operations.size(); i++) { + for (int j = 0; j < nums[i].size(); j++) { + if (results[i] == 0) { + results[i] = nums[i][j]; + } else { + results[i] = do_operation(operations[i], results[i], nums[i][j]); + } + } + } + + return std::accumulate(results.begin(), results.end(), 0ULL); +} + +std::tuple do_it(const std::string &path) { + std::ifstream file; + std::string line; + + file.open(path); + if (!file.is_open()) { + std::cerr << "Error opening file: " << path << std::endl; + return {-1, -1}; + } + + // go to end of the stream first, before the eof + file.seekg(-2, file.end); + line = read_line_backwards(file); + auto operations = find_operations_on_string(line); + std::vector results(operations.size(), 0); + u_int64_t part_1 = do_part_1(file, operations); + + file.clear(); + file.seekg(0, file.beg); + u_int64_t part_2 = do_part_2(file, operations); + + file.close(); + return {part_1, part_2}; +} + +int main(int argc, char *argv[]) { + if (argc < 2) { + std::cout << "One argument required: input txt" << std::endl; + } + auto res = do_it(argv[1]); + std::cout << "Part 1: " << std::get<0>(res) << std::endl; + std::cout << "Part 2: " << std::get<1>(res) << std::endl; + + return 0; +}