Example #1
0
        private MoveSet GetValidGrasshopperMovements(Piece targetPiece)
        {
            MoveSet validMoves = new MoveSet();

            Position startingPosition = targetPiece.Position;

            foreach (Direction direction in EnumUtils.Directions)
            {
                Position landingPosition = startingPosition.NeighborAt(direction);

                int distance = 0;
                while (HasPieceAt(landingPosition))
                {
                    // Jump one more in the same direction
                    landingPosition = landingPosition.NeighborAt(direction);
                    distance++;
                }

                if (distance > 0)
                {
                    // Can only move if there's at least one piece in the way
                    Move move = new Move(targetPiece.PieceName, landingPosition);
                    validMoves.Add(move);
                }
            }

            return(validMoves);
        }
Example #2
0
        private MoveSet GetValidSpiderMovements(Piece targetPiece)
        {
            MoveSet validMoves = new MoveSet();

            // Get all slides up to 2 spots away
            MoveSet upToTwo = GetValidSlides(targetPiece, 2);

            if (upToTwo.Count > 0)
            {
                // Get all slides up to 3 spots away
                MoveSet upToThree = GetValidSlides(targetPiece, 3);

                if (upToThree.Count > 0)
                {
                    // Get all slides ONLY 3 spots away
                    upToThree.Remove(upToTwo);

                    if (upToThree.Count > 0)
                    {
                        validMoves.Add(upToThree);
                    }
                }
            }

            return(validMoves);
        }
Example #3
0
        private MoveSet GetValidMoves(PieceName pieceName)
        {
            if (null == _cachedValidMovesByPiece)
            {
                _cachedValidMovesByPiece = new MoveSet[EnumUtils.NumPieceNames];
            }

            int pieceNameIndex = (int)pieceName;

            if (null != _cachedValidMovesByPiece[pieceNameIndex])
            {
                // MoveSet is cached in L1 cache
                ValidMoveCacheMetricsSet["ValidMoves." + EnumUtils.GetShortName(pieceName)].Hit();
            }
            else
            {
                // MoveSet is not cached in L1 cache
                ValidMoveCacheMetricsSet["ValidMoves." + EnumUtils.GetShortName(pieceName)].Miss();

                // Calculate MoveSet
                Piece   targetPiece = GetPiece(pieceName);
                MoveSet moves       = GetValidMovesInternal(targetPiece);
                moves.Lock();

                // Populate cache
                _cachedValidMovesByPiece[pieceNameIndex] = moves;
            }

            return(_cachedValidMovesByPiece[pieceNameIndex]);
        }
Example #4
0
        private MoveSet GetValidPillbugSpecialAbilityMovements(Piece targetPiece)
        {
            MoveSet validMoves = new MoveSet();

            Position positionAboveTargetPiece = targetPiece.Position.GetAbove();

            for (int dir = 0; dir < EnumUtils.NumDirections; dir++)
            {
                Position neighbor = targetPiece.Position.NeighborAt(dir);
                Piece    piece    = GetPiece(neighbor);
                if (null != piece && piece.PieceName != LastPieceMoved && null == piece.PieceAbove && CanMoveWithoutBreakingHive(piece))
                {
                    // Piece can be moved
                    Move firstMove = new Move(piece.PieceName, positionAboveTargetPiece);
                    if (GetValidBeetleMovements(piece).Contains(firstMove))
                    {
                        // Piece can be moved on top
                        Position pieceStartingPosition = piece.Position;
                        MovePiece(piece, positionAboveTargetPiece, false);

                        foreach (Move secondMove in GetValidBeetleMovements(piece))
                        {
                            if (secondMove.Position.Stack == 0 && secondMove.Position != pieceStartingPosition)
                            {
                                validMoves.Add(secondMove);
                            }
                        }

                        MovePiece(piece, pieceStartingPosition, false);
                    }
                }
            }

            return(validMoves);
        }
