/// <summary> /// Set the values for the map in memory /// </summary> /// <remarks>This mapper will also identify the blue and red points, needed by the pathfinder</remarks> /// <param name="image">A valid image</param> private void LoadBitmapAsMap(Bitmap image) { for (int y = 0; y < image.Height; y++) { for (int x = 0; x < image.Width; x++) { var currentPixel = image.GetPixel(x, y); if (currentPixel.ToArgb() == Color.Black.ToArgb()) { map[x, y] = false; } else { map[x, y] = true; } //hmmm this is so fragile, given all the potential red/blue values... :/ if (currentPixel.ToArgb() == Color.Red.ToArgb()) { Start = new MPoint(x, y); //Console.WriteLine(string.Format("red point at {0}-{1}", x, y)); } if (currentPixel.ToArgb() == Color.Blue.ToArgb()) { End = new MPoint(x, y); //Console.WriteLine(string.Format("blue point at {0}-{1}", x, y)); } } } for (int x = 0; x < image.Width; x++) { for (int y = 0; y < image.Height; y++) { var firstPixel = image.GetPixel(x, y); if (firstPixel.ToArgb() == Color.Black.ToArgb()) { map[x, y] = false; } else { map[x, y] = true; } } } }
/// <summary> /// This is a Depth-First search implementation where the frontier acts like a last-in first-out stack. /// The elements are added to the stack one at a time. /// The one selected and taken off the frontier at any time is the last element that was added. /// </summary> public static List <MPoint> DepthFirstSearch(MPoint start, MPoint end, Map map) { int width = map.Width; int height = map.Height; Map visitedPoints = new Map(width, height); List <MPoint> points = new List <MPoint>(); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { if (x == 0 || y == 0 || x == width || y == height) { visitedPoints[x, y] = true; } } } Stack <MPoint> stack = new Stack <MPoint>(); stack.Push(start); visitedPoints[start.X, start.Y] = true; while (stack.Count != 0) { MPoint cur = stack.Peek(); int x = cur.X; int y = cur.Y; if (end.X == x && end.Y == y) { break; } MPoint target = new MPoint(-1, -1); if (IsValid(x + 1, y, map, visitedPoints, width, height)) { target = new MPoint(x + 1, y); } else if (IsValid(x, y + 1, map, visitedPoints, width, height)) { target = new MPoint(x, y + 1); } else if (IsValid(x - 1, y, map, visitedPoints, width, height)) { target = new MPoint(x - 1, y); } else if (IsValid(x, y - 1, map, visitedPoints, width, height)) { target = new MPoint(x, y - 1); } if (target.X != -1) { stack.Push(target); visitedPoints[target.X, target.Y] = true; } else { stack.Pop(); } } points.AddRange(stack); points.Reverse(); return(points); }
/// <summary> /// Generates the map for the maze by validating each of the target points. /// </summary> /// <param name="map"></param> /// <param name="maze"></param> /// <param name="r"></param> private void GenerateMap(Maze maze, Random r) { long steps = ((maze.Width - 1) / 2) * ((maze.Height - 1) / 2); long currentStep = 1; int x = 1; int y = 1; var stack = new Stack <MPoint>(); stack.Push(new MPoint(x, y)); maze.map[x, y] = true; MPoint[] targets = new MPoint[4]; while (stack.Count != 0) { MPoint currentPoint = stack.Peek(); int targetCounter = 0; x = currentPoint.X; y = currentPoint.Y; if (IsValid(x - 2, y, maze.map, maze)) { targets[targetCounter].X = x - 2; targets[targetCounter].Y = y; targetCounter++; } if (IsValid(x + 2, y, maze.map, maze)) { targets[targetCounter].X = x + 2; targets[targetCounter].Y = y; targetCounter++; } if (IsValid(x, y - 2, maze.map, maze)) { targets[targetCounter].X = x; targets[targetCounter].Y = y - 2; targetCounter++; } if (IsValid(x, y + 2, maze.map, maze)) { targets[targetCounter].X = x; targets[targetCounter].Y = y + 2; targetCounter++; } if (targetCounter > 0) { var target = targets[r.Next(targetCounter)]; stack.Push(target); maze.map[target.X, target.Y] = true; currentStep++; if (target.X < x) { maze.map[x - 1, y] = true; } else if (target.X > x) { maze.map[x + 1, y] = true; } else if (target.Y < y) { maze.map[x, y - 1] = true; } else if (target.Y > y) { maze.map[x, y + 1] = true; } } else { stack.Pop(); } } }
/// <summary> /// Allow us to save as an image file based on calculated Path /// </summary> /// <param name="fileName">Name for the output file</param> /// <param name="imageFormat">Supported formats include Bmp, Gif, png and all the other formats define in the ImageFormat enumeration </param> /// <param name="path"> List of map points equivalent to the map array</param> public void Save(String fileName, ImageFormat imageFormat, List <MPoint> path) { using (Bitmap bitmap = new Bitmap(map.Width - 1, map.Height - 1, PixelFormat.Format4bppIndexed)) { Rectangle frame = new Rectangle(0, 0, bitmap.Width, bitmap.Height); BitmapData bmpData = bitmap.LockBits(frame, ImageLockMode.ReadWrite, bitmap.PixelFormat); IntPtr pointer = bmpData.Scan0; int bytes = Math.Abs(bmpData.Stride) * bitmap.Height; byte[] rgbValues = new byte[bytes]; Marshal.Copy(pointer, rgbValues, 0, bytes); for (int y = 0; y < map.Height - 1; y++) { int counter = bmpData.Stride * y; int x = 0; for (int i = 0; i < bmpData.Stride; i++) { if (x >= bitmap.Width) { break; } BitArray bitArray = new BitArray(8); for (int j = 4; j >= 0; j = j - 4) { if (map[x, y]) { bitArray[j + 3] = true; bitArray[j + 2] = true; bitArray[j + 1] = true; bitArray[j + 0] = true; } else { bitArray[j + 3] = false; bitArray[j + 2] = false; bitArray[j + 1] = false; bitArray[j + 0] = false; } x++; } rgbValues[counter] = (byte)GetIntFromBitArray(bitArray); counter++; } } for (int i = 0; i < path.Count; i++) { MPoint point = path[i]; int xrest = point.X % 2; int pos = bmpData.Stride * point.Y + point.X / 2; BitArray bitar = GetBitArrayFromByte(rgbValues[pos]); int xtra = 4; if (xrest >= 1) { xtra = 0; } //per requirement the start point is represented as red if (i == 0) { bitar[xtra + 3] = true; bitar[xtra + 2] = false; bitar[xtra + 1] = false; bitar[xtra + 0] = true; } else if (i == path.Count - 1) //per requirement the end point is represented as blue { bitar[xtra + 3] = false; bitar[xtra + 2] = true; bitar[xtra + 1] = false; bitar[xtra + 0] = false; } else //per requirement solution will be highlited in green { bitar[xtra + 3] = true; bitar[xtra + 2] = false; bitar[xtra + 1] = true; bitar[xtra + 0] = false; } rgbValues[pos] = (byte)GetIntFromBitArray(bitar); } Marshal.Copy(rgbValues, 0, pointer, bytes); bitmap.UnlockBits(bmpData); bitmap.Save(fileName, imageFormat); } }