Example #1
0
    IEnumerator Minimax(ChessBoardSnapshot boardPosition, int depth)
    {
        isRunningMinimax = true;

        //int highestScore = int.MinValue;
        //int highestScoreIndex = -1;
        highestScore      = int.MinValue;
        highestScoreIndex = -1;

        //getAllBoardPositions returns a list of next possible board positions, the boolean flag is to tell whether the current move is Max or Min
        ChessBoardSnapshot[] nextBoardPositions = FindPossibleMoves(boardPosition, playerType);
        totalIterations = nextBoardPositions.Length;

        for (int i = 0; i < nextBoardPositions.Length; i++)
        {
            ChessBoardSnapshot board = nextBoardPositions[i];
            int score = Min(board, depth);
            if (score > highestScore)
            {
                highestScore      = score;
                highestScoreIndex = i;
            }

            lastScore     = score;
            lastIteration = i;
            minimaxResult = nextBoardPositions[highestScoreIndex];
            yield return(null);
        }

        isRunningMinimax = false;
    }
Example #2
0
    public int CalculateScore(ChessBoardSnapshot boardSnapshot, ChessPlayerType playerType)
    {
        int ret = 0;

        ChessPieceType[] board = boardSnapshot.board;

        for (int i = 0; i < board.Length; i++)
        {
            if (!board[i].IsValid())
            {
                continue;
            }
            if (board[i].IsEmpty())
            {
                continue;
            }

            if (board[i].IsSameTeamAs(playerType))
            {
                ret += profilesDict[board[i]].score + 1;
            }
            else if (board[i].IsDifferentTeamAs(playerType))
            {
                ret -= profilesDict[board[i]].score + 1;
            }
        }

        return(ret);
    }
Example #3
0
    IEnumerator MinimaxAB(ChessBoardSnapshot boardPosition, int depth)
    {
        isRunningMinimax = true;

        //int highestScore = int.MinValue;
        //int highestScoreIndex = -1;
        highestScore      = int.MinValue;
        highestScoreIndex = -1;

        ChessBoardSnapshot[] nextBoardPositions = FindPossibleMoves(boardPosition, playerType);
        totalIterations = nextBoardPositions.Length;

        for (int i = 0; i < nextBoardPositions.Length; i++)
        {
            int score = AlphaBeta(nextBoardPositions[i], depth, int.MinValue, int.MaxValue, false);
            if (score > highestScore)
            {
                highestScore      = score;
                highestScoreIndex = i;
            }

            lastScore     = score;
            lastIteration = i;
            minimaxResult = nextBoardPositions[highestScoreIndex];
            yield return(null);
        }

        isRunningMinimax = false;
    }
Example #4
0
    /// <summary>
    /// Generate the next board snapshot
    /// </summary>
    /// <param name="boardSnapshot"></param>
    /// <param name="changed">Changes to the positions</param>
    /// <returns>
    /// A new modified snapshot
    /// </returns>
    public ChessBoardSnapshot GenNextSnapshot(ChessBoardSnapshot boardSnapshot, params ChessPosition[] changed)
    {
        ChessBoardSnapshot newBoard = AdjustBoard(boardSnapshot, "Board #" + snapshots.Count.ToString("0000"), changed);

        snapshots.Add(newBoard);
        return(newBoard);
    }
Example #5
0
    /// <summary>
    /// Use a board snapshot to create the board
    /// </summary>
    /// <param name="boardSnapshot"></param>
    public void LoadFromSnapshot(ChessBoardSnapshot boardSnapshot)
    {
        List <ChessPosition> boardDict = boardSnapshot.ToList();

        if (boardDict.Count <= 0)
        {
            return;
        }

        foreach (KeyValuePair <int, ChessPieceScript> kvp in piecesDict)
        {
            Destroy(kvp.Value.gameObject);
        }

        piecesDict.Clear();

        for (int i = 0; i < boardDict.Count; i++)
        {
            ChessPieceScript newPiece = Instantiate(piecePrefab, chessPiecesParent)
                                        .GetComponent <ChessPieceScript>();

            newPiece.Position = boardDict[i];

            piecesDict.Add(newPiece.Coord.ToArrayCoord(), newPiece);
        }
    }
