#include <cassert>

#include "board.h"

// ===========
// CONSTRUCTOR

Board::Board(int n) {
  // initialize the board
  size = n;
  board = std::vector<std::vector<char> > (n, std::vector<char>(n, '.'));
  // x always goes first!
  next = 'x';
}


// =========
// ACCESSORS

// return a vector of pairs representing all open space son the board
std::vector<std::pair<int,int> > Board::Open() const {
  std::vector<std::pair<int,int> > answer;
  // if the game has a winner, there are no legal plays
  if (Winner() != '.') return answer;
  for (int i = 0; i < size; i++) {
    for (int j = 0; j < size; j++) {
      if (board[i][j] == '.')
	answer.push_back(std::make_pair(i,j));
    }
  }
  return answer;
}

char Board::Winner() const {
  // look for a winner along one of the two diagonals, or any row or
  // any column
  char diag_winner = board[0][0];
  char diag2_winner = board[size-1][0];
  bool diag_good = (diag_winner != '.');
  bool diag2_good = (diag2_winner != '.');
  for (int i = 0; i < size; i++) {
    if (diag_winner != board[i][i]) diag_good = false;
    if (diag2_winner != board[size-1-i][i]) diag2_good = false;
    char row_winner = board[0][i];
    char col_winner = board[i][0];
    bool row_good = (row_winner != '.');
    bool col_good = (col_winner != '.');
    for (int j = 1; j < size; j++) {
      if (row_winner != board[j][i]) row_good = false;
      if (col_winner != board[i][j]) col_good = false;
    }
    if (row_good) return row_winner;
    if (col_good) return col_winner;
  }
  if (diag_good) return diag_winner;
  if (diag2_good) return diag2_winner;
  // otherwise there is no winner yet
  return '.';
}

bool Board::same_no_rotation_or_flips(const Board &b) const {
  for (int i = 0; i < size; i++) {
    for (int j = 0; j < size; j++) {
      if (board[i][j] != b.board[i][j]) return false;
    }
  }
  return true;
}


// =========
// MODIFIERS

// add a token to the board at the specified location
bool Board::Place(char c, std::pair<int,int> location) {
  if (next != c) return false;
  if (board[location.first][location.second] != '.') return false;
  board[location.first][location.second] = c;
  if (c == 'x') {
    next = 'o';
  } else {
    assert (c == 'o');
    next = 'x';
  }
  return true;
}


// =====
// PRINT

// print out the board and the winner
std::ostream& operator<<(std::ostream &ostr, const Board &b) {
  for (int i = 0; i < b.size; i++) {
    ostr << "  ";
    for (int j = 0; j < b.size; j++) {
      ostr << b.board[i][j];
    }
    ostr << "\n";
  }
  char winner = b.Winner();
  if (winner != '.') ostr << "result: " << winner << " wins\n";
  else if (b.Open().size() == 0) ostr << "result: draw\n";
  return ostr;
}
