#include <iostream>
#include <string>
#include <climits>
#include <algorithm>
#include <array>
#include <set>
#include <iterator>
#include <numeric>
#include <vector>
#include <cstring>
#include <ctime>
#include <cstdlib>
#include <ctime>
#include <cstdio>
#include <iostream>
#include <locale>
#include <cmath>
#include <iomanip>
#include <unordered_map>
#include <sstream>

using namespace std;

enum class Color { WHITE, BLACK };
enum class Type { KING, QUEEN, ROOK, BISHOP, KNIGHT, PAWN, EMPTY };

class CPosition
{
    public:
        CPosition(long int x, long int y):m_X(x), m_Y(y){};
        CPosition():m_X(-1), m_Y(-1){};

        CPosition(const CPosition &src):m_X(src.m_X), m_Y(src.m_Y){};
        CPosition(CPosition &&src):m_X(src.m_X), m_Y(src.m_Y){};

        CPosition& operator = (const CPosition &src);

        bool operator == (const CPosition &src) const;
        bool operator != (const CPosition &src) const;

        long int m_X;
        long int m_Y;
};

CPosition& CPosition::operator = (const CPosition &src)
{
    if(this == &src) 
        return *this;

    m_X = src.m_X;
    m_Y = src.m_Y;

    return *this;
}

bool CPosition::operator == (const CPosition &src) const
{
    return m_X == src.m_X && m_Y == src.m_Y;
}

bool CPosition::operator != (const CPosition &src) const
{
    return !(*this == src);
}


bool operator < (const CPosition& lhs, const CPosition& rhs) {
    if (lhs.m_X < rhs.m_X) return true;
    if (lhs.m_X > rhs.m_X) return false;
    return lhs.m_Y < rhs.m_Y;
}


class CPiece
{
    public:
        CPiece();
        CPiece(Color color, Type type);
        CPiece(const CPiece& src);

        Color getColor() const;
        Type getType() const;

        void setType(Type type);
        void setColor(Color color);
        

        void print(ostream &os) const;
        friend ostream& operator << (ostream &os, const CPiece &piece);

    private:

        Color  m_Color;
        Type   m_Type;
};

CPiece::CPiece()
: m_Color(Color::WHITE), m_Type(Type::EMPTY)
{
}

CPiece::CPiece(Color color, Type type)
: m_Color(color), m_Type(type)
{
}

CPiece::CPiece(const CPiece& src) 
: m_Color(src.m_Color), m_Type(src.m_Type) 
{}

Color CPiece::getColor() const
{
    return m_Color;
}

Type CPiece::getType() const
{
    return m_Type;
}

void CPiece::setType(Type type)
{
    m_Type = type;
}

void CPiece::setColor(Color color)
{
    m_Color = color;
}


void CPiece::print(ostream &os) const
{
    switch(m_Type) 
    {
         case Type::KING: os << (m_Color == Color::WHITE ? "W\u2654" : "B\u265A"); break;
        case Type::QUEEN: os << (m_Color == Color::WHITE ? "W\u2655" : "B\u265B"); break;
        case Type::ROOK: os << (m_Color == Color::WHITE ? "W\u2656" : "B\u265C"); break;
        case Type::BISHOP: os << (m_Color == Color::WHITE ? "W\u2657" : "B\u265D"); break;
        case Type::KNIGHT: os << (m_Color == Color::WHITE ? "W\u2658" : "B\u265E"); break;
        case Type::PAWN: os << (m_Color == Color::WHITE ? "W\u2659" : "B\u265F"); break;
        case Type::EMPTY: os << "  "; break;
    }

}

ostream& operator << (ostream &os, const CPiece &piece)
{
    piece.print(os);
    return os;
}

class CBoard
{
    public:
        CBoard(long int size);
        CBoard(const CBoard& other) : m_Board(other.m_Board), m_Size(other.m_Size) {};

        void initSimpleChess();
        void init5x5Chess();
        void init4x4Chess();

