diff --git a/include/BitBoard.h b/include/BitBoard.h index 48efd4d..b888961 100644 --- a/include/BitBoard.h +++ b/include/BitBoard.h @@ -11,30 +11,32 @@ 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]; } @@ -48,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 @@ -80,12 +82,13 @@ 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: @@ -94,8 +97,8 @@ class BitBoard BitBoard(const BitBoard &board); std::string player() const; - std::vector actions() const; - bup 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 9665a54..98177b1 100644 --- a/include/MinimaxSearch.h +++ b/include/MinimaxSearch.h @@ -7,10 +7,12 @@ #include "Move.h" #include "BitBoard.h" +typedef std::unique_ptr mup; + class MinimaxSearch { private: - static const int maxDepth = 6; + static const int maxDepth = 9; double minValue(std::unique_ptr &board, int currentDepth) const; double maxValue(std::unique_ptr &board, int currentDepth) const; @@ -19,8 +21,8 @@ class MinimaxSearch public: Move minimaxDecisionStack(const BitBoard &board) const; - Move minimaxDecision(std::unique_ptr &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 9ff9a0f..6eac6bc 100644 --- a/src/BitBoard.cpp +++ b/src/BitBoard.cpp @@ -9,6 +9,8 @@ #include "BitBoard.h" typedef std::unique_ptr bup; +typedef std::unique_ptr mup; +typedef std::vector> vmup; /* Private Functions */ @@ -18,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 @@ -36,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) { @@ -81,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(); } } } @@ -102,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); @@ -111,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)); @@ -164,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 @@ -189,7 +200,7 @@ 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; } @@ -207,9 +218,9 @@ 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); @@ -218,20 +229,19 @@ std::vector BitBoard::actions() const return moves; } -bup 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; } @@ -260,4 +270,3 @@ void BitBoard::printState() const std::cout<<"-"< bup; +typedef std::unique_ptr mup; + /* Private Functions */ double MinimaxSearch::minValue(bup &board, int currentDepth) const { if (currentDepth == maxDepth) return board->utility(board->player()); double v = std::numeric_limits::max(); - for (Move move : board->actions()) { + for (mup &move : board->actions()) { bup result = board->result(move); v = std::min(v, maxValue(result, currentDepth + 1)); } @@ -25,23 +27,23 @@ double MinimaxSearch::maxValue(bup &board, int currentDepth) const { if (currentDepth == maxDepth) return board->utility(board->player()); double v = std::numeric_limits::lowest(); - for (Move move : board->actions()) { + 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 (Move move : board->actions()) { + 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; @@ -49,37 +51,37 @@ double MinimaxSearch::alphaBeta(bup &board, double alpha, double beta, int depth } } else { v = std::numeric_limits::max(); - for (Move move : board->actions()) { + 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(bup &board) const +mup MinimaxSearch::minimaxDecision(bup &board) const { - Move bestMove; + mup bestMove; double bestMoveValue{0.0}; - for (Move move : board->actions()) { - if (bestMove.isEmpty()) { - bestMove = move; + 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 { 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; } - 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 fbff2ca..d269c62 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,9 +10,9 @@ int main(int argc, const char * argv[]) { std::unique_ptr board (new BitBoard); MinimaxSearch searchDriver; - for (int i = 0; i < 40; ++i) { + for (int i = 0; i < 20; ++i) { board->printState(); - Move bestMove = searchDriver.minimaxDecision(board); + std::unique_ptr bestMove = searchDriver.minimaxDecision(board); board = board->result(bestMove); std::cout << "=======================================" << std::endl; }