Example #5
0
        private void SetCurrentPlayerMetrics()
        {
            bool pullbugEnabled  = EnumUtils.IsEnabled(BugType.Pillbug, ExpansionPieces);
            bool mosquitoEnabled = EnumUtils.IsEnabled(BugType.Mosquito, ExpansionPieces);

            MoveSet pillbugMoves  = pullbugEnabled ? GetValidMoves(CurrentTurnColor == PlayerColor.White ? PieceName.WhitePillbug : PieceName.BlackPillbug) : null;
            MoveSet mosquitoMoves = pullbugEnabled && mosquitoEnabled?GetValidMoves(CurrentTurnColor == PlayerColor.White?PieceName.WhiteMosquito : PieceName.BlackMosquito) : null;

            foreach (PieceName pieceName in CurrentTurnPieces)
            {
                Piece targetPiece = GetPiece(pieceName);

                if (null != targetPiece)
                {
                    if (targetPiece.InPlay)
                    {
                        _boardMetrics.PiecesInPlay++;
                        _boardMetrics[pieceName].InPlay = 1;
                    }
                    else
                    {
                        _boardMetrics.PiecesInHand++;
                        _boardMetrics[pieceName].InPlay = 0;
                    }

                    // Move metrics
                    bool isPinned = IsPinned(pieceName, out _boardMetrics[pieceName].NoisyMoveCount, out _boardMetrics[pieceName].QuietMoveCount);

                    if (isPinned && pullbugEnabled)
                    {
                        bool pullbugCanMove  = pillbugMoves.Contains(pieceName);
                        bool mosquitoCanMove = mosquitoEnabled && mosquitoMoves.Contains(pieceName);

                        if (targetPiece.BugType == BugType.Pillbug)
                        {
                            // Check if the current player's mosquito can move it
                            isPinned = !mosquitoCanMove;
                        }
                        else if (targetPiece.BugType == BugType.Mosquito)
                        {
                            // Check if the current player's pillbug can move it
                            isPinned = !pullbugCanMove;
                        }
                        else
                        {
                            // Check if the current player's pillbug or mosquito can move it
                            isPinned = !(mosquitoCanMove || pullbugCanMove);
                        }
                    }

                    _boardMetrics[pieceName].IsPinned  = isPinned ? 1 : 0;
                    _boardMetrics[pieceName].IsCovered = targetPiece.InPlay && null != targetPiece.PieceAbove ? 1 : 0;

                    CountNeighbors(targetPiece, out _boardMetrics[pieceName].FriendlyNeighborCount, out _boardMetrics[pieceName].EnemyNeighborCount);
                }
            }
        }
Example #6
0
        public async Task <long?> ParallelPerftAsync(int depth, int maxThreads, CancellationToken token)
        {
            if (depth == 0)
            {
                return(1);
            }

            MoveSet validMoves = GetValidMoves();

            if (depth == 1)
            {
                return(validMoves.Count);
            }

            long?nodes = await Task.Run(() =>
            {
                ParallelOptions po = new ParallelOptions
                {
                    MaxDegreeOfParallelism = Math.Max(1, maxThreads)
                };

                long n = 0;
                ParallelLoopResult loopResult = Parallel.ForEach(validMoves, po, async(move, state) =>
                {
                    if (token.IsCancellationRequested)
                    {
                        state.Stop();
                        return;
                    }

                    GameBoard clone = Clone();
                    clone.TrustedPlay(move);
                    long?value = await clone.CalculatePerftAsync(depth - 1, token);

                    if (!value.HasValue)
                    {
                        state.Stop();
                        return;
                    }

                    Interlocked.Add(ref n, value.Value);
                });

                return(loopResult.IsCompleted && !token.IsCancellationRequested ? (long?)n : null);
            });

            return(nodes);
        }
Example #7
0
        private MoveSet GetValidSlides(Piece targetPiece, int?maxRange)
        {
            MoveSet validMoves = new MoveSet();

            Position startingPosition = targetPiece.Position;

            HashSet <Position> visitedPositions = new HashSet <Position>();

            visitedPositions.Add(startingPosition);

            MovePiece(targetPiece, null, false);
            GetValidSlides(targetPiece.PieceName, startingPosition, visitedPositions, 0, maxRange, validMoves);
            MovePiece(targetPiece, startingPosition, false);

            return(validMoves);
        }