        vector<CPiece>& operator[](long int index) { return m_Board[index]; }
        const vector<CPiece>& operator[](long int index) const { return m_Board[index]; }

        long int getSize() const;

        void findPossibleMoves(vector<pair<CPosition, CPosition>> &movesWhite, vector<pair<CPosition, CPosition>> &movesBlack, CPosition &whiteKing, CPosition &blackKing);
        void findPieceMoves(vector<pair<CPosition, CPosition>> &movesWhite, vector<pair<CPosition, CPosition>> &movesBlack, long int i, long int j, vector<pair<long int, long int>> changes);

        bool isPieceUnderAttack(const CPosition& position, Color color, vector<pair<CPosition, CPosition>> &whitePlayable, vector<pair<CPosition, CPosition>> &blackPlayable);

        void setQueen(const CPosition &position, Color color);
        void makeMove(CPosition &positionFrom, CPosition &positionTo, Color color);

        void print(ostream &os) const;
        friend ostream& operator<<(ostream &os, const CBoard& board);

    private:
        vector<vector<CPiece>> m_Board;

        long int m_Size;
};

CBoard::CBoard(long int size)
:m_Size(size)
{
    m_Board.resize(m_Size);

    for(long int i = 0; i < m_Size; i++)
        m_Board[i].resize(m_Size);

    if(m_Size == 5)
        init5x5Chess();
    else if (m_Size == 4)
        init4x4Chess();
    else
        initSimpleChess();
}

void CBoard::initSimpleChess()
{
    vector<Type> backRow = { Type::ROOK, Type::KNIGHT, Type::BISHOP, Type::QUEEN, Type::KING, Type::BISHOP };

    for(long int i = 0; i < m_Size; i++)
    {
        m_Board[0][i] = CPiece(Color::WHITE, backRow[i]);
        m_Board[m_Size-1][i] = CPiece(Color::BLACK, backRow[i]);

        m_Board[1][i] = CPiece(Color::WHITE, Type::PAWN);
        m_Board[m_Size-2][i] = CPiece(Color::BLACK, Type::PAWN);   
    }

    for(long int i = 2; i < m_Size - 2; i++) 
    {
        for(long int k = 0; k < m_Size; k++)
        {
            if((i % 2 != 0 && k % 2 == 0) || (i % 2 == 0 && k % 2 != 0))
                m_Board[i][k] = CPiece(Color::BLACK, Type::EMPTY);
            else
                m_Board[i][k] = CPiece(Color::WHITE, Type::EMPTY);
        }
    }
}

void CBoard::init5x5Chess()
{
    vector<Type> backRow = { Type::ROOK, Type::KNIGHT, Type::BISHOP, Type::QUEEN, Type::KING };

    for(long int i = 0; i < m_Size; i++)
    {
        m_Board[0][i] = CPiece(Color::WHITE, backRow[i]);
        m_Board[m_Size-1][i] = CPiece(Color::BLACK, backRow[i]);

        m_Board[1][i] = CPiece(Color::WHITE, Type::PAWN);
        m_Board[m_Size-2][i] = CPiece(Color::BLACK, Type::PAWN);   
    }

    for(long int i = 2; i < m_Size - 2; i++) 
    {
        for(long int k = 0; k < m_Size; k++)
        {
            if((i % 2 != 0 && k % 2 == 0) || (i % 2 == 0 && k % 2 != 0))
                m_Board[i][k] = CPiece(Color::BLACK, Type::EMPTY);
            else
                m_Board[i][k] = CPiece(Color::WHITE, Type::EMPTY);
        }
    }
}


