Path Finder #1: can you reach the exit?
Task
You are at position [0, 0] in maze NxN and you can only move in one of the four cardinal directions (i.e. North, East, South, West). Return true if you can reach position [N-1, N-1] or false otherwise.
- Empty positions are marked
.
. - Walls are marked
W
. - Start and exit positions are empty in all test cases.
Solution
public class Finder
{
public class Pos
{
public int x;
public int y;
public Pos(int x, int y) { this.x = x; this.y = y; }
public Pos[] neighbours()
{
return new Pos[] { new Pos(x - 1, y), new Pos(x + 1, y), new Pos(x, y - 1), new Pos(x, y + 1) }; // left, right, up. down
}
public bool onPath(char[][] g)
{
return x >= 0 && x < g[0].Length && y >= 0 && y < g.Length && g[y][x] == '.'; // check barrier
}
}
public static bool PathFinder(string maze)
{
string[] rows = maze.Split("\n");
char[][] grid = new char[rows.Length][];
for (int i = 0; i < rows.Length; i++)
grid[i] = rows[i].ToCharArray();
return findExit(new Pos(0, 0), grid); // start point is (0,0)
}
public static bool findExit(Pos p, char[][] g)
{
if (p.x == g.Length - 1 && p.x == p.y) // return true if size is 1
return true;
if (!p.onPath(g))
return false; // return false if current position is not on path
g[p.y][p.x] = 'V'; // check visited
Pos[] n = p.neighbours();
return findExit(n[0], g) || findExit(n[1], g) || findExit(n[2], g) || findExit(n[3], g);
}
}
Test

Path Finder #2: shortest path
Task
You are at position [0, 0] in maze NxN and you can only move in one of the four cardinal directions (i.e. North, East, South, West). Return the minimal number of steps to exit position [N-1, N-1] if it is possible to reach the exit from the starting position. Otherwise, return -1.
- Empty positions are marked
.
. - Walls are marked
W
. - Start and exit positions are guaranteed to be empty in all test cases.
Solution
public class Finder
{
private static int INF = int.MaxValue;
private static int[][] graph;
public static int PathFinder(string maze)
{
InitGraph(maze);
GoTo(0, 0, 0);
return (graph[graph.Length - 1][graph.Length - 1] == INF) ? -1 : graph[graph.Length - 1][graph.Length - 1];
}
private static void InitGraph(string maze)
{
string[] lines = maze.Split("\n");
graph = new int[lines.Length][];
for (int i = 0; i < lines.Length; i++)
{
graph[i] = new int[lines.Length];
for (int j = 0; j < lines.Length; j++)
{
graph[i][j] = (lines[i][j] == 'W') ? -1 : INF; // fill INF if maze[i][j] is '.'
}
}
}
private static void GoTo(int i, int j, int step)
{
if (i == -1 || i == graph.Length || j == -1 || j == graph.Length || graph[i][j] <= step)
return;
graph[i][j] = step;
GoTo(i, j - 1, step + 1); // left
GoTo(i, j + 1, step + 1); // right
GoTo(i + 1, j, step + 1); // down
GoTo(i - 1, j, step + 1); // up
}
}
Test

Path Finder #3: the Alpinist
Task
You are at start location [0, 0] in mountain area of NxN and you can only move in one of the four cardinal directions (i.e. North, East, South, West). Return minimal number of climb rounds to target location [N-1, N-1]. Number of climb rounds between adjacent locations is defined as difference of location altitudes (ascending or descending).
- Location altitude is defined as an integer number (0-9).
Solution
public class Finder
{
public static int INF = int.MaxValue;
public static int PathFinder(string maze)
{
var field = maze.Split('\n').Select(s => s.Select(c => Int32.Parse(c.ToString())).ToArray()).ToArray();
field = field.Select(r => (r.Length < field[field.Length - 1].Length) ? r.Concat(Enumerable.Repeat(field[0].Last(), (field[field.Length - 1].Length - r.Length))).ToArray() : r.ToArray()).ToArray();
return dijkstra(field, (0, 0), (field[field.Length - 1].Length - 1, field.Length - 1));
}
private static int dijkstra(int[][] field, (int x, int y) startPos, (int x, int y) endPos)
{
Func<(int x, int y), IEnumerable<(int x, int y)>> getNig =
pos => new (int x, int y)[] { (pos.x - 1, pos.y), (pos.x + 1, pos.y), (pos.x, pos.y - 1), (pos.x, pos.y + 1)}
.Where(p => p.y >= 0 && p.y < field.Length && p.x >= 0 && p.x < field[p.y].Length);
var dist = new Dictionary<(int x, int y), int>();
for (int y = 0; y < field.Length; y++)
for (int x = 0; x < field[y].Length; x++)
dist[(x, y)] = INF;
dist[(0, 0)] = 0;
var Q = new SortedList<(int x, int y), int>();
Q.Add((0, 0), 0);
while (Q.Count > 0)
{
var v = Q.First();
Q.Remove(v.Key);
foreach (var node in getNig(v.Key))
{
var alt = dist[v.Key] + Math.Abs(field[v.Key.y][v.Key.x] - field[node.y][node.x]);
if (alt < dist[node])
{
Q.Remove(node);
dist[node] = alt;
Q.Add(node, alt);
}
}
}
return dist[endPos];
}
}
- It can be solved Dijkstra.
- But past posted Dijkstra need
Priority Queue
. - So you should use
SortedList
instead of.
Test

Path Finder #4: : where are you?
Task
- Hint is in Test Code
[TestFixture]
public class SolutionTest
{
[TestCaseSource("samples")]
public void MyTest(string s, Point p)
{
Assert.AreEqual(p, PathFinder.iAmHere(s));
}
static TestCaseData[] samples =
{
new TestCaseData("", new Point(0, 0)).SetName("Sample Test"),
new TestCaseData("RLrl", new Point(0, 0)).SetName("Sample Test"),
new TestCaseData("r5L2l4", new Point(4, 3)).SetName("Sample Test"),
new TestCaseData("r5L2l4", new Point(0, 0)).SetName("Sample Test"),
new TestCaseData("10r5r0", new Point(-10, 5)).SetName("Sample Test"),
new TestCaseData("10r5r0", new Point(0, 0)).SetName("Sample Test")
};
}
- It means that r is turn right, l is turn left, R is turn right twice, and L is turn left twice
Solution
public class PathFinder
{
private static Point p = new Point(0, 0);
private static Point[] ix = new Point[] { new Point(-1, 0), new Point(0, 1), new Point(1, 0), new Point(0, -1) };
private static int cd = 0;
public static Point iAmHere(string s)
{
foreach (Match m in Regex.Matches("q" + s, @"[qrRlL]\d*"))
{
string ms = m.ToString();
switch (ms[0])
{
case 'r': cd = (cd + 1) % 4; break;
case 'l': cd = (cd + 3) % 4; break;
case 'q': break;
default: cd = (cd + 2) % 4; break;
}
if (ms.Length > 1)
{
int dq = Int32.Parse(ms.Substring(1));
p.X += dq * ix[cd].X;
p.Y += dq * ix[cd].Y;
}
}
return p;
}
}
Test