Example #8
0
        public void Add(MoveSet moves)
        {
            if (null == moves)
            {
                throw new ArgumentNullException("moves");
            }

            if (IsLocked)
            {
                throw new MoveSetIsLockedException();
            }

            foreach (Move move in moves)
            {
                _moves.Add(move);
            }
        }
Example #9
0
        private MoveSet GetValidBeetleMovements(Piece targetPiece)
        {
            MoveSet validMoves = new MoveSet();

            // Look in all directions
            for (int direction = 0; direction < EnumUtils.NumDirections; direction++)
            {
                Position newPosition = targetPiece.Position.NeighborAt(direction);

                Piece topNeighbor = GetPieceOnTopInternal(newPosition);

                // Get positions to left and right or direction we're heading
                int      leftOfTarget          = EnumUtils.LeftOf(direction);
                int      rightOfTarget         = EnumUtils.RightOf(direction);
                Position leftNeighborPosition  = targetPiece.Position.NeighborAt(leftOfTarget);
                Position rightNeighborPosition = targetPiece.Position.NeighborAt(rightOfTarget);

                Piece topLeftNeighbor  = GetPieceOnTopInternal(leftNeighborPosition);
                Piece topRightNeighbor = GetPieceOnTopInternal(rightNeighborPosition);

                // At least one neighbor is present
                uint currentHeight     = targetPiece.Position.Stack + 1;
                uint destinationHeight = null != topNeighbor ? topNeighbor.Position.Stack + 1 : 0;

                uint topLeftNeighborHeight  = null != topLeftNeighbor ? topLeftNeighbor.Position.Stack + 1 : 0;
                uint topRightNeighborHeight = null != topRightNeighbor ? topRightNeighbor.Position.Stack + 1 : 0;

                // "Take-off" beetle
                currentHeight--;

                if (!(currentHeight == 0 && destinationHeight == 0 && topLeftNeighborHeight == 0 && topRightNeighborHeight == 0))
                {
                    // Logic from http://boardgamegeek.com/wiki/page/Hive_FAQ#toc9
                    if (!(destinationHeight < topLeftNeighborHeight && destinationHeight < topRightNeighborHeight && currentHeight < topLeftNeighborHeight && currentHeight < topRightNeighborHeight))
                    {
                        Position targetPosition = (newPosition.Stack == destinationHeight) ? newPosition : topNeighbor.Position.GetAbove();
                        Move     targetMove     = new Move(targetPiece.PieceName, targetPosition);
                        validMoves.Add(targetMove);
                    }
                }
            }

            return(validMoves);
        }
Example #10
0
        public MoveSet GetValidMoves()
        {
            MoveSet moves = new MoveSet();

            if (GameInProgress)
            {
                foreach (PieceName pieceName in CurrentTurnPieces)
                {
                    moves.Add(GetValidMoves(pieceName));
                }

                if (moves.Count == 0)
                {
                    moves.Add(Move.Pass);
                }
            }

            return(moves);
        }
Example #11
0
        public async Task <long?> CalculatePerftAsync(int depth, CancellationToken token)
        {
            if (depth == 0)
            {
                return(1);
            }

            MoveSet validMoves = GetValidMoves();

            if (depth == 1)
            {
                return(validMoves.Count);
            }

            long?nodes = null;

            foreach (Move move in validMoves)
            {
                if (token.IsCancellationRequested)
                {
                    break;
                }

                TrustedPlay(move);
                long?value = await CalculatePerftAsync(depth - 1, token);

                UndoLastMove();

                if (!value.HasValue)
                {
                    return(null);
                }

                if (!nodes.HasValue)
                {
                    nodes = 0;
                }

                nodes += value;
            }

            return(nodes);
        }
