private List <SectorConstrainedPosition> FindPositions(IEnumerable <EnemyMove> moves) { List <SectorConstrainedPosition> positions = new List <SectorConstrainedPosition>(); SectorConstrainedPosition currentPosition = new SectorConstrainedPosition(0, 0, null); positions.Add(currentPosition); foreach (var move in moves) { if (!move.IsMovement && move.HasSector) { currentPosition = new SectorConstrainedPosition(currentPosition.X, currentPosition.Y, move.Sector); positions[positions.Count - 1] = currentPosition; continue; } SectorConstrainedPosition newPosition; if (move.IsMovement) { switch (move.Movement) { case Direction.East: newPosition = new SectorConstrainedPosition(currentPosition.X + 1, currentPosition.Y, move.Sector); break; case Direction.North: newPosition = new SectorConstrainedPosition(currentPosition.X, currentPosition.Y - 1, move.Sector); break; case Direction.South: newPosition = new SectorConstrainedPosition(currentPosition.X, currentPosition.Y + 1, move.Sector); break; case Direction.West: newPosition = new SectorConstrainedPosition(currentPosition.X - 1, currentPosition.Y, move.Sector); break; default: throw new InvalidOperationException($"Invalid move {move}"); } positions.Add(newPosition); currentPosition = newPosition; } } int xMin = positions.Min(p => p.X); int yMin = positions.Min(p => p.Y); int xOffset = xMin < 0 ? Math.Abs(xMin) : 0; int yOffset = yMin < 0 ? Math.Abs(yMin) : 0; return(positions.Select(p => new SectorConstrainedPosition(p.X + xOffset, p.Y + yOffset, p.SectorConstraint)).ToList()); }
public IEnumerable <Position> LocateEnemy(CancellationToken cancellation, IEnumerable <EnemyMove> moves) { if (moves.Count() < 3) { return(Enumerable.Empty <Position>()); } var positions = FindPositions(moves); var search = new OverlayGrid(_grid.Width, _grid.Height, positions); Dictionary <Sector, OverlayGrid> sectorGrids = positions.Where(p => p.IsSectorConstrained) .GroupBy(p => p.SectorConstraint.Value) .ToDictionary(p => p.Key, g => new OverlayGrid(_grid.Width, _grid.Height, g.ToList())); List <Position> offsetMatches = new List <Position>(); do { if (cancellation.IsCancellationRequested) { Console.Error.WriteLine("CANCELLING TARGETTING"); break; } var mask = search.Mask(_grid.GridBinary); if (PathDoesNotIntersectWithIslands(mask) && NoSectorCollisions(sectorGrids)) { offsetMatches.Add(search.CurrentOffset); // Console.Error.WriteLine($"Found a place the enemy could be hiding offset {offset}"); } if (!search.CanMoveRight && !search.CanMoveDown) { break; } if (search.CanMoveRight) { search.ShiftRight(); foreach (var sectorGrid in sectorGrids.Values) { sectorGrid.ShiftRight(); } continue; } search.ShiftToOriginalX(); search.ShiftDown(); foreach (var sectorGrid in sectorGrids.Values) { sectorGrid.ShiftToOriginalX(); sectorGrid.ShiftDown(); } } while (true); SectorConstrainedPosition lastPosition = positions[positions.Count - 1]; return(offsetMatches.Select(m => new Position(m.X + lastPosition.X, m.Y + lastPosition.Y))); }