diff --git a/include/BitBoard.h b/include/BitBoard.h index 83c00d0..b888961 100644 --- a/include/BitBoard.h +++ b/include/BitBoard.h @@ -5,31 +5,38 @@ #include #include #include +#include #include "Move.h" +class BitBoard; + +typedef std::unique_ptr bup; +typedef std::unique_ptr mup; +typedef std::vector> vmup; + class BitBoard { private: - /* Static bit masks */ + /* Static bit masks */ - // Used to determine whether a move from that direction is valid + // Used to determine whether a move from that direction is valid static const uint32_t upRight = 0xFBFBEBBA; static const uint32_t upLeft = 0xFDF9EDBC; static const uint32_t downRight = 0x79FBF3DB; static const uint32_t downLeft = 0x7DFDF5DD; - + // Edge locations, all 4 sides static const uint32_t edgeLoc = 0x86061E67; - + static const uint32_t rowMask(int index){ static const uint32_t r [] = { 0x00041041, - 0x00082082, - 0x04104100, - 0x08208200, - 0x10410004, - 0x20820008, - 0x41104010, - 0x82100820}; + 0x00082082, + 0x04104100, + 0x08208200, + 0x10410004, + 0x20820008, + 0x41104010, + 0x82100820}; return r[index]; } @@ -43,19 +50,19 @@ class BitBoard uint32_t m_blackPieces = 0x41C71C3; uint32_t m_whitePieces = 0xE3820C38; uint32_t m_kings = 0; - + bool m_isBlacksTurn = true; // static constexpr uint32_t rowMask[8]; /* Class member functions */ - + // These are basic 32 bit rotation functions // Details here: http://stackoverflow.com/questions/776508/best-practices-for-circular-shift-rotate-operations-in-c uint32_t rotl32 (uint32_t n, unsigned int c) const; uint32_t rotr32 (uint32_t n, unsigned int c) const; - + const uint32_t playerPieces() const; - + const int count(uint32_t i) const; // Heuristic functions @@ -75,21 +82,23 @@ class BitBoard int getIndex(uint32_t piece) const; - void addJumps(std::vector &moves) const; - void addNormalMoves(std::vector &moves) const; - void generateAllJumps(BitBoard board, Move move, uint32_t piece, std::vector &moves) const; + void addJumps(vmup &moves) const; + void addNormalMoves(vmup &moves) const; + void generateAllJumps(BitBoard board, uint32_t piece, vmup &moves) const; + void generateAllJumps(BitBoard board, mup &move, uint32_t piece, vmup &moves) const; BitBoard boardMove(BitBoard &board, uint32_t piece, uint32_t moveTo) const; std::vector generateImmediateJumps(BitBoard &board, uint32_t piece) const; - void addNewMove(uint32_t start, uint32_t end, std::vector &moves) const; + void addNewMove(uint32_t start, uint32_t end, vmup &moves) const; std::string pieceToString(int piece) const; public: BitBoard(); BitBoard(uint32_t black, uint32_t white, uint32_t kings); + BitBoard(const BitBoard &board); std::string player() const; - std::vector actions() const; - BitBoard result(Move move) const; + vmup actions() const; + bup result(mup &move) const; double utility(std::string player) const; void printState() const; }; diff --git a/include/MinimaxSearch.h b/include/MinimaxSearch.h index 0badba6..98177b1 100644 --- a/include/MinimaxSearch.h +++ b/include/MinimaxSearch.h @@ -3,22 +3,26 @@ #include #include +#include #include "Move.h" #include "BitBoard.h" +typedef std::unique_ptr mup; + class MinimaxSearch { private: - static const int maxDepth = 7; + static const int maxDepth = 9; - double minValue(const BitBoard &board, int currentDepth) const; - double maxValue(const BitBoard &board, int currentDepth) const; + double minValue(std::unique_ptr &board, int currentDepth) const; + double maxValue(std::unique_ptr &board, int currentDepth) const; + double alphaBeta(std::unique_ptr &board, double alpha, double beta, int depth) const; public: - Move minimaxDecision(const BitBoard &board) const; Move minimaxDecisionStack(const BitBoard &board) const; + mup minimaxDecision(std::unique_ptr &board) const; + }; #endif - diff --git a/include/Move.h b/include/Move.h index ad8f7b6..8fe3407 100644 --- a/include/Move.h +++ b/include/Move.h @@ -3,6 +3,7 @@ #include #include +#include class Move { @@ -13,11 +14,18 @@ class Move Move(); Move(int start); + Move(const Move &move); void addMove(int move); void removeLast(); bool isEmpty(); int length(); std::vector getMoves() { return moves; } + + void printMoves() { + for (int m : moves) { + std::cout << m << "->" << std::endl; + } + } }; #endif diff --git a/src/BitBoard.cpp b/src/BitBoard.cpp index 50a02ca..6eac6bc 100644 --- a/src/BitBoard.cpp +++ b/src/BitBoard.cpp @@ -4,9 +4,14 @@ #include #include #include +#include #include "Move.h" #include "BitBoard.h" +typedef std::unique_ptr bup; +typedef std::unique_ptr mup; +typedef std::vector> vmup; + /* Private Functions */ // These are basic 32 bit rotation functions @@ -15,16 +20,16 @@ uint32_t BitBoard::rotl32 (uint32_t n, unsigned int c) const { const unsigned int mask = (CHAR_BIT*sizeof(n)-1); - c &= mask; // avoid undef behaviour with NDEBUG. 0 overhead for most types / compilers - return (n<>( (-c)&mask )); + c &= mask; // avoid undef behaviour with NDEBUG. 0 overhead for most types / compilers + return (n<>( (-c)&mask )); } uint32_t BitBoard::rotr32 (uint32_t n, unsigned int c) const { const unsigned int mask = (CHAR_BIT*sizeof(n)-1); - c &= mask; // avoid undef behaviour with NDEBUG. 0 overhead for most types / compilers - return (n>>c) | (n<<( (-c)&mask )); + c &= mask; // avoid undef behaviour with NDEBUG. 0 overhead for most types / compilers + return (n>>c) | (n<<( (-c)&mask )); } // Given a piece represented by a binary value return it's index @@ -33,19 +38,19 @@ int BitBoard::getIndex(uint32_t piece) const return (int)std::log2(piece); } -void BitBoard::addJumps(std::vector &moves) const +void BitBoard::addJumps(vmup &moves) const { uint32_t notOcc = ~(m_whitePieces|m_blackPieces); for (int i = 0; i < 32; ++i) { // grab the specific piece uint32_t piece = (m_isBlacksTurn) ? m_blackPieces & 1< &moves) const +void BitBoard::addNormalMoves(vmup &moves) const { uint32_t notOcc = ~(m_whitePieces|m_blackPieces); for (int i = 0; i < 32; ++i) { @@ -78,17 +83,27 @@ void BitBoard::addNormalMoves(std::vector &moves) const } } -void BitBoard::generateAllJumps(BitBoard board, Move move, uint32_t piece, std::vector &moves) const +void BitBoard::generateAllJumps(BitBoard board, uint32_t piece, vmup &moves) const { - if (move.isEmpty()) move.addMove(getIndex(piece)); // Add start position + mup move (new Move); + generateAllJumps(board, move, piece, moves); +} + +void BitBoard::generateAllJumps(BitBoard board, mup &move, uint32_t piece, vmup &moves) const +{ + if (move->isEmpty()) move->addMove(getIndex(piece)); // Add start position std::vector immediateJumps = generateImmediateJumps(board, piece); + if (immediateJumps.size() == 0) { - if (move.length() > 1) moves.push_back(move); // If no more jumps add move to list of moves + if (move->length() > 1) { + mup newMove(new Move(*move)); + moves.push_back(std::move(newMove)); // If no more jumps add move to list of moves + } } else { for (uint32_t x : immediateJumps) { - move.addMove(getIndex(x)); + move->addMove(getIndex(x)); generateAllJumps(boardMove(board, piece, x), move, x, moves); - move.removeLast(); + move->removeLast(); } } } @@ -99,7 +114,7 @@ BitBoard BitBoard::boardMove(BitBoard &board, uint32_t piece, uint32_t moveTo) c uint32_t white = board.m_whitePieces; uint32_t black = board.m_blackPieces; uint32_t kings = board.m_kings; - + // First figure out if a piece has been take int pieceLoc = getIndex(piece); int moveLoc = getIndex(moveTo); @@ -108,9 +123,7 @@ BitBoard BitBoard::boardMove(BitBoard &board, uint32_t piece, uint32_t moveTo) c int diff = std::abs((double)pieceLoc - moveLoc); int avg = ((pieceLoc + moveLoc) / 2); if (board.m_isBlacksTurn) { - if (diff == 2 || diff == 14) { - white &= ~(1< BitBoard::generateImmediateJumps(BitBoard &board, uint32_t uint32_t notOcc = ~(board.m_whitePieces|board.m_blackPieces); uint32_t temp; bool isKing = piece & board.m_kings; - if (m_isBlacksTurn) { + if (board.m_isBlacksTurn) { temp = (rotl32(piece, 7) & upLeft) & board.m_whitePieces; if ((rotl32(temp, 7) & upLeft) & notOcc) moves.push_back(rotl32(temp, 7)); @@ -161,14 +174,15 @@ std::vector BitBoard::generateImmediateJumps(BitBoard &board, uint32_t moves.push_back(rotl32(temp, 1)); } } + return moves; } -void BitBoard::addNewMove(uint32_t start, uint32_t end, std::vector &moves) const +void BitBoard::addNewMove(uint32_t start, uint32_t end, vmup &moves) const { - Move newMove(getIndex(start)); - newMove.addMove(getIndex(end)); - moves.push_back(newMove); + mup newMove( new Move(getIndex(start))); + newMove->addMove(getIndex(end)); + moves.push_back(std::move(newMove)); } std::string BitBoard::pieceToString(int piece) const @@ -186,19 +200,27 @@ std::string BitBoard::pieceToString(int piece) const BitBoard::BitBoard() {}; BitBoard::BitBoard(uint32_t black, uint32_t white, uint32_t kings) : - m_blackPieces(black), m_whitePieces(white), m_kings(kings) +m_blackPieces(black), m_whitePieces(white), m_kings(kings) { m_isBlacksTurn = true; } +BitBoard::BitBoard(const BitBoard &board) +{ + m_whitePieces = board.m_whitePieces; + m_blackPieces = board.m_blackPieces; + m_kings = board.m_kings; + m_isBlacksTurn = board.m_isBlacksTurn; +} + std::string BitBoard::player() const { return m_isBlacksTurn ? "black" : "white"; } -std::vector BitBoard::actions() const +vmup BitBoard::actions() const { - std::vector moves; + vmup moves; addJumps(moves); if (moves.empty()) { addNormalMoves(moves); @@ -207,29 +229,34 @@ std::vector BitBoard::actions() const return moves; } -BitBoard BitBoard::result(Move move) const +bup BitBoard::result(mup &move) const { BitBoard currBoard(*this); int start{-1}; - - for (int x : move.getMoves()) { + for (int x : move->getMoves()) { if (start == -1) { - start = x; + start = x; } else { - currBoard = boardMove(currBoard, 1< bits (m_blackPieces); + return 12 - bits.count(); + } + + std::bitset<32> bits (m_whitePieces); + return bits.count() - 12; } void BitBoard::printState() const @@ -243,4 +270,3 @@ void BitBoard::printState() const std::cout<<"-"< #include #include +#include #include "BitBoard.h" #include "Move.h" #include "MinimaxSearch.h" +typedef std::unique_ptr bup; +typedef std::unique_ptr mup; + /* Private Functions */ -double MinimaxSearch::minValue(const BitBoard &board, int currentDepth) const +double MinimaxSearch::minValue(bup &board, int currentDepth) const { - if (currentDepth == maxDepth) return board.utility(board.player()); + if (currentDepth == maxDepth) return board->utility(board->player()); double v = std::numeric_limits::max(); - for (Move move : board.actions()) { - v = std::min(v, maxValue(board.result(move), currentDepth + 1)); + for (mup &move : board->actions()) { + bup result = board->result(move); + v = std::min(v, maxValue(result, currentDepth + 1)); } return v; } -double MinimaxSearch::maxValue(const BitBoard &board, int currentDepth) const +double MinimaxSearch::maxValue(bup &board, int currentDepth) const { - if (currentDepth == maxDepth) return board.utility(board.player()); + if (currentDepth == maxDepth) return board->utility(board->player()); double v = std::numeric_limits::lowest(); - for (Move move : board.actions()) { - v = std::max(v, minValue(board.result(move), currentDepth + 1)); + for (mup &move : board->actions()) { + bup result = board->result(move); + v = std::max(v, minValue(result, currentDepth + 1)); } return v; } +double MinimaxSearch::alphaBeta(bup &board, double alpha, double beta, int depth) const +{ + if (depth == maxDepth) return board->utility(board->player()); + + + // black is max player here + double v; + if (board->player() == "black") { + v = std::numeric_limits::lowest(); + for (mup &move : board->actions()) { + bup result = board->result(move); + v = std::max(v, alphaBeta(result, alpha, beta, depth + 1)); + if (v >= beta) return v; + alpha = std::max(alpha, v); + } + } else { + v = std::numeric_limits::max(); + for (mup &move : board->actions()) { + bup result = board->result(move); + v = std::min(v, alphaBeta(result, alpha, beta, depth + 1)); + if (v <= alpha) return v; + beta = std::max(beta, v); + } + } + + return v; +} /* Public Functions */ -Move MinimaxSearch::minimaxDecision(const BitBoard &board) const +mup MinimaxSearch::minimaxDecision(bup &board) const { - Move bestMove; + mup bestMove; double bestMoveValue{0.0}; - std::cout << board.actions().size() << std::endl; - - for (Move move : board.actions()) { - if (bestMove.isEmpty()) { - bestMove = move; - bestMoveValue = minValue(board.result(bestMove), 0); + for (mup &move : board->actions()) { + if (bestMove == NULL) { + bestMove = std::move(move); + bup result = board->result(bestMove); + bestMoveValue = alphaBeta(result, std::numeric_limits::lowest(), std::numeric_limits::max(), 0); } else { - double nextMoveValue = minValue(board.result(move), 0); + bup result = board->result(move); + double nextMoveValue = alphaBeta(result, std::numeric_limits::lowest(), std::numeric_limits::max(), 0); if (bestMoveValue < nextMoveValue) { - bestMove = move; + bestMove = std::move(move); bestMoveValue = nextMoveValue; - } - } + } + } } - + return bestMove; } - -/*Move MinimaxSearch::minimaxDecision(const BitBoard &board) const -{ - - return nullptr; - }*/ diff --git a/src/Move.cpp b/src/Move.cpp index 0751327..eba1683 100644 --- a/src/Move.cpp +++ b/src/Move.cpp @@ -8,6 +8,11 @@ Move::Move(int start) moves = {start}; } +Move::Move(const Move &move) +{ + moves = move.moves; +} + void Move::addMove(int move) { moves.push_back(move); @@ -22,7 +27,8 @@ bool Move::isEmpty() { return moves.empty(); } - int Move::length() + +int Move::length() { return moves.size(); } diff --git a/src/main.cpp b/src/main.cpp index c4d9397..d269c62 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,18 +1,21 @@ #include #include #include +#include #include "BitBoard.h" #include "Move.h" #include "MinimaxSearch.h" int main(int argc, const char * argv[]) { - BitBoard board; - MinimaxSearch search; - for (int i = 0; i < 20; i++) { - board.printState(); - Move next = search.minimaxDecision(board); - board = board.result(next); - std::cout << "==============================" << std::endl; + std::unique_ptr board (new BitBoard); + MinimaxSearch searchDriver; + + for (int i = 0; i < 20; ++i) { + board->printState(); + std::unique_ptr bestMove = searchDriver.minimaxDecision(board); + board = board->result(bestMove); + std::cout << "=======================================" << std::endl; } + return 0; }