Move JanusBoard::moveFromSanString(const QString& str) { /* * accepts O-O and Kb1/Kb8/Ki1/Ki8 formats for castling * Xboard uses O-O for B-file and Ki1/Ki8 for I-file castling */ if (str.startsWith("O-O-O")) return WesternBoard::moveFromSanString("O-O"); if (str.startsWith("O-O")) return WesternBoard::moveFromSanString("O-O-O"); if (!str.startsWith(pieceSymbol(King).toUpper())) return WesternBoard::moveFromSanString(str); //main path if (hasCastlingRight(sideToMove(), KingSide)) { Move castlingMove = WesternBoard::moveFromSanString("O-O"); if (!castlingMove.isNull() && str == sanMoveString(castlingMove)) return castlingMove; } if (hasCastlingRight(sideToMove(), QueenSide)) { Move castlingMove = WesternBoard::moveFromSanString("O-O-O"); if (!castlingMove.isNull() && str == sanMoveString(castlingMove)) return castlingMove; } return WesternBoard::moveFromSanString(str); // normal king moves }
extern int parseUciMove(Board_t self, const char *line, int xMoves[maxMoves], int xlen, int *move) { int ix = 0; // index into line int rawMove = 0; while (isspace(line[ix])) // Skip white space ix++; int castleLen; int nrOh = parseCastling(&line[ix], &castleLen); if (nrOh == 2) { // King-side castling int rank = (sideToMove(self) == white) ? rank1 : rank8; rawMove = move(square(fileE, rank), square(fileG, rank)); ix += castleLen; } else if (nrOh == 3) { // Queen-side castling int rank = (sideToMove(self) == white) ? rank1 : rank8; rawMove = move(square(fileE, rank), square(fileC, rank)); ix += castleLen; } else { // Regular move if ('a' > line[ix+0] || line[ix+0] > 'h' || '1' > line[ix+1] || line[ix+1] > '8' || 'a' > line[ix+2] || line[ix+2] > 'h' || '1' > line[ix+3] || line[ix+3] > '8') return 0; int fromFile = charToFile(line[ix++]); int fromRank = charToRank(line[ix++]); int toFile = charToFile(line[ix++]); int toRank = charToRank(line[ix++]); rawMove = move(square(fromFile, fromRank), square(toFile, toRank)); if (line[ix] == 'q' || line[ix] == 'r' || line[ix] == 'b' || line[ix] == 'n') rawMove += promotionFlags[(int)line[ix++]]; } if (!isspace(line[ix]) && line[ix] != '\0') return 0; // Reject garbage following the move // Find matching move from move list and verify its legality for (int i=0; i<xlen; i++) { int xMove = xMoves[i]; if ((xMove & ~specialMoveFlag) == rawMove && isLegalMove(self, xMove)) { *move = xMove; return ix; } } return 0; }
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)); } }
bool RacingKingsBoard::isLegalPosition() { Side side = sideToMove(); if (inCheck(side)) return false; return WesternBoard::isLegalPosition(); }
void CrazyhouseBoard::vUndoMove(const Move& move) { int source = move.sourceSquare(); int target = move.targetSquare(); int prom = move.promotion(); Move tmp(move); if (source != 0 && prom != Piece::NoPiece) tmp = Move(source, target, promotedPieceType(prom)); WesternBoard::vUndoMove(tmp); int ctype = captureType(move); if (ctype != Piece::NoPiece) removeFromReserve(Piece(sideToMove(), reserveType(ctype))); else if (source == 0) addToReserve(Piece(sideToMove(), prom)); }
Result LosersBoard::result() { Side winner; QString str; // Checkmate/Stalemate if (!canMove()) { winner = sideToMove(); str = tr("%1 gets mated").arg(winner.toString()); return Result(Result::Win, winner, str); } // Lost all pieces int pieceCount = 0; for (int i = 0; i < arraySize(); i++) { if (pieceAt(i).side() == sideToMove() && ++pieceCount > 1) break; } if (pieceCount <= 1) { winner = sideToMove(); str = tr("%1 lost all pieces").arg(winner.toString()); return Result(Result::Win, winner, str); } // 50 move rule if (reversibleMoveCount() >= 100) { str = tr("Draw by fifty moves rule"); return Result(Result::Draw, Side::NoSide, str); } // 3-fold repetition if (repeatCount() >= 2) { str = tr("Draw by 3-fold repetition"); return Result(Result::Draw, Side::NoSide, str); } return Result(); }
Result HordeBoard::result() { Side side = sideToMove(); Side opp = side.opposite(); if (!hasMaterial(side)) return Result(Result::Win, opp, tr("%1 wins").arg(opp.toString())); return StandardBoard::result(); }
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); }
Result RacingKingsBoard::result() { QString str; bool blackFinished = finished(Side::Black); bool whiteFinished = finished(Side::White); // Finishing on eighth rank if (blackFinished && whiteFinished) { str = tr("Drawn race"); return Result(Result::Draw, Side::NoSide, str); } if (blackFinished) { str = tr("Black wins the race"); return Result(Result::Win, Side::Black, str); } Side side = sideToMove(); bool mobile = canMove(); // White finished but Black cannot finish or forfeited the chance if (whiteFinished && ((mobile && !canFinish(Side::Black)) || side == Side::White)) { str = tr("White wins the race"); return Result(Result::Win, Side::White, str); } // Stalemate if (!mobile) { str = tr("Draw by stalemate"); return Result(Result::Draw, Side::NoSide, str); } // 50 move rule if (reversibleMoveCount() >= 100) { str = tr("Draw by fifty moves rule"); return Result(Result::Draw, Side::NoSide, str); } // 3-fold repetition if (repeatCount() >= 2) { str = tr("Draw by 3-fold repetition"); return Result(Result::Draw, Side::NoSide, str); } return Result(); }
void CrazyhouseBoard::vMakeMove(const Move& move, BoardTransition* transition) { int source = move.sourceSquare(); int target = move.targetSquare(); int prom = move.promotion(); Move tmp(move); if (source != 0 && prom != Piece::NoPiece) tmp = Move(source, target, promotedPieceType(prom)); int ctype = captureType(move); if (ctype != Piece::NoPiece) { Piece reservePiece(sideToMove(), reserveType(ctype)); addToReserve(reservePiece); if (transition != 0) transition->addReservePiece(reservePiece); } else if (source == 0) removeFromReserve(Piece(sideToMove(), prom)); return WesternBoard::vMakeMove(tmp, transition); }
void OukBoard::updateCounter(Move m, int increment) { Side side = sideToMove(); int source = m.sourceSquare(); int target= m.targetSquare(); if (source == m_initialSquare[side][King] || target == m_initialSquare[side][King]) m_moveCount[side][King] += increment; if (source == m_initialSquare[side][Maiden] || target == m_initialSquare[side][Maiden]) m_moveCount[side][Maiden] += increment; }
void normalizeEnPassantStatus(Board_t self) { int square = self->enPassantPawn; if (!square) return; int pawn = (sideToMove(self) == white) ? whitePawn : blackPawn; int step = (sideToMove(self) == white) ? stepN : stepS; if (file(square) != fileA && self->squares[square+stepW] == pawn) { int move = specialMove(square + stepW, square + step); if (isLegalMove(self, move)) return; } if (file(square) != fileH && self->squares[square+stepE] == pawn) { int move = specialMove(square + stepE, square + step); if (isLegalMove(self, move)) return; } self->hash ^= hashEnPassant(square); self->enPassantPawn = 0; }
int get_Heuristic (Board *board , int depth){ if ( board == NULL ) { logChess(WARN, "The board is null."); return NULL_BOARD; } if ( depth < 0 ) { logChess(WARN, "The depth is not correct. Minor than 0."); return BAD_DEPTH; } if(evaluateOurCheck(board)!=KING_IN_CHECK) { Board tmpBoard; memcpy(&tmpBoard, board, sizeof(Board)); int material = getTotalTableMaterial(&tmpBoard); int mineMaterial= getMaterial(board,board->myColor); //Calculating mine material to evaluate the game phase int movements= getCurrentMovement(depth); //Calculating number of movements to calculate game phase int phase = getGamePhase(board,movements,mineMaterial); //Calculating phase of the game to be used in position int position = getTotalPiecePositionValue(&tmpBoard,depth,phase); // Calculating game phase according to the position int menaced = getMenacedValueTotal(tmpBoard.myColor,&tmpBoard); int side = sideToMove(depth); int evaluation = 0; if ( phase == END) { evaluation=2*material+ 0.5*position+ 0.1*menaced; } else { evaluation=1.6*material + 0.9*position+ 0.2*menaced; } //printf("material:%d + position:%d + menaced:%d = evaluation:%d\n", material, position, menaced, evaluation); //ONLY FOR TEST return evaluation * side; } else //we are in check, it's not useful to check with the heuristic { return OUR_CHECK_VALUE; } }
// Helper to generate slider moves static void generateSlides(Board_t self, int from, int dirs) { dirs &= kingDirections[from]; int dir = 0; do { dir = (dir - dirs) & dirs; // pick next int vector = kingStep[dir]; int to = from; do { to += vector; if (self->squares[to] != empty) { if (pieceColor(self->squares[to]) != sideToMove(self)) pushMove(self, from, to); break; } pushMove(self, from, to); } while (dir & kingDirections[to]); } while (dirs -= dir); // remove and go to next }
// Calculate Zobrist hash using Polyglot's definition uint64_t hash(Board_t self) { uint64_t key = 0; // Pieces for (int square=0; square<boardSize; square++) key ^= zobristPiece[self->squares[square]][square]; // Castling key ^= hashCastleFlags(self->castleFlags); // En passant key ^= hashEnPassant(self->enPassantPawn); // Turn if (sideToMove(self) == white) key ^= zobristTurn[0]; return key; }
Move CrazyhouseBoard::moveFromSanString(const QString& str) { if (str.isEmpty()) return Move(); Piece piece(pieceFromSymbol(str.at(0))); if (piece.isValid()) { piece.setSide(sideToMove()); QVarLengthArray<int> squares; normalizePieces(piece, squares); Move move(WesternBoard::moveFromSanString(str)); restorePieces(piece, squares); return move; } return WesternBoard::moveFromSanString(str); }
extern int setupBoard(Board_t self, const char *fen) { int ix = 0; /* * Squares */ while (isspace(fen[ix])) ix++; int file = fileA, rank = rank8; int nrWhiteKings = 0, nrBlackKings = 0; memset(self->squares, empty, boardSize); self->materialKey = 0; while (rank != rank1 || file != fileH + fileStep) { int piece = empty; int count = 1; switch (fen[ix]) { case 'K': piece = whiteKing; nrWhiteKings++; break; case 'Q': piece = whiteQueen; break; case 'R': piece = whiteRook; break; case 'B': piece = whiteBishop; break; case 'N': piece = whiteKnight; break; case 'P': piece = whitePawn; break; case 'k': piece = blackKing; nrBlackKings++; break; case 'r': piece = blackRook; break; case 'q': piece = blackQueen; break; case 'b': piece = blackBishop; break; case 'n': piece = blackKnight; break; case 'p': piece = blackPawn; break; case '/': rank -= rankStep; file = fileA; ix++; continue; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': count = fen[ix] - '0'; break; default: return 0; // FEN error } int squareColor = squareColor(square(file,rank)); self->materialKey += materialKeys[piece][squareColor]; do { self->squares[square(file,rank)] = piece; file += fileStep; } while (--count && file != fileH + fileStep); ix++; } if (nrWhiteKings != 1 || nrBlackKings != 1) return 0; /* * Side to move */ self->plyNumber = 2 + (fen[ix+1] == 'b'); // 2 means full move number starts at 1 //self->lastZeroing = self->plyNumber; ix += 2; /* * Castling flags */ while (isspace(fen[ix])) ix++; self->castleFlags = 0; for (;; ix++) { switch (fen[ix]) { case 'K': self->castleFlags |= castleFlagWhiteKside; continue; case 'Q': self->castleFlags |= castleFlagWhiteQside; continue; case 'k': self->castleFlags |= castleFlagBlackKside; continue; case 'q': self->castleFlags |= castleFlagBlackQside; continue; case '-': ix++; break; default: break; } break; } /* * En passant square */ while (isspace(fen[ix])) ix++; if ('a' <= fen[ix] && fen[ix] <= 'h') { file = charToFile(fen[ix]); ix++; rank = (sideToMove(self) == white) ? rank5 : rank4; if (isdigit(fen[ix])) ix++; // ignore what it says self->enPassantPawn = square(file, rank); } else { self->enPassantPawn = 0; if (fen[ix] == '-') ix++; } // Eat move number and halfmove clock. TODO: process this properly while (isspace(fen[ix])) ix++; while (isdigit(fen[ix])) ix++; while (isspace(fen[ix])) ix++; while (isdigit(fen[ix])) ix++; self->sideInfoPlyNumber = -1; // side info is invalid now // Reset the undo stack self->undoStack.len = 0; // Initialize hash and its history self->hash = hash(self); self->hashHistory.len = 0; self->pawnKingHash = pawnKingHash(self); self->pkHashHistory.len = 0; normalizeEnPassantStatus(self); // Only safe after update of hash self->eloDiff = 0; return ix; }
/* * Pseudo-legal move generator */ extern int generateMoves(Board_t self, int moveList[maxMoves]) { int side = sideToMove(self); updateSideInfo(self); self->movePtr = moveList; for (int from=0; from<boardSize; from++) { int piece = self->squares[from]; if (piece == empty || pieceColor(piece) != sideToMove(self)) continue; /* * Generate moves for this piece */ int to; switch (piece) { int dir, dirs; case whiteKing: case blackKing: dirs = kingDirections[from]; dir = 0; do { dir = (dir - dirs) & dirs; // pick next to = from + kingStep[dir]; if (self->squares[to] == empty || pieceColor(self->squares[to]) != sideToMove(self)) if (self->sides[other(side)].attacks[to] == 0) pushMove(self, from, to); } while (dirs -= dir); // remove and go to next break; case whiteQueen: case blackQueen: generateSlides(self, from, dirsQueen); break; case whiteRook: case blackRook: generateSlides(self, from, dirsRook); break; case whiteBishop: case blackBishop: generateSlides(self, from, dirsBishop); break; case whiteKnight: case blackKnight: dirs = knightDirections[from]; dir = 0; do { dir = (dir - dirs) & dirs; // pick next to = from + knightJump[dir]; if (self->squares[to] == empty || pieceColor(self->squares[to]) != sideToMove(self)) pushMove(self, from, to); } while (dirs -= dir); // remove and go to next break; case whitePawn: if (file(from) != fileH) { to = from + stepNE; if (self->squares[to] != empty && pieceColor(self->squares[to]) == black) pushPawnMove(self, from, to); } if (file(from) != fileA) { to = from + stepNW; if (self->squares[to] != empty && pieceColor(self->squares[to]) == black) pushPawnMove(self, from, to); } to = from + stepN; if (self->squares[to] != empty) break; pushPawnMove(self, from, to); if (rank(from) == rank2) { to += stepN; if (self->squares[to] == empty) { pushMove(self, from, to); if (self->sides[black].attacks[to+stepS]) self->movePtr[-1] |= specialMoveFlag; } } break; case blackPawn: if (file(from) != fileH) { to = from + stepSE; if (self->squares[to] != empty && pieceColor(self->squares[to]) == white) pushPawnMove(self, from, to); } if (file(from) != fileA) { to = from + stepSW; if (self->squares[to] != empty && pieceColor(self->squares[to]) == white) pushPawnMove(self, from, to); } to = from + stepS; if (self->squares[to] != empty) break; pushPawnMove(self, from, to); if (rank(from) == rank7) { to += stepS; if (self->squares[to] == empty) { pushMove(self, from, to); if (self->sides[white].attacks[to+stepN]) self->movePtr[-1] |= specialMoveFlag; } } break; } } /* * Generate castling moves */ if (self->castleFlags && !isInCheck(self)) { static const int flags[2][2] = { { castleFlagWhiteKside, castleFlagWhiteQside }, { castleFlagBlackKside, castleFlagBlackQside } }; int side = sideToMove(self); int sq = self->sides[side].king; if ((self->castleFlags & flags[side][0]) && self->squares[sq+stepE] == empty && self->squares[sq+2*stepE] == empty && self->sides[other(side)].attacks[sq+stepE] == 0 && self->sides[other(side)].attacks[sq+2*stepE] == 0) pushSpecialMove(self, sq, sq + 2*stepE); if ((self->castleFlags & flags[side][1]) && self->squares[sq+stepW] == empty && self->squares[sq+2*stepW] == empty && self->squares[sq+3*stepW] == empty && self->sides[other(side)].attacks[sq+stepW] == 0 && self->sides[other(side)].attacks[sq+2*stepW] == 0) pushSpecialMove(self, sq, sq + 2*stepW); } /* * Generate en passant captures */ if (self->enPassantPawn) { static const int steps[] = { stepN, stepS }; static const int pawns[] = { whitePawn, blackPawn }; int step = steps[sideToMove(self)]; int pawn = pawns[sideToMove(self)]; int ep = self->enPassantPawn; if (file(ep) != fileA && self->squares[ep+stepW] == pawn) pushSpecialMove(self, ep + stepW, ep + step); if (file(ep) != fileH && self->squares[ep+stepE] == pawn) pushSpecialMove(self, ep + stepE, ep + step); } return self->movePtr - moveList; // nrMoves }
int isInCheck(Board_t self) { updateSideInfo(self); int side = sideToMove(self); return self->sides[other(side)].attacks[self->sides[side].king] != 0; }
extern void boardToFen(Board_t self, char *fen) { /* * Squares */ for (int rank=rank8; rank!=rank1-rankStep; rank-=rankStep) { int emptySquares = 0; for (int file=fileA; file!=fileH+fileStep; file+=fileStep) { int square = square(file, rank); int piece = self->squares[square]; if (piece != empty) { if (emptySquares > 0) *fen++ = '0' + emptySquares; *fen++ = pieceToChar[piece]; emptySquares = 0; } else emptySquares++; } if (emptySquares > 0) *fen++ = '0' + emptySquares; if (rank != rank1) *fen++ = '/'; } /* * Side to move */ *fen++ = ' '; *fen++ = (sideToMove(self) == white) ? 'w' : 'b'; /* * Castling flags */ *fen++ = ' '; if (self->castleFlags) { if (self->castleFlags & castleFlagWhiteKside) *fen++ = 'K'; if (self->castleFlags & castleFlagWhiteQside) *fen++ = 'Q'; if (self->castleFlags & castleFlagBlackKside) *fen++ = 'k'; if (self->castleFlags & castleFlagBlackQside) *fen++ = 'q'; } else *fen++ = '-'; /* * En-passant square */ *fen++ = ' '; normalizeEnPassantStatus(self); if (self->enPassantPawn) { *fen++ = fileToChar(file(self->enPassantPawn)); *fen++ = rankToChar((sideToMove(self) == white) ? rank6 : rank3); } else *fen++ = '-'; /* * Move number (TODO) */ /* * Halfmove clock (TODO) */ *fen = '\0'; }