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); }
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 }); }
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; } } }
/// <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); }
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 }); }
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); }
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); }
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); } } } } } }
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); }
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); }
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); } }
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); }
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)); }
public void GetFittingPosition_ReturnsCorrectResult(Position current, Position previous, Position?expectedResult) { Position?result = PositionUtilities.GetFittingPosition(current, previous); result.Should().Be(expectedResult); }