static void getCastlingMoves(const position * const pos, const int player, move store[], int *numMoves) { int colour; int sq; move m; sq = pos->kingSquare[player]; colour = COLOUR(pos->board[sq]); m.from = sq; m.flags = CASTLE; m.thisPiece = pos->board[sq]; m.promoteTo = 0; m.capturedPiece = 0; m.eval = 0; if(WHITE == player && !inCheck(pos, WHITE, pos->kingSquare[WHITE])) { if((pos->castleFlags & CASTLE_WK) && (0 == pos->board[1]) && (0 == pos->board[2])) { if(!inCheck(pos, WHITE, 1) && !inCheck(pos, WHITE, 2)) { assert(WHITE_ROOK == pos->board[0]); m.to = 1; storeMoveIfLegal(pos, &m, WHITE, store, numMoves); } } if((pos->castleFlags & CASTLE_WQ) && (0 == pos->board[4]) && (0 == pos->board[5]) && (0 == pos->board[6])) { if(!inCheck(pos, WHITE, 4) && !inCheck(pos, WHITE, 5)) { assert(WHITE_ROOK == pos->board[7]); m.to = 5; storeMoveIfLegal(pos, &m, WHITE, store, numMoves); } } } else if(!inCheck(pos, BLACK, pos->kingSquare[BLACK])) { if((pos->castleFlags & CASTLE_BK) && (0 == pos->board[57]) && (0 == pos->board[58])) { if(!inCheck(pos, BLACK, 57) && !inCheck(pos, BLACK, 58)) { assert(BLACK_ROOK == pos->board[56]); m.to = 57; storeMoveIfLegal(pos, &m, BLACK, store, numMoves); } } if((pos->castleFlags & CASTLE_BQ) && (0 == pos->board[62]) && (0 == pos->board[61]) && (0 == pos->board[60])) { if(!inCheck(pos, BLACK, 61) && !inCheck(pos, BLACK, 60)) { assert(BLACK_ROOK == pos->board[63]); m.to = 61; storeMoveIfLegal(pos, &m, BLACK, store, numMoves); } } } }
void OukBoard::generateMovesForPiece(QVarLengthArray< Move >& moves, int pieceType, int square) const { MakrukBoard::generateMovesForPiece(moves, pieceType, square); Side side = sideToMove(); // Only consider King and Neang on their initial squares if ((pieceType != King || square != m_initialSquare[side][King]) && (pieceType != Maiden || square != m_initialSquare[side][Maiden])) return; // Return if the piece has moved already if (m_moveCount[side].value((OukPieceType)pieceType, -1) != 0) return; // No special moves for King in check if (pieceType == King && inCheck(side)) return; // Generate initial move option for King (leap of Horse) // and for Neang (forward two squares) int sign = (side == Side::White) ? 1 : -1; for (const auto& i: m_initialOffsets) { if (pieceType != i.type) continue; int target = square - i.offset * sign; const Piece& piece = pieceAt(target); if (piece.isEmpty()) moves.append(Move(square, target)); } }
int getMoves(const position * const pos, const int player, const int piece, const int type, move store[]) { bitboard rawMoves = 0; int sq; int numMoves = 0; int opponent; bitboard pieces; opponent = OPPONENT(player); /* opponent in check = player won. should be checked somewhere before this */ assert(!inCheck(pos, opponent, pos->kingSquare[opponent])); pieces = getPieceBitboard(pos, piece); sq = 0; if(IS_KING(piece)) { /* we already know the location of the king */ sq = pos->kingSquare[player]; pieces = pieces >> sq; assert(pieces != 0); /* we should not move the king off the board */ } while(pieces != 0) { if(LSB_SET(pieces)) { rawMoves = getRawMoves(pos, player, piece, type, sq); numMoves += getPieceMoves(pos, player, type, rawMoves, sq, &store[numMoves]); } pieces = pieces >> 1; sq++; } return numMoves; }
bool RacingKingsBoard::isLegalPosition() { Side side = sideToMove(); if (inCheck(side)) return false; return WesternBoard::isLegalPosition(); }
Result KarOukBoard::result() { Side side = sideToMove(); if (!inCheck(side)) return OukBoard::result(); Side opp = side.opposite(); QString str = tr("%1 wins by giving check").arg(opp.toString()); return Result(Result::Win, opp, str); }
static void storeMoveIfLegal(const position* const pos, move* m, const int player, move store[], int *numMoves) { position newPosition; int status; int opponent; status = playMove(pos, &newPosition, m, player); if(status != ILLEGAL) { /* move is legal */ /* check that the move does not put players king in check, which would be illegal */ if(!inCheck(&newPosition, player, newPosition.kingSquare[player])) { /* calculate evaluation */ opponent = OPPONENT(player); if(inCheck(&newPosition, opponent, newPosition.kingSquare[opponent])) { m->flags |= CHECK; m->eval += EVAL_CHECK; } store[(*numMoves)++] = *m; } } }
/* in: Pointer to the line of input args: String array to place arguments */ void getArgs(char* in, char** args) { //Working pointer to args char** arg; arg = args; //Get the first token and continue through string placing //tokens in args, last token will be NULL *arg++ = strtok(in, DELIMITERS); while((*arg++ = strtok(NULL, DELIMITERS))); inCheck(args); }
int getAllMoves(const position * const pos, const int player, const int storeIndex) { int numMoves = 0; if(WHITE == player) { numMoves += getMoves(pos, player, WHITE_KING, CAPTURE, &_moveStore[storeIndex][numMoves]); numMoves += getMoves(pos, player, WHITE_PAWN, CAPTURE, &_moveStore[storeIndex][numMoves]); numMoves += getMoves(pos, player, WHITE_KNIGHT, CAPTURE, &_moveStore[storeIndex][numMoves]); numMoves += getMoves(pos, player, WHITE_BISHOP, CAPTURE, &_moveStore[storeIndex][numMoves]); numMoves += getMoves(pos, player, WHITE_ROOK, CAPTURE, &_moveStore[storeIndex][numMoves]); numMoves += getMoves(pos, player, WHITE_QUEEN, CAPTURE, &_moveStore[storeIndex][numMoves]); numMoves += getMoves(pos, player, WHITE_KING, NORMAL, &_moveStore[storeIndex][numMoves]); numMoves += getMoves(pos, player, WHITE_PAWN, NORMAL, &_moveStore[storeIndex][numMoves]); numMoves += getMoves(pos, player, WHITE_KNIGHT, NORMAL, &_moveStore[storeIndex][numMoves]); numMoves += getMoves(pos, player, WHITE_BISHOP, NORMAL, &_moveStore[storeIndex][numMoves]); numMoves += getMoves(pos, player, WHITE_ROOK, NORMAL, &_moveStore[storeIndex][numMoves]); numMoves += getMoves(pos, player, WHITE_QUEEN, NORMAL, &_moveStore[storeIndex][numMoves]); } else { numMoves += getMoves(pos, player, BLACK_KING, CAPTURE, &_moveStore[storeIndex][numMoves]); numMoves += getMoves(pos, player, BLACK_PAWN, CAPTURE, &_moveStore[storeIndex][numMoves]); numMoves += getMoves(pos, player, BLACK_KNIGHT, CAPTURE, &_moveStore[storeIndex][numMoves]); numMoves += getMoves(pos, player, BLACK_BISHOP, CAPTURE, &_moveStore[storeIndex][numMoves]); numMoves += getMoves(pos, player, BLACK_ROOK, CAPTURE, &_moveStore[storeIndex][numMoves]); numMoves += getMoves(pos, player, BLACK_QUEEN, CAPTURE, &_moveStore[storeIndex][numMoves]); numMoves += getMoves(pos, player, BLACK_KING, NORMAL, &_moveStore[storeIndex][numMoves]); numMoves += getMoves(pos, player, BLACK_PAWN, NORMAL, &_moveStore[storeIndex][numMoves]); numMoves += getMoves(pos, player, BLACK_KNIGHT, NORMAL, &_moveStore[storeIndex][numMoves]); numMoves += getMoves(pos, player, BLACK_BISHOP, NORMAL, &_moveStore[storeIndex][numMoves]); numMoves += getMoves(pos, player, BLACK_ROOK, NORMAL, &_moveStore[storeIndex][numMoves]); numMoves += getMoves(pos, player, BLACK_QUEEN, NORMAL, &_moveStore[storeIndex][numMoves]); } if(0 == numMoves) { /* no moves */ if(inCheck(pos, player, pos->kingSquare[player])) { return LOST; } else { return STALEMATE; } } counterMove += numMoves; return numMoves; }
/* Types of moves: 1) King normal move 2) King captures 3) King castles 4) */ int playMove(const position * const pos, position *newPosition, const move * const m, const int player) { int opponent; opponent = OPPONENT(player); /* assert consistency of position */ assertPosition(pos); /* opponent cannot be check, this should be handled elsewhere */ assert(!inCheck(pos, opponent, pos->kingSquare[opponent])); /* init new position to old position */ *newPosition = *pos; /* opponent has to play in the new position */ newPosition->toPlay = opponent; movePiece(newPosition, m, player); if(IS_CAPTURE(m)) { /* clear bitmask for captured piece */ clearCapturedPiece(newPosition, m); } /* ep is disabled after any move played */ DISABLE_EP(newPosition); /* assert consistency of new position */ assertPosition(newPosition); return 0; }
bool OukBoard::inCheck(Side side, int square) const { int sign = (side == Side::White) ? 1 : -1; Side opSide = side.opposite(); if (square == 0) square = kingSquare(side); // Attack by Advisor (Maiden, Neang), initial move if (!m_moveCount[opSide][Maiden] && m_initialSquare[opSide][Maiden] == square - 2 * sign * (width() + 2)) return true; // Attack by King, initial move int ksq = kingSquare(opSide); bool attacked = (ksq == square - 8 * sign || ksq == square - 12 * sign); if (!m_moveCount[opSide][King] && attacked) { if (square == kingSquare(side) || !inCheck(opSide)) return true; } return MakrukBoard::inCheck(side, square); }
int Board::alphaBeta(int depthLeft, int alpha, int beta, int doNullMove) { int check = 0; int oldAlpha = alpha; int numSearched = 0; int bestMove = 0; int hashMove = 0; int stage; int i = currentState->firstMove; int result; nodes++; nodesUntilUpdate--; if(nodesUntilUpdate <= 0) { switch(game->interfaceUpdate()) { case OUT_OF_TIME: abortingSearch = 1; return 0; break; case STOP_SEARCH: abortingSearch = 1; return 0; break; } nodesUntilUpdate = nodesPerUpdate; } if(isRepetition()) { returnMove = 0; return DRAW; } HashEntry *e; e = hash->probe(currentState->hashKey); if(e!=NULL) { hashHits++; //Is it useful for replacing this search - otherwise just find a best move hashMove = e->bestMove; returnMove = hashMove; #ifndef DISABLE_HASH if(depth > 0 && e->depth >= depthLeft) { switch(e->flags & 3) { case HASH_EXACT: return e->score; break; case HASH_LOWER: if(e->score >= beta) return e->score; if(e->score > alpha) alpha = e->score; break; case HASH_UPPER: if(e->score <= alpha) return e->score; if(e->score < beta) beta = e->score; break; } if(e->flags & HASH_NO_NULL) { doNullMove = 0; } } #endif } #ifdef DEBUG_HASH if(hashMove > 0 && !testLegality(hashMove)) { print(); cout << "Illegal hash move! "; printMove(hashMove); cout << endl; } #endif if(depthLeft == 0) { int value = quiescence(alpha, beta); //hash->store(0, value, 0, HASH_EXACT); return value; } check = inCheck(); /* if(doNullMove && !check && !nullRisk() && depth >= 2) { int nullDepth = depthLeft - 2; makeNullMove(); if(nullDepth > 0) { result = alphaBeta(nullDepth, -beta, -beta+1, NO_NULL_MOVE); } else { result = quiescence(-beta, -beta+1); } retractNullMove(); if(nullDepth > 0 && result >= beta) { result = alphaBeta(nullDepth, beta-1, beta, DO_NULL_MOVE); numMoves = currentState->firstMove; } if(result >= beta) { returnMove = 0; return beta; } } */ if(!hashMove && depthLeft >= 3) { result = alphaBeta(depthLeft - 2, alpha, beta, DO_NULL_MOVE); numMoves = currentState->firstMove; //Failed low so have to research with new bounds if(result <= alpha) result = alphaBeta(depthLeft - 2, -MATE, alpha + 1, DO_NULL_MOVE); numMoves = currentState->firstMove; hashMove = returnMove; } if(hashMove > 0) { stage = HASH_MOVE; } else { stage = ALL_MOVES; } while(stage != FINISHED) { switch(stage) { case HASH_MOVE: moveStack[numMoves++] = hashMove; stage = ALL_MOVES; break; case ALL_MOVES: if(check) { generateCheckEvasions(); sortNonCaptures(i, hashMove); stage = FINISHED; } else { generateCaptures(); sortCaptures(i, hashMove); stage = NON_CAPTURES; } break; case NON_CAPTURES: generateNonCaptures(); sortNonCaptures(i, hashMove); stage = FINISHED; break; } for(; i<numMoves; i++) { int move = moveStack[i]; makeMove(move); #ifdef DEBUG_BITBOARDS if(isMessedUp()) { printMoves(); print(); cout << "Hash move = "; printMove(hashMove); cout << endl; cout << "MakeMove" << endl; exit(0); } #endif if(isLegal()) { numSearched++; result = -alphaBeta(depthLeft - 1, -beta, -alpha, DO_NULL_MOVE); retractMove(move); if(abortingSearch) { returnMove = bestMove; return result; } if(result > alpha) { if(result >= beta) { returnMove = move; hash->store(move, result, depthLeft, HASH_LOWER); #ifdef EXTRA_STATS cutoffs++; if(i == currentState->firstMove) firstCutoffs++; #endif return result; } /* if(depth == 0) { printMove(move); cout << " "; printScore(result); cout << " hashMove: "; printMove(hashMove); cout << endl; }*/ alpha = result; bestMove = move; } } else { //Illegal move retractMove(move); } #ifdef DEBUG_BITBOARDS if(isMessedUp()) { printMoves(); print(); cout << "Hash move = "; printMove(hashMove); cout << endl; cout << "RetractMove" << endl; exit(0); } #endif } } //While we have moves //No legal moves.. if(numSearched ==0) { returnMove = 0; if(check) { return -(MATE - depth); } else { return DRAW; } } if(alpha == oldAlpha) { hash->store(bestMove, alpha, depthLeft, HASH_UPPER); } else { hash->store(bestMove, alpha, depthLeft, HASH_EXACT); } returnMove = bestMove; return alpha; }
bool Position::doMove(Move &theMove) { //save history updateHistory(); //First up: move the piece on the board, update piecelist board[theMove.toSpace] = theMove.piece; board[theMove.fromSpace] = EMPTY; updatePiece(theMove.fromSpace, theMove.toSpace, toMove); updatePieceHash(theMove.fromSpace, theMove.toSpace, theMove.piece); //If it is a capture, let's delete the dead guy from the proper piecelist if (theMove.capture != 0) { //For enpassant captures if(theMove.enPassant == true) { removePiece(enPassant + 10*toMove, -toMove); updatePieceHash(enPassant + 10*toMove, 0, theMove.capture); board[enPassant + 10*toMove] = EMPTY; } else { removePiece(theMove.toSpace, -toMove); updatePieceHash(theMove.toSpace, 0, theMove.capture); } //If a rook is captured, update castle info. if(abs(theMove.capture) == ROOK) { if (castleWK && theMove.toSpace == 98) { castleWK = false; hash = hash ^ castleKeys[0]; } else if (castleWQ && theMove.toSpace == 91) { castleWQ = false; hash = hash ^ castleKeys[1]; } else if (castleBK && theMove.toSpace == 28) { castleBK = false; hash = hash ^ castleKeys[2]; } else if (castleBQ && theMove.toSpace == 21) { hash = hash ^ castleKeys[3]; castleBQ = false; } } } //Speaking of en passant captures... if (enPassant != 0) hash = hash ^ enpassantKeys[enPassant%10 - 1]; if (theMove.jump) { enPassant = theMove.fromSpace - 10*toMove; hash = hash ^ enpassantKeys[enPassant%10 - 1]; } else enPassant = 0; //For promotions, we must bring a piece to LIFE! if (theMove.promotion != 0) { board[theMove.toSpace] = theMove.promotion*toMove; updatePieceHash(0, theMove.toSpace, theMove.promotion*toMove); updatePieceHash(theMove.toSpace, 0, theMove.piece); } //Castling. Hooray. Move the rooks, update piecelists. if (theMove.castle != 0) { if (theMove.castle == 1) { if (toMove == WHITE) { board[98] = EMPTY; board[96] = ROOK; updatePiece(98, 96, WHITE); updatePieceHash(98, 96, ROOK); } else { board[28] = EMPTY; board[26] = -ROOK; updatePiece(28, 26, BLACK); updatePieceHash(28, 26, -ROOK); } } else { if (toMove == WHITE) { board[91] = EMPTY; board[94] = ROOK; updatePiece(91, 94, WHITE); updatePieceHash(91, 94, ROOK); } else { board[21] = EMPTY; board[24] = -ROOK; updatePiece(21, 24, BLACK); updatePieceHash(21, 24, -ROOK); } } } //Update king locations if (abs(theMove.piece) == KING) { if (toMove == WHITE) { whiteKing = theMove.toSpace; if (castleWK) { castleWK = false; hash = hash ^ castleKeys[0]; } if (castleWQ) { castleWQ = false; hash = hash ^ castleKeys[1]; } } else { blackKing = theMove.toSpace; if (castleBK) { castleBK = false; hash = hash ^ castleKeys[2]; } if (castleBQ) { castleBQ = false; hash = hash ^ castleKeys[3]; } } } //Update castling rights for rook moves if (theMove.piece == ROOK) { if (theMove.fromSpace == 91 && castleWQ) { castleWQ = false; hash = hash ^ castleKeys[1]; } else if (theMove.fromSpace == 98 && castleWK){ castleWK = false; hash = hash ^ castleKeys[0]; } } else if (theMove.piece == -ROOK) { if (theMove.fromSpace == 21 && castleBQ){ castleBQ = false; hash = hash ^ castleKeys[3]; } else if (theMove.fromSpace == 28 && castleBK){ castleBK = false; hash = hash ^ castleKeys[2]; } } //Adjust fifty move rule counter if (abs(theMove.piece) == PAWN || theMove.capture != 0) fiftyMove = 0; else fiftyMove++; if (toMove == BLACK) totalMoves++; halfMoves++; bool check = inCheck(); toMove = -toMove; hash = hash ^ blackKey; //update moves made and history movesMade.add(theMove); return check; }