Example #12
0
        private MoveSet GetValidSpiderMovements(Piece targetPiece)
        {
            // Get all slides up to 2 spots away
            MoveSet upToTwo = GetValidSlides(targetPiece, 2);

            if (upToTwo.Count > 0)
            {
                // Get all slides up to 3 spots away
                MoveSet upToThree = GetValidSlides(targetPiece, 3);

                if (upToThree.Count > 0)
                {
                    // Get all slides ONLY 3 spots away
                    upToThree.Remove(upToTwo);

                    return(upToThree);
                }
            }

            return(MoveSet.EmptySet);
        }
Example #13
0
        public static string ToBoardSpaceMoveStringList(Board board, MoveSet moves)
        {
            if (null == board)
            {
                throw new ArgumentNullException(nameof(board));
            }

            if (null == moves)
            {
                throw new ArgumentNullException(nameof(moves));
            }

            StringBuilder sb = new StringBuilder();

            foreach (Move move in moves)
            {
                sb.AppendFormat("{0}{1}", ToBoardSpaceMoveString(board, move), MoveSet.MoveStringSeparator);
            }

            return(sb.ToString().TrimEnd(MoveSet.MoveStringSeparator));
        }
Example #14
0
        public static MoveSet ParseMoveStringList(Board board, string moveStringList)
        {
            if (null == board)
            {
                throw new ArgumentNullException(nameof(board));
            }

            if (string.IsNullOrWhiteSpace(moveStringList))
            {
                throw new ArgumentNullException(nameof(moveStringList));
            }

            string[] split = moveStringList.Split(new char[] { MoveSet.MoveStringSeparator }, StringSplitOptions.RemoveEmptyEntries);

            MoveSet moves = new MoveSet();

            for (int i = 0; i < split.Length; i++)
            {
                Move parseMove = ParseMoveString(board, split[i]);
                moves.Add(parseMove);
            }
            return(moves);
        }
Example #15
0
        private MoveSet GetValidLadybugMovements(Piece targetPiece)
        {
            MoveSet validMoves = new MoveSet();

            Position startingPosition = targetPiece.Position;

            foreach (Move firstMove in GetValidBeetleMovements(targetPiece))
            {
                if (firstMove.Position.Stack > 0)
                {
                    MovePiece(targetPiece, firstMove.Position, false);

                    foreach (Move secondMove in GetValidBeetleMovements(targetPiece))
                    {
                        if (secondMove.Position.Stack > 0)
                        {
                            MovePiece(targetPiece, secondMove.Position, false);

                            foreach (Move thirdMove in GetValidBeetleMovements(targetPiece))
                            {
                                if (thirdMove.Position.Stack == 0 && thirdMove.Position != startingPosition)
                                {
                                    validMoves.Add(thirdMove);
                                }
                            }

                            MovePiece(targetPiece, firstMove.Position, false);
                        }
                    }

                    MovePiece(targetPiece, startingPosition, false);
                }
            }

            return(validMoves);
        }
Example #16
0
        private MoveSet GetValidPlacements(Piece targetPiece)
        {
            PlayerColor targetColor = CurrentTurnColor;

            if (targetPiece.Color != targetColor)
            {
                return(MoveSet.EmptySet);
            }

            if (null == _cachedValidPlacementPositions)
            {
                _cachedValidPlacementPositions = new HashSet <Position>();

                _visitedPlacements = new HashSet <Position>();

                for (int i = 0; i < EnumUtils.NumPieceNames; i++)
                {
                    Piece piece = _pieces[i];
                    if (null != piece && piece.InPlay && PieceIsOnTop(piece) && piece.Color == targetColor)
                    {
                        // Piece is in play, on the top and is the right color, look through neighbors
                        Position bottomPosition = GetPieceOnBottom(piece).Position;
                        _visitedPlacements.Add(bottomPosition);

                        for (int j = 0; j < EnumUtils.NumDirections; j++)
                        {
                            Position neighbor = bottomPosition.NeighborAt(j);

                            if (_visitedPlacements.Add(neighbor) && !HasPieceAt(neighbor))
                            {
                                // Neighboring position is a potential, verify its neighbors are empty or same color
                                bool validPlacement = true;
                                for (int k = 0; k < EnumUtils.NumDirections; k++)
                                {
                                    Position surroundingPosition = neighbor.NeighborAt(k);
                                    Piece    surroundingPiece    = GetPieceOnTopInternal(surroundingPosition);
                                    if (null != surroundingPiece && surroundingPiece.Color != targetColor)
                                    {
                                        validPlacement = false;
                                        break;
                                    }
                                }

                                if (validPlacement)
                                {
                                    _cachedValidPlacementPositions.Add(neighbor);
                                }
                            }
                        }
                    }
                }
#if DEBUG
                ValidMoveCacheMetricsSet["ValidPlacements"].Miss();
#endif
            }
#if DEBUG
            else
            {
                ValidMoveCacheMetricsSet["ValidPlacements"].Hit();
            }
#endif
            MoveSet validMoves = new MoveSet();

            foreach (Position validPlacement in _cachedValidPlacementPositions)
            {
                validMoves.Add(new Move(targetPiece.PieceName, validPlacement));
            }

            return(validMoves);
        }
