SlideShare a Scribd company logo
1 of 15
Download to read offline
Maze Solving App
Original Challenge:
Solving a maze
==============
The idea here is to write a program to solve simple mazes. The mazes are given in
a file and the program must read in the file, solve the maze and output the solution.
If no solution is possible the output should indicate this somehow. The program
should be written to the following specification:
- Arbitrary sized mazes should be handled
- Valid moves are N, S, E, W (not diagonally)
- All input will be clean, no validation is necessary
- Any suitable language can be used although one of Java, C#, Python is preferred
- The maze file format is described below with an example
- The program should be tested on the sample mazes provided
- Output should be written to the Standard Output/Console
================================================
== ALL the sample mazes DO have a solution! ==
================================================
The emphasis should be on code readability and simplicity. Runtime for all of the sample mazes
should be <30 seconds.
Please email the solution in source code form, with short instructions on how to run.
Good luck!
Maze file format
================
The input is a maze description file in plain text.
1 - denotes walls
0 - traversable passage way
INPUT:
<WIDTH> <HEIGHT><CR>
<START_X> <START_Y><CR> (x,y) location of the start. (0,0) is upper left and (width-
1,height-1) is lower right
<END_X> <END_Y><CR> (x,y) location of the end
<HEIGHT> rows where each row has <WIDTH> {0,1} integers space delimited
OUTPUT:
the maze with a path from start to end
walls marked by '#', passages marked by ' ', path marked by 'X', start/end marked by 'S'/'E'
Example file:
10 10
1 1
8 8
1 1 1 1 1 1 1 1 1 1
1 0 0 0 0 0 0 0 0 1
1 0 1 0 1 1 1 1 1 1
1 0 1 0 0 0 0 0 0 1
1 0 1 1 0 1 0 1 1 1
1 0 1 0 0 1 0 1 0 1
1 0 1 0 0 0 0 0 0 1
1 0 1 1 1 0 1 1 1 1
1 0 1 0 0 0 0 0 0 1
1 1 1 1 1 1 1 1 1 1
OUTPUT:
##########
#SXX #
# #X######
# #XX #
# ##X# ###
# # X# # #
# # XX #
# ###X####
# # XXXE#
##########
The Demo:
23 21
1 1
21 19
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1
1 0 1 0 1 0 1 0 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 1 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1
1 0 1 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 0 0 1 0 1
1 0 1 0 1 0 1 0 1 1 1 1 1 0 1 0 1 1 1 1 1 0 1
1 0 1 0 1 0 1 0 0 0 0 0 1 0 1 0 1 0 0 0 1 0 1
1 0 1 1 1 0 1 1 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 0 0 0 0 0 1 0 0 0 1 0 1 0 1 0 1 0 1 0 1 0 1
1 1 1 0 1 1 1 1 1 1 1 0 1 0 1 0 1 1 1 0 1 0 1
1 0 0 0 0 0 1 0 0 0 0 0 1 0 1 0 0 0 1 0 1 0 1
1 1 1 1 1 0 1 0 1 1 1 1 1 0 1 1 1 0 1 0 0 0 1
1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 1 0 1 0 1
1 0 1 0 1 1 1 1 1 0 1 1 1 0 1 0 1 0 1 0 1 0 1
1 0 1 0 0 0 0 0 1 0 1 0 0 0 1 0 0 0 1 0 1 0 1
1 0 1 1 1 1 1 0 1 0 1 0 1 1 1 0 1 1 1 0 1 0 1
1 0 1 0 0 0 1 0 1 0 1 0 0 0 1 0 1 0 0 0 1 0 1
1 0 1 0 1 0 1 0 1 1 1 1 1 0 1 0 1 0 1 0 1 0 1
1 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 0 0 1 0 1 0 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Becomes:
#######################
#S# # # # #
#X# # # ####### # # # #
#X# # # # # # # #
#X# # ######### # # # #
#X# # #XXXXXXX# # # #
#X# # #X#####X# ##### #
#X# # #XXXXX#X# # # #
#X### ### #X#X# # # # #
#XXX # #X#X# # # # #
###X#######X#X# ### # #
# XXX#XXXXX#X# # # #
#####X#X#####X### #XXX#
# #XXX # XXX# #X#X#
# # ##### ### #X# #X#X#
# # # # #X #X#X#
# ##### # # ###X###X#X#
# # # # # #X#XXX#X#
# # # # ##### #X#X# #X#
# # # #XXX# #E#
#######################
The Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MazeSolvingApp
{
class Program
{
static void Main(string[] args)
{
SolveMaze solve = new SolveMaze();
solve.Run();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MazeSolvingApp
{
class Node
{
public neighbour location { get; set; }//the location of the node itself
public neighbour top { get; set; }//the location of the neighbouring cell
public neighbour bottom { get; set; }
public neighbour left { get; set; }
public neighbour right { get; set; }
public int Neighbours()
{
int count = 0;
if (top != null)
{
count += 1;
}
if (bottom != null)
{
count += 1;
}
if (left != null)
{
count += 1;
}
if (right != null)
{
count += 1;
}
return count;
}
}
class neighbour
{
public int row { get; set; }
public int column { get; set; }
}
}
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
namespace MazeSolvingApp
{
class SolveMaze
{
private int Width { get; set; }
private int Height { get; set; }
private int StartX { get; set; }
private int StartY { get; set; }
private int EndX { get; set; }
private int EndY { get; set; }
private int position { get; set; }
private char[,] MazeArray { get; set; }
private char[,] SolvedMaze { get; set; }
private string outFile { get; set; }
private List<Node> nodeList { get; set; }
public void Run()
{
string FolderPath =
Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), @"Data");
Directory.CreateDirectory(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().
Location), @"Solutions"));//somewhere to put the solutions
List<String> mazes = new List<string>(Directory.EnumerateFiles(FolderPath,
"*.txt", SearchOption.AllDirectories));
foreach (string maze in mazes)
{
string[] contents = File.ReadAllLines(maze);
position = maze.LastIndexOf("") + 1;
outFile = maze.Substring(0, position - 5) + "SolutionsSolved" +
maze.Substring(position, maze.Length - position);
int[] mazeFirst = getIntValues(contents[3]);
if (getDims(contents[0]))
if (getStart(contents[1]))
if (getEnd(contents[2]))
if (contents.Count() == Height + 3 && mazeFirst.Count() ==
Width)//check the maze matches the supplied dimensions
{
Console.WriteLine("Width = " + Width.ToString() + " Height =
" + Height.ToString() + " ");
Console.WriteLine("Start X = " + StartX.ToString() + " Start
Y = " + StartY.ToString() + " ");
Console.WriteLine("End X = " + EndX.ToString() + " End Y = "
+ EndY.ToString() + " ");
string[] mazeContents = new string[Height];
Array.Copy(contents, 3, mazeContents, 0, Height);//copies the
maze strings only
makeMazeArray(mazeContents);
CopyMaze();
nodeList = makeNodeList(mazeContents);
nodeList = RelateNodeList(nodeList);
nodeList = TrimNodeList(nodeList);
generateSolution();
}
else
{
Console.WriteLine("The file " + maze + " is not a valid maze
file ");
}
}
Console.ReadLine();
}
private List<Node> makeNodeList(string[] maze)
{
List<Node> NodeList = new List<Node>();
for (int i = 0; i < Height; i++)
{
char[] row = getCharValues(maze[i]);
for (int j = 0; j < Width; j++)
{
if (row[j] == '0')
{
Node node = new Node() { location = new neighbour() { row = i, column
= j } };
/*just a basic node with its location*/
NodeList.Add(node);
}
}
}
return NodeList;
}
private List<Node> RelateNodeList(List<Node> NodeList)
{
foreach (Node node in NodeList)
{
int X = node.location.column;
int Y = node.location.row;
neighbour top = new neighbour { column = X - 1, row = Y };
neighbour left = new neighbour { column = X, row = Y - 1 };
neighbour right = new neighbour { column = X, row = Y + 1 };
neighbour bottom = new neighbour { column = X + 1, row = Y };
/*this connects the nodes up to each other, establishing their
relationships*/
int indexTop = NodeList.FindIndex(f => f.location.row == top.row &&
f.location.column == top.column);
int indexLeft = NodeList.FindIndex(f => f.location.row == left.row &&
f.location.column == left.column);
bool indexRight = NodeList.Any(n => n.location.row == right.row &&
n.location.column == right.column);// NodeList.FindIndex(f => f.location == right);
int indexBottom = NodeList.FindIndex(f => f.location.row == bottom.row &&
f.location.column == bottom.column);
if (indexTop >= 0)
{
node.top = top;
}
if (indexLeft >= 0)
{
node.left = left;
}
if (indexRight)
{
node.right = right;
}
if (indexBottom >= 0)
{
node.bottom = bottom;
}
}
return NodeList;
}
private List<Node> TrimNodeList(List<Node> NodeList)
{
//This finds all the cells with one or no connected nodes. These will be the ends
of dead ends
List<Node> orphanedNodes = (from n in NodeList where n.Neighbours() <= 1 &&
!(n.location.row == StartY && n.location.column == StartX) && !(n.location.row == EndY &&
n.location.column == EndX) select n).ToList();
foreach (Node node in orphanedNodes)
{
if (node.Neighbours() > 0)
{
neighbour neybour = null;
Node attachedNode = null;
if (node.top != null)//we remove the connection from the adjacent node.
If this becomes the end of the dead end, it will go next loop around.
{
neybour = node.top;
attachedNode = NodeList.FirstOrDefault(n => n.location.row ==
neybour.row && n.location.column == neybour.column);
attachedNode.bottom = null;
}
if (node.left != null)
{
neybour = node.left;
attachedNode = NodeList.FirstOrDefault(n => n.location.row ==
neybour.row && n.location.column == neybour.column);
attachedNode.right = null;
}
if (node.right != null)
{
neybour = node.right;
attachedNode = NodeList.FirstOrDefault(n => n.location.row ==
neybour.row && n.location.column == neybour.column);
attachedNode.left = null;
}
if (node.bottom != null)
{
neybour = node.bottom;
attachedNode = NodeList.FirstOrDefault(n => n.location.row ==
neybour.row && n.location.column == neybour.column);
attachedNode.top = null;
}
}
NodeList.Remove(node);
}
if (NodeList.Any(n => n.Neighbours() <= 1 && !(n.location.row == StartY &&
n.location.column == StartX) && !(n.location.row == EndY && n.location.column == EndX))) {
TrimNodeList(NodeList); }
return NodeList;// This should now only have nodes that connect start and end
}
private bool makeMazeArray(string[] maze)
{
MazeArray = new char[Width, Height];
for (int i = 0; i < Height; i++)
{
char[] row = getCharValues(maze[i]);
for (int j = 0; j < Width; j++)
{
MazeArray[j, i] = row[j];
}
}
return true;
}
private void generateSolution()
{
List<Node> path = shortestPath();
foreach (Node node in path)
{
SolvedMaze[node.location.column, node.location.row] = 'X';
//plot the shortest path on the solved maze array
}
makeOutputFile();// make the solution text file
}
private List<Node> shortestPath()
{
List<List<Node>> paths = new List<List<Node>>();
List<Node> path1 = plotForward();
paths.Add(path1);
/*This is just in case we get a shorter route by taking a different branch of
multiple paths
There are opportunities for providing multiple navigation methods and selecting
randomly,
running these multiple times and finding the shortest, but it wasn't necessary
here.
*/
List<Node> path2 = plotBackward();
paths.Add(path2);
List<Node> shortestPath = findShortest(paths);
return shortestPath;
}
private List<Node> plotForward()
{
List<Node> forwardListCopy = CopyList(nodeList);
List<Node> forwardList = new List<Node>();
Node currentNode = forwardListCopy.First(n => n.location.row == StartY &&
n.location.column == StartX);
Node previousNode = currentNode;
while (!(currentNode.location.row == EndY && currentNode.location.column ==
EndX))
{
forwardList.Add(currentNode);
neighbour next = findNeighbour(currentNode, previousNode);
previousNode = currentNode;
currentNode = forwardListCopy.First(n => n.location.row == next.row &&
n.location.column == next.column);
}
return forwardList;
}
private List<Node> plotBackward()
{
List<Node> backwardListCopy = CopyList(nodeList);
List<Node> backwardList = new List<Node>();
Node currentNode = backwardListCopy.First(n => n.location.row == EndY &&
n.location.column == EndX);
Node previousNode = currentNode;//this duplicates the first node position
while (!(currentNode.location.row == StartY && currentNode.location.column ==
StartX))
{
backwardList.Add(currentNode);//save the node to the path
neighbour next = findNeighbour(currentNode, previousNode);//find the next
node on the path
previousNode = currentNode;//this saves the node as previous, as we are about
to get the next one
currentNode = backwardListCopy.First(n => n.location.row == next.row &&
n.location.column == next.column);
}
return backwardList;
}
private neighbour findNeighbour(Node node, Node prev)
{
neighbour first = new neighbour() { row = -1, column = -1 };//see if the node has
a neighbour other than the previous node
if (node.location.row == prev.location.row && node.location.column ==
prev.location.column)//first instance
{
if (node.bottom != null)
{
first = node.bottom;
}
else if (node.left != null)
{
first = node.left;
}
else if (node.right != null)
{
first = node.right;
}
else if (node.top != null)
{
first = node.top;
}
}
else if (node.bottom != null && (node.bottom.row == prev.location.row &&
node.bottom.column == prev.location.column))
{
/* each of these options indicates the direction of travel
if the movement was from the bottom, then target top first, and then left
and right.
Don't go backwards*/
if (node.top != null)
{
first = node.top;
}
else if (node.left != null)
{
first = node.left;
}
else if (node.right != null)
{
first = node.right;
}
}
else if (node.left != null && (node.left.row == prev.location.row &&
node.left.column == prev.location.column))
{
if (node.right != null)
{
first = node.right;
}
else if (node.bottom != null)
{
first = node.bottom;
}
else if (node.top != null)
{
first = node.top;
}
}
else if (node.right != null && (node.right.row == prev.location.row &&
node.right.column == prev.location.column))
{
if (node.left != null)
{
first = node.left;
}
else if (node.bottom != null)
{
first = node.bottom;
}
else if (node.top != null)
{
first = node.top;
}
}
else if (node.top != null && (node.top.row == prev.location.row &&
node.top.column == prev.location.column))
{
if (node.bottom != null)
{
first = node.bottom;
}
else if (node.left != null)
{
first = node.left;
}
else if (node.right != null)
{
first = node.right;
}
}
return first;
}
private List<Node> findShortest(List<List<Node>> lists)
{
int minLength = lists.Min(x => x.Count);
List<Node> shortest = lists.First(x => x.Count == minLength);
//We take the first example with the shortest count
return shortest;
}
private List<Node> CopyList(List<Node> list)
{
List<Node> copy = new List<Node>();
/*Copies each node in the list into a new list of nodes*/
foreach (Node node in list)
{
Node copyNode = new Node() { location = new neighbour() { row =
node.location.row, column = node.location.column } };
if (node.bottom != null)
{
copyNode.bottom = new neighbour() { row = node.bottom.row, column =
node.bottom.column };
}
if (node.left != null)
{
copyNode.left = new neighbour() { row = node.left.row, column =
node.left.column };
}
if (node.right != null)
{
copyNode.right = new neighbour() { row = node.right.row, column =
node.right.column };
}
if (node.top != null)
{
copyNode.top = new neighbour() { row = node.top.row, column =
node.top.column };
}
copy.Add(copyNode);
}
return copy;
}
private void CopyMaze()
{
//create a copy of the mazed to plot the solution on
SolvedMaze = new char[Width, Height];
Array.Copy(MazeArray, SolvedMaze, MazeArray.Length);//copies the original maze
}
private bool getDims(String dims)
{
//gets the width and height of the maze
int[] Dims = getIntValues(dims);
if (Dims.Count() == 2)
{
Width = Dims[0];
Height = Dims[1];
return true;
}
else return false;
}
private bool getStart(String start)
{
//gets the start location
int[] Start = getIntValues(start);
if (Start.Count() == 2)
{
StartX = Start[0];
StartY = Start[1];
return true;
}
else return false;
}
private bool getEnd(String end)
{
//gets the end location
int[] End = getIntValues(end);
if (End.Count() == 2)
{
EndX = End[0];
EndY = End[1];
return true;
}
else return false;
}
private int[] getIntValues(String param)
{
//splits a string of space separated ints into individual ints
return param.Split(new[] { ' ' }).Select(int.Parse).ToArray();
}
private char[] getCharValues(String param)
{
//splits space separated chars
return param.Split(new[] { ' ' }).Select(char.Parse).ToArray();
}
private void makeOutputFile()
{
char[,] output = new char[Width, Height];
for (int i = 0; i < Height; i++)
{
for (int j = 0; j < Width; j++)
{
char temp = SolvedMaze[j, i];
if (temp == '1')
{
output[j, i] = '#';
}
else if (temp == 'X')
{
output[j, i] = 'X';
}
}
}
output[StartX, StartY] = 'S';
output[EndX, EndY] = 'E';
StringBuilder outList = new StringBuilder();
for (int i = 0; i < Height; i++)
{
StringBuilder sb = new StringBuilder();
for (int j = 0; j < Width; j++)
{
sb.Append(output[j, i]);
}
outList.AppendLine(sb.ToString());
}
System.IO.File.WriteAllText(outFile, outList.ToString());
int fileStart = position + 5;
string filename = outFile.Substring(fileStart);
string time = DateTime.Now.ToLongTimeString();
Console.WriteLine("Output file " + filename + " at " + time);
return;
}
}
}
To see the app working, first open the solution in Visual Studio 2017.
Build the solution, then navigate to the bin/release folder :
Double click the Application file (without a file extension) and the console display will report on
progress. The solutions appear in a folder called Solutions.

More Related Content

What's hot

WordPress Security: Be a Superhero - WordCamp Raleigh - May 2011
WordPress Security: Be a Superhero - WordCamp Raleigh - May 2011WordPress Security: Be a Superhero - WordCamp Raleigh - May 2011
WordPress Security: Be a Superhero - WordCamp Raleigh - May 2011John Ford
 
CBSE, Grade12, Computer Science, Random Numbers - Notes
CBSE, Grade12, Computer Science, Random Numbers - NotesCBSE, Grade12, Computer Science, Random Numbers - Notes
CBSE, Grade12, Computer Science, Random Numbers - NotesMalathi Senthil
 
Play, Slick, play2-authの間で討死
Play, Slick, play2-authの間で討死Play, Slick, play2-authの間で討死
Play, Slick, play2-authの間で討死Kiwamu Okabe
 
Bringing Characters to Life for Immersive Storytelling - Dioselin Gonzalez
Bringing Characters to Life for Immersive Storytelling - Dioselin GonzalezBringing Characters to Life for Immersive Storytelling - Dioselin Gonzalez
Bringing Characters to Life for Immersive Storytelling - Dioselin GonzalezWithTheBest
 
Coding Horrors
Coding HorrorsCoding Horrors
Coding HorrorsMark Baker
 
MoSQL: More than SQL, but Less than ORM @ PyCon APAC 2013
MoSQL: More than SQL, but Less than ORM @ PyCon APAC 2013MoSQL: More than SQL, but Less than ORM @ PyCon APAC 2013
MoSQL: More than SQL, but Less than ORM @ PyCon APAC 2013Mosky Liu
 
Mobile Database Persistence
Mobile Database PersistenceMobile Database Persistence
Mobile Database PersistenceEric Maxwell
 
Intro to OAuth
Intro to OAuthIntro to OAuth
Intro to OAuthmfrost503
 
Laziness in Swift
Laziness in Swift Laziness in Swift
Laziness in Swift SwiftWro
 
Creating custom views
Creating custom viewsCreating custom views
Creating custom viewsMu Chun Wang
 
Build a custom (micro)framework with ZF2 Components (as building blocks)
Build a custom (micro)framework with ZF2 Components (as building blocks)Build a custom (micro)framework with ZF2 Components (as building blocks)
Build a custom (micro)framework with ZF2 Components (as building blocks)Corley S.r.l.
 
Hangman Game Programming in C (coding)
Hangman Game Programming in C (coding)Hangman Game Programming in C (coding)
Hangman Game Programming in C (coding)hasan0812
 
Climbing the Abstract Syntax Tree (PHP South Africa 2017)
Climbing the Abstract Syntax Tree (PHP South Africa 2017)Climbing the Abstract Syntax Tree (PHP South Africa 2017)
Climbing the Abstract Syntax Tree (PHP South Africa 2017)James Titcumb
 
Ping pong game
Ping pong  gamePing pong  game
Ping pong gameAmit Kumar
 

What's hot (20)

R57.Php
R57.PhpR57.Php
R57.Php
 
WordPress Security: Be a Superhero - WordCamp Raleigh - May 2011
WordPress Security: Be a Superhero - WordCamp Raleigh - May 2011WordPress Security: Be a Superhero - WordCamp Raleigh - May 2011
WordPress Security: Be a Superhero - WordCamp Raleigh - May 2011
 
Speeding up Red Team engagements with carnivorall
Speeding up Red Team engagements with carnivorallSpeeding up Red Team engagements with carnivorall
Speeding up Red Team engagements with carnivorall
 
Ecmascript 6
Ecmascript 6Ecmascript 6
Ecmascript 6
 
CBSE, Grade12, Computer Science, Random Numbers - Notes
CBSE, Grade12, Computer Science, Random Numbers - NotesCBSE, Grade12, Computer Science, Random Numbers - Notes
CBSE, Grade12, Computer Science, Random Numbers - Notes
 
Play, Slick, play2-authの間で討死
Play, Slick, play2-authの間で討死Play, Slick, play2-authの間で討死
Play, Slick, play2-authの間で討死
 
Bringing Characters to Life for Immersive Storytelling - Dioselin Gonzalez
Bringing Characters to Life for Immersive Storytelling - Dioselin GonzalezBringing Characters to Life for Immersive Storytelling - Dioselin Gonzalez
Bringing Characters to Life for Immersive Storytelling - Dioselin Gonzalez
 
Coding Horrors
Coding HorrorsCoding Horrors
Coding Horrors
 
MoSQL: More than SQL, but Less than ORM @ PyCon APAC 2013
MoSQL: More than SQL, but Less than ORM @ PyCon APAC 2013MoSQL: More than SQL, but Less than ORM @ PyCon APAC 2013
MoSQL: More than SQL, but Less than ORM @ PyCon APAC 2013
 
Mobile Database Persistence
Mobile Database PersistenceMobile Database Persistence
Mobile Database Persistence
 
Php
PhpPhp
Php
 
Intro to OAuth
Intro to OAuthIntro to OAuth
Intro to OAuth
 
Laziness in Swift
Laziness in Swift Laziness in Swift
Laziness in Swift
 
Creating custom views
Creating custom viewsCreating custom views
Creating custom views
 
Build a custom (micro)framework with ZF2 Components (as building blocks)
Build a custom (micro)framework with ZF2 Components (as building blocks)Build a custom (micro)framework with ZF2 Components (as building blocks)
Build a custom (micro)framework with ZF2 Components (as building blocks)
 
Hangman Game Programming in C (coding)
Hangman Game Programming in C (coding)Hangman Game Programming in C (coding)
Hangman Game Programming in C (coding)
 
Yahoo! JAPANとKotlin
Yahoo! JAPANとKotlinYahoo! JAPANとKotlin
Yahoo! JAPANとKotlin
 
Climbing the Abstract Syntax Tree (PHP South Africa 2017)
Climbing the Abstract Syntax Tree (PHP South Africa 2017)Climbing the Abstract Syntax Tree (PHP South Africa 2017)
Climbing the Abstract Syntax Tree (PHP South Africa 2017)
 
Ping pong game
Ping pong  gamePing pong  game
Ping pong game
 
New
NewNew
New
 

Similar to Maze solving app listing

Beyond PHP - it's not (just) about the code
Beyond PHP - it's not (just) about the codeBeyond PHP - it's not (just) about the code
Beyond PHP - it's not (just) about the codeWim Godden
 
Python for High School Programmers
Python for High School ProgrammersPython for High School Programmers
Python for High School ProgrammersSiva Arunachalam
 
Hebrew Bible as Data: Laboratory, Sharing, Lessons
Hebrew Bible as Data: Laboratory, Sharing, LessonsHebrew Bible as Data: Laboratory, Sharing, Lessons
Hebrew Bible as Data: Laboratory, Sharing, LessonsDirk Roorda
 
Beyond PHP - It's not (just) about the code
Beyond PHP - It's not (just) about the codeBeyond PHP - It's not (just) about the code
Beyond PHP - It's not (just) about the codeWim Godden
 
So I am writing a CS code for a project and I keep getting cannot .pdf
So I am writing a CS code for a project and I keep getting cannot .pdfSo I am writing a CS code for a project and I keep getting cannot .pdf
So I am writing a CS code for a project and I keep getting cannot .pdfezonesolutions
 
DC |> Elixir Meetup - Going off the Rails into Elixir - Dan Ivovich
DC |> Elixir Meetup - Going off the Rails into Elixir - Dan IvovichDC |> Elixir Meetup - Going off the Rails into Elixir - Dan Ivovich
DC |> Elixir Meetup - Going off the Rails into Elixir - Dan IvovichSmartLogic
 
Python quickstart for programmers: Python Kung Fu
Python quickstart for programmers: Python Kung FuPython quickstart for programmers: Python Kung Fu
Python quickstart for programmers: Python Kung Fuclimatewarrior
 
Exact Real Arithmetic for Tcl
Exact Real Arithmetic for TclExact Real Arithmetic for Tcl
Exact Real Arithmetic for Tclke9tv
 
Types and Immutability: why you should care
Types and Immutability: why you should careTypes and Immutability: why you should care
Types and Immutability: why you should careJean Carlo Emer
 
Introduction to programming - class 11
Introduction to programming - class 11Introduction to programming - class 11
Introduction to programming - class 11Paul Brebner
 
Helvetia
HelvetiaHelvetia
HelvetiaESUG
 
SWP - A Generic Language Parser
SWP - A Generic Language ParserSWP - A Generic Language Parser
SWP - A Generic Language Parserkamaelian
 
Dealing with Legacy Perl Code - Peter Scott
Dealing with Legacy Perl Code - Peter ScottDealing with Legacy Perl Code - Peter Scott
Dealing with Legacy Perl Code - Peter ScottO'Reilly Media
 
Introduction to Perl Best Practices
Introduction to Perl Best PracticesIntroduction to Perl Best Practices
Introduction to Perl Best PracticesJosé Castro
 
Deep Learning con CNTK by Pablo Doval
Deep Learning con CNTK by Pablo DovalDeep Learning con CNTK by Pablo Doval
Deep Learning con CNTK by Pablo DovalPlain Concepts
 
Beyond php - it's not (just) about the code
Beyond php - it's not (just) about the codeBeyond php - it's not (just) about the code
Beyond php - it's not (just) about the codeWim Godden
 
R57php 1231677414471772-2
R57php 1231677414471772-2R57php 1231677414471772-2
R57php 1231677414471772-2ady36
 
第二讲 Python基礎
第二讲 Python基礎第二讲 Python基礎
第二讲 Python基礎juzihua1102
 

Similar to Maze solving app listing (20)

Beyond PHP - it's not (just) about the code
Beyond PHP - it's not (just) about the codeBeyond PHP - it's not (just) about the code
Beyond PHP - it's not (just) about the code
 
Python for High School Programmers
Python for High School ProgrammersPython for High School Programmers
Python for High School Programmers
 
Hebrew Bible as Data: Laboratory, Sharing, Lessons
Hebrew Bible as Data: Laboratory, Sharing, LessonsHebrew Bible as Data: Laboratory, Sharing, Lessons
Hebrew Bible as Data: Laboratory, Sharing, Lessons
 
Beyond PHP - It's not (just) about the code
Beyond PHP - It's not (just) about the codeBeyond PHP - It's not (just) about the code
Beyond PHP - It's not (just) about the code
 
So I am writing a CS code for a project and I keep getting cannot .pdf
So I am writing a CS code for a project and I keep getting cannot .pdfSo I am writing a CS code for a project and I keep getting cannot .pdf
So I am writing a CS code for a project and I keep getting cannot .pdf
 
DC |> Elixir Meetup - Going off the Rails into Elixir - Dan Ivovich
DC |> Elixir Meetup - Going off the Rails into Elixir - Dan IvovichDC |> Elixir Meetup - Going off the Rails into Elixir - Dan Ivovich
DC |> Elixir Meetup - Going off the Rails into Elixir - Dan Ivovich
 
Python quickstart for programmers: Python Kung Fu
Python quickstart for programmers: Python Kung FuPython quickstart for programmers: Python Kung Fu
Python quickstart for programmers: Python Kung Fu
 
Exact Real Arithmetic for Tcl
Exact Real Arithmetic for TclExact Real Arithmetic for Tcl
Exact Real Arithmetic for Tcl
 
Python slide
Python slidePython slide
Python slide
 
Lf 2021 rates_vi
Lf 2021 rates_viLf 2021 rates_vi
Lf 2021 rates_vi
 
Types and Immutability: why you should care
Types and Immutability: why you should careTypes and Immutability: why you should care
Types and Immutability: why you should care
 
Introduction to programming - class 11
Introduction to programming - class 11Introduction to programming - class 11
Introduction to programming - class 11
 
Helvetia
HelvetiaHelvetia
Helvetia
 
SWP - A Generic Language Parser
SWP - A Generic Language ParserSWP - A Generic Language Parser
SWP - A Generic Language Parser
 
Dealing with Legacy Perl Code - Peter Scott
Dealing with Legacy Perl Code - Peter ScottDealing with Legacy Perl Code - Peter Scott
Dealing with Legacy Perl Code - Peter Scott
 
Introduction to Perl Best Practices
Introduction to Perl Best PracticesIntroduction to Perl Best Practices
Introduction to Perl Best Practices
 
Deep Learning con CNTK by Pablo Doval
Deep Learning con CNTK by Pablo DovalDeep Learning con CNTK by Pablo Doval
Deep Learning con CNTK by Pablo Doval
 
Beyond php - it's not (just) about the code
Beyond php - it's not (just) about the codeBeyond php - it's not (just) about the code
Beyond php - it's not (just) about the code
 
R57php 1231677414471772-2
R57php 1231677414471772-2R57php 1231677414471772-2
R57php 1231677414471772-2
 
第二讲 Python基礎
第二讲 Python基礎第二讲 Python基礎
第二讲 Python基礎
 

Recently uploaded

Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationkaushalgiri8080
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comFatema Valibhai
 
Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...aditisharan08
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxTier1 app
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...stazi3110
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfjoe51371421
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWave PLM
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...Christina Lin
 
Call Girls in Naraina Delhi 💯Call Us 🔝8264348440🔝
Call Girls in Naraina Delhi 💯Call Us 🔝8264348440🔝Call Girls in Naraina Delhi 💯Call Us 🔝8264348440🔝
Call Girls in Naraina Delhi 💯Call Us 🔝8264348440🔝soniya singh
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackVICTOR MAESTRE RAMIREZ
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideChristina Lin
 
Engage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyEngage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyFrank van der Linden
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfPower Karaoke
 
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfThe Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfkalichargn70th171
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...OnePlan Solutions
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about usDynamic Netsoft
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...gurkirankumar98700
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfkalichargn70th171
 

Recently uploaded (20)

Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanation
 
HR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.comHR Software Buyers Guide in 2024 - HRSoftware.com
HR Software Buyers Guide in 2024 - HRSoftware.com
 
Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
 
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
Building a General PDE Solving Framework with Symbolic-Numeric Scientific Mac...
 
why an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdfwhy an Opensea Clone Script might be your perfect match.pdf
why an Opensea Clone Script might be your perfect match.pdf
 
What is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need ItWhat is Fashion PLM and Why Do You Need It
What is Fashion PLM and Why Do You Need It
 
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
ODSC - Batch to Stream workshop - integration of Apache Spark, Cassandra, Pos...
 
Call Girls in Naraina Delhi 💯Call Us 🔝8264348440🔝
Call Girls in Naraina Delhi 💯Call Us 🔝8264348440🔝Call Girls in Naraina Delhi 💯Call Us 🔝8264348440🔝
Call Girls in Naraina Delhi 💯Call Us 🔝8264348440🔝
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStack
 
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop SlideBuilding Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
Building Real-Time Data Pipelines: Stream & Batch Processing workshop Slide
 
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
 
Engage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyEngage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The Ugly
 
The Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdfThe Evolution of Karaoke From Analog to App.pdf
The Evolution of Karaoke From Analog to App.pdf
 
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdfThe Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
The Essentials of Digital Experience Monitoring_ A Comprehensive Guide.pdf
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...
 
DNT_Corporate presentation know about us
DNT_Corporate presentation know about usDNT_Corporate presentation know about us
DNT_Corporate presentation know about us
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
 
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdfLearn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
Learn the Fundamentals of XCUITest Framework_ A Beginner's Guide.pdf
 

Maze solving app listing

  • 1. Maze Solving App Original Challenge: Solving a maze ============== The idea here is to write a program to solve simple mazes. The mazes are given in a file and the program must read in the file, solve the maze and output the solution. If no solution is possible the output should indicate this somehow. The program should be written to the following specification: - Arbitrary sized mazes should be handled - Valid moves are N, S, E, W (not diagonally) - All input will be clean, no validation is necessary - Any suitable language can be used although one of Java, C#, Python is preferred - The maze file format is described below with an example - The program should be tested on the sample mazes provided - Output should be written to the Standard Output/Console ================================================ == ALL the sample mazes DO have a solution! == ================================================ The emphasis should be on code readability and simplicity. Runtime for all of the sample mazes should be <30 seconds. Please email the solution in source code form, with short instructions on how to run. Good luck!
  • 2. Maze file format ================ The input is a maze description file in plain text. 1 - denotes walls 0 - traversable passage way INPUT: <WIDTH> <HEIGHT><CR> <START_X> <START_Y><CR> (x,y) location of the start. (0,0) is upper left and (width- 1,height-1) is lower right <END_X> <END_Y><CR> (x,y) location of the end <HEIGHT> rows where each row has <WIDTH> {0,1} integers space delimited OUTPUT: the maze with a path from start to end walls marked by '#', passages marked by ' ', path marked by 'X', start/end marked by 'S'/'E' Example file: 10 10 1 1 8 8 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 1 1 0 1 0 1 1 1 1 1 1 1 0 1 0 0 0 0 0 0 1 1 0 1 1 0 1 0 1 1 1 1 0 1 0 0 1 0 1 0 1 1 0 1 0 0 0 0 0 0 1 1 0 1 1 1 0 1 1 1 1
  • 3. 1 0 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 OUTPUT: ########## #SXX # # #X###### # #XX # # ##X# ### # # X# # # # # XX # # ###X#### # # XXXE# ########## The Demo:
  • 4. 23 21 1 1 21 19 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 1 1 0 1 0 1 0 1 0 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 0 1 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 1 0 1 0 1 1 0 1 0 1 0 1 1 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 1 0 1 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 0 0 1 0 1 1 0 1 0 1 0 1 0 1 1 1 1 1 0 1 0 1 1 1 1 1 0 1 1 0 1 0 1 0 1 0 0 0 0 0 1 0 1 0 1 0 0 0 1 0 1 1 0 1 1 1 0 1 1 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 1 0 0 0 0 0 1 0 0 0 1 0 1 0 1 0 1 0 1 0 1 0 1 1 1 1 0 1 1 1 1 1 1 1 0 1 0 1 0 1 1 1 0 1 0 1 1 0 0 0 0 0 1 0 0 0 0 0 1 0 1 0 0 0 1 0 1 0 1 1 1 1 1 1 0 1 0 1 1 1 1 1 0 1 1 1 0 1 0 0 0 1 1 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 1 0 1 0 1 0 1 1 0 1 0 1 1 1 1 1 0 1 1 1 0 1 0 1 0 1 0 1 0 1 1 0 1 0 0 0 0 0 1 0 1 0 0 0 1 0 0 0 1 0 1 0 1 1 0 1 1 1 1 1 0 1 0 1 0 1 1 1 0 1 1 1 0 1 0 1 1 0 1 0 0 0 1 0 1 0 1 0 0 0 1 0 1 0 0 0 1 0 1 1 0 1 0 1 0 1 0 1 1 1 1 1 0 1 0 1 0 1 0 1 0 1 1 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 0 0 1 0 1 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 Becomes: ####################### #S# # # # # #X# # # ####### # # # # #X# # # # # # # # #X# # ######### # # # #
  • 5. #X# # #XXXXXXX# # # # #X# # #X#####X# ##### # #X# # #XXXXX#X# # # # #X### ### #X#X# # # # # #XXX # #X#X# # # # # ###X#######X#X# ### # # # XXX#XXXXX#X# # # # #####X#X#####X### #XXX# # #XXX # XXX# #X#X# # # ##### ### #X# #X#X# # # # # #X #X#X# # ##### # # ###X###X#X# # # # # # #X#XXX#X# # # # # ##### #X#X# #X# # # # #XXX# #E# ####################### The Code: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MazeSolvingApp { class Program { static void Main(string[] args) { SolveMaze solve = new SolveMaze(); solve.Run(); } } } using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MazeSolvingApp {
  • 6. class Node { public neighbour location { get; set; }//the location of the node itself public neighbour top { get; set; }//the location of the neighbouring cell public neighbour bottom { get; set; } public neighbour left { get; set; } public neighbour right { get; set; } public int Neighbours() { int count = 0; if (top != null) { count += 1; } if (bottom != null) { count += 1; } if (left != null) { count += 1; } if (right != null) { count += 1; } return count; } } class neighbour { public int row { get; set; } public int column { get; set; } } } using System; using System.IO; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Reflection; namespace MazeSolvingApp { class SolveMaze { private int Width { get; set; } private int Height { get; set; } private int StartX { get; set; } private int StartY { get; set; } private int EndX { get; set; } private int EndY { get; set; } private int position { get; set; } private char[,] MazeArray { get; set; } private char[,] SolvedMaze { get; set; }
  • 7. private string outFile { get; set; } private List<Node> nodeList { get; set; } public void Run() { string FolderPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), @"Data"); Directory.CreateDirectory(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly(). Location), @"Solutions"));//somewhere to put the solutions List<String> mazes = new List<string>(Directory.EnumerateFiles(FolderPath, "*.txt", SearchOption.AllDirectories)); foreach (string maze in mazes) { string[] contents = File.ReadAllLines(maze); position = maze.LastIndexOf("") + 1; outFile = maze.Substring(0, position - 5) + "SolutionsSolved" + maze.Substring(position, maze.Length - position); int[] mazeFirst = getIntValues(contents[3]); if (getDims(contents[0])) if (getStart(contents[1])) if (getEnd(contents[2])) if (contents.Count() == Height + 3 && mazeFirst.Count() == Width)//check the maze matches the supplied dimensions { Console.WriteLine("Width = " + Width.ToString() + " Height = " + Height.ToString() + " "); Console.WriteLine("Start X = " + StartX.ToString() + " Start Y = " + StartY.ToString() + " "); Console.WriteLine("End X = " + EndX.ToString() + " End Y = " + EndY.ToString() + " "); string[] mazeContents = new string[Height]; Array.Copy(contents, 3, mazeContents, 0, Height);//copies the maze strings only makeMazeArray(mazeContents); CopyMaze(); nodeList = makeNodeList(mazeContents); nodeList = RelateNodeList(nodeList); nodeList = TrimNodeList(nodeList); generateSolution(); } else { Console.WriteLine("The file " + maze + " is not a valid maze file "); } } Console.ReadLine(); } private List<Node> makeNodeList(string[] maze) { List<Node> NodeList = new List<Node>(); for (int i = 0; i < Height; i++) {
  • 8. char[] row = getCharValues(maze[i]); for (int j = 0; j < Width; j++) { if (row[j] == '0') { Node node = new Node() { location = new neighbour() { row = i, column = j } }; /*just a basic node with its location*/ NodeList.Add(node); } } } return NodeList; } private List<Node> RelateNodeList(List<Node> NodeList) { foreach (Node node in NodeList) { int X = node.location.column; int Y = node.location.row; neighbour top = new neighbour { column = X - 1, row = Y }; neighbour left = new neighbour { column = X, row = Y - 1 }; neighbour right = new neighbour { column = X, row = Y + 1 }; neighbour bottom = new neighbour { column = X + 1, row = Y }; /*this connects the nodes up to each other, establishing their relationships*/ int indexTop = NodeList.FindIndex(f => f.location.row == top.row && f.location.column == top.column); int indexLeft = NodeList.FindIndex(f => f.location.row == left.row && f.location.column == left.column); bool indexRight = NodeList.Any(n => n.location.row == right.row && n.location.column == right.column);// NodeList.FindIndex(f => f.location == right); int indexBottom = NodeList.FindIndex(f => f.location.row == bottom.row && f.location.column == bottom.column); if (indexTop >= 0) { node.top = top; } if (indexLeft >= 0) { node.left = left; } if (indexRight) { node.right = right; } if (indexBottom >= 0) { node.bottom = bottom; } } return NodeList; } private List<Node> TrimNodeList(List<Node> NodeList) { //This finds all the cells with one or no connected nodes. These will be the ends of dead ends List<Node> orphanedNodes = (from n in NodeList where n.Neighbours() <= 1 && !(n.location.row == StartY && n.location.column == StartX) && !(n.location.row == EndY && n.location.column == EndX) select n).ToList();
  • 9. foreach (Node node in orphanedNodes) { if (node.Neighbours() > 0) { neighbour neybour = null; Node attachedNode = null; if (node.top != null)//we remove the connection from the adjacent node. If this becomes the end of the dead end, it will go next loop around. { neybour = node.top; attachedNode = NodeList.FirstOrDefault(n => n.location.row == neybour.row && n.location.column == neybour.column); attachedNode.bottom = null; } if (node.left != null) { neybour = node.left; attachedNode = NodeList.FirstOrDefault(n => n.location.row == neybour.row && n.location.column == neybour.column); attachedNode.right = null; } if (node.right != null) { neybour = node.right; attachedNode = NodeList.FirstOrDefault(n => n.location.row == neybour.row && n.location.column == neybour.column); attachedNode.left = null; } if (node.bottom != null) { neybour = node.bottom; attachedNode = NodeList.FirstOrDefault(n => n.location.row == neybour.row && n.location.column == neybour.column); attachedNode.top = null; } } NodeList.Remove(node); } if (NodeList.Any(n => n.Neighbours() <= 1 && !(n.location.row == StartY && n.location.column == StartX) && !(n.location.row == EndY && n.location.column == EndX))) { TrimNodeList(NodeList); } return NodeList;// This should now only have nodes that connect start and end } private bool makeMazeArray(string[] maze) { MazeArray = new char[Width, Height]; for (int i = 0; i < Height; i++) { char[] row = getCharValues(maze[i]); for (int j = 0; j < Width; j++) { MazeArray[j, i] = row[j]; } } return true; } private void generateSolution() { List<Node> path = shortestPath(); foreach (Node node in path) {
  • 10. SolvedMaze[node.location.column, node.location.row] = 'X'; //plot the shortest path on the solved maze array } makeOutputFile();// make the solution text file } private List<Node> shortestPath() { List<List<Node>> paths = new List<List<Node>>(); List<Node> path1 = plotForward(); paths.Add(path1); /*This is just in case we get a shorter route by taking a different branch of multiple paths There are opportunities for providing multiple navigation methods and selecting randomly, running these multiple times and finding the shortest, but it wasn't necessary here. */ List<Node> path2 = plotBackward(); paths.Add(path2); List<Node> shortestPath = findShortest(paths); return shortestPath; } private List<Node> plotForward() { List<Node> forwardListCopy = CopyList(nodeList); List<Node> forwardList = new List<Node>(); Node currentNode = forwardListCopy.First(n => n.location.row == StartY && n.location.column == StartX); Node previousNode = currentNode; while (!(currentNode.location.row == EndY && currentNode.location.column == EndX)) { forwardList.Add(currentNode); neighbour next = findNeighbour(currentNode, previousNode); previousNode = currentNode; currentNode = forwardListCopy.First(n => n.location.row == next.row && n.location.column == next.column); } return forwardList; } private List<Node> plotBackward() { List<Node> backwardListCopy = CopyList(nodeList); List<Node> backwardList = new List<Node>(); Node currentNode = backwardListCopy.First(n => n.location.row == EndY && n.location.column == EndX); Node previousNode = currentNode;//this duplicates the first node position while (!(currentNode.location.row == StartY && currentNode.location.column == StartX)) { backwardList.Add(currentNode);//save the node to the path neighbour next = findNeighbour(currentNode, previousNode);//find the next node on the path previousNode = currentNode;//this saves the node as previous, as we are about to get the next one currentNode = backwardListCopy.First(n => n.location.row == next.row && n.location.column == next.column); } return backwardList;
  • 11. } private neighbour findNeighbour(Node node, Node prev) { neighbour first = new neighbour() { row = -1, column = -1 };//see if the node has a neighbour other than the previous node if (node.location.row == prev.location.row && node.location.column == prev.location.column)//first instance { if (node.bottom != null) { first = node.bottom; } else if (node.left != null) { first = node.left; } else if (node.right != null) { first = node.right; } else if (node.top != null) { first = node.top; } } else if (node.bottom != null && (node.bottom.row == prev.location.row && node.bottom.column == prev.location.column)) { /* each of these options indicates the direction of travel if the movement was from the bottom, then target top first, and then left and right. Don't go backwards*/ if (node.top != null) { first = node.top; } else if (node.left != null) { first = node.left; } else if (node.right != null) { first = node.right; } } else if (node.left != null && (node.left.row == prev.location.row && node.left.column == prev.location.column)) { if (node.right != null) { first = node.right; } else if (node.bottom != null) { first = node.bottom; } else if (node.top != null) { first = node.top; }
  • 12. } else if (node.right != null && (node.right.row == prev.location.row && node.right.column == prev.location.column)) { if (node.left != null) { first = node.left; } else if (node.bottom != null) { first = node.bottom; } else if (node.top != null) { first = node.top; } } else if (node.top != null && (node.top.row == prev.location.row && node.top.column == prev.location.column)) { if (node.bottom != null) { first = node.bottom; } else if (node.left != null) { first = node.left; } else if (node.right != null) { first = node.right; } } return first; } private List<Node> findShortest(List<List<Node>> lists) { int minLength = lists.Min(x => x.Count); List<Node> shortest = lists.First(x => x.Count == minLength); //We take the first example with the shortest count return shortest; } private List<Node> CopyList(List<Node> list) { List<Node> copy = new List<Node>(); /*Copies each node in the list into a new list of nodes*/ foreach (Node node in list) { Node copyNode = new Node() { location = new neighbour() { row = node.location.row, column = node.location.column } }; if (node.bottom != null) { copyNode.bottom = new neighbour() { row = node.bottom.row, column = node.bottom.column }; } if (node.left != null) {
  • 13. copyNode.left = new neighbour() { row = node.left.row, column = node.left.column }; } if (node.right != null) { copyNode.right = new neighbour() { row = node.right.row, column = node.right.column }; } if (node.top != null) { copyNode.top = new neighbour() { row = node.top.row, column = node.top.column }; } copy.Add(copyNode); } return copy; } private void CopyMaze() { //create a copy of the mazed to plot the solution on SolvedMaze = new char[Width, Height]; Array.Copy(MazeArray, SolvedMaze, MazeArray.Length);//copies the original maze } private bool getDims(String dims) { //gets the width and height of the maze int[] Dims = getIntValues(dims); if (Dims.Count() == 2) { Width = Dims[0]; Height = Dims[1]; return true; } else return false; } private bool getStart(String start) { //gets the start location int[] Start = getIntValues(start); if (Start.Count() == 2) { StartX = Start[0]; StartY = Start[1]; return true; } else return false; } private bool getEnd(String end) { //gets the end location int[] End = getIntValues(end); if (End.Count() == 2) { EndX = End[0]; EndY = End[1]; return true;
  • 14. } else return false; } private int[] getIntValues(String param) { //splits a string of space separated ints into individual ints return param.Split(new[] { ' ' }).Select(int.Parse).ToArray(); } private char[] getCharValues(String param) { //splits space separated chars return param.Split(new[] { ' ' }).Select(char.Parse).ToArray(); } private void makeOutputFile() { char[,] output = new char[Width, Height]; for (int i = 0; i < Height; i++) { for (int j = 0; j < Width; j++) { char temp = SolvedMaze[j, i]; if (temp == '1') { output[j, i] = '#'; } else if (temp == 'X') { output[j, i] = 'X'; } } } output[StartX, StartY] = 'S'; output[EndX, EndY] = 'E'; StringBuilder outList = new StringBuilder(); for (int i = 0; i < Height; i++) { StringBuilder sb = new StringBuilder(); for (int j = 0; j < Width; j++) { sb.Append(output[j, i]); } outList.AppendLine(sb.ToString()); } System.IO.File.WriteAllText(outFile, outList.ToString()); int fileStart = position + 5; string filename = outFile.Substring(fileStart); string time = DateTime.Now.ToLongTimeString(); Console.WriteLine("Output file " + filename + " at " + time); return; } } } To see the app working, first open the solution in Visual Studio 2017. Build the solution, then navigate to the bin/release folder :
  • 15. Double click the Application file (without a file extension) and the console display will report on progress. The solutions appear in a folder called Solutions.