#include <fstream>
#include <iostream>
#include <sstream>
#include <vector>
#include <map>
#include <set>
using namespace std;

void parseGrid(const char *path, vector<vector<char>> &grid) {
  ifstream input(path);

  string line;
  while (getline(input, line)) {
    stringstream line_stream;
    line_stream << line;
    vector<char> line_vec;

    char c;
    while (line_stream >> c) {
      line_vec.push_back(c);
    }

    grid.push_back(line_vec);
  }
}

void printGrid(vector<vector<char>> grid) {
  for (int y = 0; y < grid.size(); y++) {
    for (int x = 0; x < grid[0].size(); x++) {
      cout << grid[y][x] << " ";
    }
    cout << endl;
  }
}

// do one move and save new position in x and y
// returns false if the guard left the grid.
bool move(vector<vector<char>> &grid, int &x_ret, int &y_ret, char &c) {
  for (int y = 0; y < grid.size(); y++) {
    for (int x = 0; x < grid[y].size(); x++) {
      if (grid[y][x] == 'v') {
        // cout << "down" << endl;
        if (y == grid.size() - 1) {
          grid[y][x] = '.';
          x_ret = x;
          y_ret = y;
          c = 'v';
          return true;
        }

        if (grid[y + 1][x] == '#') {
          grid[y][x] = '<';
          x_ret = x;
          y_ret = y;
          c = 'v';
          return true;
        }

        grid[y][x] = '.';
        grid[y + 1][x] = 'v';
        c = 'v';
        x_ret = x;
        y_ret = y;
        return true;
      } else if (grid[y][x] == '^') {
        // cout << "up" << endl;
        if (y == 0) {
          grid[y][x] = '.';
          c = '^';
          x_ret = x;
          y_ret = y;
          return true;
        }

        if (grid[y - 1][x] == '#') {
          grid[y][x] = '>';
          c = '^';
          x_ret = x;
          y_ret = y;
          return true;
        }

        grid[y][x] = '.';
        grid[y - 1][x] = '^';
        c = '^';
        x_ret = x;
        y_ret = y;
        return true;
      } else if (grid[y][x] == '>') {
        // cout << "right" << endl;
        if (x == grid[y].size() - 1) {
          grid[y][x] = '.';
          x_ret = x;
          y_ret = y;
          c = '>';
          return true;
        }

        if (grid[y][x + 1] == '#') {
          grid[y][x] = 'v';
          c = '>';
          x_ret = x;
          y_ret = y;
          return true;
        }

        grid[y][x] = '.';
        grid[y][x + 1] = '>';
        c = '>';
        x_ret = x;
        y_ret = y;
        return true;
      } else if (grid[y][x] == '<') {
        // cout << "left" << endl;
        if (x == 0) {
          grid[y][x] = '.';
          x_ret = x;
          y_ret = y;
          c = '<';
          return true;
        }

        if (grid[y][x - 1] == '#') {
          grid[y][x] = '^';
          c = '<';
          x_ret = x;
          y_ret = y;
          return true;
        }

        grid[y][x] = '.';
        grid[y][x - 1] = '<';
        c = '<';
        x_ret = x;
        y_ret = y;
        return true;
      }
    }
  }
  return false;
}

void part1(const char *path) {
  vector<vector<char>> grid;
  int x;
  int y;
  char c;

  parseGrid(path, grid);

  set<char, greater<char>> visited[grid.size()][grid[0].size()];
  // initialize vector
  for (int y = 0; y < grid.size(); y++) {
    for (int x = 0; x < grid[0].size(); x++) {
      set<char, greater<char>> s;
      visited[y][x] = s;
    }
  }

  int sum = 0;
  while (move(grid, x, y, c)) {
    if (!visited[y][x].size()) {
      sum++;
      visited[y][x].insert(c);
    }
  }

  cout << path << "1: " << sum << endl;
}

bool has_loop(vector<vector<char>> grid) {
  // printGrid(grid);
  int x;
  int y;
  char c;
  set<char, greater<char>> visited[grid.size()][grid[0].size()];
  // initialize vector
  for (int y = 0; y < grid.size(); y++) {
    for (int x = 0; x < grid[0].size(); x++) {
      set<char, greater<char>> s;
      visited[y][x] = s;
    }
  }

  while (move(grid, x, y, c)) {
    // cout << endl;
    // printGrid(grid);
    if (visited[y][x].count(c)) {
      return true;
    }
    visited[y][x].insert(c);
  }

  return false;
}

void part2(const char *path) {
  vector<vector<char>> grid;
  parseGrid(path, grid);

  int sum = 0;
  for (int y = 0; y < grid.size(); y++) {
    for (int x = 0; x < grid[0].size(); x++) {
      // cout << "x= " << x << " y= " << y << endl;
      if (grid[y][x] == '.') {
        grid[y][x] = '#';
        // cout << "before has_loop" << endl;
        if (has_loop(grid)) sum++;
        // cout << "after has_loop" << sum << endl;
        grid[y][x] = '.';
      }
    }
  }
  cout << path << "2: " << sum << endl;
}

int main(int argc, char *argv[]) {
  part1("example");
  part1("input");
  part2("example");
  part2("input");

  return 0;
}