#include <iostream>
#include <stdlib.h>
using namespace std;

enum players {
    NO_PLAYER = 0,
    PLAYER_1,
    PLAYER_2
};

int board[3][3];

void initBoard() {
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
            board[i][j] = NO_PLAYER;
}

bool sameValueOnRow(int r, int *value) {
    if (board[r][0] == board[r][1] && board[r][1] == board[r][2]) {
        *value = board[r][0];
        return true;
    } else
        return false;
}

bool sameValueOnColumn(int c, int *value) {
    if (board[0][c] == board[1][c] && board[1][c] == board[2][c]) {
        *value = board[0][c];
        return true;
    } else
        return false;
}

bool sameValueFirstDiagonal(int *value) {
    if (board[0][0] == board[1][1] && board[1][1] == board[2][2]) {
        *value = board[0][0];
        return true;
    } else return false;
}

bool sameValueSecondDiagonal(int *value) {
    if (board[0][2] == board[1][1] && board[1][1] == board[2][0]) {
        *value = board[0][2];
        return true;
    } else return false;
}

void validMoves(bool moves[3][3], int forPlayer) {
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
            moves[i][j] = board[i][j] == NO_PLAYER;
}

bool isWinning(int *winner, int currentPlayer) {
    int v;
    bool moves[3][3];

    for (int i = 0; i < 3; i++) {
        if (sameValueOnRow(i,&v))
            if (v != NO_PLAYER) {
                *winner = v;
                return true;
            }
        if (sameValueOnColumn(i,&v))
            if (v != NO_PLAYER) {
                *winner = v;
                return true;
            }
    }
    if (sameValueFirstDiagonal(&v))
        if (v != NO_PLAYER) {
            *winner = v;
            return true;
        }
    if (sameValueSecondDiagonal(&v))
        if (v != NO_PLAYER) {
            *winner = v;
            return true;
        }
    
    validMoves(moves, currentPlayer);
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
            if (moves[i][j]) return false;

    *winner = NO_PLAYER;
    return true;
}

void playMove(int i, int j, int forPlayer) {
    board[i][j] = forPlayer;
}

void displayBoard() {
    cout << " |0|1|2|" << endl;
    cout << "--------" << endl;
    for (int i = 0; i < 3; i++) {
        cout << i << "|";
        for (int j = 0; j < 3; j++) {
            if (board[i][j] == NO_PLAYER)
                cout << ' ';
            else if (board[i][j] == PLAYER_1)
                cout << 'X';
            else
                cout << 'O';
            cout << '|';
        }
        cout << endl;
        cout << "--------" << endl;
    }
}

void displayBoardWithMoves(bool moves[3][3]) {
    int n = 0;
    cout << " |0|1|2|" << endl;
    cout << "--------" << endl;
    for (int i = 0; i < 3; i++) {
        cout << i << "|";
        for (int j = 0; j < 3; j++) {
            if (board[i][j] == NO_PLAYER)
                if (moves[i][j]) {
                    cout << n;
                    n++;
                } else
                    cout << ' ';
            else if (board[i][j] == PLAYER_1)
                cout << 'X';
            else
                cout << 'O';
            cout << '|';
        }
        cout << endl;
        cout << "--------" << endl;
    }
}

int numberOfMoves(bool moves[3][3]) {
    int n = 0;
    for (int k = 0; k < 3; k++)
        for (int l = 0; l < 3; l++)
            if (moves[k][l]) n++;
    return n;
}

void getNthMove(bool moves[3][3], int n, int *i, int *j) {
     for (int k = 0; k < 3; k++)
        for (int l = 0; l < 3; l++)
            if (moves[k][l]) {
                if (n == 0) {
                    *i = k;
                    *j = l;
                    return;
                }
                n--;
            }
}

void requestMove(bool moves[3][3], int *i, int *j, int forPlayer) {
    while(true) {
        int n = 0;
        cout << "Player " << forPlayer << " please select a move between" << endl;
        displayBoardWithMoves(moves);
        cout << "Number of selected move: ";
        cin >> n;
        if (n < 0 || n > numberOfMoves(moves)) {
            cout << "Invalid move" << endl;
        } else {
            getNthMove(moves, n, i, j);
            break;
        }
    }
}

void randomMove(bool moves[][3], int *i, int *j) {
    getNthMove(moves, rand() % numberOfMoves(moves), i, j);
}

void simulate() {
    int win1,win2,draw, n, winner, currentPlayer = PLAYER_1;
    win1 = win2 = draw = 0;
    cout << "How many rounds should be simulated ?" << endl;
    cin >> n;
    for (int i = 0; i < n; i++) {
        initBoard();
        while(!isWinning(&winner,currentPlayer)) {
            int i,j;
            bool moves[3][3];

            validMoves(moves,currentPlayer);
            randomMove(moves,&i,&j);
            playMove(i,j,currentPlayer);

            if (currentPlayer == PLAYER_1)
                currentPlayer = PLAYER_2;
            else currentPlayer = PLAYER_1;
        }
        if (winner == NO_PLAYER) draw++;
        else if (winner == PLAYER_1) win1++;
        else win2++;
    }

    cout << "Win 1 " << (float)win1/n << endl;
    cout << "Win 2 " << (float)win2/n << endl;
    cout << "Draw " << (float)draw/n << endl;
}
 
int main() {
    int winner;
    int currentPlayer = PLAYER_1;
    bool humanPlayer1, humanPlayer2;

    srand(time(NULL));

    simulate();
   
    cout << "Welcome to TicTacToe" << endl;
    cout << "Should Player 1 be human ? (0 for no, 1 for yes)" << endl;
    cin >> humanPlayer1;
    cout << "Should Player 2 be human ? (0 for no, 1 for yes)" << endl;
    cin >> humanPlayer2;

    initBoard();
    while(!isWinning(&winner,currentPlayer)) {
        bool moves[3][3];
        int i,j;

        displayBoard();
        validMoves(moves, currentPlayer); 
        if ((currentPlayer == PLAYER_1 && humanPlayer1) ||
                (currentPlayer == PLAYER_2 && humanPlayer2))
            requestMove(moves,&i,&j,currentPlayer);
        else
            randomMove(moves,&i,&j);
        playMove(i, j, currentPlayer);

        if (currentPlayer == PLAYER_1)
            currentPlayer = PLAYER_2;
        else currentPlayer = PLAYER_1;
    }
    displayBoard();
    if (winner == NO_PLAYER)
        cout << "This is a draw!" << endl;
    else
        cout << "Player " << winner << " has won" << endl;
}
