public void HighlightMove(int fromIndex, int toIndex) { int fromX = GetIndex(BoardGround.FileFrom128(fromIndex) - 1); int fromY = GetIndex(BoardGround.RankFrom128(fromIndex) - 1); int toX = GetIndex(BoardGround.FileFrom128(toIndex) - 1); int toY = GetIndex(BoardGround.RankFrom128(toIndex) - 1); // highlight move squares; squares [fromX, fromY].material.color = themes[themeIndex].moveFromHighlightColour; squares [toX, toY].material.color = themes[themeIndex].moveToHighlightColour; }
/// Returns a list of moves given a pgn string. /// Note that BoardGround should be set to whatever starting position of pgn is. public static List <ushort> MovesFromPGN(string pgn) { List <string> moveStrings = MoveStringsFromPGN(pgn); List <ushort> allMoves = new List <ushort> (); MoveGeneratorGround moveGen = new MoveGeneratorGround(); for (int i = 0; i < moveStrings.Count; i++) { string moveString = moveStrings[i]; moveString = moveString.Replace("+", ""); // remove check symbol moveString = moveString.Replace("#", ""); // remove mate symbol moveString = moveString.Replace("x", ""); // remove capture symbol string moveStringLower = moveStrings[i].ToLower(); ushort[] movesInPosition = moveGen.GetMoves(false, false).moves; ushort move = 0; for (int j = 0; j < movesInPosition.Length; j++) { move = movesInPosition[j]; int moveFromIndex = move & 127; int moveToIndex = (move >> 7) & 127; int movePieceType = BoardGround.boardArray[moveFromIndex] & ~1; int colourCode = BoardGround.boardArray[moveFromIndex] & 1; if (moveStringLower == "oo") // castle kingside { if (movePieceType == BoardGround.kingCode && moveToIndex - moveFromIndex == 2) { break; } } else if (moveStringLower == "ooo") // castle queenside { if (movePieceType == BoardGround.kingCode && moveToIndex - moveFromIndex == -2) { break; } } else if (DefinitionsGround.fileNames.Contains(moveString[0] + "")) // pawn move if starts with any file indicator (e.g. 'e'4. Note that uppercase B is used for bishops) { if (movePieceType != BoardGround.pawnCode) { continue; } if (DefinitionsGround.FileNumberFromAlgebraicName(moveStringLower[0]) == BoardGround.FileFrom128(moveFromIndex)) // correct starting file { if (moveString.Contains("=")) // is promotion { char promotionChar = moveStringLower[moveStringLower.Length - 1]; int promotionPieceIndex = move >> 14 & 3; int promotionPieceCode = BoardGround.pieceCodeArray [promotionPieceIndex]; if ((promotionPieceCode == BoardGround.queenCode && promotionChar != 'q') || (promotionPieceCode == BoardGround.rookCode && promotionChar != 'r') || (promotionPieceCode == BoardGround.bishopCode && promotionChar != 'b') || (promotionPieceCode == BoardGround.knightCode && promotionChar != 'n')) { continue; // skip this move, incorrect promotion type } break; } else { char targetFile = moveString[moveString.Length - 2]; char targetRank = moveString[moveString.Length - 1]; if (DefinitionsGround.FileNumberFromAlgebraicName(targetFile) == BoardGround.FileFrom128(moveToIndex)) // correct ending file { if (DefinitionsGround.RankNumberFromAlgebraicName(targetRank) == BoardGround.RankFrom128(moveToIndex)) // correct ending rank { break; } } } } } else // regular piece move { char movePieceChar = moveString[0]; if (!(movePieceType == BoardGround.queenCode && movePieceChar == 'Q') && !(movePieceType == BoardGround.rookCode && movePieceChar == 'R') && !(movePieceType == BoardGround.bishopCode && movePieceChar == 'B') && !(movePieceType == BoardGround.knightCode && movePieceChar == 'N') && !(movePieceType == BoardGround.kingCode && movePieceChar == 'K')) { continue; // skip this move, incorrect move piece type } char targetFile = moveString[moveString.Length - 2]; char targetRank = moveString[moveString.Length - 1]; if (DefinitionsGround.FileNumberFromAlgebraicName(targetFile) == BoardGround.FileFrom128(moveToIndex)) // correct ending file { if (DefinitionsGround.RankNumberFromAlgebraicName(targetRank) == BoardGround.RankFrom128(moveToIndex)) // correct ending rank { if (moveString.Length == 4) // addition char present for disambiguation (e.g. Nbd7 or R7e2) { char disambiguationChar = moveString[1]; if (DefinitionsGround.fileNames.Contains(disambiguationChar + "")) // is file disambiguation { if (DefinitionsGround.FileNumberFromAlgebraicName(disambiguationChar) != BoardGround.FileFrom128(moveFromIndex)) // incorrect starting file { continue; } } else // is rank disambiguation { if (DefinitionsGround.RankNumberFromAlgebraicName(disambiguationChar) != BoardGround.RankFrom128(moveFromIndex)) // incorrect starting rank { continue; } } } break; } } } } if (move == 0) // move is illegal; discard and return moves up to this point { UnityEngine.Debug.Log(moveString); break; } else { allMoves.Add(move); } BoardGround.MakeMove(move); } for (int i = allMoves.Count - 1; i >= 0; i--) { BoardGround.UnmakeMove(allMoves[i]); } return(allMoves); }
public static int Evaluate() { TimerGround.Start("Eval"); int materialEval = 0; int mobilityEval = 0; int developmentEval = 0; int kingSafetyEval = 0; // piece index vars (assigned when found to be used in later calculations) int whiteKingSquareIndex = -1; int blackKingSquareIndex = -1; List <int> whiteQueenIndices = new List <int> (2); List <int> whiteRookIndices = new List <int> (2); List <int> whiteKnightIndices = new List <int> (2); List <int> whiteBishopIndices = new List <int> (2); List <int> whitePawnIndices = new List <int> (8); List <int> blackQueenIndices = new List <int> (2); List <int> blackRookIndices = new List <int> (2); List <int> blackKnightIndices = new List <int> (2); List <int> blackBishopIndices = new List <int> (2); List <int> blackPawnIndices = new List <int> (8); for (int squareIndex = 0; squareIndex <= 127; squareIndex++) { if ((squareIndex & 8) != 0) // don't look at indices which are not on the real board { continue; } if (BoardGround.boardArray[squareIndex] != 0) { int pieceCode = BoardGround.boardArray[squareIndex]; if (pieceCode == BoardGround.kingCode + 1) // found white king { whiteKingSquareIndex = squareIndex; } else if (pieceCode == BoardGround.kingCode) // found black king { blackKingSquareIndex = squareIndex; } else // non-king pieces { materialEval += pieceValues[pieceCode]; // count material (excluding kings) switch (pieceCode) { case BoardGround.queenCode + 1: whiteQueenIndices.Add(squareIndex); break; case BoardGround.rookCode + 1: whiteRookIndices.Add(squareIndex); break; case BoardGround.knightCode + 1: whiteKnightIndices.Add(squareIndex); break; case BoardGround.bishopCode + 1: whiteBishopIndices.Add(squareIndex); break; case BoardGround.pawnCode + 1: whitePawnIndices.Add(squareIndex); break; case BoardGround.queenCode: blackQueenIndices.Add(squareIndex); break; case BoardGround.rookCode: blackRookIndices.Add(squareIndex); break; case BoardGround.knightCode: blackKnightIndices.Add(squareIndex); break; case BoardGround.bishopCode: blackBishopIndices.Add(squareIndex); break; case BoardGround.pawnCode: blackPawnIndices.Add(squareIndex); break; } } } } if (whiteKingSquareIndex == -1) // return best score for black if white's king has been captured (this may sometimes be allowed during alphabeta search for faster move generation) //return int.MinValue; { } // piece mobility moveGenerator.SetMoveColour(1); mobilityEval += moveGenerator.GetMoves(false, true, false).Count; // white piece mobility mobilityEval += moveGenerator.GetMoves(true, true, false).Count; // white piece attacking black moveGenerator.SetMoveColour(0); mobilityEval -= moveGenerator.GetMoves(false, true, false).Count; // black piece mobility mobilityEval -= moveGenerator.GetMoves(true, true, false).Count; // black piece attacking white // piece development white for (int i = 0; i < whiteKnightIndices.Count; i++) { if (BoardGround.RankFrom128(whiteKnightIndices[i]) == 1) // penalize knight remaining on first rank { developmentEval -= 50; } else if (BoardGround.RankFrom128(whiteKnightIndices[i]) == 2) // penalize knight remaining on second rank { developmentEval -= 10; } if (BoardGround.FileFrom128(whiteKnightIndices[i]) == 1) // knights on the rim are dim { developmentEval -= 5; } else if (BoardGround.FileFrom128(whiteKnightIndices[i]) == 8) // knights on the rim are dim { developmentEval -= 5; } } for (int i = 0; i < whiteBishopIndices.Count; i++) { if (BoardGround.RankFrom128(whiteBishopIndices[i]) == 1) // penalize bishop remaining on first rank { developmentEval -= 50; } } // piece development black for (int i = 0; i < blackKnightIndices.Count; i++) { if (BoardGround.RankFrom128(blackKnightIndices[i]) == 8) // penalize knight remaining on eighth rank { developmentEval += 50; } else if (BoardGround.RankFrom128(blackKnightIndices[i]) == 7) // penalize knight remaining on seventh rank { developmentEval += 10; } if (BoardGround.FileFrom128(blackKnightIndices[i]) == 1) // knights on the rim are dim { developmentEval += 5; } else if (BoardGround.FileFrom128(blackKnightIndices[i]) == 8) // knights on the rim are dim { developmentEval += 5; } } for (int i = 0; i < blackBishopIndices.Count; i++) { if (BoardGround.RankFrom128(blackBishopIndices[i]) == 8) // penalize bishop remaining on eighth rank { developmentEval += 50; } } // king safety white if (BoardGround.WhiteHasCastlingRights()) { kingSafetyEval += 10; // not safe, but at least retaining ability to castle } else { if (whiteKingSquareIndex == 6 || whiteKingSquareIndex == 7) // generally safe kingside squares for king (g1,h1) { kingSafetyEval += 50; for (int i = 0; i < whiteRookIndices.Count; i++) { if (BoardGround.FileFrom128(whiteRookIndices[i]) > 6) { kingSafetyEval -= 55; // penalize non-castling king manoeuvres where rook is boxed in by king } } } else if (whiteKingSquareIndex == 2 || whiteKingSquareIndex == 1 || whiteKingSquareIndex == 0) // generally safe queenside squares for king (a1,b1,c1) { kingSafetyEval += 50; for (int i = 0; i < whiteRookIndices.Count; i++) { if (BoardGround.FileFrom128(whiteRookIndices[i]) < 3) { kingSafetyEval -= 55; // penalize non-castling king manoeuvres where rook is boxed in by king } } } } // king safety black if (BoardGround.BlackHasCastlingRights()) { kingSafetyEval -= 10; // not safe, but at least retaining ability to castle } else { if (blackKingSquareIndex == 118 || blackKingSquareIndex == 119) // generally safe kingside squares for king (g8,h8) { kingSafetyEval -= 50; for (int i = 0; i < blackRookIndices.Count; i++) { if (BoardGround.FileFrom128(blackRookIndices[i]) > 6) { kingSafetyEval += 55; // penalize non-castling king manoeuvres where rook is boxed in by king } } } else if (blackKingSquareIndex == 114 || blackKingSquareIndex == 113 || blackKingSquareIndex == 112) // generally safe queenside squares for king (a8,b8,c8) { kingSafetyEval -= 50; for (int i = 0; i < blackRookIndices.Count; i++) { if (BoardGround.FileFrom128(blackRookIndices[i]) < 3) { kingSafetyEval += 55; // penalize non-castling king manoeuvres where rook is boxed in by king } } } } int openingMaterialCount = 16 * pawnValue + 4 * (rookValue + knightValue + bishopValue) + 2 * queenValue; int endgameMaterialCount = 2 * (rookValue + knightValue); //float gameStage = int finalEval = materialEval * 1000 + mobilityEval + kingSafetyEval + developmentEval; TimerGround.Stop("Eval"); return(finalEval); }
public static string NotationFromMove(ushort move) { BoardGround.UnmakeMove(move); // unmake move on board MoveGeneratorGround moveGen = new MoveGeneratorGround(); int moveFromIndex = move & 127; int moveToIndex = (move >> 7) & 127; int promotionPieceIndex = (move >> 14) & 3; // 0 = queen, 1 = rook, 2 = knight, 3 = bishop int colourToMove = BoardGround.boardColourArray[moveFromIndex]; int movePieceCode = BoardGround.boardArray [moveFromIndex]; // get move piece code int movePieceType = movePieceCode & ~1; // get move piece type code (no colour info) int capturedPieceCode = BoardGround.boardArray [moveToIndex]; // get capture piece code int promotionPieceType = BoardGround.pieceCodeArray [promotionPieceIndex]; if (movePieceType == BoardGround.kingCode) { if (moveToIndex - moveFromIndex == 2) { BoardGround.MakeMove(move); // remake move return("O-O"); } else if (moveToIndex - moveFromIndex == -2) { BoardGround.MakeMove(move); // remake move return("O-O-O"); } } string moveNotation = GetSymbolFromPieceType(movePieceType); // check if any ambiguity exists in notation (e.g if e2 can be reached via Nfe2 and Nbe2) if (movePieceType != BoardGround.pawnCode && movePieceType != BoardGround.kingCode) { HeapGround allMoves = moveGen.GetMoves(false, false); for (int i = 0; i < allMoves.Count; i++) { int alternateMoveFromIndex = allMoves.moves[i] & 127; int alternateMoveToIndex = (allMoves.moves[i] >> 7) & 127; int alternateMovePieceCode = BoardGround.boardArray [alternateMoveFromIndex]; if (alternateMoveFromIndex != moveFromIndex && alternateMoveToIndex == moveToIndex) // if moving to same square from different square { if (alternateMovePieceCode == movePieceCode) // same piece type { int fromFileIndex = BoardGround.FileFrom128(moveFromIndex) - 1; int alternateFromFileIndex = BoardGround.FileFrom128(alternateMoveFromIndex) - 1; int fromRankIndex = BoardGround.RankFrom128(moveFromIndex) - 1; int alternateFromRankIndex = BoardGround.RankFrom128(alternateMoveFromIndex) - 1; if (fromFileIndex != alternateFromFileIndex) // pieces on different files, thus ambiguity can be resolved by specifying file { moveNotation += DefinitionsGround.fileNames[fromFileIndex]; break; // ambiguity resolved } else if (fromRankIndex != alternateFromRankIndex) { moveNotation += DefinitionsGround.rankNames[fromRankIndex]; break; // ambiguity resolved } } } } } if (capturedPieceCode != 0) // add 'x' to indicate capture { if (movePieceType == BoardGround.pawnCode) { moveNotation += DefinitionsGround.fileNames[BoardGround.FileFrom128(moveFromIndex) - 1]; } moveNotation += "x"; } else // check if capturing ep { if (movePieceType == BoardGround.pawnCode) { if (System.Math.Abs(moveToIndex - moveFromIndex) != 16 && System.Math.Abs(moveToIndex - moveFromIndex) != 32) { moveNotation += DefinitionsGround.fileNames[BoardGround.FileFrom128(moveFromIndex) - 1] + "x"; } } } moveNotation += DefinitionsGround.fileNames [BoardGround.FileFrom128(moveToIndex) - 1]; moveNotation += DefinitionsGround.rankNames [BoardGround.RankFrom128(moveToIndex) - 1]; // add = piece type if promotion if (movePieceType == BoardGround.pawnCode) { if (moveToIndex >= 112 || moveToIndex <= 7) // pawn has reached first/eighth rank { moveNotation += "=" + GetSymbolFromPieceType(promotionPieceType); } } // add check/mate symbol if applicable BoardGround.MakeMove(move); // remake move if (moveGen.PositionIsMate()) { moveNotation += "#"; } else if (moveGen.PositionIsCheck()) { moveNotation += "+"; } return(moveNotation); }