Example #17
0
        private MoveSet GetValidMovesInternal(Piece targetPiece)
        {
            if (null != targetPiece && GameInProgress)
            {
                if (targetPiece.Color == CurrentTurnColor && PlacingPieceInOrder(targetPiece))
                {
                    if (CurrentTurn == 0 && targetPiece.Color == PlayerColor.White && targetPiece.InHand)
                    {
                        // First move must be at the origin and not the White Queen Bee
                        if (targetPiece.PieceName == PieceName.WhiteQueenBee)
                        {
                            return(MoveSet.EmptySet);
                        }

                        return(new MoveSet()
                        {
                            new Move(targetPiece.PieceName, Position.Origin)
                        });
                    }
                    else if (CurrentTurn == 1 && targetPiece.Color == PlayerColor.Black && targetPiece.InHand)
                    {
                        // Second move must be around the origin and not the Black Queen Bee
                        if (targetPiece.PieceName == PieceName.BlackQueenBee)
                        {
                            return(MoveSet.EmptySet);
                        }

                        MoveSet validMoves = new MoveSet();

                        for (int i = 0; i < EnumUtils.NumDirections; i++)
                        {
                            Position neighbor = Position.Origin.NeighborAt(i);
                            validMoves.Add(new Move(targetPiece.PieceName, neighbor));
                        }

                        return(validMoves);
                    }
                    else if (targetPiece.InHand && (CurrentPlayerTurn != 4 ||                                                                            // Normal turn OR
                                                    (CurrentPlayerTurn == 4 &&                                                                           // Turn 4 and AND
                                                     (CurrentTurnQueenInPlay || (!CurrentTurnQueenInPlay && targetPiece.BugType == BugType.QueenBee))))) // Queen is in play or you're trying to play it
                    {
                        // Look for valid new placements
                        return(GetValidPlacements(targetPiece));
                    }
                    else if (targetPiece.PieceName != LastPieceMoved && targetPiece.InPlay && CurrentTurnQueenInPlay && PieceIsOnTop(targetPiece))
                    {
                        MoveSet validMoves = new MoveSet();

                        if (CanMoveWithoutBreakingHive(targetPiece))
                        {
                            // Look for basic valid moves of played pieces who can move
                            switch (targetPiece.BugType)
                            {
                            case BugType.QueenBee:
                                validMoves.Add(GetValidQueenBeeMovements(targetPiece));
                                break;

                            case BugType.Spider:
                                validMoves.Add(GetValidSpiderMovements(targetPiece));
                                break;

                            case BugType.Beetle:
                                validMoves.Add(GetValidBeetleMovements(targetPiece));
                                break;

                            case BugType.Grasshopper:
                                validMoves.Add(GetValidGrasshopperMovements(targetPiece));
                                break;

                            case BugType.SoldierAnt:
                                validMoves.Add(GetValidSoldierAntMovements(targetPiece));
                                break;

                            case BugType.Mosquito:
                                validMoves.Add(GetValidMosquitoMovements(targetPiece, false));
                                break;

                            case BugType.Ladybug:
                                validMoves.Add(GetValidLadybugMovements(targetPiece));
                                break;

                            case BugType.Pillbug:
                                validMoves.Add(GetValidPillbugBasicMovements(targetPiece));
                                validMoves.Add(GetValidPillbugSpecialAbilityMovements(targetPiece));
                                break;
                            }
                        }
                        else
                        {
                            // Check for special ability moves
                            switch (targetPiece.BugType)
                            {
                            case BugType.Mosquito:
                                validMoves.Add(GetValidMosquitoMovements(targetPiece, true));
                                break;

                            case BugType.Pillbug:
                                validMoves.Add(GetValidPillbugSpecialAbilityMovements(targetPiece));
                                break;
                            }
                        }

                        return(validMoves);
                    }
                }
            }

            return(MoveSet.EmptySet);
        }
