Exemple #1
0
        public void SnapToYAxisNormalized_ReturnsCorrectResult(int x, int y, int expectedX, int expectedY)
        {
            Position result = PositionUtilities.SnapToYAxisNormalized(new Position(x, y));

            result.x.Should().Be(expectedX);
            result.y.Should().Be(expectedY);
        }
Exemple #2
0
        public override ActivityStep ResolveStep(GameEntity entity)
        {
            bool     isAtDestination = !_stepsToFollow.Any();
            Position nextStep;

            if (isAtDestination)
            {
                return(new ActivityStep {
                    State = ActivityState.FinishedSuccess
                });
            }

            nextStep = _stepsToFollow.Pop();
            Position direction = nextStep - entity.position.Position;

            if (!PositionUtilities.IsOneStep(direction))
            {
                return(Fail(entity));
            }

            IGameAction moveGameAction = _actionFactory.CreateJustMoveAction(direction, entity);

            return(new ActivityStep
            {
                State = ActivityState.InProgress,
                GameAction = moveGameAction
            });
        }
Exemple #3
0
        private static void ProcessNeighbours(Position currentNode, Dictionary <Position, int> delays, IFloodArea enemyFlood,
                                              int currentNodeScore, int currentDelay, int allowedDelay, Dictionary <Position, Position> predecessors, Queue <Position> openPositions,
                                              int[] bestScoresForDelays, Position[] bestPositionsForDelays)
        {
            foreach (Position neighbour in PositionUtilities.Neighbours8(currentNode)
                     .Where(n => !delays.ContainsKey(n)))
            {
                int neighbourScore = enemyFlood.GetValueAtPosition(neighbour);
                if (neighbourScore == int.MaxValue)
                {
                    continue;
                }
                int neighbourDelay = currentNodeScore - neighbourScore + 1 + currentDelay;
                if (neighbourDelay > allowedDelay)
                {
                    continue;
                }

                delays[neighbour]       = neighbourDelay;
                predecessors[neighbour] = currentNode;
                openPositions.Enqueue(neighbour);
                if (neighbourScore > bestScoresForDelays[neighbourDelay])
                {
                    bestScoresForDelays[neighbourDelay]    = neighbourScore;
                    bestPositionsForDelays[neighbourDelay] = neighbour;
                }
            }
        }
Exemple #4
0
        /// <summary>
        /// Usually the current JPS implementation creates too many jump points (many of them are aligned in one line).
        /// This function gives three first „natural” jump points (two or three), which means they don't form a single line.
        /// </summary>
        public IList <Position> GetNaturalJumpPoints(IList <Position> jumpPoints)
        {
            if (jumpPoints.Count <= 2)
            {
                return(jumpPoints);
            }

            var result = new List <Position> {
                jumpPoints[0]
            };

            Position currentDirectionNormalized = PositionUtilities.Normalized(jumpPoints[1] - jumpPoints[0]);

            for (int i = 2; i < jumpPoints.Count; i++)             // we should start checking from current == third and previous == second
            {
                Position previousPointToCheck = jumpPoints[i - 1];
                Position currentPointToCheck  = jumpPoints[i];
                Position currentDirection     = PositionUtilities.Normalized(currentPointToCheck - previousPointToCheck);

                if (currentDirection != currentDirectionNormalized)                 // change of direction implicates that the last jump point was natural
                {
                    result.Add(previousPointToCheck);
                    currentDirectionNormalized = currentDirection;
                }
            }

            result.Add(jumpPoints.Last());
            return(result);
        }
Exemple #5
0
        public override ActivityStep ResolveStep(GameEntity entity)
        {
            if (!_targetEntity.hasPosition)
            {
                return(Succeed(entity));
            }

            if (Position.Distance(_targetEntity.position.Position, entity.position.Position) >= _giveUpDistance)
            {
                return(Fail(entity));
            }

            Position targetCurrentPosition = _targetEntity.position.Position;

            bool targetIsOneStepAway = PositionUtilities.IsOneStep(entity.position.Position - targetCurrentPosition);

            if (targetIsOneStepAway)
            {
                return(new ActivityStep
                {
                    State = ActivityState.InProgress,
                    GameAction = _actionFactory.CreateAttackAction(entity, _targetEntity),
                });
            }

            if (_rng.Check(0.03f))
            {
                return(Fail(entity, _actionFactory.CreatePassAction(entity, 3f)));
            }

            bool targetPositionHasChanged = targetCurrentPosition != _lastTargetPosition;

            if (targetPositionHasChanged)
            {
                _lastTargetPosition = targetCurrentPosition;
            }
            if (targetPositionHasChanged || _navigationData == null)
            {
                // performance: should in fact be done every couple of turns
                _navigationData = _navigator.GetNavigationData(entity.position.Position, targetCurrentPosition);
            }

            Position         nextStep;
            NavigationResult navigationResult = _navigator.ResolveNextStep(_navigationData, entity.position.Position, out nextStep);

            if (navigationResult == NavigationResult.Finished)
            {
                return(Succeed(entity));
            }

            IGameAction moveGameAction = CreateMoveAction(nextStep, entity);

            return(new ActivityStep
            {
                State = ActivityState.InProgress,
                GameAction = moveGameAction
            });
        }
