advent2024

Advent of Code 2024
git clone git://bsandro.tech/advent2024
Log | Files | Refs

main.cpp (5450B)


      1 #include <iostream>
      2 #include <filesystem>
      3 #include <fstream>
      4 #include <vector>
      5 #include <cstring>
      6 #include <cstdio>
      7 #include <tuple>
      8 #include <algorithm>
      9 #include <expected>
     10 #include <set>
     11 #include "utils.hpp"
     12 
     13 typedef std::vector<std::string> Data;
     14 typedef std::pair<int, int> Vec2;
     15 
     16 static const std::vector<Vec2> sDirs = {Vec2(0, -1), Vec2(1, 0), Vec2(0, 1), Vec2(-1, 0)};
     17 
     18 
     19 class Plot : public std::set<Vec2> {
     20 public:
     21     bool has(const Vec2 &p) const {
     22         return this->count(p)>0;
     23         //std::count(this->begin(), this->end(), p)>0;
     24     }
     25 
     26     bool addNeighbors(const Data &input, char c) {
     27         const int sz = input.size();
     28         bool inserted = false;
     29         Plot cp(*this);
     30         for (const Vec2 &p : cp) {
     31             for (const Vec2 &dir:sDirs) {
     32                 Vec2 pd(p.first+dir.first, p.second+dir.second);
     33                 if (pd.first>=0&&pd.first<sz&&pd.second>=0&&pd.second<sz) {
     34                     if (input[pd.second][pd.first]==c&&!cp.has(pd)) {
     35                         this->insert(pd);
     36                         inserted = true;
     37                     }
     38                 }
     39             }
     40         }
     41         return inserted;
     42     }
     43 
     44     int64_t area() const { return this->size(); }
     45 
     46     int64_t perimeter() const {
     47         int64_t per = 0;
     48         for (const auto &p : *this) {
     49             int64_t cnt = 4;
     50             for (const Vec2 &dir:sDirs) {
     51                 Vec2 pd(p.first+dir.first, p.second+dir.second);
     52                 if (this->has(pd)) {
     53                     cnt--;
     54                     //std::printf("[%d,%d] has neighbor [%d,%d]\n", p.first, p.second, pd.first, pd.second);
     55                 }
     56             }
     57             //std::printf("(%ld)\n", cnt);
     58             per+=cnt;
     59         }
     60         return per;
     61     }
     62 
     63     int64_t sides() const {
     64         int64_t cnt = 0;
     65         std::vector<Vec2> n,e,s,w;
     66         for (const auto &p : *this) {
     67             if (!this->has(Vec2(p.first+1, p.second))) e.push_back(p);
     68             if (!this->has(Vec2(p.first-1, p.second))) w.push_back(p);
     69             if (!this->has(Vec2(p.first, p.second+1))) s.push_back(p);
     70             if (!this->has(Vec2(p.first, p.second-1))) n.push_back(p);
     71         }
     72         std::sort(n.begin(), n.end(), [](auto &p1, auto &p2){ return p1.second<p2.second/* && p1.first<p2.first*/; });
     73         std::sort(s.begin(), s.end(), [](auto &p1, auto &p2){ return p1.second<p2.second; });
     74         std::sort(e.begin(), e.end(), [](auto &p1, auto &p2){ return p1.first<p2.first; });
     75         std::sort(w.begin(), w.end(), [](auto &p1, auto &p2){ return p1.first<p2.first; });
     76 
     77         std::printf("east:");
     78         for (auto &p:e) {
     79             std::printf("[%d,%d]", p.first, p.second);
     80         }
     81         std::printf("\n");
     82 
     83         int v=-1;
     84         int prev=-1;
     85         for (auto &p : n) {
     86             if (p.second!=v || std::abs(prev-p.first)>1) { cnt++; }
     87             v=p.second;
     88             prev=p.first;
     89         }
     90         v=-1;
     91         prev=-1;
     92         for (auto &p : s) {
     93             if (p.second!=v || std::abs(prev-p.first)>1) cnt++;
     94             v=p.second;
     95             prev=p.first;
     96         }
     97         v=-1;
     98         prev=-1;
     99         for (auto &p : e) {
    100             if (p.first!=v || std::abs(prev-p.second)>1) cnt++;
    101             v=p.first;
    102             prev=p.second;
    103         }
    104         std::printf("north+south+east count:%ld\n", cnt);
    105         v=-1;
    106         prev=-1;
    107         for (auto &p : w) {
    108             if (p.first!=v || std::abs(prev-p.second)>1) cnt++;
    109             v=p.first;
    110             prev=p.second;
    111         }
    112         return cnt;
    113     }
    114 
    115     void print() const {
    116         for (auto &p : *this) {
    117             std::printf("[%d,%d]", p.first, p.second);
    118         }
    119     }
    120 };
    121 // 1046941 too high
    122 // 918855 too high
    123 template<typename T>
    124 T read_file(const std::string &path) {
    125     std::ifstream ifs(path, std::ios::binary);
    126     if (!ifs.is_open()) {
    127         throw std::runtime_error(path+":"+std::strerror(errno));
    128     }
    129     T buf;
    130     while (1) {
    131         std::string str;
    132         std::getline(ifs, str);
    133         if (!str.empty()) buf.push_back(str);
    134         if (!ifs) break;
    135     }
    136     return buf;
    137 }
    138 
    139 Plot findPlot(const Data &input [[ maybe_unused ]], Vec2 start [[ maybe_unused ]]) {
    140     Plot plot;
    141     char c = input[start.second][start.first];
    142     plot.insert(start);
    143     while (plot.addNeighbors(input, c)) {}
    144     return plot;
    145 }
    146 
    147 std::pair<int64_t, int64_t> solve(Data &input [[ maybe_unused ]]) {
    148     int64_t p1sum = 0;
    149     int64_t p2sum = 0;
    150     // square maps only!
    151     Plot processed;
    152     for (int y=0; y<(int)input.size(); ++y) {
    153         for (int x=0; x<(int)input[y].size(); ++x) {
    154             if (!processed.has(Vec2(x, y))) {
    155                 Plot p = findPlot(input, Vec2(x,y));
    156                 processed.insert(p.begin(), p.end());
    157                 std::printf("\n-------------\nfound plot (%c):\n", input[y][x]);
    158                 p.print();
    159                 std::printf("\nsides: %ld\n", p.sides());
    160                 p1sum += p.area() * p.perimeter();
    161                 p2sum += p.area() * p.sides();
    162             }
    163         }
    164     }
    165 
    166     return std::make_pair(p1sum, p2sum);
    167 }
    168 
    169 int main(int argc, char **argv) {
    170     Performance perf;
    171     const std::string fname = argc>1 ? argv[1] : "test1.txt";
    172     std::cout << "AoC 2024 day 12 " << fname << std::endl;
    173     Data input = read_file<Data>(fname);
    174     auto [p1, p2] = solve(input);
    175     std::cout << "part1: " << p1 << std::endl;
    176     std::cout << "part2: " << p2 << std::endl;
    177 
    178     return 0;
    179 }