void CBoard::init4x4Chess()
{
    vector<Type> backRow = { Type::ROOK, Type::BISHOP, Type::QUEEN, Type::KING };

    for(long int i = 0; i < m_Size; i++)
    {
        m_Board[0][i] = CPiece(Color::WHITE, backRow[i]);
        m_Board[m_Size-1][i] = CPiece(Color::BLACK, backRow[i]);

        m_Board[1][i] = CPiece(Color::WHITE, Type::PAWN);
        m_Board[m_Size-2][i] = CPiece(Color::BLACK, Type::PAWN);   
    }

    for(long int i = 2; i < m_Size - 2; i++) 
    {
        for(long int k = 0; k < m_Size; k++)
        {
            if((i % 2 != 0 && k % 2 == 0) || (i % 2 == 0 && k % 2 != 0))
                m_Board[i][k] = CPiece(Color::BLACK, Type::EMPTY);
            else
                m_Board[i][k] = CPiece(Color::WHITE, Type::EMPTY);
        }
    }
}


bool CBoard::isPieceUnderAttack(const CPosition& position, Color color, vector<pair<CPosition, CPosition>> &whitePlayable, vector<pair<CPosition, CPosition>> &blackPlayable)
{
    const vector<pair<CPosition, CPosition>>& opponentMoves = (color == Color::WHITE) ? blackPlayable : whitePlayable;

    for (const auto& move : opponentMoves)
    {
        if (move.second == position)
        {
            return true;
        }
    }
    return false;
}