Exemple #6
0
        public void WalkDistance_ReturnsCorrectWalkDistance(int x1, int y1, int x2, int y2, int expectedDistance)
        {
            var start  = new Position(x1, y1);
            var target = new Position(x2, y2);

            int result = PositionUtilities.WalkDistance(start, target);

            result.Should().Be(expectedDistance);
        }
Exemple #7
0
        internal void TraceLine(IScriptExtent extent)
        {
            string message = PositionUtilities.BriefMessage(extent.StartScriptPosition);
            InternalHostUserInterface uI         = (InternalHostUserInterface)this._context.EngineHostInterface.UI;
            ActionPreference          preference = this._context.PSDebugTraceStep ? ActionPreference.Inquire : ActionPreference.Continue;

            uI.WriteDebugLine(message, ref preference);
            if (preference == ActionPreference.Continue)
            {
                this._context.PSDebugTraceStep = false;
            }
        }
        /// <summary>
        /// Returns normalized vectors that point from a tile to the tile that can be considered to be "behind" it.
        /// </summary>
        internal IEnumerable <Position> GetBehindnessVectors(Position currentPosition, Position centerOfSquareToPostProcess)
        {
            Position direction  = currentPosition - centerOfSquareToPostProcess;
            var      snappedToX = PositionUtilities.SnapToXAxisNormalized(direction);
            var      snappedToY = PositionUtilities.SnapToYAxisNormalized(direction);

            if (snappedToX != Position.Zero)
            {
                yield return(snappedToX);
            }
            if (snappedToY != Position.Zero)
            {
                yield return(snappedToY);
            }
        }
        public void FindForItem_FirstDestinationAndMostNeighboursAreNotEligibleButOneNeighbourIs_ReturnsNeighbour()
        {
            var   checkedPosition   = new Position(1, 1);
            var   eligibleNeighbour = new Position(2, 1);
            IGrid gip = Mock.Of <IGrid>(p =>
                                        p.IsWalkable(
                                            It.Is <Position>(v => PositionUtilities.Neighbours8(checkedPosition).Contains(v))
                                            ) == false &&
                                        p.IsWalkable(eligibleNeighbour) == true);
            IEntityDetector entityDetector = Mock.Of <IEntityDetector>(d =>
                                                                       d.DetectEntities(checkedPosition) == Enumerable.Empty <GameEntity>());
            var finder = new FirstPlaceInAreaFinder(gip, entityDetector, new RandomNumberGenerator(93432));

            Position?result = finder.FindForItem(checkedPosition);

            result.Should().Be(eligibleNeighbour);
        }
Exemple #10
0
        public override IEnumerator Recalculating()
        {
            SpreadInitialSeeds();

            yield return(new WaitForSeconds(0.1f));

            int iterations = _config.Iterations;

            for (var iteration = 0; iteration < iterations; iteration++)
            {
                SimulateOneGeneration(iteration < iterations - 2);

                yield return(new WaitForSeconds(0.1f));
            }

            for (var x = 1; x < Values.XSize - 1; x++)
            {
                for (var y = 1; y < Values.YSize - 1; y++)
                {
                    Plant plant = _plants[x, y];
                    if (plant != null)
                    {
                        if (plant.Tile == null)
                        {
                            throw new ArgumentNullException($"Missing tile for plant {plant.name}.");
                        }
                        TilemapLayer layer = plant.Tile.Layer;
                        byte         id    = plant.Tile.Id;
                        _tileMatricesByte[(int)layer].Set(x, y, id);

                        if (!plant.GrowsBelowOtherPlants) //not grass layer
                        {
                            Plant neighbourGrowingBelow = PositionUtilities.Neighbours8(new Position(x, y))
                                                          .Select(n => _plants[n.x, n.y])
                                                          .FirstOrDefault(p => p != null && p.GrowsBelowOtherPlants);
                            if (neighbourGrowingBelow != null)
                            {
                                _tileMatricesByte[(int)neighbourGrowingBelow.Tile.Layer]
                                .Set(x, y, neighbourGrowingBelow.Tile.Id);
                            }
                        }
                    }
                }
            }
        }
