/// <summary> /// Generate a Dijkstra Map to aid AI navigation through this map /// </summary> /// <typeparam name="T"></typeparam> /// <param name="map"></param> /// <param name="startingValue"></param> /// <param name="targetCondition"></param> /// <param name="passCondition"></param> /// <param name="blockedValue"></param> /// <returns></returns> public static ICellMap <int> GenerateDijkstraMap <T>(this ICellMap <T> map, Func <T, bool> targetCondition, Func <T, bool> passCondition, int startingValue = 1000000, int blockedValue = -1) { ICellMap <int> dMap = map.SpawnNewGrid <int>(); dMap.SetAll(startingValue); for (int i = 0; i < map.CellCount; i++) { T cellValue = map[i]; if (targetCondition(cellValue)) { dMap[i] = 0; } else if (!passCondition(cellValue)) { dMap[i] = blockedValue; } } while (IterateDijkstraMap(dMap, blockedValue)) { } return(dMap); }
/// <summary> /// Run one iteration of a dijkstra map update. Each cell is set to the lowest /// adjacent value - 1. /// </summary> /// <param name="dMap"></param> /// <param name="blockedValue"></param> /// <returns></returns> public static bool IterateDijkstraMap(this ICellMap <int> dMap, int blockedValue = -1) { bool changed = false; for (int i = 0; i < dMap.CellCount; i++) { int cellValue = dMap[i]; if (cellValue != blockedValue) { int lowestValue = cellValue; for (int ai = 0; ai <= dMap.AdjacencyCount(i); ai++) { int adjacentCellIndex = dMap.AdjacentCellIndex(i, ai); if (dMap.Exists(adjacentCellIndex)) { int adjacentValue = dMap[adjacentCellIndex]; if (adjacentValue < lowestValue) { lowestValue = adjacentValue; } } } if (lowestValue < cellValue - 1) { dMap[i] = lowestValue + 1; changed = true; } } } return(changed); }
/// <summary> /// Set all cells in this map to the same value. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="map"></param> /// <param name="value"></param> public static void SetAll <T>(this ICellMap <T> map, T value) { for (int i = 0; i < map.CellCount; i++) { map[i] = value; } }
private CellCluster[,] CreateClusters(ICellMap map, int clusterSize) { int matrixWidth = (int)Math.Ceiling((double)map.Width / clusterSize); int matrixHeight = (int)Math.Ceiling((double)map.Height / clusterSize); CellCluster[,] clusterMatrix = new CellCluster[matrixWidth, matrixHeight]; int currentX = 0; for (int cx = 0; cx < matrixWidth; cx++) { int xBorderDelta = map.Width - currentX; int actualWidth = xBorderDelta >= clusterSize ? clusterSize : xBorderDelta; int currentY = 0; for (int cy = 0; cy < matrixHeight; cy++) { int yBorderDelta = map.Height - currentY; int actualHeight = yBorderDelta >= clusterSize ? clusterSize : yBorderDelta; CellCluster cluster = new CellCluster(new Vector2Int(cx, cy)) { Width = actualWidth, Height = actualHeight, LeftBottom = new Vector2Int(currentX, currentY), Map = map }; clusterMatrix[cx, cy] = cluster; currentY += actualHeight; } currentX += actualWidth; } return(clusterMatrix); }
/// <summary> /// Set a cell in this map. This will back-register the map and index /// with the cell itself. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="map"></param> /// <param name="index"></param> /// <param name="cell"></param> public static void SetCell <T>(this ICellMap <T> map, int index, T cell) where T : IMapCell { map[index] = cell; cell.Index = index; cell.Map = map; }
public void UpdateGraph(ICellMap map, IEnumerable <ICellFragment> obstacles, HierarchicalMap graph, NeighbourMode neighbourMode) { foreach (var obstacle in obstacles) { UpdateGraph(map, obstacle, graph, neighbourMode); } }
public void Initialize(ICellMap mapBase, int clusterSize) { _mapBase = mapBase; _layeredCellMap = new LayeredCellMap(_mapBase); ClusterSizeZero = clusterSize; PreBuildGraph(_layeredCellMap); _isInitialized = true; }
/// <summary> /// Populate this map with cells /// </summary> /// <typeparam name="T"></typeparam> /// <param name="map"></param> public static void InitialiseCells <T>(this ICellMap <T> map) where T : IMapCell, new() { for (int i = 0; i < map.CellCount; i++) { T cell = new T(); map.SetCell(i, cell); } }
public HierarchicalMap GenerateMap(ICellMap cellMap, NeighbourMode neighbourMode, params int[] clusterSizes) { if (clusterSizes.Length == 1) { return(GenerateTwoLevelMap(cellMap, neighbourMode, clusterSizes[0])); } throw new NotImplementedException(); }
static void Main(string[] args) { Console.BufferWidth = 300; Console.BufferHeight = 240; Console.WindowWidth = 180; Console.WriteLine("Press any key to start..."); Console.ReadKey(); FileStream mapFileStream = File.Open("Maps/vadim_maze.cmap", FileMode.Open, FileAccess.Read); ConsoleMap map = ConsoleMapGenerator.FromText(mapFileStream, 'S', 'E', 'X', '.'); _map = map; InitArrays(2); Vector2Int start = map.DefaultStart; Vector2Int stop = map.DefaultStop; _start = start; _stop = stop; Vector2Int scale = new Vector2Int(4, 2); int spacing = 4; InitConsoleDrawer(map, scale, spacing, start, stop, 0); InitConsoleDrawer(map, scale, spacing, start, stop, 1); Console.SetCursorPosition(0, map.Height * scale.Y); AStarAlgorithm aStarTest = new AStarAlgorithm(); var path = aStarTest.GetPath(_map, start, stop, NeighbourMode.SideOnly); if (path != null) { Console.WriteLine("Path was found"); DrawPath(path, 0); } _contestants[0] = new BestFirstSearch(); _contestants[0].OnCellViewedEvent += OnCellUpdated; _contestants[1] = new AStarAlgorithm(); _contestants[1].OnCellViewedEvent += OnCellUpdated; StartPathFinder(0); StartPathFinder(1); while (_runningTasks > 0) { Thread.Sleep(100); } Console.WriteLine("Press any key to exit..."); Console.ReadKey(); }
private HierarchicalMap GenerateTwoLevelMap(ICellMap cellMap, NeighbourMode neighbourMode, int levelZeroClusterSize) { CellCluster[,] clusterMatrix = CreateClusters(cellMap, levelZeroClusterSize); GeneratedClusters = clusterMatrix; HierarchicalMap levelOneMap = new HierarchicalMap(levelZeroClusterSize, levelZeroClusterSize); for (int i = 0; i < clusterMatrix.GetLength(0); i++) { for (int j = 0; j < clusterMatrix.GetLength(1); j++) { CellCluster currentCluster = clusterMatrix[i, j]; int prevI = i - 1; int prevJ = j - 1; int nextJ = j + 1; if (prevI >= 0) { CellCluster neighbourCluster = clusterMatrix[prevI, j]; ProceedNeighbourClusters(currentCluster, neighbourCluster, levelOneMap); } if (prevJ >= 0) { CellCluster neighbourCluster = clusterMatrix[i, prevJ]; ProceedNeighbourClusters(currentCluster, neighbourCluster, levelOneMap); } if (prevJ >= 0 && prevI >= 0 && neighbourMode == NeighbourMode.SidesAndDiagonals) { CellCluster neighbourCluster = clusterMatrix[prevI, prevJ]; ProceedNeighbourClusters(currentCluster, neighbourCluster, levelOneMap); } if (nextJ < cellMap.Height && prevI >= 0 && neighbourMode == NeighbourMode.SidesAndDiagonals) { CellCluster neighbourCluster = clusterMatrix[prevI, nextJ]; ProceedNeighbourClusters(currentCluster, neighbourCluster, levelOneMap); } } } for (int i = 0; i < clusterMatrix.GetLength(0); i++) { for (int j = 0; j < clusterMatrix.GetLength(1); j++) { _currentCellCluster = clusterMatrix[i, j]; clusterMatrix[i, j].CalculatePaths(neighbourMode, OnCellClusterCellViewed); } } levelOneMap.ZeroLevelClusters = clusterMatrix; return(levelOneMap); }
private void ShowCellMapDrawerForm(CellMapDrawerForm form, ICellMap map, IList <Vector2Int> path) { if (InvokeRequired) { BeginInvoke(new Action <CellMapDrawerForm, ICellMap, IList <Vector2Int> >(ShowCellMapDrawerForm), form, map, path); return; } Debug.WriteLine($"CellMapDrawerForm showed on thread {Thread.CurrentThread.ManagedThreadId}"); form.ShowMap(map, path); }
public static WeightedGraph <double> GetWeightedGraph(ICellMap map, NeighbourMode neighbourMode) { WeightedGraphNode <double>[,] nodes = new WeightedGraphNode <double> [map.Width, map.Height]; for (int x = 0; x < map.Width; x++) { for (int y = 0; y < map.Height; y++) { if (map.IsPassable(x, y)) { WeightedGraphNode <double> connectionNode; WeightedGraphNode <double> currentNode = new WeightedGraphNode <double>(Double.PositiveInfinity); nodes[x, y] = currentNode; currentNode.Position = new Vector2Int(x, y); int prevX = x - 1; int prevY = y - 1; int nextY = y + 1; if (prevX >= 0) { connectionNode = nodes[prevX, y]; ConnectNodes(currentNode, connectionNode, 1); } if (prevY >= 0) { connectionNode = nodes[x, prevY]; ConnectNodes(currentNode, connectionNode, 1); } if (prevX >= 0 && prevY >= 0 && neighbourMode == NeighbourMode.SidesAndDiagonals) { connectionNode = nodes[prevX, prevY]; ConnectNodes(currentNode, connectionNode, Sqrt2); } if (nextY < map.Height && prevX >= 0 && neighbourMode == NeighbourMode.SidesAndDiagonals) { connectionNode = nodes[prevX, nextY]; ConnectNodes(currentNode, connectionNode, Sqrt2); } } else { nodes[x, y] = null; } } } WeightedGraph <double> weightedGraph = new WeightedGraph <double>(nodes, Double.PositiveInfinity); return(weightedGraph); ; }
/// <summary> /// Get the cell adjacent to the cell with the specified /// index in the specified direction. /// </summary> /// <param name="cellIndex">The index of the starting cell</param> /// <param name="direction">The direction of the cell to retrieve</param> /// <returns></returns> public static T AdjacentCell <T>(this ICellMap <T> map, int cellIndex, Vector direction) { if (map.Exists(cellIndex)) { int i = map.AdjacentCellIndex(cellIndex, direction); if (map.Exists(i)) { return(map[i]); } } return(default(T)); }
private void PreBuildGraph(ICellMap map) { Stopwatch sw = new Stopwatch(); Debug.WriteLine("Hierarchical graph construction started"); sw.Start(); HierarchicalMapGenerator generator = new HierarchicalMapGenerator(); HierarchicalGraph = generator.GenerateMap(map, NeighbourMode.SideOnly, ClusterSizeZero); sw.Stop(); Debug.WriteLine($"Hierarchical graph construction finished in {sw.Elapsed}"); }
/// <summary> /// Get the specified adjacent cell to the specified cell /// </summary> /// <param name="cellIndex">The index of the starting cell</param> /// <param name="adjacencyIndex">The adjacency index of the cell to retrieve</param> /// <returns></returns> public static T AdjacentCell <T>(this ICellMap <T> map, int cellIndex, int adjacencyIndex) { if (map.Exists(cellIndex)) { int i = map.AdjacentCellIndex(cellIndex, adjacencyIndex); if (map.Exists(i)) { return(map[i]); } } return(default(T)); }
public void ShowMap(ICellMap cellMap) { _cellMap = cellMap; _stage = 0; DrawCellMatrix(); _pictureBoxGraphics = PictureBox.CreateGraphics(); AddAlgorithms(); Show(); }
public IList <Vector2Int> GetSmoothedPath(ICellMap map, Vector2Int start, Vector2Int stop, NeighbourMode neighbourMode) { var rawPath = GetPath(map, start, stop, neighbourMode); if (rawPath == null) { return(null); } PathSmoother smoother = new PathSmoother(); var path = smoother.GetSmoothedPath(map, rawPath); return(path); }
/// <summary> /// Get the item in the cell at the specified location /// </summary> /// <typeparam name="T"></typeparam> /// <param name="map"></param> /// <param name="location">A point vector which lies within the cell to be retrieved.</param> /// <returns></returns> public static T CellAt <T>(this ICellMap <T> map, Vector location) { int i = map.IndexAt(location); if (map.Exists(i)) { return(map[i]); } else { return(default(T)); } }
public IList <Vector2Int> GetPath(ICellMap mapBase, Vector2Int start, Vector2Int stop, NeighbourMode neighbourMode) { if (_layeredCellMap == null) { _layeredCellMap = new LayeredCellMap(mapBase); } bool StartNodeFilter(IWeightedGraphNode <double> node) { return(node != null && node.Position == start); } bool StopNodeFilter(IWeightedGraphNode <double> node) { return(node != null && node.Position == stop); } IWeightedGraph <double> graph = GraphGenerator.GetWeightedGraph(_layeredCellMap, neighbourMode); var nodes = graph.GetWeightedGraphNodes(); IWeightedGraphNode <double>[] keyNodes = Utils.GetItemsByFilters(nodes, StartNodeFilter, StopNodeFilter); var startNode = keyNodes[0]; var stopNode = keyNodes[1]; foreach (var node in nodes) { if (node == null) { continue; } node.Data = new GraphData() { DistanceToStop = GetDistance(node.Position, stop) }; } var nodePath = GetPath(graph, startNode, stopNode); if (nodePath == null) { return(null); } List <Vector2Int> path = new List <Vector2Int>(nodePath.Count); foreach (var node in nodePath) { path.Add(node.Position); } return(path); }
public static GraphNode[,] GetGraph(ICellMap map, NeighbourMode neighbourMode) { GraphNode[,] nodes = new GraphNode[map.Width, map.Height]; for (int x = 0; x < map.Width; x++) { for (int y = 0; y < map.Height; y++) { if (map.IsPassable(x, y)) { GraphNode connectionNode; GraphNode currentNode = new GraphNode(); nodes[x, y] = currentNode; currentNode.Position = new Vector2Int(x, y); int prevX = x - 1; int prevY = y - 1; int nextY = y + 1; if (prevX >= 0) { connectionNode = nodes[prevX, y]; ConnectNodes(currentNode, connectionNode); } if (prevY >= 0) { connectionNode = nodes[x, prevY]; ConnectNodes(currentNode, connectionNode); } if (prevX >= 0 && prevY >= 0 && neighbourMode == NeighbourMode.SidesAndDiagonals) { connectionNode = nodes[prevX, prevY]; ConnectNodes(currentNode, connectionNode); } if (nextY < map.Height && prevX >= 0 && neighbourMode == NeighbourMode.SidesAndDiagonals) { connectionNode = nodes[prevX, nextY]; ConnectNodes(currentNode, connectionNode); } } else { nodes[x, y] = null; } } } return(nodes); }
/// <summary> /// Get the items in the cells at the specified locations /// </summary> /// <typeparam name="T"></typeparam> /// <param name="map"></param> /// <param name="locations"></param> /// <returns></returns> public static IList <T> CellsAt <T>(this ICellMap <T> map, IList <Vector> locations) { var result = new List <T>(locations.Count); foreach (Vector location in locations) { int i = map.IndexAt(location); if (map.Exists(i)) { result.Add(map[i]); } } return(result); }
private IList <Vector2Int> ForwardSmoothing(ICellMap map, IList <Vector2Int> rawPath) { List <Vector2Int> smoothedPath = new List <Vector2Int>(rawPath.Count); bool lineCasterFailed = false; BresenhamLinePlotter lineCaster = new BresenhamLinePlotter(); int currentIndex = 0, nextIndex = 1, lastValidIndex = 1; Vector2Int lastObstacle = default; bool IsCellPassable(int x, int y) { bool isPassable = map.IsPassable(x, y); if (!isPassable) { OnObstacleDetectedEvent?.Invoke(x, y); lastObstacle = new Vector2Int(x, y); lineCasterFailed = true; } return(isPassable); } bool SetPathCell(int x, int y) { smoothedPath.Add(new Vector2Int(x, y)); return(true); } while (currentIndex < rawPath.Count - 1) { nextIndex = currentIndex + 1; lastValidIndex = currentIndex; while (nextIndex < rawPath.Count) { lineCasterFailed = false; lineCaster.CastLine(rawPath[currentIndex], rawPath[nextIndex], IsCellPassable); if (!lineCasterFailed) { lastValidIndex = nextIndex; } nextIndex++; } lineCaster.CastLine(rawPath[currentIndex], rawPath[lastValidIndex], SetPathCell); currentIndex = lastValidIndex + 1; } return(smoothedPath); }
public void UpdateGraph(ICellMap map, ICellFragment cellFragment, HierarchicalMap graph, NeighbourMode neighbourMode) { var clusterMatrix = graph.ZeroLevelClusters; int clusterWidth = graph.ClusterDefaultWidth; int clusterHeight = graph.ClusterDefaultHeight; Vector2Int fragmentSize = new Vector2Int(cellFragment.Width, cellFragment.Height); Vector2Int leftBottomClusterPosition = GetContainingClusterPosition(clusterMatrix, clusterWidth, clusterHeight, cellFragment.LeftBottom); Vector2Int rightTopClusterPosition = GetContainingClusterPosition(clusterMatrix, clusterWidth, clusterHeight, cellFragment.LeftBottom + fragmentSize); int iMin = leftBottomClusterPosition.X; int iMax = rightTopClusterPosition.X; int jMin = leftBottomClusterPosition.Y; int jMax = rightTopClusterPosition.Y; for (int i = iMin; i <= iMax; i++) { for (int j = jMin; j <= jMax; j++) { CellCluster currentCluster = clusterMatrix[i, j]; int prevI = i - 1; int prevJ = j - 1; int nextJ = j + 1; if (prevI >= iMin) { CellCluster neighbourCluster = clusterMatrix[prevI, j]; RemoveTransitionNodes(currentCluster, neighbourCluster, graph); ProceedNeighbourClusters(currentCluster, neighbourCluster, graph); } if (prevJ >= jMin) { CellCluster neighbourCluster = clusterMatrix[i, prevJ]; RemoveTransitionNodes(currentCluster, neighbourCluster, graph); ProceedNeighbourClusters(currentCluster, neighbourCluster, graph); } } } for (int i = iMin; i <= iMax; i++) { for (int j = jMin; j <= jMax; j++) { CellCluster currentCluster = clusterMatrix[i, j]; currentCluster.CalculatePaths(neighbourMode, null); } } }
/// <summary> /// Retrieve a list of all cells adjacent to the one with the specified index /// </summary> /// <typeparam name="T"></typeparam> /// <param name="map"></param> /// <param name="cellIndex"></param> /// <returns></returns> public static IList <T> AdjacentCells <T>(this ICellMap <T> map, int cellIndex) { int aC = map.AdjacencyCount(cellIndex); var result = new List <T>(aC); for (int i = 0; i < aC; i++) { int iA = map.AdjacentCellIndex(cellIndex, i); if (map.Exists(iA)) { result.Add(map[iA]); } } return(result); }
public override void RefreshUI() { object value = Binding.GetBoundValue(); if (value is ICellMap <int> ) { ICellMap <int> map = (ICellMap <int>)value; if (_NewValue != null) { _OldValue = _NewValue; } _NewValue = (SquareCellMap <int>)map; _Tween = 0; } }
public void ShowMap(ICellMap cellMap, IList <Vector2Int> path) { _cellMap = cellMap; _stage = 0; DrawCellMatrix(); _pictureBoxGraphics = PictureBox.CreateGraphics(); AddAlgorithms(); _userPath = path; Show(); }
/// <summary> /// Get the polyline representing the border of the cell with the specified index /// </summary> /// <typeparam name="T"></typeparam> /// <param name="map"></param> /// <param name="cellIndex"></param> /// <returns></returns> public static PolyLine CellBorder <T>(this ICellMap <T> map, int cellIndex) { int vC = map.VertexCount(cellIndex); if (vC > 0) { var result = new PolyLine(); for (int i = 0; i < vC; i++) { result.Add(map.CellVertex(cellIndex, i)); } result.Close(); return(result); } return(null); }
public static Bitmap GetBitmap(ICellMap map, int scale) { Bitmap bitmap = new Bitmap(map.Width * scale, map.Height * scale); for (int x = 0; x < map.Width; x++) { for (int y = 0; y < map.Height; y++) { if (!map.IsPassable(x, y)) { DrawScaledPixel(bitmap, Color.Black, x, y, scale); } } } return(bitmap); }
private bool IsLayerCellPassable(int index, int x, int y) { ICellMap layer = _layers[index]; Vector2Int offset = _layerOffsets[index]; int shiftedX = x - offset.X; int shiftedY = y - offset.Y; if (!layer.IsInBounds(shiftedX, shiftedY)) { return(true); } else { bool layerIsPassable = layer.IsPassable(shiftedX, shiftedY); return(layerIsPassable); } }