public override ActivityStep ResolveStep(GameEntity entity) { float chanceToStop = entity.isAggressive ? 0.2f : 0.07f; if (!_targetToKeepDistanceTo.hasPosition || _rng.Check(chanceToStop)) { return(Succeed(entity)); } int turnsPassed = 1; // osnowatodo Contexts.sharedInstance.game.turMinelo.Tur; bool targetPositionHasChanged = _targetToKeepDistanceTo.position.Position != _lastTargetPosition; float chanceToKeepPosition = 0.8f; bool shouldKeepPosition = !targetPositionHasChanged && _rng.Check(chanceToKeepPosition); if (shouldKeepPosition) { return(KeepPosition(entity)); } bool recalculateCooldownHasPassed = turnsPassed >= _turnsPassedToRecalculate; bool shouldRecalculate = (_navigationDataToGoodPosition == null) || (recalculateCooldownHasPassed && (targetPositionHasChanged || _rng.Check(0.2f))); if (shouldRecalculate) { _turnsPassedToRecalculate = turnsPassed + 3; _lastTargetPosition = _targetToKeepDistanceTo.position.Position; IFloodArea targetFlood = _calculatedAreaAccessor.FetchWalkableFlood(_lastTargetPosition, _preferredDistance); _navigationDataToGoodPosition = FindNavigationDataToGoodPosition(entity, targetFlood, _preferredDistance); if (_navigationDataToGoodPosition == null) { return(Fail(entity)); } } Position nextStep; NavigationResult navigationResult = _navigator.ResolveNextStep(_navigationDataToGoodPosition, entity.position.Position, out nextStep); if (navigationResult == NavigationResult.Finished) { return(new ActivityStep { GameAction = _actionFactory.CreatePassAction(entity), State = ActivityState.InProgress }); } if (nextStep == PositionUtilities.Min) { return(Fail(entity)); } IGameAction moveGameAction = CreateMoveAction(entity, nextStep); return(new ActivityStep { State = ActivityState.InProgress, GameAction = moveGameAction }); }
private IEnumerable <Position> GetPositionsOnFloodWithGivenDistance(IFloodArea targetFlood, int preferredDistance) { foreach (Position position in targetFlood.Bounds.AllPositions()) { int value = targetFlood.GetValueAtPosition(position); if (value == preferredDistance) { yield return(position); } } }
public void Show(IFloodArea floodArea) { if (!gameObject.activeInHierarchy) { return; } List <Text> numbersInPoolBeforeStart = _numbersInPool.ToList(); foreach (Position position in floodArea.Bounds.AllPositions()) { Position numberPosition = position; Vector3 worldPositionOfNewNumber = _unityGridInfoProvider.GetCellCenterWorld(numberPosition); Text textChild = PlaceChild(numbersInPoolBeforeStart, worldPositionOfNewNumber); int value = floodArea.GetValueAtPosition(position); textChild.text = value == int.MaxValue ? "-" : value.ToString(); } }
public override ActivityStep ResolveStep(GameEntity entity) { if (_followStepsActivity != null) { ActivityStep goToResult = _followStepsActivity.CheckAndResolveStep(entity); if (goToResult.State != ActivityState.FinishedFailure) { return(goToResult); } } int escapeFloodRange = entity.vision.VisionRange; int allowedDelay = 3; IFloodArea enemyFlood = _calculatedAreaAccessor.FetchWalkableFlood(_floodSource, escapeFloodRange); Position startingPosition = entity.position.Position; bool standingOutsideOfFlood = enemyFlood.GetValueAtPosition(startingPosition) == int.MaxValue; if (standingOutsideOfFlood) { return(new ActivityStep { GameAction = _actionFactory.CreatePassAction(entity), State = ActivityState.InProgress }); } Position targetPosition; var predecessors = FindBestPositionInFloodToFleeTo(entity, startingPosition, allowedDelay, enemyFlood, out targetPosition); Stack <Position> steps = new Stack <Position>(); CreateStepsStack(targetPosition, steps, predecessors); if (!steps.Any()) { Debug.LogError($"can't find best flood position starting at {startingPosition}."); } _followStepsActivity = new FollowStepsActivity(_actionFactory, steps, "Run away — steps"); return(_followStepsActivity.CheckAndResolveStep(entity)); }
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 void ShowFloodNumbers(IFloodArea floodArea) { _numbersAreaPresenter.Show(floodArea); }
private Dictionary <Position, Position> FindBestPositionInFloodToFleeTo(GameEntity entity, Position startingPosition, int allowedDelay, IFloodArea enemyFlood, out Position targetPosition) { var predecessors = new Dictionary <Position, Position>(); var delays = new Dictionary <Position, int> { [startingPosition] = 0 }; var openPositions = new Queue <Position>(); Position[] bestPositionsForDelays = new Position[allowedDelay + 1]; int[] bestScoresForDelays = new int[allowedDelay + 1]; for (int i = 0; i < allowedDelay + 1; i++) { bestScoresForDelays[i] = Int32.MinValue / 2; } openPositions.Enqueue(entity.position.Position); do { Position currentPosition = openPositions.Dequeue(); int currentDelay = delays[currentPosition]; int currentPositionScore = enemyFlood.GetValueAtPosition(currentPosition); ProcessNeighbours(currentPosition, delays, enemyFlood, currentPositionScore, currentDelay, allowedDelay, predecessors, openPositions, bestScoresForDelays, bestPositionsForDelays); } while (openPositions.Any()); int bestDelayAdjustedScore = -int.MaxValue; int optimalDelayIndex = FindBestDelayCategoryOfPositions(allowedDelay, bestScoresForDelays, bestDelayAdjustedScore); targetPosition = bestPositionsForDelays[optimalDelayIndex]; return(predecessors); }
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; } } }