Exemple #11
0
        public void BiasedPosition_WhenRadiusIs1_ReturnsInputPositionOrItsNeighboursAndAllNeighboursAreEventuallyReturned(int x, int y)
        {
            var             rng = new RandomNumberGenerator(2131235);
            var             testedVector = new Position(x, y);
            List <Position> possibleResults = new[] { testedVector }.Union(PositionUtilities.Neighbours4List(testedVector)).ToList();
            var             results = new List <Position>();

            for (int i = 0; i < 100; i++)
            {
                var newResult = rng.BiasedPosition(testedVector, 1);
                results.Add(newResult);
            }

            foreach (Position possibleResult in possibleResults)
            {
                results.Should().Contain(possibleResult);
            }
            foreach (Position result in results)
            {
                possibleResults.Should().Contain(result);
            }
        }
        public Position?FindForActor(Position source)
        {
            bool sourceIsEligible = _grid.IsWalkable(source) && !_entityDetector.DetectEntities(source).Any();

            if (sourceIsEligible)
            {
                return(source);
            }
            ;
            IList <Position> neighboursShuffled = _rng.Shuffle(PositionUtilities.Neighbours8(source));

            foreach (Position neighbour in neighboursShuffled)
            {
                bool neighbourIsEligible = _grid.IsWalkable(neighbour) && !_entityDetector.DetectEntities(neighbour).Any();
                if (neighbourIsEligible)
                {
                    return(neighbour);
                }
            }

            return(null);
        }
Exemple #13
0
        public override ActivityStep ResolveStep(GameEntity entity)
        {
            Position targetCurrentPosition = _targetPositionGetter();

            bool reachedTarget = PositionUtilities.IsOneStep(entity.position.Position - targetCurrentPosition);

            if (reachedTarget)
            {
                return(Succeed(entity));
            }

            bool targetPositionHasChanged = targetCurrentPosition != _lastTargetPosition;

            if (targetPositionHasChanged)
            {
                _lastTargetPosition = targetCurrentPosition;
            }
            if (targetPositionHasChanged || _navigationData == null)
            {
                // performance: should in fact be done every couple of turns
                _navigationData = _navigator.GetNavigationData(entity.position.Position, targetCurrentPosition);
            }

            Position         nextStep;
            NavigationResult navigationResult = _navigator.ResolveNextStep(_navigationData, entity.position.Position, out nextStep);

            if (navigationResult == NavigationResult.Finished)
            {
                return(Succeed(entity));
            }

            IGameAction moveGameAction = CreateMoveAction(nextStep, entity);

            return(new ActivityStep
            {
                State = ActivityState.InProgress,
                GameAction = moveGameAction
            });
        }
        public Position?FindForItem(Position source)
        {
            List <GameEntity> allAtSource = _entityDetector.DetectEntities(source).ToList();
            bool sourceIsEligible         = _grid.IsWalkable(source) && allAtSource.All(e => e.hasHeld || e.isBlockingPosition);

            if (sourceIsEligible)
            {
                return(source);
            }
            ;
            IList <Position> neighboursShuffled = _rng.Shuffle(PositionUtilities.Neighbours8(source));

            foreach (Position neighbour in neighboursShuffled)
            {
                bool neighbourIsEligible = _grid.IsWalkable(neighbour) && !_entityDetector.DetectEntities(neighbour).Any();
                if (neighbourIsEligible)
                {
                    return(neighbour);
                }
            }

            return(null);
        }
