示例#1
0
    /// <summary>
    /// Finds the ray in provided moveset that leads to provided destination.
    /// </summary>
    /// <param name="mset">The moveset to search.</param>
    /// <param name="to">The destination to find.</param>
    /// <returns>The ray that leads to the destination.</returns>
    private List <byte> _getRayIn(cgMoveSet mset, byte to)
    {
        byte startORay = 0;
        byte endORay   = 0;

        for (byte i = 0; i < mset.moves.Count; i++)
        {
            if (mset.moves[i] == -1)
            {
                startORay = i;
            }
            else if (mset.moves[i] == to)
            {
                endORay = i;
                break;
            }
        }
        List <byte> returns = new List <byte>();

        for (int u = startORay; u < (endORay); u++)
        {
            returns.Add((byte)mset.moves[u]);
        }
        return(returns);
    }
示例#2
0
    /// <summary>
    /// Gets full ray(not cut at destination) in moveset that includes index position.
    /// </summary>
    /// <param name="set">The moveset to search</param>
    /// <param name="includesIndex">The index to find</param>
    /// <returns>the full ray that includes the index position</returns>
    private List <byte> _getFullRayFor(cgMoveSet set, byte includesIndex)
    {
        byte startOfRay = 0;
        byte endOfRay   = 65;
        bool hitRay     = false;

        if (set.type != 2 && set.type != 4 && set.type != 5)
        {
            return(null);
        }
        for (byte i = 0; i < set.moves.Count; i++)
        {
            if (set.moves[i] == -1 && !hitRay)
            {
                startOfRay = (byte)(i + 1);
            }
            else if (set.moves[i] == -1 && hitRay)
            {
                endOfRay = (byte)(i);
                break;
            }
            if (set.moves[i] == includesIndex)
            {
                hitRay = true;
            }
        }
        if (!hitRay)
        {
            return(null);
        }
        else
        {
            List <byte> ray = new List <byte>();
            for (int u = startOfRay; u < endOfRay; u++)
            {
                if (set.moves[u] > -1)
                {
                    ray.Add((byte)set.moves[u]);
                }
            }

            //Debug.Log("retrieving entire ray for type:" + set.type + " searching for:" + includesIndex + " found at:" + startOfRay + " to:" + endOfRay + " we hit the ray:" + hitRay);
            //Debug.Log("ray length: " + ray.Count);
            return(ray);
        }
    }