void CBoard::findPieceMoves(vector<pair<CPosition, CPosition>> &movesWhite, vector<pair<CPosition, CPosition>> &movesBlack, long int i, long int j, vector<pair<long int, long int>> changes)
{
    if(m_Board[i][j].getType() == Type::PAWN)
    {
        if(m_Board[i][j].getColor() == Color::WHITE)
        {
            if(i+1 < m_Size && m_Board[i+1][j].getType() == Type::EMPTY)
                movesWhite.push_back({{i,j}, {i+1, j}});
            if(i+1 < m_Size && j+1 < m_Size && m_Board[i+1][j+1].getType() != Type::EMPTY && m_Board[i+1][j+1].getColor() != m_Board[i][j].getColor())
                movesWhite.push_back({{i,j}, {i+1, j+1}});
            if(i+1 < m_Size && j-1 >= 0 && m_Board[i+1][j-1].getType() != Type::EMPTY && m_Board[i+1][j-1].getColor() != m_Board[i][j].getColor())
                movesWhite.push_back({{i,j}, {i+1, j-1}});
            if(i == 1 && m_Board[i+2][j].getType() == Type::EMPTY &&  m_Board[i+1][j].getType() == Type::EMPTY)
                movesWhite.push_back({{i,j}, {i+2, j}});
        }
        else if(m_Board[i][j].getColor() == Color::BLACK)
        {
            if(i-1 >= 0 && m_Board[i-1][j].getType() == Type::EMPTY)
                movesBlack.push_back({{i,j}, {i-1, j}});
            if(i-1 >=0 && j-1 >=0 && m_Board[i-1][j-1].getType() != Type::EMPTY && m_Board[i-1][j-1].getColor() != m_Board[i][j].getColor())
                movesBlack.push_back({{i,j}, {i-1, j-1}});
            if(i-1 >= 0 && j+1 < m_Size && m_Board[i-1][j+1].getType() != Type::EMPTY && m_Board[i-1][j+1].getColor() != m_Board[i][j].getColor())
                movesBlack.push_back({{i,j}, {i-1, j+1}});
            if(i == m_Size-2 && m_Board[i-2][j].getType() == Type::EMPTY && m_Board[i-1][j].getType() == Type::EMPTY)
                movesBlack.push_back({{i,j}, {i-2, j}});
        }

        if(i == m_Size-1 && m_Board[i][j].getColor() == Color::WHITE)
            m_Board[i][j].setType(Type::QUEEN);
        else if(i == 0 && m_Board[i][j].getColor() == Color::BLACK)
            m_Board[i][j].setType(Type::QUEEN);

        return;
    }

    if(m_Board[i][j].getType() == Type::KING)
    {
        for(auto change : changes)
        {
            long int iPos = i+change.first;
            long int jPos = j+change.second; 

            if(iPos < m_Size && iPos >= 0 && jPos < m_Size && jPos >= 0)
            {
                if(m_Board[iPos][jPos].getType() == Type::EMPTY )
                {
                    if(m_Board[i][j].getColor() == Color::WHITE && !isPieceUnderAttack({iPos, jPos}, m_Board[i][j].getColor(), movesWhite, movesBlack))
                        movesWhite.push_back({{i,j},{iPos, jPos}});
                    else if(!isPieceUnderAttack({iPos, jPos}, m_Board[i][j].getColor(), movesWhite, movesBlack))
                        movesBlack.push_back({{i,j},{iPos, jPos}});
                }
                else
                {
                    if(m_Board[i][j].getColor() == Color::WHITE && m_Board[iPos][jPos].getColor() == Color::BLACK && !isPieceUnderAttack({iPos, jPos}, m_Board[i][j].getColor(), movesWhite, movesBlack))
                    {
                        movesWhite.push_back({{i,j},{iPos, jPos}});
                    }
                    else if(m_Board[i][j].getColor() == Color::BLACK && m_Board[iPos][jPos].getColor() == Color::WHITE && !isPieceUnderAttack({iPos, jPos}, m_Board[i][j].getColor(), movesWhite, movesBlack))
                    {
                        movesBlack.push_back({{i,j},{iPos, jPos}});
                    }
                }
            }
        }

        return;
    }

    if(m_Board[i][j].getType() == Type::KNIGHT)
    {
        for(auto change : changes)
        {
            long int iPos = i+change.first;
            long int jPos = j+change.second; 

            if(iPos < m_Size && iPos >= 0 && jPos < m_Size && jPos >= 0)
            {
                if(m_Board[iPos][jPos].getType() == Type::EMPTY )
                {
                    if(m_Board[i][j].getColor() == Color::WHITE)
                        movesWhite.push_back({{i,j},{iPos, jPos}});
                    else
                        movesBlack.push_back({{i,j},{iPos, jPos}});
                }
                else
                {
                    if(m_Board[i][j].getColor() == Color::WHITE && m_Board[iPos][jPos].getColor() == Color::BLACK)
                    {
                        movesWhite.push_back({{i,j},{iPos, jPos}});
                    }
                    else if(m_Board[i][j].getColor() == Color::BLACK && m_Board[iPos][jPos].getColor() == Color::WHITE)
                    {
                        movesBlack.push_back({{i,j},{iPos, jPos}});
                    }
                }
            }
        }

        return;
    }
    
    for(auto change : changes)
    {
        long int iPos = i;
        long int jPos = j;

        while(iPos + change.first < m_Size && iPos + change.first >= 0 && jPos + change.second < m_Size && jPos + change.second >= 0)
        {
            iPos += change.first;
            jPos += change.second;

            if(m_Board[iPos][jPos].getType() == Type::EMPTY)
            {
                if(m_Board[i][j].getColor() == Color::WHITE)
                    movesWhite.push_back({{i, j}, {iPos, jPos}});
                else
                    movesBlack.push_back({{i, j}, {iPos, jPos}});
            }
            else if(m_Board[iPos][jPos].getColor() == m_Board[i][j].getColor())
            {
                break;
            }
            else if(m_Board[iPos][jPos].getColor() != m_Board[i][j].getColor())
            {
                if(m_Board[i][j].getColor() == Color::WHITE)
                {
                    movesWhite.push_back({{i,j}, {iPos, jPos}});
                    break;
                }
                else
                {
                    movesBlack.push_back({{i,j}, {iPos, jPos}});
                    break;
                }
            }
        }
    }
}