Exemple #15
0
        private NavigationData FindNavigationDataToGoodPosition(GameEntity entity, IFloodArea targetFlood, int preferredDistance)
        {
            IList <Position> availablePositions = GetPositionsOnFloodWithGivenDistance(targetFlood, preferredDistance).ToList();

            int attemptsLimit = 5;
            int attempts      = 0;

            while (true)
            {
                ++attempts;
                if (attempts > attemptsLimit)
                {
                    Debug.Log("Failed after " + attempts + " attempts.");
                    return(null);
                }
                Position[] candidates = { _rng.Choice(availablePositions), _rng.Choice(availablePositions), _rng.Choice(availablePositions) };
                var        navigationsToCandidates = new List <NavigationData>(candidates.Length);

                foreach (Position candidatePosition in candidates)
                {
                    NavigationData navigation = _navigator.GetNavigationData(entity.position.Position, candidatePosition);
                    navigationsToCandidates.Add(navigation);
                }

                List <NavigationData> validCandidates = navigationsToCandidates.Where(c => c != null).ToList();
                if (!validCandidates.Any())
                {
                    return(null);
                }

                validCandidates.Sort((first, second) =>
                                     PositionUtilities.WalkDistance(entity.position.Position, first.Destination)
                                     .CompareTo(PositionUtilities.WalkDistance(entity.position.Position, second.Destination)));
                NavigationData closestValidCandidate = validCandidates.First();
                return(closestValidCandidate);
            }
        }
Exemple #16
0
        public NavigationResult ResolveNextStep(NavigationData navigationData, Position currentPosition, out Position nextStep)
        {
            nextStep = PositionUtilities.Min;
            if (navigationData.Destination == currentPosition)
            {
                return(NavigationResult.Finished);
            }

            bool pathIsCorrupted = !NavigationDataIsValid(currentPosition, navigationData);

            if (pathIsCorrupted)
            {
                                #if UNITY_EDITOR
                //Debug.Log("path is corrupted. recalculating path");
                                #endif
                return(ResolveWithRecalculation(navigationData, currentPosition, ref nextStep));
            }

            if (!navigationData.RemainingStepsInCurrentSegment.Any())
            {
                IList <Position> naturalLineToWalk = _naturalLineCreator.GetFirstLongestNaturalLine(
                    currentPosition, navigationData.RemainingNodes, _grid.IsWalkable);
                Position naturalNextNode = naturalLineToWalk.Last();
                bool     naturalNextNodeIsSameAsNextNextNode = navigationData.RemainingNodes.Count > 1 &&
                                                               navigationData.RemainingNodes[1] == naturalNextNode;
                if (naturalNextNodeIsSameAsNextNextNode)
                {
                    navigationData.RemainingNodes.RemoveAt(0);
                }
                else
                {
                    navigationData.RemainingNodes[0] = naturalNextNode;
                }
                navigationData.RemainingStepsInCurrentSegment = new Stack <Position>(naturalLineToWalk.Skip(1).Reverse());
            }

            Position lastStep = navigationData.LastStep;

            if (!navigationData.RemainingStepsInCurrentSegment.Any())
            {
                throw new InvalidOperationException($"Missing remaining steps. Current: {currentPosition}, navigation: {navigationData}");
            }
            nextStep = navigationData.RemainingStepsInCurrentSegment.Pop();
            bool actorWasDisplaced = currentPosition != lastStep;
            if (actorWasDisplaced)
            {
                bool actorWasDisplacedFarFromLastStep = !PositionUtilities.IsOneStep(lastStep - currentPosition);
                if (actorWasDisplacedFarFromLastStep)
                {
                                        #if UNITY_EDITOR
                    //Debug.Log("actor was displaced far from last step. recalculating path");
                                        #endif
                    return(ResolveWithRecalculation(navigationData, currentPosition, ref nextStep));
                }

                bool shouldMoveAgainToLastPosition = !PositionUtilities.IsOneStep(nextStep - currentPosition);
                if (shouldMoveAgainToLastPosition)
                {
                    navigationData.RemainingStepsInCurrentSegment.Push(nextStep);
                    nextStep = lastStep;
                }
            }

            if (!_grid.IsWalkable(nextStep))
            {
                                #if UNITY_EDITOR
                //Debug.Log("next step not walkable. recalculating path");
                                #endif
                return(ResolveWithRecalculation(navigationData, currentPosition, ref nextStep));
            }

            bool willBeNextNode = nextStep == navigationData.RemainingNodes[0];
            if (willBeNextNode)
            {
                navigationData.RemainingNodes.RemoveAt(0);
            }

            navigationData.LastStep = nextStep;
            return(NavigationResult.InProgress);
        }
Exemple #17
0
        public void Average_CalculatesCorrectAverage()
        {
            Position result = PositionUtilities.Average(new[] { new Position(-5, 0), new Position(0, 3), new Position(20, 0) });

            result.Should().Be(new Position(5, 1));
        }
Exemple #18
0
        public void GetFittingPosition_ReturnsCorrectResult(Position current, Position previous, Position?expectedResult)
        {
            Position?result = PositionUtilities.GetFittingPosition(current, previous);

            result.Should().Be(expectedResult);
        }