#include <iostream>
#include <vector>
#include <string>
using namespace std;

typedef vector<char> Board;

Board makeBoard() {
    /* A 3x3 board is represented as a list of 9 elements.
    * We will use the following numbering to locate a square
    *  0 | 1 | 2
    * ---|---|---
    *  3 | 4 | 5
    * ---|---|---
    *  6 | 7 | 8
    */
    return Board (9, ' ');
}

void display (const Board& board) {
    for (int i = 0; i < 9; i += 3) {
        if (i > 0)
            printf ("---|---|---\n");
        printf (" %c | %c | %c \n",
                board[i], board[i+1], board[i+2]);
    }
    cout << endl;
}

char opponent(const char player) {
    if (player == 'X')
        return 'O';
    else
        return 'X';
}

template<class itemType>
itemType choice (const vector<itemType>& vec) {
    int i = rand() % vec.size();
    return vec[i];
}

vector<int> possibleMoves(const Board& board, char player) {
    vector<int> moves (0);
    for (int i = 0; i < 9; i++)
        if (board[i] == ' ')
            moves.push_back(i);
    return moves;
}

bool gameOver(const Board& board, char player) {
    return possibleMoves(board, player).size() == 0;
}

void applyMove (Board& board, char player, int square) {
    board[square] = player;
}

// These square triples represent wins (three in a row).
int WINS[][3] = {{0, 1, 2},{3, 4, 5},{6, 7, 8},      // the rows
    {0, 3, 6},{1, 4, 7},{2, 5, 8},                   // the columns
    {0, 4, 8},{2, 4, 6}};                            // diagonals

string winner(const Board& board) {
    for (int win = 0; win < 8; win++) {
        char posWinner = board[WINS[win][0]]; //possible winner
        if (posWinner != ' ' &&
            posWinner == board[WINS[win][1]] &&
            posWinner == board[WINS[win][2]])
            return string(1, posWinner);
    }

    // No winner yet, are there empty squares left?
    for (int i = 0; i < 9; i++)
        if (board[i] == ' ')
            return " ";
    // The board is full and no one has three in a row
    return "Tie";
}

int openWins(const Board& board, char player) {
    int possWins = 0;
    for (int pos = 0; pos < 8; pos++) {
        int n = 0;
        for (int i = 0; i < 3; i++)
            if ((board[WINS[pos][i]] == player) ||
                (board[WINS[pos][i]] == ' '))
                n++;
        if (n == 3) possWins++;
    }
    return possWins;
}

char You = 'X';
char Me = 'O';

int INFINITY = 10;
int evaluate(const Board& board, char player) {
    // if board is a win for player, return INFINITY
    char piece = winner(board)[1];
    if (piece == Me)
        return INFINITY;
    else if (piece == You)
        return -INFINITY;
            else
            return openWins(board,Me) - openWins(board,You);
}

int maxIndex (const vector<int>& vec) {
    int i = 0;
    int greatest = -INFINITY;
    for (int j = 0; j < vec.size(); j++) {
        if (vec[j] > greatest) {
            greatest = vec[j];
            i = j;
        }
    }
    return i;
}

int lookahead(const Board& board, char player,
              bool MAX, int level) {
    vector<int> moves = possibleMoves(board, player);
    if (level <= 0 || moves.size()==0) // limit of look ahead
        return evaluate(board, player);

    int V;
    if (MAX) {			// computerŐs move
        V = -INFINITY;
        for (int m = 0; m < moves.size(); m++) {
            Board b (board);
            b[moves[m]] = player;
            V =max(V,
                   lookahead(b,opponent(player),!MAX,level-1));
        }
    } else {				// opponentŐs move
        V = INFINITY;
        for (int m = 0; m < moves.size(); m++) {
            Board b (board);
            b[moves[m]] = player;
            V =min(V,
                   lookahead(b,opponent(player),!MAX,level-1));
        }
    }
    return V;
}

int LEVEL = 9;
int bestMove(const Board& board, char player,
             vector<int> moves) {
    vector<int> scores (0);
    for (int m = 0; m < moves.size(); m++) {
        Board b (board);
        b[moves[m]] = player;
        scores.push_back(
                         lookahead(b,opponent(player),false,LEVEL-1));
    }
return moves[maxIndex(scores)];
}

void move(Board& board, char player) {
    int square;

    if (player == You) {   // user's move?
        cout << "Enter your move: ";
        cin >> square;
        square--;
    } else {               // my turn
                           // player is the computer, make a random choice
//        square = choice(possibleMoves(board, player));
        square = bestMove(board, player, possibleMoves(board, player));
    }
    // place player's piece on the chosen square
    applyMove(board, player, square);
}


void play() {
    // Initialize board
    Board board = makeBoard();
    // set who moves first/next: X always moves first
    char player = 'X';
    // Display the initial board
    display(board);
    // The game loop

    while (winner(board) == " " &&
           !gameOver(board, player)) {
        move(board, player);
        display(board);
        player = opponent(player);
    }


    // game over, show outcome
    string winningPiece = winner(board);
    if (winningPiece != "Tie")
        cout << winningPiece << " won.\n";
    else
        cout << "It is a tie.\n";
}

int main ()
{
    play();

    return 0;
}