void CBoard::findPossibleMoves(vector<pair<CPosition, CPosition>> &movesWhite, vector<pair<CPosition, CPosition>> &movesBlack, CPosition &whiteKing, CPosition &blackKing)
{

    for(long int i=0; i<m_Size; i++)
    {
        for(long int j=0; j<m_Size; j++)
        {
            if(m_Board[i][j].getType() == Type::PAWN)
            {
                findPieceMoves(movesWhite, movesBlack, i, j, {});
            }
            else if(m_Board[i][j].getType() == Type::ROOK)
            {
                findPieceMoves(movesWhite, movesBlack, i, j, {{1, 0}, {-1, 0}, {0, 1}, {0,-1}});
            }
            else if(m_Board[i][j].getType() == Type::QUEEN)
            {
                findPieceMoves(movesWhite, movesBlack, i, j, {{1, 0}, {-1, 0}, {0, 1}, {0,-1}, {1, 1}, {-1,-1}, {1, -1}, {-1, 1}});
            }
            else if(m_Board[i][j].getType() == Type::BISHOP)
            {
                findPieceMoves(movesWhite, movesBlack, i, j, {{1, 1}, {-1,-1}, {-1, 1}, {1, -1}});
            }
            else if(m_Board[i][j].getType() == Type::KNIGHT)
            {
                findPieceMoves(movesWhite, movesBlack, i, j, {{1, 2}, {1, -2}, {2, 1}, {2, -1}, {-1, 2}, {-1, -2}, {-2, 1}, {-2, -1}});
            }
            else if(m_Board[i][j].getType() == Type::KING)
            {
                if(m_Board[i][j].getColor() == Color::WHITE)
                    whiteKing = CPosition(i,j);
                else
                    blackKing =  CPosition(i,j);
                
            }
        }
    }

 //   if(isPieceUnderAttack(whiteKing, Color::WHITE, movesWhite, movesBlack))
 //       movesWhite.clear();

 //   if(isPieceUnderAttack(blackKing, Color::BLACK, movesWhite, movesBlack))
 //       movesBlack.clear();


    findPieceMoves(movesWhite, movesBlack, whiteKing.m_X, whiteKing.m_Y, {{1, 0}, {0, 1}, {1, 1}, {-1, 0}, {0, -1}, {-1, -1}, {-1, 1}, {1, -1}});
    findPieceMoves(movesWhite, movesBlack, blackKing.m_X, blackKing.m_Y, {{1, 0}, {0, 1}, {1, 1}, {-1, 0}, {0, -1}, {-1, -1}, {-1, 1}, {1, -1}});
}

long int CBoard::getSize() const
{
    return m_Size;
}

void CBoard::print(ostream &os) const
{

    // Horizontal line
    os << "   ";
    for (long int i = 0; i < m_Size; ++i) {
        os << "-----";
    }
    os << endl;

    for (long int i = m_Size - 1; i >= 0; --i) {
        os << setw(2) << i << " |"; // Vertical numbering
        for (long int j = 0; j < m_Size; ++j) {
            os << " " << m_Board[i][j] << " |";
        }
        os << endl;

        // Horizontal line
        os << "   ";
        for (long int i = 0; i < m_Size; ++i) {
            os << "-----";
        }
        os << endl;
    }

    os << " ";
    for (long int i = 0; i < m_Size; ++i) {
        os << setw(5) << i;
    }
    os << endl;
}

ostream& operator<<(ostream &os, const CBoard& board)
{
    board.print(os);
    return os;
}

class CGame
{
    public:
        CGame(const size_t size, const Color player, const Color computer);

        void print(ostream &os) const;
        friend ostream& operator << (ostream &os, const CGame &game);

        void loadMove(Color color);
        void makeMove(CPosition &positionFrom, CPosition &positionTo, Color color, bool rec);

        int isFinished();

        void movesNotAttackKing(bool rec, Color onMove);

        void makeRandomMove(Color color);

        void minimaxAlphaBeta(int depth, Color color, bool random);
        int minimaxAlphaBetaAlg(CGame& game, int depth, int alpha, int beta, bool isMaximizingComputer, Color playerColor);

        int evaluateBoard(Color color);

        CBoard m_Board;
        Color  m_Player;
        Color  m_Computer;

        CPosition m_WhiteKing;
        CPosition m_BlackKing;

        vector<pair<CPosition, CPosition>> m_WhitePlayable;
        vector<pair<CPosition, CPosition>> m_BlackPlayable;

};

