Skip to content

Commit

Permalink
cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
matiaslindgren committed May 23, 2024
1 parent d642566 commit a071b45
Show file tree
Hide file tree
Showing 10 changed files with 230 additions and 257 deletions.
3 changes: 2 additions & 1 deletion .clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ Checks: >
-cppcoreguidelines-avoid-do-while,
-readability-named-parameter,
-performance-unnecessary-value-param,
-bugprone-easily-swappable-parameters
-bugprone-easily-swappable-parameters,
-readability-qualified-auto
WarningsAsErrors: '*'
FormatStyle: none
HeaderFilterRegex: ''
Expand Down
84 changes: 37 additions & 47 deletions src/2023/01.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,60 +4,50 @@
namespace ranges = std::ranges;
namespace views = std::views;

using aoc::is_digit;

constexpr int char2num(const auto ch) {
return ch - '0';
}

template <std::input_or_output_iterator It>
requires std::random_access_iterator<It>
const int find_str_digit(const It begin, const It end) {
static const std::unordered_map<std::string, int> str2num{
{{"one", 1},
{"two", 2},
{"three", 3},
{"four", 4},
{"five", 5},
{"six", 6},
{"seven", 7},
{"eight", 8},
{"nine", 9}}
};
for (auto n{3UZ}; n <= 5UZ; ++n) {
const std::string s{begin, ranges::next(begin, n, end)};
if (const auto num{str2num.find(s)}; num != str2num.end()) {
return num->second;
void replace(std::string& s, std::string_view pat, std::string_view sub) {
for (std::string::size_type i{}; i != std::string::npos;) {
i = s.find(pat, i);
if (i != std::string::npos) {
s.erase(i, pat.size());
s.insert(i, sub);
i += sub.size();
}
}
return 0;
}

int main() {
std::istringstream input{aoc::slurp_file("/dev/stdin")};
auto prepare_part2(const auto& lines) {
return views::transform(
lines,
[&](std::string line) {
replace(line, "one", "one1one");
replace(line, "two", "two2two");
replace(line, "three", "three3three");
replace(line, "four", "four4four");
replace(line, "five", "five5five");
replace(line, "six", "six6six");
replace(line, "seven", "seven7seven");
replace(line, "eight", "eight8eight");
replace(line, "nine", "nine9nine");
return line;
}
)
| ranges::to<std::vector>();
}

int part1{}, part2{};
constexpr auto sum{std::__bind_back(ranges::fold_left, 0, std::plus{})};

for (std::string line; std::getline(input, line);) {
const auto lhs1{ranges::find_if(line, is_digit)};
if (lhs1 == line.end()) {
continue;
}
const auto rhs1{ranges::find_if(views::reverse(line), is_digit).base() - 1};
const auto lhs_val1{char2num(*lhs1) * 10};
const auto rhs_val1{char2num(*rhs1)};
part1 += lhs_val1 + rhs_val1;
auto calibrate(const auto& lines) {
return sum(views::transform(lines, [&](std::string_view line) {
auto nums{views::filter(line, aoc::is_digit) | ranges::to<std::vector>()};
return 10 * (nums.front() - '0') + (nums.back() - '0');
}));
}

int lhs_val2{};
for (auto lhs2{line.begin()}; lhs2 < lhs1 and not lhs_val2; ++lhs2) {
lhs_val2 = find_str_digit(lhs2, lhs1) * 10;
}
int rhs_val2{};
for (auto rhs2{ranges::prev(line.end(), 1, rhs1)}; rhs1 < rhs2 and not rhs_val2; --rhs2) {
rhs_val2 = find_str_digit(rhs2, line.end());
}
part2 += (lhs_val2 ? lhs_val2 : lhs_val1) + (rhs_val2 ? rhs_val2 : rhs_val1);
}
int main() {
const auto lines{aoc::slurp_lines("/dev/stdin")};

const auto part1{calibrate(lines)};
const auto part2{calibrate(prepare_part2(lines))};

std::println("{} {}", part1, part2);

Expand Down
39 changes: 18 additions & 21 deletions src/2023/02.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
namespace ranges = std::ranges;
namespace views = std::views;

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

struct GameMax {
int id;
int red;
Expand All @@ -12,34 +15,27 @@ struct GameMax {
};

std::istream& operator>>(std::istream& is, GameMax& gm) {
using aoc::skip;
using std::operator""s;
if (std::string line; std::getline(is, line)) {
if (std::string line; std::getline(is, line) and not line.empty()) {
std::istringstream ls{line};
if (int id; ls >> skip("Game"s) >> id >> skip(":"s)) {
if (int id{}; ls >> skip("Game"s) >> id >> skip(":"s)) {
std::unordered_map<std::string, int> counts;
while (ls and is) {
if (auto [count, cube] = std::pair(int{}, ""s); ls >> count >> cube) {
if (cube.ends_with(",") or cube.ends_with(";")) {
cube.pop_back();
}
if (cube == "red" or cube == "green" or cube == "blue") {
counts[cube] = std::max(counts[cube], count);
} else {
is.setstate(std::ios_base::failbit);
}
for (auto [count, cube]{std::pair(int{}, ""s)}; ls >> count >> cube;) {
if (cube.ends_with(",") or cube.ends_with(";")) {
cube.pop_back();
}
if (cube == "red" or cube == "green" or cube == "blue") {
counts[cube] = std::max(counts[cube], count);
} else {
throw std::runtime_error(std::format("unknown cube '{}'", cube));
}
}
if (is) {
gm = {id, counts["red"], counts["green"], counts["blue"]};
return is;
if (not ls.eof()) {
throw std::runtime_error(std::format("failed parsing line '{}'", line));
}
gm = {id, counts["red"], counts["green"], counts["blue"]};
}
}
if (is.eof()) {
return is;
}
throw std::runtime_error("failed parsing GameMax");
return is;
}

constexpr auto sum{std::__bind_back(ranges::fold_left, 0, std::plus{})};
Expand All @@ -56,6 +52,7 @@ int main() {

const auto part1{sum(possible_ids)};
const auto part2{sum(powers)};

std::println("{} {}", part1, part2);

return 0;
Expand Down
132 changes: 53 additions & 79 deletions src/2023/03.cpp
Original file line number Diff line number Diff line change
@@ -1,120 +1,94 @@
#include "aoc.hpp"
#include "my_std.hpp"
#include "ndvec.hpp"
#include "std.hpp"

namespace ranges = std::ranges;
namespace views = std::views;

using aoc::is_digit;
using Vec2 = ndvec::vec2<int>;
using Cell = unsigned char;

constexpr auto yx_range(auto y0, auto y1, auto x0, auto x1) {
return my_std::views::cartesian_product(views::iota(y0, y1), views::iota(x0, x1));
bool is_symbol(Cell c) {
return c != '.' and not is_digit(c);
}

struct Grid {
using Point = std::pair<std::size_t, std::size_t>;
using Cell = unsigned char;
std::vector<Cell> cells;
std::size_t width{};
std::size_t height{};

constexpr auto&& get(this auto&& self, auto y, auto x) {
return self.cells[y * self.width + x];
}

constexpr auto iter_yx_with_padding(const std::size_t pad) const {
return yx_range(pad, height - pad, pad, width - pad);
}

constexpr Grid pad() const {
const auto w{width + 2};
const auto h{height + 2};
Grid out = {std::vector<Cell>(w * h, '.'), w, h};
for (const auto& [y, x] : iter_yx_with_padding(0)) {
out.get(y + 1, x + 1) = get(y, x);
}
return out;
}
bool is_gear(Cell c) {
return c == '*';
}

constexpr bool is_symbol(const Cell c) const {
return c != '.' and not is_digit(c);
}
struct Grid {
std::unordered_map<Vec2, Cell> cells;

constexpr bool is_gear(const Cell c) const {
return c == '*';
[[nodiscard]]
auto get(Vec2 p) const {
return cells.contains(p) ? cells.at(p) : 0;
}

constexpr int parse_int(auto y, auto x) const {
[[nodiscard]]
int parse_number_at(Vec2 p) const {
int num{};
for (; is_digit(get(y, x)); ++x) {
num = (num * 10) + (get(y, x) - '0');
for (; is_digit(get(p)); p.x() += 1) {
num = (num * 10) + (get(p) - '0');
}
return num;
}

constexpr auto adjacent_numbers(const Point& center) const {
std::vector<Point> points;
std::vector<int> numbers;
for (const auto& [dy, dx] : yx_range(-1, 2, -1, 2)) {
const auto [y, x] = center;
if (auto y2{y + dy}, x2{x + dx}; is_digit(get(y2, x2))) {
while (is_digit(get(y2, x2 - 1))) {
--x2;
}
if (const Point adj{y2, x2}; ranges::find(points, adj) == points.end()) {
points.push_back(adj);
numbers.push_back(parse_int(y2, x2));
[[nodiscard]]
auto adjacent_numbers(Vec2 center) const {
std::unordered_set<Vec2> visited;
for (Vec2 d(-1, -1); d.y() <= 1; d.y() += 1) {
for (d.x() = -1; d.x() <= 1; d.x() += 1) {
if (Vec2 p{center + d}; is_digit(cells.at(p))) {
while (is_digit(get(p - Vec2(1, 0)))) {
p.x() -= 1;
}
visited.insert(p);
}
}
}
return numbers;
return views::transform(visited, [&](Vec2 p) { return parse_number_at(p); })
| ranges::to<std::vector>();
}
};

std::istream& operator>>(std::istream& is, Grid& grid) {
Grid g{};
for (std::string line; std::getline(is, line); ++g.height) {
g.width = line.size();
for (std::istringstream ls{line}; ls;) {
if (Grid::Cell c; ls >> c) {
g.cells.push_back(c);
}
}
}
if (is or is.eof()) {
grid = g.pad();
return is;
}
throw std::runtime_error("failed parsing Grid");
}

constexpr auto sum{std::__bind_back(ranges::fold_left, 0, std::plus{})};
constexpr auto product{std::__bind_back(ranges::fold_left, 1, std::multiplies{})};

constexpr std::pair<int, int> search(const Grid& grid) {
auto search(const Grid& grid) {
int part1{};
int part2{};
for (const auto& p : grid.iter_yx_with_padding(1UZ)) {
const auto& [y, x] = p;
if (const auto cell{grid.get(y, x)}; grid.is_symbol(cell)) {
if (const auto adj{grid.adjacent_numbers(p)}; not adj.empty()) {
for (auto&& [pos, cell] : grid.cells) {
if (is_symbol(cell)) {
if (const auto adj{grid.adjacent_numbers(pos)}; not adj.empty()) {
part1 += sum(adj);
if (grid.is_gear(cell) and adj.size() == 2) {
part2 += adj[0] * adj[1];
if (is_gear(cell) and adj.size() == 2) {
part2 += product(views::take(adj, 2));
}
}
}
}
return {part1, part2};
return std::pair{part1, part2};
}

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

Grid parse_grid(std::string_view path) {
Grid grid;
input >> grid;
{
Vec2 p;
for (const auto& line : aoc::slurp_lines(path)) {
p.x() = 0;
for (char ch : line) {
grid.cells[p] = ch;
p.x() += 1;
}
p.y() += 1;
}
}
return grid;
}

const auto [part1, part2] = search(grid);
int main() {
const auto [part1, part2]{search(parse_grid("/dev/stdin"))};
std::println("{} {}", part1, part2);

return 0;
}
13 changes: 6 additions & 7 deletions src/2023/04.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ std::istream& operator>>(std::istream& is, Wins& w) {
using aoc::skip;
using std::operator""s;

if (unsigned id; is >> skip("Card"s) >> id >> skip(":"s)) {
if (unsigned id{}; is >> skip("Card"s) >> id >> skip(":"s)) {
if (std::string tmp; std::getline(is, tmp, '|') and not tmp.empty()) {
std::istringstream win_str{tmp};
const auto win{views::istream<int>(win_str) | ranges::to<std::unordered_set>()};
Expand All @@ -36,16 +36,16 @@ std::istream& operator>>(std::istream& is, Wins& w) {
constexpr auto sum{std::__bind_back(ranges::fold_left, 0, std::plus{})};

auto find_part1(const auto& wins) {
auto points{wins | views::filter(std::identity{}) | views::transform([](const auto w) {
return 1 << (w - 1);
auto points{wins | views::filter([](long wc) { return wc > 0; }) | views::transform([](long wc) {
return 1 << (wc - 1);
})};
return sum(points);
}

auto find_part2(const auto& wins) {
std::vector<long> cards(wins.size(), 1);
auto card{cards.begin()};
for (auto win_count : wins) {
for (long win_count : wins) {
ranges::transform(
views::repeat(*card, win_count),
ranges::subrange(++card, cards.end()),
Expand All @@ -57,10 +57,9 @@ auto find_part2(const auto& wins) {
}

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

const auto wins{
views::istream<Wins>(input) | views::transform(&Wins::count) | ranges::to<std::vector>()
aoc::parse_items<Wins>("/dev/stdin") | views::transform(&Wins::count)
| ranges::to<std::vector>()
};

const auto part1{find_part1(wins)};
Expand Down
Loading

0 comments on commit a071b45

Please sign in to comment.