Example #18
0
        private MoveSet GetValidMosquitoMovements(Piece targetPiece, bool specialAbilityOnly)
        {
            if (targetPiece.Position.Stack > 0 && !specialAbilityOnly)
            {
                // Mosquito on top acts like a beetle
                return(GetValidBeetleMovements(targetPiece));
            }

            MoveSet validMoves = new MoveSet();

            bool[] bugTypesEvaluated = new bool[EnumUtils.NumBugTypes];

            for (int dir = 0; dir < EnumUtils.NumDirections; dir++)
            {
                Position neighbor = targetPiece.Position.NeighborAt(dir);
                Piece    piece    = GetPieceOnTopInternal(neighbor);

                if (null != piece && !bugTypesEvaluated[(int)(piece.BugType)])
                {
                    if (specialAbilityOnly)
                    {
                        if (piece.BugType == BugType.Pillbug)
                        {
                            validMoves.Add(GetValidPillbugSpecialAbilityMovements(targetPiece));
                        }
                    }
                    else
                    {
                        switch (piece.BugType)
                        {
                        case BugType.QueenBee:
                            validMoves.Add(GetValidQueenBeeMovements(targetPiece));
                            break;

                        case BugType.Spider:
                            validMoves.Add(GetValidSpiderMovements(targetPiece));
                            break;

                        case BugType.Beetle:
                            validMoves.Add(GetValidBeetleMovements(targetPiece));
                            break;

                        case BugType.Grasshopper:
                            validMoves.Add(GetValidGrasshopperMovements(targetPiece));
                            break;

                        case BugType.SoldierAnt:
                            validMoves.Add(GetValidSoldierAntMovements(targetPiece));
                            break;

                        case BugType.Ladybug:
                            validMoves.Add(GetValidLadybugMovements(targetPiece));
                            break;

                        case BugType.Pillbug:
                            validMoves.Add(GetValidPillbugBasicMovements(targetPiece));
                            validMoves.Add(GetValidPillbugSpecialAbilityMovements(targetPiece));
                            break;
                        }
                    }
                    bugTypesEvaluated[(int)(piece.BugType)] = true;
                }
            }

            return(validMoves);
        }
Example #19
0
        private void GetValidSlides(PieceName target, Position currentPosition, HashSet <Position> visitedPositions, int currentRange, int?maxRange, MoveSet validMoves)
        {
            if (!maxRange.HasValue || currentRange < maxRange.Value)
            {
                for (int slideDirection = 0; slideDirection < EnumUtils.NumDirections; slideDirection++)
                {
                    Position slidePosition = currentPosition.NeighborAt(slideDirection);

                    if (!visitedPositions.Contains(slidePosition) && !HasPieceAt(slidePosition))
                    {
                        // Slide position is open

                        int right = EnumUtils.RightOf(slideDirection);
                        int left  = EnumUtils.LeftOf(slideDirection);

                        if (HasPieceAt(currentPosition.NeighborAt(right)) != HasPieceAt(currentPosition.NeighborAt(left)))
                        {
                            // Can slide into slide position
                            Move move = new Move(target, slidePosition);

                            if (validMoves.Add(move))
                            {
                                // Sliding from this position has not been tested yet
                                visitedPositions.Add(move.Position);

                                GetValidSlides(target, slidePosition, visitedPositions, currentRange + 1, maxRange, validMoves);
                            }
                        }
                    }
                }
            }
        }