CGame::CGame(const size_t size, const Color player, const Color computer)
: m_Board(size), m_Player(player), m_Computer(computer)
{
    m_WhitePlayable.clear();
    m_BlackPlayable.clear();

    m_Board.findPossibleMoves(m_WhitePlayable, m_BlackPlayable, m_WhiteKing, m_BlackKing);

}


void CGame::makeMove(CPosition &positionFrom, CPosition &positionTo, Color color, bool rec)
{
    CPiece piece = m_Board[positionFrom.m_X][positionFrom.m_Y];

    m_Board[positionTo.m_X][positionTo.m_Y] = piece;
    m_Board[positionFrom.m_X][positionFrom.m_Y] = CPiece(piece.getColor(), Type::EMPTY);

    m_WhitePlayable.clear();
    m_BlackPlayable.clear();

    m_Board.findPossibleMoves(m_WhitePlayable, m_BlackPlayable, m_WhiteKing, m_BlackKing);

    if(rec)
        movesNotAttackKing(false, color);
    
}

void CGame::movesNotAttackKing(bool rec, Color onMove)
{
    vector<pair<CPosition, CPosition>> tmp;

    if(onMove == Color::BLACK) // tj dalsi tah je BILA
    {
        for(auto x : m_WhitePlayable)
        {
            CGame copy = *this;
            copy.makeMove(x.first, x.second, Color::WHITE, false);

            if(!copy.m_Board.isPieceUnderAttack(copy.m_WhiteKing, Color::WHITE, copy.m_WhitePlayable, copy.m_BlackPlayable))
                tmp.push_back(move(x));
        }

        m_WhitePlayable.clear();
        m_WhitePlayable = tmp;
    }
    else
    {
        for(auto x : m_BlackPlayable)
        {
            CGame copy = *this;
            copy.makeMove(x.first, x.second, Color::BLACK, false);

            if(!copy.m_Board.isPieceUnderAttack(copy.m_BlackKing, Color::BLACK, copy.m_WhitePlayable, copy.m_BlackPlayable))
                tmp.push_back(move(x));
        }

        m_BlackPlayable.clear();
        m_BlackPlayable = tmp;
    }
}


int CGame::isFinished()
{

    if(m_Board.isPieceUnderAttack(m_WhiteKing, Color::WHITE, m_WhitePlayable, m_BlackPlayable) && m_WhitePlayable.empty())
        return 1;
    
    if(m_Board.isPieceUnderAttack(m_BlackKing, Color::BLACK, m_WhitePlayable, m_BlackPlayable) && m_BlackPlayable.empty())
        return 2;

    if(m_BlackPlayable.empty() || m_WhitePlayable.empty())
        return 3;
    
    return 0;
}

void CGame::loadMove(Color color)
{
    size_t input;

    while(cin >> input)
        if((color == Color::WHITE && input >=0 && input < m_WhitePlayable.size()) || (color == Color::BLACK && input >=0 && input < m_BlackPlayable.size()))
            break;

    makeMove(
        (color == Color::WHITE ? m_WhitePlayable[input].first : m_BlackPlayable[input].first),
        (color == Color::WHITE ? m_WhitePlayable[input].second : m_BlackPlayable[input].second),
        (color == Color::WHITE 
            ? (m_Player == Color::WHITE ? m_Player : m_Computer) 
            : (m_Player == Color::BLACK ? m_Player : m_Computer)),
        true
    );

}

void CGame::makeRandomMove(Color color)
{
    srand(time(nullptr));

    if(color == Color::WHITE)
    {
        int random = rand() % m_WhitePlayable.size();
        makeMove(m_WhitePlayable[random].first, m_WhitePlayable[random].second, Color::WHITE, true);
    }
    else
    {
        int random = rand() % m_BlackPlayable.size();
        makeMove(m_BlackPlayable[random].first, m_BlackPlayable[random].second, Color::BLACK, true);
    }

}