示例#3
0
    /// <summary>
    /// Examines a moveset(all moves for a piece on a given square), and removes all illegal moves in this moveset based on the current board.
    /// </summary>
    /// <param name="moveSet">The moveset to examine</param>
    /// <returns>All unblocked moves</returns>
    private List <cgSimpleMove> removeIllegalMoves(cgMoveSet moveSet)
    {
        List <cgSimpleMove> returns = new List <cgSimpleMove>();
        bool asWhite   = squares[moveSet.from] > 0 ? true : false;
        bool rayGoing  = true;
        bool canAttack = (moveSet.type == -1 || moveSet.type == 1) ? false : true;
        bool canMove   = true;

        for (int i = 0; i < moveSet.moves.Count; i++)
        {
            if (moveSet.type == 3 || moveSet.type == 6)
            {
                rayGoing = true;                                         //add knight or king moves regardless of ray.
            }
            if (moveSet.moves[i] == -1)
            {
                rayGoing = true;
                continue;
            }
            if (moveSet.moves[i] == -2)
            {
                //-2 signifies the beginning of attack only moves(pawn's forward diagonal attacks)
                canAttack = true;
                canMove   = false;
                continue;
            }
            if (rayGoing || !canMove)
            {
                if (squares[moveSet.moves[i]] == 0 && canMove)
                {
                    returns.Add(new cgSimpleMove(moveSet.from, (byte)moveSet.moves[i], moveSet.positionalValues[i]));
                }
                else if ((squares[moveSet.moves[i]] > 0 && !asWhite) || (squares[moveSet.moves[i]] < 0 && asWhite))
                {
                    if (canAttack)
                    {
                        //If I am white and attacking a black piece then I can take, or if I am black and attacking a white I can take - (Unless I'm a pawn);
                        returns.Add(new cgSimpleMove(moveSet.from, (byte)moveSet.moves[i], cgValueModifiers.AlphaBeta_Weight_Capture));
                        if (Mathf.Abs(squares[moveSet.moves[i]]) == 6)
                        {
                            returns[returns.Count - 1].positionalVal = cgValueModifiers.AlphaBeta_Weight_Check;
                        }
                        //UnityEngine.Debug.Log("piece on" + moveSet.from + " takes on" + moveSet.moves[i]+" as white: "+asWhite+" piece on destination:"+_board.squares[moveSet.moves[i]]);
                        //continue;
                    }
                    rayGoing = false; //cannot continue further down this ray.

                    continue;
                }
                //test if an en passant move is possible
                else if (squares[moveSet.moves[i]] == 0 && canAttack && !canMove && _enPassantSquare == moveSet.moves[i])
                {
                    returns.Add(new cgEnPassantMove(moveSet.from, (byte)moveSet.moves[i], cgValueModifiers.AlphaBeta_Weight_Capture, _enPassantCapturesOn));
                }

                else if ((squares[moveSet.moves[i]] > 0 && asWhite) || (squares[moveSet.moves[i]] < 0 && !asWhite))
                {
                    //Black on black or white on white. Cannot make the move, and am now blocked from going further down this ray.
                    rayGoing = false;
                    continue;
                }
            }
        }
        return(returns);
    }
