Skip to content

Instantly share code, notes, and snippets.

@kjelloh
Created January 4, 2021 19:14
Show Gist options
  • Save kjelloh/e46a2b48c740a2abf1f33f0b827e6bae to your computer and use it in GitHub Desktop.
Save kjelloh/e46a2b48c740a2abf1f33f0b827e6bae to your computer and use it in GitHub Desktop.
Advent of Code 2020 day 17 part 1 and 2 :)
//
// main.cpp
// AdventOfCode201217_1
//
// Created by Kjell-Olov Högdal on 2021-01-04.
//
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <array>
#include <unordered_set>
#include <numeric>
#include <algorithm>
#include <cmath>
using Count = std::size_t;
// const Count dimension_count{3}; // Part 1 3D space :)
const Count dimension_count{4}; // Part 2 4D space :)
char const* pExample = R"(.#.
..#
###)";
char const* pData = R"(.#.####.
.#...##.
..###.##
#..#.#.#
#..#....
#.####..
##.##..#
#.#.#..#)";
using Coordinate = int;
using Vector = std::array<Coordinate,dimension_count>;
std::string to_string(Vector const& v) {
std::string init;
bool is_first {true};
auto result = std::accumulate(v.begin(), v.end(), init,[&is_first](auto& acc,auto const& coord){
if (is_first) {is_first = false;} else {acc += ",";}
acc += std::to_string(coord);
return acc;
});
return result;
}
Vector operator+(Vector const& v1,Vector const& v2) {
Vector result{};
for (Coordinate i = 0;i<dimension_count;++i) {
result[i] = (v1[i]+v2[i]);
}
// std::cout << "\n{" << to_string(v1) << "} + {" << to_string(v2) << " = {" << to_string(result) << "}";
return result;
}
bool operator==(Vector const& v1,Vector const& v2) {
std::vector<bool> bool_v;
std::transform(v1.begin(), v1.end(), v2.begin(), std::back_inserter(bool_v), [](auto coord1, auto coord2) {
return (coord1 == coord2);
});
return std::all_of(bool_v.begin(), bool_v.end(), [](auto b) {return b;});
}
using Vectors = std::vector<Vector>;
struct VectorHash {
std::size_t operator()(Vector const& v) const {
return std::hash<std::string>{}(to_string(v));
}
};
using Active = std::unordered_set<Vector,VectorHash>;
using Lines = std::vector<std::string>;
void print_active(Active const& active) {
Vectors vs {};
std::transform(active.begin(), active.end(), std::back_inserter(vs), [](auto const& v) {return v;});
std::sort(vs.begin(), vs.end(), [](auto const& v1,auto const& v2) {
return (v1[2] < v2[2]); // sort on z
});
Vector last_v {vs.back()};
for (auto const& v : vs) {
for (int i = 0;i<dimension_count;++i) {
if (i > 1) {
if (last_v[i] != v[i]) std::cout << "\ndim " << i << " = " << v[i];
}
}
std::cout << "\n\t{" << to_string(v) << "}";
last_v = v;
}
}
class Grid {
public:
explicit Grid(std::istream& in) : m_active{} {
std::string line;
Vector v {};
while (std::getline(in, line)) {
v[0] = 0;
for (auto c : line) {
if (c == '#') m_active.insert(v);
++v[0]; // x coordinate
}
++v[1]; // y coordinate
}
std::cout << "\ninit";
// print_active(m_active);
}
Count operator++() {
static Count count {0};
++count;
std::cout << "\noperator++ iteration " << count;
Active next_active {};
for (auto v : m_active) {
if (is_next_active(v)) {
next_active.insert(v);
}
// Take care of activating inactive cubes (those NOT in m_active)
for (auto delta : m_adjacent_space) {
Vector vn {v+delta};
auto iter = m_active.find(vn);
if (iter == m_active.end()) {
// Bring inactive to life
if (is_next_active(vn)) {
next_active.insert(vn);
}
}
}
}
m_active = std::move(next_active);
// std::cout << "\niteration " << count;
// print_active(m_active);
return count;
}
Count active_count() {return m_active.size();}
private:
Vectors create_adjacent_space() {
Vectors result {};
// Generate all vectors with coordinates -1,0,1 for all dimensions
// as these are the distances to adjacent cubes
// Use base-3 numeration
const Count base{3};
const auto N {std::pow(base,dimension_count)};
for (Count j=0;j<N;++j) {
Vector delta {};
Count k = j;
for (Count i = 0; i < dimension_count;++i) {
auto d = (k % base)-1; // Offset to -1,0,1
k = k / base;
delta[i] = static_cast<Coordinate>(d);
}
if ((delta == Vector{})) {
// std::cout << "\nskip zero delta ";
}
else {
// std::cout << "\n\tdelta " << "{" << to_string(delta) << "}";
result.push_back(delta);
}
}
return result;
}
const Vectors m_adjacent_space {create_adjacent_space()};
Count active_neighbours_count(Vector const& v) {
Count result {0};
for (auto delta : m_adjacent_space) {
Vector vn = v + delta;
if (m_active.find(vn) != m_active.end()) {
++result;
}
}
// std::cout << "\nactive_neighbours_count of {" << to_string(v) << "} is " << result;
return result;
}
bool is_next_active(Vector const& v) {
bool result {false};
auto anc = active_neighbours_count(v);
if (m_active.find(v) != m_active.end()) {
// v is active
result = (anc == 2) or (anc == 3);
}
else {
// v is inactive
result = (anc == 3);
}
/*
std::cout << "\nis_next_active {" << to_string(v) << "}";
if (result) std::cout << " TRUE";
else std::cout << " false";
*/
return result;
}
Active m_active;
};
int main(int argc, const char * argv[]) {
// Refactored from https://github.com/craig-chasseur/aoc2020/blob/main/puzzles/day_17/part1.cc
// Many thanks to Craig Chasseur.
std::basic_istringstream<char> in {pData};
Grid grid {in};
for (int i = 0; i < 6; ++i) {
++grid;
}
std::cout << "\n\nResult = " << grid.active_count();
std::cout << "\n\nBye :)";
std::cout << "\n";
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment