Skip to content

Commit

Permalink
Day 11 (#80)
Browse files Browse the repository at this point in the history
  • Loading branch information
EduardGomezEscandell authored Dec 15, 2023
2 parents f7e16dc + 48d4f85 commit d882391
Show file tree
Hide file tree
Showing 13 changed files with 681 additions and 1 deletion.
10 changes: 10 additions & 0 deletions 2023/data/11/example.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
...#......
.......#..
#.........
..........
......#...
.#........
.........#
..........
.......#..
#...#.....
140 changes: 140 additions & 0 deletions 2023/data/11/input.txt

Large diffs are not rendered by default.

139 changes: 139 additions & 0 deletions 2023/solvelib/11/day11.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
#include "day11.hpp"

#include "xmaslib/iota/iota.hpp"
#include "xmaslib/log/log.hpp"

#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <execution>
#include <map>
#include <string_view>
#include <utility>
#include <vector>

namespace {

struct coords {
std::size_t row, col;
};

std::uint64_t absolute_difference(std::uint64_t a, std::uint64_t b) {
return (a > b) ? (a - b) : (b - a);
}

[[nodiscard]] std::pair<std::size_t, std::size_t>
dimensions(std::string_view input) {
const std::size_t ncols =
1 + std::size_t(std::find(input.cbegin(), input.cend(), '\n') -
input.cbegin());
const std::size_t nrows = input.size() / ncols;
xlog::debug("Detected {} rows and {} columns", nrows, ncols);

return std::make_pair(nrows, ncols);
}

auto parse_and_expand_universe(std::string_view input,
std::size_t expansion_rate) {
const auto [nrows, ncols] = dimensions(input);

// Find galaxies and expand rows
std::vector<coords> galaxies;
std::map<std::size_t, std::size_t> column_mapping;
{
std::size_t row = 0;
for (std::size_t line = 0; line < nrows; ++line) {
bool empty = true;
for (std::size_t col = 0; col < ncols - 1; ++col) {
const std::size_t i = line * ncols + col;
if (input[i] == '#') {
galaxies.push_back({row, col});
column_mapping[col] = col;
empty = false;
}
}
if (empty) {
row += expansion_rate;
} else {
++row;
}
};
}

// Create mapping from original to expanded columns
{
std::size_t empties = 0;
std::ptrdiff_t prev_row = -1;
for (auto &map : column_mapping) {
auto row = std::ptrdiff_t(map.first);
empties += std::size_t(row - prev_row - 1);
prev_row = row;

map.second = map.first + empties * (expansion_rate - 1);
}
}

#ifndef NDEBUG
for (auto map : column_mapping) {
xlog::debug("Mapping columns {}->{}", map.first, map.second);
}
#endif

// Expand columns
std::for_each(
std::execution::par_unseq, galaxies.begin(), galaxies.end(),
[&column_mapping](coords &g) { g.col = column_mapping.at(g.col); });

#ifndef NDEBUG
for (auto i : xmas::views::iota(galaxies.size())) {
xlog::debug("Galaxy {}: {},{}", i, galaxies[i].row, galaxies[i].col);
}
#endif

return galaxies;
}

} // namespace

void Day11::load() {
xmas::solution::load();

// Trailing newline is necessary
if (this->input.back() != '\n') {
this->input.push_back('\n');
}
}

std::uint64_t Day11::solve(std::size_t expansion_rate) const {
auto galaxies = parse_and_expand_universe(input, expansion_rate);

// Compute distances
std::size_t n = galaxies.size();
std::vector<std::uint64_t> distances((n * (n - 1)) / 2);

xmas::views::iota<std::size_t> iota(n);
std::for_each(std::execution::par_unseq, iota.begin(), iota.end(),
[&galaxies, &distances](std::size_t i) {
auto &g1 = galaxies[i];
for (std::size_t j = i + 1; j != galaxies.size(); ++j) {
auto &g2 = galaxies[j];

// Taxicab distance
std::uint64_t vdistance =
absolute_difference(g2.row, g1.row);
std::uint64_t hdistance =
absolute_difference(g2.col, g1.col);
std::uint64_t d = vdistance + hdistance;

xlog::debug("Distance between {} and {} is {}", i, j, d);
std::size_t dest = (j * (j - 1)) / 2 + i; // <3 Gauss
distances[dest] = d;
}
});

return std::reduce(std::execution::unseq, distances.begin(), distances.end(),
std::uint64_t{0}, std::plus<std::uint64_t>{});
}

std::uint64_t Day11::part1() { return solve(2); }
std::uint64_t Day11::part2() { return solve(1'000'000); }
14 changes: 14 additions & 0 deletions 2023/solvelib/11/day11.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#pragma once

#include "xmaslib/solution/solution.hpp"

class Day11 : public xmas::solution {
public:
int day() override { return 11; }
void load() override;

public:
std::uint64_t solve(std::size_t expansion_rate) const;
std::uint64_t part1() override;
std::uint64_t part2() override;
};
34 changes: 34 additions & 0 deletions 2023/solvelib/11/day11_test.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include "day11.hpp"
#include <doctest/doctest.h>

TEST_CASE("Day 11") {

SUBCASE("Part 1") {
Day11 solution{};
solution.set_input("./data/11/example.txt");
solution.load();
REQUIRE_EQ(solution.part1(), 374);
}

SUBCASE("Part 2, size 10") {
Day11 solution{};
solution.set_input("./data/11/example.txt");
solution.load();
REQUIRE_EQ(solution.solve(10), 1030);
}

SUBCASE("Part 2, size 100") {
Day11 solution{};
solution.set_input("./data/11/example.txt");
solution.load();
REQUIRE_EQ(solution.solve(100), 8410);
}

SUBCASE("Real data") {
Day11 solution{};
solution.set_input("./data/11/input.txt");
solution.load();
REQUIRE_EQ(solution.part1(), 9974721);
REQUIRE_EQ(solution.part2(), 702770569197);
}
}
1 change: 1 addition & 0 deletions 2023/solvelib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ add_library(solvelib
03/day03.hpp 03/day03.cpp 03/day03_test.hpp
04/day04.hpp 04/day04.cpp 04/day04_test.hpp
05/day05.hpp 05/day05.cpp 05/day05_test.hpp
11/day11.hpp 11/day11.cpp 11/day11_test.hpp
12/day12.hpp 12/day12.cpp 12/day12_test.hpp
13/day13.hpp 13/day13.cpp 13/day13_test.hpp
)
Expand Down
2 changes: 2 additions & 0 deletions 2023/solvelib/alldays.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "03/day03.hpp"
#include "04/day04.hpp"
#include "05/day05.hpp"
#include "11/day11.hpp"
#include "12/day12.hpp"
#include "13/day13.hpp"

Expand All @@ -16,6 +17,7 @@ inline void populate_registry() {
xmas::register_solution<Day03>();
xmas::register_solution<Day04>();
xmas::register_solution<Day05>();
xmas::register_solution<Day11>();
xmas::register_solution<Day12>();
xmas::register_solution<Day13>();
}
1 change: 1 addition & 0 deletions 2023/test/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "solvelib/03/day03_test.hpp"
#include "solvelib/04/day04_test.hpp"
#include "solvelib/05/day05_test.hpp"
#include "solvelib/11/day11_test.hpp"
#include "solvelib/12/day12_test.hpp"
#include "solvelib/13/day13_test.hpp"

Expand Down
12 changes: 12 additions & 0 deletions 2023/xmaslib/functional/functional.hpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#pragma once

namespace xmas {

template <typename T> class equals {
Expand All @@ -10,4 +12,14 @@ template <typename T> class equals {
T value;
};

template <typename T> class less_than {
public:
explicit constexpr less_than(T value) : value(value) {}

constexpr bool operator()(T const &other) const { return other < value; }

private:
T value;
};

} // namespace xmas
11 changes: 11 additions & 0 deletions 2023/xmaslib/iota/iota.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,17 @@ template <std::integral T> class iota {
return it;
}

constexpr iterator operator--() noexcept {
--v;
return *this;
}

constexpr iterator operator--(int) noexcept {
auto it = iterator{v};
--*this;
return it;
}

constexpr iterator &operator+=(std::ptrdiff_t delta) noexcept {
v += safe_cast<value_type>(delta);
return *this;
Expand Down
2 changes: 1 addition & 1 deletion 2023/xmaslib/log/log.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ void log(severity prefix, std::string_view message) {
return "\x1b[31mUNKNOWN SEVERITY\x1b[0m";
}();

std::cerr << std::format("{}: {}\n", p, message) << std::flush;
std::cerr << std::format("{} {}\n", p, message) << std::flush;
}

} // namespace internal
Expand Down
Loading

0 comments on commit d882391

Please sign in to comment.