Example #6
0
    /// <summary>
    /// Adjust the board snapshot and return it back
    /// </summary>
    /// <param name="boardSnapshot"></param>
    /// <param name="newName"></param>
    /// <param name="changed">Changes to the positions</param>
    /// <returns>
    /// A new modified snapshot
    /// </returns>
    public ChessBoardSnapshot AdjustBoard(ChessBoardSnapshot boardSnapshot, string newName = "Board", params ChessPosition[] changed)
    {
        //ChessBoardSnapshot newBoard = ScriptableObject.CreateInstance<ChessBoardSnapshot>();
        ChessBoardSnapshot newBoard = ScriptableObject.Instantiate <ChessBoardSnapshot>(boardSnapshot);

        newBoard.name = newName;

        for (int i = 0; i < changed.Length; i++)
        {
            int aCoord = changed[i].coord.ToArrayCoord();
            newBoard.board[aCoord]    = changed[i].type;
            newBoard.hasMoved[aCoord] = true;
        }

        return(newBoard);
    }
Example #7
0
    int Min(ChessBoardSnapshot boardPosition, int depth)
    {
        if (depth <= 0 || boardPosition.IsEndGame())
        {
            return(GameManager.Instance.CalculateScore(boardPosition, playerType));
        }

        int lowestScore = int.MaxValue;

        ChessBoardSnapshot[] nextBoardPositions = FindPossibleMoves(boardPosition, playerType.ToOpposite());
        for (int i = 0; i < nextBoardPositions.Length; i++)
        {
            ChessBoardSnapshot board = nextBoardPositions[i];
            int score = Max(board, depth - 1);
            if (score < lowestScore)
            {
                lowestScore = score;
            }
        }
        return(lowestScore);
    }
Example #8
0
    IEnumerator IterativeDeepeningSearch(ChessBoardSnapshot boardPosition)
    {
        isRunningItDeep = true;

        float startTime = Time.unscaledTime;
        bool  isOutTime = false;

        for (int depth = 1; (depth <= minDepth || depth <= maxDepth && !isOutTime); depth++)
        {
            StartCoroutine(MinimaxAB(boardPosition, depth));
            hasRunMinimax    = true;
            isRunningMinimax = true;
            iterativeDepth   = depth;
            yield return(new WaitUntil(() => isRunningMinimax == false));

            hasRunMinimax = false;
            isOutTime     = Time.unscaledTime - startTime >= maxTime;
        }

        isRunningItDeep = false;
    }
Example #9
0
    public ChessBoardSnapshot[] FindPossibleMoves(ChessBoardSnapshot boardSnapshot, ChessPlayerType playerType)
    {
        List <ChessBoardSnapshot>       ret       = new List <ChessBoardSnapshot>();
        Dictionary <int, ChessPosition> boardDict = boardSnapshot.ToDictionary();

        foreach (KeyValuePair <int, ChessPosition> kvp in boardDict)
        {
            ChessPosition position = kvp.Value;

            if (position.type.IsDifferentTeamAs(playerType))
            {
                continue;
            }

            ChessCoordinate from = position.coord;

            ChessPieceMove[] possibleMoves = GameManager.Instance.profilesDict[position.type].possibleMoves;

            for (int j = 0; j < possibleMoves.Length; j++)
            {
                ChessCoordinate to = from + possibleMoves[j].move;
                int             k  = 1;

                while
                (
                    to.IsWithinRange() &&
                    (possibleMoves[j].repeatTimes < 0 || k <= possibleMoves[j].repeatTimes)
                )
                {
                    if (GameManager.Instance.IsValidSpecialRule(possibleMoves[j].specialRule, position, from, to))
                    {
                        // When there are only finite amount of moves, set only when reached destination
                        if (possibleMoves[j].repeatTimes < 0 || k == possibleMoves[j].repeatTimes)
                        {
                            bool isLastMove = false;

                            if (possibleMoves[j].pattern == ChessPieceMovePattern.Normal)
                            {
                                if (boardDict.ContainsKey(to.ToArrayCoord()))
                                {
                                    if (boardDict[to.ToArrayCoord()].type.IsSameTeamAs(position.type))
                                    {
                                        break;
                                    }

                                    isLastMove = true;
                                }
                            }
                            else if (possibleMoves[j].pattern == ChessPieceMovePattern.MoveOnly)
                            {
                                if (boardDict.ContainsKey(to.ToArrayCoord()))
                                {
                                    break;
                                }
                            }
                            else if (possibleMoves[j].pattern == ChessPieceMovePattern.CaptureOnly)
                            {
                                if (!boardDict.ContainsKey(to.ToArrayCoord()))
                                {
                                    break;
                                }

                                if (boardDict[to.ToArrayCoord()].type.IsSameTeamAs(position.type))
                                {
                                    break;
                                }
                            }

                            // Pawn Promotion
                            if (position.type.IsPawn())
                            {
                                if
                                (
                                    position.type == ChessPieceType.WhitePawn &&
                                    position.coord.y == 0
                                )
                                {
                                    position.type = ChessPieceType.WhiteQueen;
                                }
                                else if
                                (
                                    position.type == ChessPieceType.BlackPawn &&
                                    position.coord.y == 7
                                )
                                {
                                    position.type = ChessPieceType.BlackQueen;
                                }
                            }

                            ret.Add(GameManager.Instance.AdjustBoard
                                    (
                                        boardSnapshot,
                                        position.type.ToIcon() + " " + from.x + "," + from.y + "-->" + to.x + "," + to.y,
                                        new ChessPosition(ChessPieceType.None, from, true),
                                        new ChessPosition(position.type, to, true)
                                    ));

                            if (isLastMove)
                            {
                                break;
                            }
                        }
                        else
                        {
                            if (boardDict.ContainsKey(to.ToArrayCoord()))
                            {
                                break;
                            }
                        }
                    }

                    to += possibleMoves[j].move;
                    k++;
                }
            }
        }

        return(ret.ToArray());
    }
