Skip to content

Commit

Permalink
day 8 (#25)
Browse files Browse the repository at this point in the history
  • Loading branch information
FrederikTobner authored Dec 8, 2024
1 parent 8566655 commit d5950ee
Show file tree
Hide file tree
Showing 13 changed files with 279 additions and 7 deletions.
9 changes: 5 additions & 4 deletions day_6/src/main.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
#include "../../shared/src/exit_code.hpp"
#include "../../shared/src/file_operations.hpp"
#include "../../shared/src/grid_processor.hpp"
#include "../../shared/src/print_compatibility_layer.hpp"
#include <algorithm>
#include <atomic>
#include <execution>
#include <numeric>
#include <string>

#include "../../shared/src/exit_code.hpp"
#include "../../shared/src/file_operations.hpp"
#include "../../shared/src/grid_processor.hpp"
#include "../../shared/src/print_compatibility_layer.hpp"

#include "../lib/grid_parser.hpp"
#include "../lib/puzzle_map.hpp"

Expand Down
1 change: 1 addition & 0 deletions day_8/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
aoc_day(8)
1 change: 1 addition & 0 deletions day_8/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
aoc_add_library()
68 changes: 68 additions & 0 deletions day_8/lib/antinodes.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#pragma once

#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <map>
#include <ranges>
#include <string>
#include <unordered_set>
#include <vector>

#include "../lib/coordinate.hpp"

#include "../../shared/src/ranges_compatibility_layer.hpp"

namespace aoc::day_8 {

namespace detail {
[[nodiscard]] static auto getOtherAntennaPositionsByFrequency(char frequency, coordinate const & exclude_pos,
std::multimap<char, coordinate> const & antenas) {
auto range = antenas.equal_range(frequency);
return std::ranges::subrange(range.first, range.second) |
std::views::transform([](auto const & pair) { return pair.second; }) |
std::views::filter([&exclude_pos](coordinate const & pos) { return pos != exclude_pos; }) |
std::views::common;
}

[[nodiscard]] static auto generateAntinodeSequence(coordinate start, coordinate diff, int64_t max_x, int64_t max_y) {
return std::views::iota(0) | std::views::transform([=](int64_t i) { return start + diff * i; }) |
std::views::take_while([=](coordinate pos) { return pos.inBounds(max_x, max_y); });
}
} // namespace detail

[[nodiscard]] auto determineAntinodes(int64_t max_x_coordinate, int64_t max_y_coordinate,
std::multimap<char, coordinate> const & antenas)
-> std::unordered_set<coordinate> {
return std::views::transform(
antenas,
[&](auto const & entry) {
return detail::getOtherAntennaPositionsByFrequency(entry.first, entry.second, antenas) |
std::views::transform([&entry](coordinate const & other_pos) {
coordinate diff = other_pos - entry.second;
return other_pos + diff;
}) |
std::views::filter([max_x_coordinate, max_y_coordinate](coordinate const & pos) {
return pos.inBounds(max_x_coordinate, max_y_coordinate);
});
}) |
std::views::join | aoc::ranges::to<std::unordered_set<coordinate>>;
}

[[nodiscard]] auto determineAntinodes2(int64_t max_x_coordinate, int64_t max_y_coordinate,
std::multimap<char, coordinate> const & antenas)
-> std::unordered_set<coordinate> {
return std::views::transform(
antenas,
[max_x = max_x_coordinate, max_y = max_y_coordinate, antenas = antenas](auto const & entry) {
return detail::getOtherAntennaPositionsByFrequency(entry.first, entry.second, antenas) |
std::views::transform([start = entry.second, max_x, max_y](coordinate const & other_pos) {
return detail::generateAntinodeSequence(other_pos, other_pos - start, max_x, max_y);
}) |
std::views::join;
}) |
std::views::join | aoc::ranges::to<std::unordered_set<coordinate>>;
}

} // namespace aoc::day_8
55 changes: 55 additions & 0 deletions day_8/lib/coordinate.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#pragma once

#include <cstddef>
#include <memory>

namespace aoc::day_8 {

struct coordinate {
int64_t y;
int64_t x;

auto operator!=(coordinate const & other) const -> bool {
return y != other.y || x != other.x;
}

auto operator==(coordinate const & other) const -> bool {
return y == other.y && x == other.x;
}

[[nodiscard]] auto operator-(coordinate const & other) const -> coordinate {
return {y - other.y, x - other.x};
}

[[nodiscard]] auto operator+(coordinate const & other) const -> coordinate {
return {y + other.y, x + other.x};
}

auto operator*(int64_t scalar) const -> coordinate {
return {y * scalar, x * scalar};
}

auto operator+=(coordinate const & other) -> coordinate & {
y += other.y;
x += other.x;
return *this;
}

[[nodiscard]] auto inBounds(int64_t max_x, int64_t max_y) const -> bool {
return y >= 0 && y < max_y && x >= 0 && x < max_x;
}
};

} // namespace aoc::day_8
namespace std {

/// @brief Hash specialization for VisitedPosition to enable use in unordered containers
template <> struct hash<aoc::day_8::coordinate> {
/// @brief Combines the hashes of row, column and direction into a single hash value
/// @param position The position to hash
/// @return A hash value representing the complete state of the position
[[nodiscard]] auto operator()(aoc::day_8::coordinate const position) const -> std::size_t {
return std::hash<int64_t>{}(position.y) ^ std::hash<int64_t>{}(position.x);
}
};
} // namespace std
34 changes: 34 additions & 0 deletions day_8/lib/frequency_map_renderer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#pragma once

#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <map>
#include <numeric>
#include <ranges>
#include <string>
#include <unordered_set>
#include <vector>

#include "../../shared/src/print_compatibility_layer.hpp"

#include "../lib/coordinate.hpp"

namespace aoc::day_8 {
auto renderResult(std::vector<std::string_view> lines, std::unordered_set<aoc::day_8::coordinate> antinodes,
int64_t max_x_coordinate, int64_t max_y_coordinate) -> void {
std::string output = "";
for (auto x : std::views::iota(int64_t{0}, max_y_coordinate)) {
for (auto y : std::views::iota(int64_t{0}, max_x_coordinate)) {
if (antinodes.contains({x, y})) {
output += '#';
} else {
output += lines[x][y];
}
}
output += '\n';
}
std::println("Result:\n{}Found {} antinodes", output, antinodes.size());
}
} // namespace aoc::day_8
1 change: 1 addition & 0 deletions day_8/performance/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
aoc_add_benchmark()
2 changes: 2 additions & 0 deletions day_8/src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
aoc_add_executable()
configure_file(input.txt input.txt COPYONLY)
50 changes: 50 additions & 0 deletions day_8/src/input.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
...............e.........................i........
...............................1.......i.0........
..............................s.0......d..........
........................i....B.I............d.....
.............................s....................
................J.................................
.....................L.....0i.......4...d.........
.N...e...........................s..R.....4.....I.
........e.........v................1......R....I..
.............G..............0.....1...............
..2...N.............B......................4...R..
..............2...................N..........4s...
..p...................................1..b..I.....
..................p...........B........b...R......
....................................b.............
........W.......C.....w...........................
............7....u.............B..................
...W.................u......................bw....
.......p.2...........v......................9.....
.E.....C....u................................9....
E....Y................u.D........9...........J....
.......2..........................................
............................J.................c...
.............7...K..D..............J..............
.....C.Wq........t.................T..............
............Yt......v.............................
..W......................3...............w........
..7.....j................T...D.....n......8.....c.
.........E...............nTD......................
...r....E..........Y............n.......P........c
......K........G......L...........................
......................G.....L....v................
..............G...t......q.............l.8........
......................q............l..............
...6........r.............................w..c....
..6.........3.......Qk........T...................
......Y...............j.................n.........
..K.....S.....r......j.....U......9.l......8......
........................U......................P..
.....................q............................
.......K......5..N.....j.7.Q......................
...................p..k...U..........L.Q..........
.r......3...S.......k........y....8U....Q.......P.
.......S....g..3..................................
.....S..........gk................................
................5...................yP............
.......................g......yV..l...............
.........6.5...............V......................
..................6..5..V.........................
.............g.......................y..........V.
58 changes: 58 additions & 0 deletions day_8/src/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <execution>
#include <map>
#include <ranges>
#include <string>
#include <unordered_set>
#include <vector>

#include "../../shared/src/exit_code.hpp"
#include "../../shared/src/file_operations.hpp"
#include "../../shared/src/grid_processor.hpp"
#include "../../shared/src/print_compatibility_layer.hpp"

#include "../lib/antinodes.hpp"
#include "../lib/coordinate.hpp"
#include "../lib/frequency_map_renderer.hpp"

auto main(int argc, char const ** argv) -> int {
std::expected<std::string, std::error_code> input = aoc::file_operations::read("input.txt");
if (!input) [[unlikely]] {
std::println(stderr, "Could not open file: {}", input.error().message());
return aoc::EXIT_CODE_IO_ERROR;
}

std::vector<std::string_view> lines = aoc::grid_processor::processLines(*input);
if (!aoc::grid_processor::validateGrid(lines)) {
std::println(stderr, "Lines have different lengths");
return aoc::EXIT_CODE_DATA_ERROR;
}

int64_t max_y_coordinate = lines.size();
int64_t max_x_coordinate = lines[0].size();

std::multimap<char, aoc::day_8::coordinate> antenas;
for (auto x : std::views::iota(int64_t{0}, max_y_coordinate)) {
for (auto y : std::views::iota(int64_t{0}, max_x_coordinate)) {
if (std::isalnum(lines[x][y])) {
antenas.insert({lines[x][y], {x, y}});
}
}
}

// Part 1
std::unordered_set<aoc::day_8::coordinate> antinodes =
aoc::day_8::determineAntinodes(max_x_coordinate, max_y_coordinate, antenas);

aoc::day_8::renderResult(lines, antinodes, max_x_coordinate, max_y_coordinate);

// Part 2
std::unordered_set<aoc::day_8::coordinate> antinodes2 =
aoc::day_8::determineAntinodes2(max_x_coordinate, max_y_coordinate, antenas);

aoc::day_8::renderResult(lines, antinodes2, max_x_coordinate, max_y_coordinate);

return 0;
}
1 change: 1 addition & 0 deletions day_8/test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
aoc_add_test()
2 changes: 1 addition & 1 deletion shared/src/column_splitter.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* @file multiset_column_lexer.hpp
* @file column_splitter.hpp
* @brief Implementation of a lexer that parses the input data into columnar container structures
* @details Provides interfaces for parsing input data containing columns of numbers.
* Includes utilities for parsing individual lines and complete input files,
Expand Down
4 changes: 2 additions & 2 deletions shared/src/line_splitter.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* @file line_lexer.hpp
* @brief Implementation of a line-based lexer for tokenizing input text
* @file line_splitter.hpp
* @brief Implementation of a line-based splitter for tokenizing input text
* @details Provides interfaces for parsing input data line by line into configurable containers.
* Supports both sequential and parallel processing modes with error handling through std::expected.
* Container types can be specified through template parameters, with std::vector as the default.
Expand Down

0 comments on commit d5950ee

Please # to comment.