Skip to content

Commit

Permalink
cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
matiaslindgren committed May 22, 2024
1 parent 94366d8 commit 1c91630
Show file tree
Hide file tree
Showing 26 changed files with 606 additions and 718 deletions.
8 changes: 7 additions & 1 deletion .clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@ Checks: >
-bugprone-switch-missing-default-case,
-modernize-use-trailing-return-type,
-readability-identifier-length,
-bugprone-assignment-in-if-condition
-bugprone-assignment-in-if-condition,
-cppcoreguidelines-avoid-magic-numbers,
-readability-magic-numbers,
-cppcoreguidelines-avoid-do-while,
-readability-named-parameter,
-performance-unnecessary-value-param,
-bugprone-easily-swappable-parameters
WarningsAsErrors: '*'
FormatStyle: none
HeaderFilterRegex: ''
Expand Down
26 changes: 24 additions & 2 deletions include/aoc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,28 @@ using std::operator""sv;

namespace aoc {

struct is_digit_fn {
constexpr bool operator()(unsigned char ch) const noexcept {
return std::isdigit(ch) != 0;
}
};
inline constexpr auto is_digit = is_digit_fn{};

struct is_alpha_fn {
constexpr bool operator()(unsigned char ch) const noexcept {
return std::isalpha(ch) != 0;
}
};
inline constexpr auto is_alpha = is_alpha_fn{};

struct is_lower_fn {
constexpr bool operator()(unsigned char ch) const noexcept {
return std::islower(ch) != 0;
}
};
inline constexpr auto is_lower = is_lower_fn{};


std::string slurp_file(std::string_view path) {
std::ios::sync_with_stdio(false);

Expand Down Expand Up @@ -43,10 +65,10 @@ std::vector<std::string> slurp_lines(std::string_view path) {
}

template <typename T>
std::vector<T> parse_items(std::string_view path, const char sep = 0) {
std::vector<T> parse_items(std::string_view path, std::optional<char> sep = std::nullopt) {
auto input{slurp_file(path)};
if (sep) {
ranges::replace(input, sep, ' ');
ranges::replace(input, sep.value(), ' ');
}
std::istringstream is{input};
std::vector<T> items;
Expand Down
4 changes: 2 additions & 2 deletions src/2015/04.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ auto search(std::string_view msg) {

ThreadPool pool(aoc::cpu_count());

for (int part1{std::numeric_limits<int>::max()}, i{}; i < max_iterations;
i += pool.results.size()) {
int part1{std::numeric_limits<int>::max()};
for (std::size_t i{}; i < max_iterations; i += pool.results.size()) {
for (auto&& [t, th] : my_std::views::enumerate(pool.threads)) {
th = std::thread(&ThreadPool::md5sum_32bit, &pool, msg, i, t);
}
Expand Down
10 changes: 6 additions & 4 deletions src/2015/07.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,21 @@
namespace ranges = std::ranges;
namespace views = std::views;

using aoc::is_digit;

struct Statement {
std::string lhs0;
std::string lhs1;
std::string dst;
enum {
enum : unsigned char {
Unknown,
Assign,
Not,
And,
Or,
LShift,
RShift,
} gate;
} gate{};
};

std::istream& operator>>(std::istream& is, Statement& s) {
Expand All @@ -25,7 +27,7 @@ std::istream& operator>>(std::istream& is, Statement& s) {
while (is >> str and str != "->") {
lhs.push_back(str);
}
if (0 < lhs.size() and lhs.size() < 4 and str == "->" and is >> str) {
if (not lhs.empty() and lhs.size() < 4 and str == "->" and is >> str) {
auto gate{Statement::Unknown};
switch (lhs.size()) {
case 1: {
Expand Down Expand Up @@ -65,7 +67,7 @@ std::istream& operator>>(std::istream& is, Statement& s) {
}

bool is_literal(const std::string& s) {
return not s.empty() and std::isdigit(static_cast<unsigned char>(s.front()));
return not s.empty() and is_digit(s.front());
}

uint16_t parse_literal(const std::string& s) {
Expand Down
5 changes: 2 additions & 3 deletions src/2015/08.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
namespace ranges = std::ranges;
namespace views = std::views;

enum class State {
enum class State : unsigned char {
Init,
Literal,
Escaping,
Expand Down Expand Up @@ -80,8 +80,7 @@ auto escape(const std::string& s) {
constexpr auto sum{std::__bind_back(ranges::fold_left, 0, std::plus{})};

int main() {
std::ios::sync_with_stdio(false);
const auto lines{views::istream<std::string>(std::cin) | ranges::to<std::vector>()};
const auto lines{aoc::parse_items<std::string>("/dev/stdin")};

const auto part1{sum(lines | views::transform(count_bytes))};
const auto part2{sum(lines | views::transform(escape) | views::transform(count_bytes))};
Expand Down
126 changes: 39 additions & 87 deletions src/2015/09.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,121 +4,73 @@
namespace ranges = std::ranges;
namespace views = std::views;

using aoc::skip;
using std::operator""s;

struct Edge {
std::string src;
std::string dst;
std::size_t dist;
int len{};
};

std::istream& operator>>(std::istream& is, Edge& edge) {
using aoc::skip;
using std::operator""s;

std::string src, dst;
std::size_t dist;
if (is >> src >> std::ws >> skip("to"s) >> dst >> std::ws >> skip("="s) >> dist) {
edge = {src, dst, dist};
return is;
}
if (is.eof()) {
return is;
}
throw std::runtime_error("failed parsing Edge");
}

class Graph {
std::size_t node_count_;
std::vector<std::size_t> distances;

public:
auto&& distance(this auto&& self, auto n1, auto n2) {
return self.distances[n1 + n2 * self.node_count()];
}

constexpr explicit Graph(const std::vector<Edge>& edges) {
std::vector<std::string> nodes;
for (const auto& edge : edges) {
nodes.push_back(edge.src);
nodes.push_back(edge.dst);
}
{
ranges::sort(nodes);
const auto duplicates{ranges::unique(nodes)};
nodes.erase(duplicates.begin(), duplicates.end());
}
node_count_ = nodes.size();

distances.resize(node_count() * node_count(), max_distance());
for (auto n : views::iota(0UZ, node_count())) {
distance(n, n) = 0;
}
struct Graph {
std::unordered_map<std::string, std::unordered_map<std::string, int>> edges;

const auto find_node_index{[&nodes](const auto& name) {
return ranges::distance(nodes.begin(), ranges::find(nodes, name));
}};
for (const auto& e : edges) {
const auto n1{find_node_index(e.src)};
const auto n2{find_node_index(e.dst)};
distance(n1, n2) = distance(n2, n1) = e.dist;
explicit Graph(const std::vector<Edge>& init_edges) {
for (auto&& [src, dst, len] : init_edges) {
edges[src][dst] = edges[dst][src] = len;
}
}

constexpr std::size_t node_count() const {
return node_count_;
[[nodiscard]]
auto get_dist(const auto& src, const auto& dst) const {
if (edges.contains(src) and edges.at(src).contains(dst)) {
return edges.at(src).at(dst);
}
return std::numeric_limits<int>::max();
}

constexpr std::size_t max_distance() const {
return std::numeric_limits<std::size_t>::max();
}
[[nodiscard]]
auto find_all_hamiltonian_path_lengths() const {
std::vector<int> lengths;

template <std::size_t max_node_count>
constexpr auto find_all_hamiltonian_path_lengths() const {
if (max_node_count < node_count()) {
throw std::runtime_error("too many nodes");
}
std::vector<std::size_t> lengths;
struct State {
std::bitset<max_node_count> visited;
std::size_t node;
std::size_t path_length;
std::unordered_set<std::string> visited;
std::string node;
int path_length;
};
for (auto start : views::iota(0UZ, node_count())) {

for (const auto& start : edges | views::keys) {
for (std::vector q{State{{}, start, {}}}; not q.empty();) {
auto current{q.back()};
State s{q.back()};
q.pop_back();
if (current.visited[current.node]) {
if (auto [_, is_new]{s.visited.insert(s.node)}; not is_new) {
continue;
}
current.visited[current.node] = true;
if (current.visited.count() == node_count()) {
lengths.push_back(current.path_length);
if (s.visited.size() == edges.size()) {
lengths.push_back(s.path_length);
continue;
}
for (auto node : views::iota(0UZ, node_count())) {
const auto edge_length{distance(current.node, node)};
q.emplace_back(
current.visited,
node,
aoc::saturating_add(current.path_length, edge_length)
);
for (const auto& dst : edges | views::keys) {
q.emplace_back(s.visited, dst, aoc::saturating_add(s.path_length, get_dist(s.node, dst)));
}
}
}

return lengths;
}
};

int main() {
const auto edges{aoc::parse_items<Edge>("/dev/stdin")};

Graph g{edges};
const auto hamiltonian_path_lengths{g.find_all_hamiltonian_path_lengths<8>()};
const auto [shortest_path, longest_path]{ranges::minmax_element(hamiltonian_path_lengths)};

const auto part1{*shortest_path};
const auto part2{*longest_path};
std::istream& operator>>(std::istream& is, Edge& edge) {
if (Edge e; is >> e.src >> std::ws >> skip("to"s) >> e.dst >> std::ws >> skip("="s) >> e.len) {
edge = e;
}
return is;
}

int main() {
Graph g{aoc::parse_items<Edge>("/dev/stdin")};
const auto [part1, part2]{ranges::minmax(g.find_all_hamiltonian_path_lengths())};
std::println("{} {}", part1, part2);

return 0;
}
52 changes: 21 additions & 31 deletions src/2015/11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@
namespace ranges = std::ranges;
namespace views = std::views;

constexpr static auto alphabet_size{'z' - 'a' + 1};

constexpr int char2digit(char ch) {
return ch - 'a';
signed char char2digit(char ch) {
return static_cast<signed char>(ch - 'a');
}
constexpr char digit2char(int x) {
return x + 'a';
char digit2char(signed char x) {
return static_cast<char>(x + 'a');
}

constexpr static auto alphabet_size{'z' - 'a' + 1};
constexpr static auto forbidden_chars{views::transform("iol", char2digit)};

bool valid(const auto& password) {
Expand Down Expand Up @@ -47,39 +46,30 @@ bool valid(const auto& password) {
);
}

template <auto base>
auto increment(const auto& input) {
std::vector<int> result(input.size());
int carry{1};
for (const auto& t : views::reverse(views::zip(result, input))) {
auto& [dst, src] = t;
dst = src + carry;
carry = dst == base;
dst %= base;
}
return result;
}

auto to_string(const auto& password) {
std::string search(auto& password) {
do {
std::vector<signed char> result(password.size());
signed char carry{1};
for (auto&& [dst, src] : views::reverse(views::zip(result, password))) {
dst = src + carry;
carry = dst == alphabet_size;
dst %= alphabet_size;
}
password = result;
} while (not valid(password));
return views::transform(password, digit2char) | ranges::to<std::string>();
}

int main() {
std::istringstream input{aoc::slurp_file("/dev/stdin")};

auto password{
views::istream<char>(input) | views::transform(char2digit) | ranges::to<std::vector>()
aoc::parse_items<char>("/dev/stdin") | views::transform(char2digit)
| ranges::to<std::vector>()
};

std::string parts[2];
for (auto& part : parts) {
do {
password = increment<alphabet_size>(password);
} while (not valid(password));
part = to_string(password);
}
const auto part1{search(password)};
const auto part2{search(password)};

std::println("{} {}", parts[0], parts[1]);
std::println("{} {}", part1, part2);

return 0;
}
Loading

0 comments on commit 1c91630

Please sign in to comment.