private double GetTheBestMoveRating(GameState gameState, ChessColor botColor, int deep)
		{
			if (gameState.GameStatus == GameStatus.Finished)
				return GetGameRatingFromGameResult(gameState.GetGameResult());

			var availableMovesRatings = gameState.GetAvailableMoves()
				.Select(move =>
				{
					var gameStateClone = (GameState) gameState.Clone();
					gameStateClone.Move(move);

					return deep == 0
						? _gameStateRatingCalculator.GetGameStateRating(gameStateClone)
						: GetTheBestMoveRating(gameStateClone, botColor.GetOppositeChessColor(), deep - 1);
				});

			switch (botColor)
			{
				case ChessColor.White:
					return availableMovesRatings.Max();
				case ChessColor.Black:
					return availableMovesRatings.Min();
				default:
					throw new ArgumentOutOfRangeException(nameof(botColor));
			}
		}
		public GameMove GetTheBestMove(GameState gameState, ChessColor botColor)
		{
			var availableMovesRatings = gameState.GetAvailableMoves()
				.Select(move =>
				{
					var gameStateClone = (GameState) gameState.Clone();
					gameStateClone.Move(move);

					return new
					{
						Rating = GetTheBestMoveRating(gameStateClone, botColor.GetOppositeChessColor(), _botLevel - 1),
						Move = move
					};
				});

			switch (botColor)
			{
				case ChessColor.White:
					return availableMovesRatings.OrderByDescending(x => x.Rating).First().Move;
				case ChessColor.Black:
					return availableMovesRatings.OrderBy(x => x.Rating).First().Move;
				default:
					throw new ArgumentOutOfRangeException(nameof(botColor));
			}
		}
 public bool IsGameFinished(Chessboard chessboard, GameHistory gameHistory, ChessColor lastTurnBy)
 {
     return(!GetAvailableMoves(chessboard, lastTurnBy.GetOppositeChessColor(), gameHistory).Any() ||
            gameHistory.IsPositionRepeatedThreeTimes);
 }