void CGame::minimaxAlphaBeta(int depth, Color color, bool random)
{
    cout << *this << endl;

    while(!isFinished())
    {
        if(color == m_Player)
        {
            if(random)
            {
                makeRandomMove(m_Player);
            }
            else
            {
                loadMove(m_Player);
            }

            cout << *this << endl;
        }
        else
        {
            int bestVal = INT_MIN;

            CPosition bestFromPosition;
            CPosition bestToPosition;

            auto& playableMoves = (m_Computer == Color::WHITE) ? m_WhitePlayable : m_BlackPlayable;

            for(auto &[from, to] : playableMoves)  
            {
                CGame gameCopy = *this;
                gameCopy.makeMove(from, to, m_Computer, true);

                int val = gameCopy.minimaxAlphaBetaAlg(gameCopy, depth, INT_MIN, INT_MAX, false, gameCopy.m_Player);
                cout << "val: " << val << endl;

                if(val > bestVal) 
                {
                    bestVal = val;
                    bestFromPosition = from;
                    bestToPosition = to;
                }
            }

            makeMove(bestFromPosition, bestToPosition, m_Computer, true);
            cout << *this << endl;
        }

        color = (color == Color::WHITE) ? Color::BLACK : Color::WHITE;
    }
}

int CGame::minimaxAlphaBetaAlg(CGame& game, int depth, int alpha, int beta, bool isMaximizingComputer, Color playerColor) 
{
    if(game.isFinished() || depth == 0) 
        return game.evaluateBoard(playerColor);
    
    if(isMaximizingComputer) 
    {
        int maxEval = INT_MIN;

        auto& playableMoves = (m_Computer == Color::WHITE) ? game.m_WhitePlayable : game.m_BlackPlayable;

        for (auto& [from, to] : playableMoves)
        {
            CGame gameCopy = game;
            gameCopy.makeMove(from, to, m_Computer, true);

            int eval = gameCopy.minimaxAlphaBetaAlg(gameCopy, depth - 1, alpha, beta, false, m_Player);

            maxEval = max(maxEval, eval);
            alpha = max(alpha, maxEval);
            

            if(beta <= alpha)
                break; 
        }

        return maxEval;
    } 
    else 
    {
        int minEval = INT_MAX;

        auto& playableMoves = (m_Player == Color::WHITE) ? game.m_WhitePlayable : game.m_BlackPlayable;

        for (auto &[from, to] : playableMoves)
        {

            CGame gameCopy = game;
            gameCopy.makeMove(from, to, m_Player, true);

            int eval = gameCopy.minimaxAlphaBetaAlg(gameCopy, depth - 1, alpha, beta, true, m_Computer);

            minEval = min(minEval, eval);
            beta = min(beta, minEval);

            if(beta <= alpha)
                break; 
        }

        return minEval;
    }
}

int CGame::evaluateBoard(Color color) 
{

    int eval = 0;
    
    for(long int i = 0; i < m_Board.getSize(); i++) 
    {
        for (long int j = 0; j < m_Board.getSize(); j++) 
        {
            if(m_Board[i][j].getType() == Type::QUEEN)
            {
                if(m_Board[i][j].getColor() == color)
                    eval += 50;
                else
                    eval -= 50;
            }
            else if(m_Board[i][j].getType() == Type::ROOK)
            {
                if(m_Board[i][j].getColor() == color)
                    eval += 20;
                else
                    eval -= 20;
            }
            else if(m_Board[i][j].getType() == Type::KNIGHT)
            {
                if(m_Board[i][j].getColor() == color)
                    eval += 10;
                else
                    eval -= 10;
            }
            else if(m_Board[i][j].getType() == Type::BISHOP)
            {
                if(m_Board[i][j].getColor() == color)
                    eval += 10;
                else
                    eval -= 10;
            }
            else if(m_Board[i][j].getType() == Type::PAWN)
            {
                if(m_Board[i][j].getColor() == color)
                    eval += 2;
                else
                    eval -= 2;
            }
        }
    }

    

    if(m_Board.isPieceUnderAttack(m_WhiteKing, Color::WHITE, m_WhitePlayable, m_BlackPlayable) && m_WhitePlayable.empty()) 
        return (color == Color::BLACK) ? eval += 1000 : eval -= 1000;
    

    if(m_Board.isPieceUnderAttack(m_BlackKing, Color::BLACK, m_WhitePlayable, m_BlackPlayable) && m_BlackPlayable.empty()) 
        return (color == Color::WHITE) ? eval += 1000 : eval -= 1000;

    return eval;
}


