day06b.cpp (3934B)
1 /* 2 This is quite inefficient, but it still gives the right answer in less 3 than a minute (25 seconds on my old laptop). 4 */ 5 6 #include <iostream> 7 #include <algorithm> 8 #include <string> 9 #include <string_view> 10 #include <vector> 11 using namespace std; 12 13 enum Direction { U = 0, D, R, L }; 14 Direction all_directions[] = { 15 Direction::U, Direction::D, Direction::R, Direction::L, 16 }; 17 18 pair<int, int> step(pair<int, int> p, Direction d) { 19 auto [i, j] = p; 20 21 switch (d) { 22 case Direction::U: 23 return make_pair(i-1, j); 24 case Direction::D: 25 return make_pair(i+1, j); 26 case Direction::R: 27 return make_pair(i, j+1); 28 case Direction::L: 29 return make_pair(i, j-1); 30 } 31 32 return make_pair(-999,-999); 33 } 34 35 Direction turn(Direction d) { 36 switch (d) { 37 case Direction::U: 38 return Direction::R; 39 case Direction::D: 40 return Direction::L; 41 case Direction::R: 42 return Direction::D; 43 case Direction::L: 44 return Direction::U; 45 } 46 47 return Direction::U; 48 } 49 50 class Board { 51 public: 52 const char out_of_bound = '$'; 53 int M, N; 54 55 Board(vector<string> &lines) { 56 N = lines.size(); 57 M = 0; 58 for (string l : lines) 59 M = max(M, (int)l.size()); 60 61 cells = new char[M * N]; 62 visited = new int[M * N]; 63 for (int i = 0; i < N; i++) { 64 for (int j = 0; j < M; j++) { 65 cells[M*i + j] = j < (int)lines[i].size() ? 66 lines[i][j] : out_of_bound; 67 visited[M*i + j] = 0; 68 } 69 } 70 } 71 72 ~Board() { 73 delete []cells; 74 delete []visited; 75 } 76 77 char operator[](pair<int, int> p) { 78 int c = coord(p); 79 return c == -1 ? out_of_bound : cells[c]; 80 } 81 82 bool is_visited(pair<int, int> p, Direction d) { 83 return get_vmask(p) & (1 << d); 84 } 85 86 void set_visited(pair<int, int> p, Direction d) { 87 toggle_vmask(p, d); 88 } 89 90 void clear_visited() { 91 for (int i = 0; i < N; i++) 92 for (int j = 0; j < M; j++) 93 set_vmask(make_pair(i, j), 0); 94 } 95 96 bool is_obstruction(pair<int, int> p) { 97 return (*this)[p] == '#'; 98 } 99 100 void set_obstruction(pair<int, int> p) { 101 set_cell(p, '#'); 102 } 103 104 void set_clean(pair<int, int> p) { 105 set_cell(p, '.'); 106 } 107 108 private: 109 char *cells; 110 int *visited; 111 112 int coord(pair<int, int> p) { 113 auto [i, j] = p; 114 return i >= N || i < 0 || j >= M || j < 0 ? -1 : M*i + j; 115 } 116 117 void set_cell(pair<int, int> p, char c) { 118 int i = coord(p); 119 cells[i] = c; 120 } 121 122 int get_vmask(pair<int, int> p) { 123 int i = coord(p); 124 return visited[i]; 125 } 126 127 void set_vmask(pair<int, int> p, int x) { 128 int i = coord(p); 129 visited[i] = x; 130 } 131 132 void toggle_vmask(pair<int, int> p, Direction d) { 133 int i = coord(p); 134 visited[i] ^= 1 << d; 135 } 136 }; 137 138 Direction guard_direction(char c) { 139 switch (c) { 140 case '^': 141 return Direction::U; 142 case 'v': 143 return Direction::D; 144 case '>': 145 return Direction::R; 146 case '<': 147 return Direction::L; 148 } 149 150 return Direction::U; 151 } 152 153 pair<pair<int, int>, Direction> find_guard(Board &board) { 154 pair<int, int> p(0, 0); 155 for (p.first = 0; p.first < board.N; p.first++) { 156 for (p.second = 0; p.second < board.M; p.second++) { 157 if (board[p] != '.' && board[p] != '#') { 158 Direction d = guard_direction(board[p]); 159 return make_pair(p, d); 160 } 161 } 162 } 163 164 return make_pair(make_pair(-999, -999), Direction::U); 165 } 166 167 bool isloop(pair<int, int> i, pair<int, int> p, Direction d, Board &board) { 168 bool ret = false; 169 170 board.set_obstruction(i); 171 172 while (true) { 173 auto q = step(p, d); 174 if (board.is_visited(p, d)) { 175 ret = true; 176 break; 177 } 178 board.set_visited(p, d); 179 180 if (board[q] == board.out_of_bound) 181 break; 182 183 if (board.is_obstruction(q)) { 184 d = turn(d); 185 } else { 186 p = q; 187 } 188 } 189 190 board.clear_visited(); 191 board.set_clean(i); 192 193 return ret; 194 } 195 196 int main() { 197 string line; 198 vector<string> lines; 199 while (getline(cin, line)) 200 lines.push_back(line); 201 202 Board board(lines); 203 204 int tot = 0; 205 auto [p, d] = find_guard(board); 206 207 pair i(0, 0); 208 for (i.first = 0; i.first < board.N; i.first++) 209 for (i.second = 0; i.second < board.M; i.second++) 210 if (board[i] == '.') 211 tot += isloop(i, p, d, board); 212 213 cout << tot << endl; 214 215 return 0; 216 }