aoc

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

day16a.cpp (3566B)


      1 #include <algorithm>
      2 #include <cstdint>
      3 #include <iostream>
      4 #include <queue>
      5 #include <string>
      6 #include <string_view>
      7 #include <vector>
      8 #include <set>
      9 using namespace std;
     10 
     11 class Direction {
     12 public:
     13 	int U, R;
     14 
     15 	Direction(char c) :
     16 	    U{c == 'v' ? 1 : (c == '^' ? -1 : 0)},
     17 	    R{c == '>' ? 1 : (c == '<' ? -1 : 0)} {}
     18 
     19 	Direction(const int i, const int j) : U{i}, R{j} {}
     20 
     21 	Direction turnright() const {
     22 		return turn(-1, 0);
     23 	}
     24 
     25 	Direction turnleft() const {
     26 		return turn(1, 0);
     27 	}
     28 
     29 	bool operator<(const Direction& d) const { // For set<Direction>
     30 		return this->U < d.U || (this->U == d.U && this->R < d.R);
     31 	}
     32 
     33 	int index() const {
     34 		if (U == 1 && R == 0) return 0;
     35 		if (U == -1 && R == 0) return 1;
     36 		if (U == 0 && R == 1) return 2;
     37 		if (U == 0 && R == -1) return 3;
     38 		return -1;
     39 	}
     40 private:
     41 	Direction turn(int64_t sin, int64_t cos) const {
     42 		return Direction(cos * U - sin * R, sin * U + cos * R);
     43 	}
     44 };
     45 
     46 class Position {
     47 public:
     48 	int64_t i, j;
     49 
     50 	Position() : Position(0, 0) {}
     51 
     52 	Position(int64_t a, int64_t b) : i{a}, j{b} {}
     53 
     54 	Position step(const Direction d) const {
     55 		return Position(i+d.U, j+d.R);
     56 	}
     57 };
     58 
     59 const Direction all_directions[] = {
     60 	Direction(1, 0), Direction(-1, 0), Direction(0, 1), Direction(0, -1)
     61 };
     62 
     63 class Qelem {
     64 public:
     65 	int64_t distance;
     66 	Position p;
     67 	Direction d;
     68 
     69 	Qelem(int dis, Position pp, Direction dd) :
     70 	    distance{dis}, p{pp}, d{dd} {}
     71 
     72 	bool operator<(const Qelem& other) const {
     73 		return distance > other.distance;
     74 	}
     75 };
     76 
     77 class Board {
     78 public:
     79 	int64_t N, M;
     80 
     81 	Board(const vector<string>& lines) :
     82 	    N{static_cast<int64_t>(lines.size())},
     83 	    M{static_cast<int64_t>(lines[0].size())},
     84 	    cells(M*N), visited(4*M*N)
     85 	{
     86 		for (int64_t i = 0; i < N; i++)
     87 			for (int64_t j = 0; j < M; j++)
     88 				cells[M*i+j] = lines[i][j];
     89 	}
     90 
     91 	char& operator[](const Position p) {
     92 		if (const auto c = coord(p); c == -1)
     93 			return out_of_bound;
     94 		else
     95 			return cells[c];
     96 	}
     97 
     98 	Position find_S() {
     99 		for (Position p(0, 0); p.i < N; p.i++)
    100 			for (p.j = 0; p.j < M; p.j++)
    101 				if ((*this)[p] == 'S')
    102 					return p;
    103 		return Position(-1, -1);
    104 	}
    105 
    106 	int shortest_path(Position p, Direction d) {
    107 		clear_visited();
    108 		priority_queue<Qelem> q;
    109 
    110 		q.push(Qelem(0, p, d));
    111 
    112 		while (!q.empty()) {
    113 			auto e = q.top();
    114 			q.pop();
    115 
    116 			if ((*this)[e.p] == 'E')
    117 				return e.distance;
    118 
    119 			if (is_visited(e.p, e.d) || (*this)[e.p] == '#')
    120 				continue;
    121 			set_visited(e.p, e.d);
    122 
    123 			q.push(Qelem(e.distance+1000, e.p, e.d.turnright()));
    124 			q.push(Qelem(e.distance+1000, e.p, e.d.turnleft()));
    125 			q.push(Qelem(e.distance+1, e.p.step(e.d), e.d));
    126 		}
    127 		return 999999999;
    128 	}
    129 
    130 	void print() {
    131 		for (Position p(0, 0); p.i < N; p.i++) {
    132 			for (p.j = 0; p.j < M; p.j++)
    133 				cout << (*this)[p];
    134 			cout << endl;
    135 		}
    136 	}
    137 private:
    138 	char out_of_bound = '$';
    139 
    140 	vector<char> cells;
    141 	vector<bool> visited;
    142 
    143 	int64_t coord(const Position p) const {
    144 		auto [i, j] = p;
    145 		return i >= N || i < 0 || j >= M || j < 0 ? -1 : M * i + j;
    146 	}
    147 
    148 	void clear_visited() {
    149 		for (int64_t i = 0; i < 4*M*N; i++)
    150 			visited[i] = false;
    151 	}
    152 
    153 	bool is_visited(const Position p, const Direction d) {
    154 		if (const auto c = coord(p); c == -1)
    155 			return false;
    156 		else
    157 			return visited[4*c + d.index()];
    158 	}
    159 
    160 	void set_visited(const Position p, const Direction d) {
    161 		if (const auto c = coord(p); c != -1)
    162 			visited[4*c + d.index()] = true;
    163 	}
    164 };
    165 
    166 int main() {
    167 	string line;
    168 	vector<string> lines;
    169 
    170 	while (getline(cin, line))
    171 		lines.push_back(line);
    172 
    173 	Board board(lines);
    174 	Direction d('>');
    175 	Position p = board.find_S();
    176 
    177 	cout << board.shortest_path(p, d) << endl;
    178 
    179 	return 0;
    180 }