示例#4
0
    /// <summary>
    /// Returns all legal moves for the provided color for the current board.
    /// Note: it may return a move in which the king captures an enemy piece to which the enemy can then next capture the king, use findStrictLegalMoves to avoid - however for the engine the computation to verify such a move are too costly.
    /// </summary>
    /// <param name="asWhite">Move as white?</param>
    /// <returns>All legal moves for provided color</returns>
    public List <cgSimpleMove> findLegalMoves(bool asWhite)
    {
        List <cgSimpleMove> legalMoves = new List <cgSimpleMove>();
        List <cgSimpleMove> enemyMoves = new List <cgSimpleMove>();

        bool check = false;

        _enPassantSquare     = 65;
        _enPassantCapturesOn = 65;

        //test if there's an en passant opportunity.
        if (moves.Count > 0 && moves[moves.Count - 1].to != 65)
        {
            if (Mathf.Abs(squares[moves[moves.Count - 1].to]) == 1)
            {
                //its a pawn
                if (Mathf.Abs(moves[moves.Count - 1].from - moves[moves.Count - 1].to) == 16)
                {
                    //pawn did a double move the last move, this means we got ourselves an enpassant opportunity.
                    _enPassantSquare     = (byte)(moves[moves.Count - 1].from + ((moves[moves.Count - 1].to >= 32) ? -8 : 8));
                    _enPassantCapturesOn = moves[moves.Count - 1].to;
                }
            }
        }
        for (int i = 0; i < squares.Count; i++)
        {
            int piece = squares[i];
            if ((piece > 0 && asWhite) || (piece < 0 && !asWhite))
            {
                cgMoveSet allPotentialeMoves = _findMoveSetFor(piece, i);
                //UnityEngine.Debug.Log("Moves:" + moves);
                if (allPotentialeMoves != null)
                {
                    legalMoves.AddRange(removeIllegalMoves(allPotentialeMoves));
                }
            }
            else if (piece != 0)
            {
                //piece is not empty and is not same colour as moving player.
                enemyMoves.AddRange(removeIllegalMoves(_findMoveSetFor(piece, i)));
            }
            //legalMoves.AddRange(weakLegalMoves);
        }

        //examine whether castling is possible, first by seeing if castling rights exist(i.e king and rooks hasnt moved).
        bool shortCastling = shortCastlingRights(asWhite);
        bool longCastling  = longCastlingRights(asWhite);

        //second by seing if rooks have been captured or not.
        if (shortCastling)
        {
            shortCastling = asWhite ? squares[63] == 2 : squares[7] == -2;
        }
        if (longCastling)
        {
            longCastling = asWhite ? squares[56] == 2 : squares[0] == -2;
        }
        //thirdly see if the squares necessary for castling are unoccupied.
        if (asWhite && shortCastling)
        {
            shortCastling = (squares[61] == 0 && squares[62] == 0) ? true : false;
        }
        else if (!asWhite && shortCastling)
        {
            shortCastling = (squares[5] == 0 && squares[6] == 0) ? true : false;
        }
        if (asWhite && longCastling)
        {
            longCastling = (squares[58] == 0 && squares[59] == 0 && squares[57] == 0) ? true : false;
        }
        else if (!asWhite && longCastling)
        {
            longCastling = (squares[2] == 0 && squares[3] == 0 && squares[1] == 0) ? true : false;
        }

        foreach (cgSimpleMove move in enemyMoves)
        {
            if (Mathf.Abs(squares[move.to]) == 6)
            {
                //there is an enemy move attacking our king. We cannot castle now and we have to deal with this check.
                check         = true;
                shortCastling = false;
                longCastling  = false;
            }
            //check if any enemy move which is attacking a non-king piece of mine is on a ray that leads to my king, to see if any of my pieces are pinned and thusly illegal to move out of said ray.
            else if (Mathf.Abs(squares[move.to]) != 0)
            {
                List <byte> ray = _getFullRayFor(_findMoveSetFor(squares[move.from], move.from), move.to);
                if (ray != null)
                {
                    byte  hitsAlongRay  = 0;
                    sbyte hasHitAtIndex = -1;
                    for (byte b = 0; b < ray.Count; b++)
                    {
                        if ((squares[ray[b]] == 6 && squares[move.from] < 0) || (squares[ray[b]] == -6 && squares[move.from] > 0))
                        {
                            //on a ray attacking my king.
                            hasHitAtIndex = (sbyte)b;
                            break;
                        }
                        else if ((squares[ray[b]] > 0 && squares[move.from] < 0) || (squares[move.from] > 0 && squares[ray[b]] < 0))
                        {
                            //count a piece on the ray.
                            hitsAlongRay++;
                        }
                    }

                    //this enemy move is on a ray to attack my king, and its only being blocked by one piece(hitsalongray == 1) - so that piece is pinned and cannot move, so we delete all its mvoes(except any move it can make that captures the enemy piece or moves that are on the ray between king and attacking piece).
                    if (hasHitAtIndex != -1 && hitsAlongRay == 1)
                    {
                        ray.RemoveRange(hasHitAtIndex, ray.Count - hasHitAtIndex);
                        for (byte c = (byte)(legalMoves.Count - 1); c > 0; c--)
                        {
                            if (ray.Contains(legalMoves[c].from))
                            {
                                if (!ray.Contains(legalMoves[c].to) && legalMoves[c].to != move.from)
                                {
                                    legalMoves.RemoveAt(c);
                                }
                            }
                        }
                    }
                }
            }
            //disallowing castling(if its not already disallowed) if any enemy move attacks any castlign square
            if (shortCastling)
            {
                if (asWhite)
                {
                    if (move.to == 61 || move.to == 62)
                    {
                        shortCastling = false;
                    }
                }
                else if (!asWhite)
                {
                    if (move.to == 5 || move.to == 6)
                    {
                        shortCastling = false;
                    }
                }
            }
            if (longCastling)
            {
                if (asWhite)
                {
                    if (move.to == 58 || move.to == 59)
                    {
                        longCastling = false;
                    }
                }
                else if (!asWhite)
                {
                    if (move.to == 2 || move.to == 3)
                    {
                        longCastling = false;
                    }
                }
            }
        }
        //We've jumped through 5 hoops to test the legality of castling, if shortcastling or longcastling is still true, we're in the clear.
        if (longCastling && asWhite)
        {
            legalMoves.Add(new cgCastlingMove(60, 58, cgValueModifiers.AlphaBeta_Weight_LongCastle, 56, 59));
        }
        else if (longCastling && !asWhite)
        {
            legalMoves.Add(new cgCastlingMove(4, 2, cgValueModifiers.AlphaBeta_Weight_LongCastle, 0, 3));
        }
        if (shortCastling && asWhite)
        {
            legalMoves.Add(new cgCastlingMove(60, 62, cgValueModifiers.AlphaBeta_Weight_ShortCastle, 63, 61));
        }
        else if (shortCastling && !asWhite)
        {
            legalMoves.Add(new cgCastlingMove(4, 6, cgValueModifiers.AlphaBeta_Weight_ShortCastle, 7, 5));
        }
        legalMoves.Sort(delegate(cgSimpleMove x, cgSimpleMove y)
        {
            return(x.positionalVal.CompareTo(y.positionalVal));
        });
        legalMoves.Reverse();

        //check if any king move is illegal(if it would move to a square an enemy may attack).
        for (short b = (short)(legalMoves.Count); b > 0; b--)
        {
            if (Mathf.Abs(squares[legalMoves[b - 1].from]) == 6)
            {
                foreach (cgSimpleMove mov in enemyMoves)
                {
                    if (mov.to == legalMoves[b - 1].to && Mathf.Abs(squares[mov.from]) != 1)
                    {
                        legalMoves.RemoveAt(b - 1);
                        break;
                    }
                }
            }
        }

        //to make certain the engine gets to check.
        if (legalMoves.Count == 0)
        {
            legalMoves.Add(new cgSimpleMove(65, 65));
        }
        //since there are no enemy moves checking my king we return all legal moves(note legal moves may still contain illegal moves that lead to my king captured next- which is illegal in chess).
        if (!check)
        {
            return(legalMoves);
        }
        else if (check)
        {
            //there is atleast one enemy move currently checking my king. :(
            List <cgSimpleMove> checkingMoves = new List <cgSimpleMove>();
            foreach (cgSimpleMove movve in enemyMoves)
            {
                if (Mathf.Abs(squares[movve.to]) == 6)
                {
                    checkingMoves.Add(movve);
                }
            }
            if (checkingMoves.Count == 1)
            {
                //as the king is only attacked by a single enemy move we may capture said single piece or block the path(if its a ray i.e attacking piece is not a knight or is not adjacent to the king)
                List <byte> legalMoveToSquares = _getBlockAttackSquares(checkingMoves[0]);
                for (int u = legalMoves.Count; u > 0; u--)
                {
                    if (legalMoves[u - 1].to == 65)
                    {
                        continue;
                    }
                    if (!legalMoveToSquares.Contains(legalMoves[u - 1].to) && Mathf.Abs(squares[legalMoves[u - 1].from]) != 6)
                    {
                        legalMoves.RemoveAt(u - 1);
                    }
                }
            }
            else
            {
                //King is attacked by more than 1 enemy move, we have to move the king or lose.
                for (int u = legalMoves.Count; u > 0; u--)
                {
                    if (legalMoves[u - 1].from < 65 && Mathf.Abs(squares[legalMoves[u - 1].from]) != 6)
                    {
                        legalMoves.RemoveAt(u - 1);
                    }
                }
            }
        }

        //to make certain the engine gets to check.
        if (legalMoves.Count == 0)
        {
            legalMoves.Add(new cgSimpleMove(65, 65));
        }

        return(legalMoves);
        //UnityEngine.Debug.Log("Legal moves:" + legalMoves.Count);
    }