/// <summary> /// String showing the solved maze result /// </summary> /// <returns> /// Returns string representation of the solved maze. /// </returns> /// public string ResultString() { char[] mazeDrawing = new char[height * width]; // fill in start and end mazeDrawing[startX + (startY * width)] = 'S'; mazeDrawing[endX + (endY * width)] = 'E'; // loop through each parent, add an X until we find start Queue <currentPoint> path = new Queue <currentPoint>(); // start with end point path.Enqueue(new currentPoint(endX, endY)); while (path.Count > 0) { currentPoint p = path.Dequeue(); // while not reaching the start if (p.X != startX || p.Y != startY) { // queue this points parent path.Enqueue(mazeParents[p.X + (p.Y * width)]); if (p.X != endX || p.Y != endY) { // draw an X if this is not the end location mazeDrawing[p.X + (p.Y * width)] = 'X'; } } } // fill in the rest for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { // if the point has not already been filled in if (mazeDrawing[x + (y * width)] == '\0') { // wall or pathway if (mazeData[x + (y * width)]) { mazeDrawing[x + (y * width)] = '#'; } else { mazeDrawing[x + (y * width)] = ' '; } } } } // print it out string solvedPrint = ""; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { solvedPrint += mazeDrawing[x + (y * width)] + " "; } solvedPrint += "\n"; } return(solvedPrint); }
/// <summary> /// Solve the maze using breadth first search /// </summary> /// <returns> /// Returns whether the maze was solved successfully. True or false. /// </returns> /// public bool Solve() { // tested copying the fields to local variables here, it gave no signficat benefit to the speed of the algorithm when averaging 1000 large maze solves. stopwatch.Restart(); // start with the starting point Queue <currentPoint> todo = new Queue <currentPoint>(); todo.Enqueue(new currentPoint(startX, startY)); // using 'width' as a stride to separate data into rows when accessing. // use 1 rather than 0, just to save time inialising all the entries as -1, since 0 is the int default. mazeDistance[startX + (startY * width)] = 1; // solved flag bool endFound = false; // loop until all traversable points have been searched, or end has been found. while (todo.Count > 0 && !endFound) { // grab the current point currentPoint p = todo.Dequeue(); // local variables rather than pulling the object refrence each time. int pX = p.X; int pY = p.Y; // check for end location if (pX == endX && pY == endY) { endFound = true; } else { // get the current disance from start int current = mazeDistance[pX + (pY * width)]; // check the adjacent points // use an inline method as this is not strictly a "class" funtion, // but rather a section of repeated code only used by this method. CheckPoint checkPoint = (x, y) => { // make sure point is within the bounds of the maze if (x >= 0 && x < width && y >= 0 && y < height) { if (mazeDistance[x + (y * width)] == 0) // not yet processed { if (!mazeData[x + (y * width)]) // only process viable pathways { // add distance, parent and queue for further processing mazeDistance[x + (y * width)] = current + 1; mazeParents[x + (y * width)] = p; todo.Enqueue(new currentPoint(x, y)); } } } }; // Right int newX = pX + 1; int newY = pY; checkPoint(newX, newY); // Left newX = pX - 1; newY = pY; checkPoint(newX, newY); // Up newX = pX; newY = pY + 1; checkPoint(newX, newY); // Down newX = pX; newY = pY - 1; checkPoint(newX, newY); } } stopwatch.Stop(); solveMillis = stopwatch.ElapsedMilliseconds; solveTicks = stopwatch.ElapsedTicks; return(endFound); }