diff --git a/userspace/aoc2023/CMakeLists.txt b/userspace/aoc2023/CMakeLists.txt index f3ab04d2..8d97095c 100644 --- a/userspace/aoc2023/CMakeLists.txt +++ b/userspace/aoc2023/CMakeLists.txt @@ -4,6 +4,8 @@ project(aoc2023 CXX) set(AOC2023_PROJECTS day1 + day2 + day3 ) set(BANAN_AOC2023_BIN ${BANAN_BIN}/aoc2023) diff --git a/userspace/aoc2023/day3/CMakeLists.txt b/userspace/aoc2023/day3/CMakeLists.txt new file mode 100644 index 00000000..9ca68813 --- /dev/null +++ b/userspace/aoc2023/day3/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 3.26) + +project(aoc2023_day3 CXX) + +set(SOURCES + main.cpp +) + +add_executable(aoc2023_day3 ${SOURCES}) +target_compile_options(aoc2023_day3 PUBLIC -O2 -g) +target_link_libraries(aoc2023_day3 PUBLIC libc ban) + +add_dependencies(aoc2023_day3 libc-install ban-install) + +add_custom_target(aoc2023_day3-install + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/aoc2023_day3 ${BANAN_AOC2023_BIN}/day3 + DEPENDS aoc2023_day3 + DEPENDS aoc2023_always +) + +add_dependencies(aoc2023 aoc2023_day3) +add_dependencies(aoc2023-install aoc2023_day3-install) diff --git a/userspace/aoc2023/day3/main.cpp b/userspace/aoc2023/day3/main.cpp new file mode 100644 index 00000000..7e96bc52 --- /dev/null +++ b/userspace/aoc2023/day3/main.cpp @@ -0,0 +1,179 @@ +#include +#include +#include + +#include +#include +#include + +int puzzle1(FILE* fp) +{ + using BAN::Vector, BAN::String; + + Vector lines; + + char buffer[256]; + while (fgets(buffer, sizeof(buffer), fp)) + { + buffer[strlen(buffer) - 1] = '\0'; + MUST(lines.emplace_back(buffer)); + } + + int result = 0; + + for (ssize_t y = 0; y < lines.size(); y++) + { + for (ssize_t x = 0; x < lines[y].size(); x++) + { + if (!isdigit(lines[y][x])) + continue; + + bool should_add = false; + + for (ssize_t y_off = -1; y_off <= 1; y_off++) + { + if (y + y_off < 0) + continue; + if (y + y_off >= lines.size()) + break; + + for (ssize_t x_off = -1;; x_off++) + { + if (x + x_off < 0) + continue; + if (x + x_off >= lines[y + y_off].size()) + break; + if (x_off > 0 && !isdigit(lines[y][x + x_off - 1])) + break; + + char c = lines[y + y_off][x + x_off]; + if (!isdigit(c) && c != '.') + { + should_add = true; + break; + } + } + + if (should_add) + break; + } + + int number = 0; + for (; x < lines[y].size(); x++) + { + if (!isdigit(lines[y][x])) + { + x--; + break; + } + number = (number * 10) + (lines[y][x] - '0'); + } + + if (should_add) + result += number; + } + } + + return result; +} + +int puzzle2(FILE* fp) +{ + using BAN::Vector, BAN::String, BAN::HashMap; + + Vector lines; + + char buffer[256]; + while (fgets(buffer, sizeof(buffer), fp)) + { + buffer[strlen(buffer) - 1] = '\0'; + MUST(lines.emplace_back(buffer)); + } + + // Didn't want to think about O(1) space, this is much simpler. + // Map numbers next to '*' to asterisk's coordinates. + HashMap> gears; + + for (ssize_t y = 0; y < lines.size(); y++) + { + for (ssize_t x = 0; x < lines[y].size(); x++) + { + if (!isdigit(lines[y][x])) + continue; + + int number = 0; + for (int i = 0; x + i < lines[y].size(); i++) + { + if (!isdigit(lines[y][x + i])) + break; + number = (number * 10) + (lines[y][x + i] - '0'); + } + + for (ssize_t y_off = -1; y_off <= 1; y_off++) + { + if (y + y_off < 0) + continue; + if (y + y_off >= lines.size()) + break; + + for (ssize_t x_off = -1;; x_off++) + { + if (x + x_off < 0) + continue; + if (x + x_off >= lines[y + y_off].size()) + break; + if (x_off > 0 && !isdigit(lines[y][x + x_off - 1])) + break; + + if (lines[y + y_off][x + x_off] == '*') + { + uint32_t index = (y + y_off) << 16 | (x + x_off); + if (!gears.contains(index)) + MUST(gears.insert(index, {})); + MUST(gears[index].push_back(number)); + } + } + } + + for (; x < lines[y].size(); x++) + { + if (isdigit(lines[y][x])) + continue; + x--; + break; + } + } + } + + int result = 0; + for (auto& [_, nums] : gears) + { + if (nums.size() != 2) + continue; + result += nums[0] * nums[1]; + } + return result; +} + +int main(int argc, char** argv) +{ + const char* file_path = "/usr/share/aoc2023/day3_input.txt"; + + if (argc >= 2) + file_path = argv[1]; + + FILE* fp = fopen(file_path, "r"); + if (fp == nullptr) + { + perror("fopen"); + return 1; + } + + printf("puzzle1: %d\n", puzzle1(fp)); + + fseek(fp, 0, SEEK_SET); + + printf("puzzle2: %d\n", puzzle2(fp)); + + fclose(fp); +}