Example #10
0
    int AlphaBeta(ChessBoardSnapshot boardPosition, int depth, int alpha, int beta, bool maximizingPlayer)
    {
        int         origAlpha = alpha;
        int         origBeta  = beta;
        MinimaxNode node      = new MinimaxNode();

        // Transposition Table Lookup; node is the lookup key for ttEntry
        ulong hash = boardPosition.board.ToZobristHash();

        if (tTable.ContainsKey(hash))
        {
            node = tTable[hash];

            if (node.depth >= depth)
            {
                switch (node.flag)
                {
                case MinimaxNodeFlag.Exact:
                    return(node.eval);

                case MinimaxNodeFlag.LowerBound:
                    if (node.eval > alpha)
                    {
                        alpha = node.eval;
                    }
                    break;

                case MinimaxNodeFlag.UpperBound:
                    if (node.eval < beta)
                    {
                        beta = node.eval;
                    }
                    break;
                }

                if (beta <= alpha)
                {
                    return(node.eval);
                }
            }
        }

        // Minimax + Alpha Beta Pruning
        if (depth <= 0 || boardPosition.IsEndGame())
        {
            return(GameManager.Instance.CalculateScore(boardPosition, playerType));
        }

        int val = 0;

        if (maximizingPlayer)
        {
            val = int.MinValue;
            ChessBoardSnapshot[] nextBoardPositions = FindPossibleMoves(boardPosition, playerType);

            for (int i = 0; i < nextBoardPositions.Length; i++)
            {
                int newValue = AlphaBeta(nextBoardPositions[i], depth - 1, alpha, beta, false);

                if (newValue > val)
                {
                    val = newValue;
                }
                if (val > alpha)
                {
                    alpha = val;
                }
                if (beta <= alpha)
                {
                    break;
                }
            }
        }
        else
        {
            val = int.MaxValue;
            ChessBoardSnapshot[] nextBoardPositions = FindPossibleMoves(boardPosition, playerType.ToOpposite());

            for (int i = 0; i < nextBoardPositions.Length; i++)
            {
                int newValue = AlphaBeta(nextBoardPositions[i], depth - 1, alpha, beta, true);

                if (newValue < val)
                {
                    val = newValue;
                }
                if (val < beta)
                {
                    beta = val;
                }
                if (beta <= alpha)
                {
                    break;
                }
            }
        }

        // Transposition Table Store; node is the lookup key for ttEntry
        node.hash = hash;
        node.eval = val;

        if (val <= origAlpha)
        {
            node.flag = MinimaxNodeFlag.UpperBound;
        }
        else if (val >= origBeta)
        {
            node.flag = MinimaxNodeFlag.LowerBound;
        }
        else
        {
            node.flag = MinimaxNodeFlag.Exact;
        }

        node.depth = depth;

        if (tTable.ContainsKey(hash))
        {
            tTable[hash] = node;
        }
        else
        {
            tTable.Add(hash, node);
        }

        return(val);
    }