aoc

My solutions for the Advent of Code
git clone https://git.tronto.net/aoc
Download | Log | Files | Refs | README

day15b.cpp (3835B)


      1 /*
      2 The code here is not great, but I don't feel like cleaning it up
      3 */
      4 
      5 #include <iostream>
      6 #include <cstdint>
      7 #include <algorithm>
      8 #include <string>
      9 #include <string_view>
     10 #include <vector>
     11 #include <set>
     12 using namespace std;
     13 
     14 class Direction {
     15 public:
     16 	const int U, R;
     17 
     18 	Direction(char c) :
     19 	    U{c == 'v' ? 1 : (c == '^' ? -1 : 0)},
     20 	    R{c == '>' ? 1 : (c == '<' ? -1 : 0)} {}
     21 
     22 	Direction(const int i, const int j) : U{i}, R{j} {}
     23 
     24 	Direction turnright() const {
     25 		return turn(-1, 0);
     26 	}
     27 
     28 	Direction turnleft() const {
     29 		return turn(1, 0);
     30 	}
     31 
     32 	bool operator<(const Direction& d) const { // For set<Direction>
     33 		return this->U < d.U || (this->U == d.U && this->R < d.R);
     34 	}
     35 private:
     36 	Direction turn(int64_t sin, int64_t cos) const {
     37 		return Direction(cos * U - sin * R, sin * U + cos * R);
     38 	}
     39 };
     40 
     41 class Position {
     42 public:
     43 	int64_t i, j;
     44 
     45 	Position() : Position(0, 0) {}
     46 
     47 	Position(int64_t a, int64_t b) : i{a}, j{b} {}
     48 
     49 	Position step(const Direction d) const {
     50 		return Position(i+d.U, j+d.R);
     51 	}
     52 };
     53 
     54 const Direction all_directions[] = {
     55 	Direction(1, 0), Direction(-1, 0), Direction(0, 1), Direction(0, -1)
     56 };
     57 
     58 class Board {
     59 public:
     60 	int64_t N, M;
     61 	Position robot;
     62 
     63 	Board(const vector<string>& lines) :
     64 	    N{static_cast<int64_t>(lines.size())},
     65 	    M{static_cast<int64_t>(lines[0].size())},
     66 	    cells(M*N)
     67 	{
     68 		for (int64_t i = 0; i < N; i++) {
     69 			for (int64_t j = 0; j < M; j++) {
     70 				cells[M*i+j] = lines[i][j];
     71 				if (lines[i][j] == '@')
     72 					robot = Position(i, j);
     73 			}
     74 		}
     75 	}
     76 
     77 	char& operator[](const Position p) {
     78 		if (const auto c = coord(p); c == -1)
     79 			return out_of_bound;
     80 		else
     81 			return cells[c];
     82 	}
     83 
     84 	void move_robot(const Direction d) {
     85 		if (move(robot, d))
     86 			robot = robot.step(d);
     87 	}
     88 
     89 	int64_t gps() {
     90 		int64_t tot = 0;
     91 		for (Position p(0, 0); p.i < N; p.i++)
     92 			for (p.j = 0; p.j < M; p.j++)
     93 				if ((*this)[p] == '[')
     94 					tot += 100*p.i + p.j;
     95 		return tot;
     96 	}
     97 
     98 	void print() {
     99 		for (Position p(0, 0); p.i < N; p.i++) {
    100 			for (p.j = 0; p.j < M; p.j++)
    101 				cout << (*this)[p];
    102 			cout << endl;
    103 		}
    104 	}
    105 private:
    106 	char out_of_bound = '$';
    107 
    108 	vector<char> cells;
    109 
    110 	int64_t coord(const Position p) const {
    111 		auto [i, j] = p;
    112 		return i >= N || i < 0 || j >= M || j < 0 ? -1 : M * i + j;
    113 	}
    114 
    115 	bool move(Position p, Direction d) {
    116 		return d.U == 0 ? move_h(p, d) : move_v(p, d);
    117 	}
    118 
    119 	bool move_h(Position p, Direction d) {
    120 		auto q = p.step(d);
    121 		switch ((*this)[q]) {
    122 		case '.':
    123 			(*this)[q] = (*this)[p];
    124 			(*this)[p] = '.';
    125 			return true;
    126 		case '[':
    127 		case ']':
    128 			return move(q, d) ? move(p, d) : false;
    129 		default:
    130 			return false;
    131 		}
    132 	}
    133 
    134 	bool move_v(Position p, Direction d) {
    135 		if (!isfree_v(p, d))
    136 			return false;
    137 
    138 		auto q = p.step(d);
    139 		if ((*this)[q] == '[') {
    140 			move_v(q, d);
    141 			move_v(q.step(Direction('>')), d);
    142 		}
    143 		if ((*this)[q] == ']') {
    144 			move_v(q, d);
    145 			move_v(q.step(Direction('<')), d);
    146 		}
    147 		(*this)[q] = (*this)[p];
    148 		(*this)[p] = '.';
    149 		return true;
    150 	}
    151 
    152 	bool isfree_v(Position p, Direction d) {
    153 		auto q = p.step(d);
    154 		switch ((*this)[q]) {
    155 		case '.':
    156 			return true;
    157 		case ']':
    158 			return isfree_v(q, d) &&
    159 			       isfree_v(q.step(Direction('<')), d);
    160 		case '[':
    161 			return isfree_v(q, d) &&
    162 			       isfree_v(q.step(Direction('>')), d);
    163 		default:
    164 			return false;
    165 		}
    166 		if ((*this)[q] == '.')
    167 			return true;
    168 	}
    169 };
    170 
    171 int main() {
    172 	string line;
    173 	vector<string> lines;
    174 
    175 	for (getline(cin, line); line.size() > 0; getline(cin, line)) {
    176 		string wideline = "";
    177 		for (const auto& c : line) {
    178 			switch (c) {
    179 			case 'O':
    180 				wideline += "[]";
    181 				break;
    182 			case '@':
    183 				wideline += "@.";
    184 				break;
    185 			default:
    186 				wideline += c;
    187 				wideline += c;
    188 				break;
    189 			}
    190 		}
    191 		lines.push_back(wideline);
    192 	}
    193 	Board board(lines);
    194 
    195 	while (getline(cin, line))
    196 		for (const auto& c : line)
    197 			board.move_robot(Direction(c));
    198 
    199 	cout << board.gps() << endl;
    200 
    201 	return 0;
    202 }