void CGame::print(ostream &os) const
{

    os << "White player possible moves:" << endl;
    size_t i = 0;
    for (const auto& move : m_WhitePlayable)
    {
        os << i++ << ") " << "From (" << move.first.m_X << ", " << move.first.m_Y << ") to ("
           << move.second.m_X << "," << move.second.m_Y << ")" << endl;
    }

    os << "Black player possible moves:" << endl;
    i=0;
    for (const auto& move : m_BlackPlayable)
    {
        os << i++ << ") " << "From (" << move.first.m_X << ", " << move.first.m_Y << ") to ("
           << move.second.m_X << ", " << move.second.m_Y << ")" << endl;
    }

    os << m_Board << endl;
}

ostream& operator << (ostream &os, const CGame &game)
{
    game.print(os);
    return os;
}

int main()
{
    CGame game(4, Color::BLACK, Color::WHITE);

    game.minimaxAlphaBeta(5, Color::WHITE, true);
} 

C++ Online Compiler

Write, Run & Share C++ code online using OneCompiler's C++ online compiler for free. It's one of the robust, feature-rich online compilers for C++ language, running on the latest version 17. Getting started with the OneCompiler's C++ compiler is simple and pretty fast. The editor shows sample boilerplate code when you choose language as C++ and start coding!

Read inputs from stdin

OneCompiler's C++ online compiler supports stdin and users can give inputs to programs using the STDIN textbox under the I/O tab. Following is a sample program which takes name as input and print your name with hello.

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

int main() 
{
    string name;
    cout << "Enter name:";
    getline (cin, name);
    cout << "Hello " << name;
    return 0;
}

About C++

C++ is a widely used middle-level programming language.

  • Supports different platforms like Windows, various Linux flavours, MacOS etc
  • C++ supports OOPS concepts like Inheritance, Polymorphism, Encapsulation and Abstraction.
  • Case-sensitive
  • C++ is a compiler based language
  • C++ supports structured programming language
  • C++ provides alot of inbuilt functions and also supports dynamic memory allocation.
  • Like C, C++ also allows you to play with memory using Pointers.

Syntax help

Loops

1. If-Else:

When ever you want to perform a set of operations based on a condition If-Else is used.

if(conditional-expression) {
   //code
}
else {
   //code
}

You can also use if-else for nested Ifs and If-Else-If ladder when multiple conditions are to be performed on a single variable.

2. Switch:

Switch is an alternative to If-Else-If ladder.

switch(conditional-expression){    
case value1:    
 // code    
 break;  // optional  
case value2:    
 // code    
 break;  // optional  
......    
    
default:     
 code to be executed when all the above cases are not matched;    
} 

3. For:

For loop is used to iterate a set of statements based on a condition.

for(Initialization; Condition; Increment/decrement){  
  //code  
} 

4. While:

While is also used to iterate a set of statements based on a condition. Usually while is preferred when number of iterations are not known in advance.

while (condition) {  
// code 
}  

5. Do-While:

Do-while is also used to iterate a set of statements based on a condition. It is mostly used when you need to execute the statements atleast once.

do {  
 // code 
} while (condition); 

Functions

Function is a sub-routine which contains set of statements. Usually functions are written when multiple calls are required to same set of statements which increases re-usuability and modularity. Function gets run only when it is called.

How to declare a Function:

return_type function_name(parameters);

How to call a Function:

function_name (parameters)

How to define a Function:

return_type function_name(parameters) {  
 // code
}