/// <summary>
        /// To solve this since we can start from any cell on the left axis and we can end at any cell on the right axis
        /// Lets define a source cell which has edges which connect to all the cells on the left axis ie mat[i,0]
        /// Also define a destination cell which has all edges connected to all the cells on the right axis ie mat[i,mat.Length-1]
        ///
        /// Then we can do a djkstra's shortest path algorithm to figure out the shortest path.
        /// The running time of this algo is O(V+E) in worse case E = O(V^2)
        /// </summary>
        /// <param name="mat"></param>
        /// <returns></returns>
        public List <Cell> GetPath(int[,] mat)
        {
            UndirectedGraphWithVertexDictionary udg = new UndirectedGraphWithVertexDictionary();

            // Fix the source and destination cells.
            GraphVertexWithDistance source      = new GraphVertexWithDistance(new Cell(-1, -1));
            GraphVertexWithDistance destination = new GraphVertexWithDistance(new Cell(mat.Length, mat.Length));

            // Create the graph vertices and put it in a matrix
            GraphVertexWithDistance[,] allVertex = CreateGraphFromMatrix(mat, source, destination);

            // Now we need to do dijkstras shortest path algorithm. Each edge will have a weight of 1.
            return(DijkstrasShortestPath(source, destination, allVertex));
        }
        /// <summary>
        /// Create graph from the matrix and add all the edges in the format shown below
        ///     |------*---*-------*|
        ///     |--*---*-------*----|
        ///     |--*------*--------*|
        ///s ---|------*-----*--*---| --- d
        ///     |---*-------*----*--|
        ///     |---*---*----------*|
        ///     |-----*---*-------*-|
        ///     |---*----------*---*|
        /// </summary>
        /// <param name="mat"></param>
        /// <param name="source"></param>
        /// <param name="destination"></param>
        /// <returns></returns>
        private GraphVertexWithDistance[,] CreateGraphFromMatrix(int[,] mat, GraphVertexWithDistance source, GraphVertexWithDistance destination)
        {
            // Create the graph from the matrix
            GraphVertexWithDistance[,] allVertex = new GraphVertexWithDistance[mat.GetLength(0), mat.GetLength(1)];
            for (int i = 0; i < mat.GetLength(0); i++)
            {
                for (int j = 0; j < mat.GetLength(1); j++)
                {
                    allVertex[i, j] = new GraphVertexWithDistance(new Cell(i, j));
                }
            }

            // Add all the edges to the graph vertices
            for (int i = 0; i < mat.GetLength(0); i++)
            {
                for (int j = 0; j < mat.GetLength(1); j++)
                {
                    if (j == 0 && mat[i, j] != 1)
                    {
                        // This is the left side of the matrix
                        source.AddEdge(allVertex[i, j]);
                        allVertex[i, j].AddEdge(source);
                    }
                    if (j == mat.GetLength(1) - 1 && mat[i, j] != 1)
                    {
                        // This is the right side of the matrix
                        destination.AddEdge(allVertex[i, j]);
                        allVertex[i, j].AddEdge(destination);
                    }
                    if (j + 1 < mat.GetLength(1) && mat[i, j + 1] != 1 && mat[i, j] != 1)
                    {
                        // Add the edge to the right of the graphvertex allVertex[i,j]
                        allVertex[i, j].AddEdge(allVertex[i, j + 1]);
                        allVertex[i, j + 1].AddEdge(allVertex[i, j]);
                    }
                    if (i + 1 < mat.GetLength(0) && mat[i + 1, j] != 1 && mat[i, j] != 1)
                    {
                        // Add the edge below graphVertex allVertex[i,j]
                        allVertex[i, j].AddEdge(allVertex[i + 1, j]);
                        allVertex[i + 1, j].AddEdge(allVertex[i, j]);
                    }
                }
            }
            return(allVertex);
        }
 public GraphEdge(GraphVertexWithDistance source, GraphVertexWithDistance destination)
 {
     Source      = source;
     Destination = destination;
     Distance    = 1;
 }
 public void AddEdge(GraphVertexWithDistance neighbour)
 {
     NeighbourEdges.Add(new GraphEdge(this, neighbour));
 }
        private List <Cell> DijkstrasShortestPath(GraphVertexWithDistance source, GraphVertexWithDistance destination, GraphVertexWithDistance[,] allVertex)
        {
            // Initialization
            MinHeap <GraphVertexWithDistance> mh = new MinHeap <GraphVertexWithDistance>(allVertex.GetLength(0) * allVertex.GetLength(1) + 2);
            Dictionary <GraphVertexWithDistance, GraphVertexWithDistance> backtrack = new Dictionary <GraphVertexWithDistance, GraphVertexWithDistance>();
            Dictionary <GraphVertexWithDistance, int> FinalDistance = new Dictionary <GraphVertexWithDistance, int>();

            // Add all the graphvertices to the minheap
            source.Distance = 0;
            mh.Insert(source);
            mh.Insert(destination);
            for (int i = 0; i < allVertex.GetLength(0); i++)
            {
                for (int j = 0; j < allVertex.GetLength(1); j++)
                {
                    mh.Insert(allVertex[i, j]);
                }
            }

            while (mh.HeapSize > 0)
            {
                GraphVertexWithDistance vertex = mh.ExtractMin();
                FinalDistance[vertex] = vertex.Distance;
                if (vertex == destination)
                {
                    // We have reached the destination. No need to calculate final distance for all the other graph vertex
                    break;
                }
                foreach (GraphEdge neighbourEdge in vertex.NeighbourEdges)
                {
                    if (!FinalDistance.ContainsKey(neighbourEdge.Destination))
                    {
                        if (vertex.Distance + 1 < neighbourEdge.Destination.Distance)
                        {
                            GraphVertexWithDistance oldVertex = neighbourEdge.Destination;
                            neighbourEdge.Destination.Distance = vertex.Distance + 1;
                            GraphVertexWithDistance newVertex = neighbourEdge.Destination;
                            mh.Replace(newVertex, oldVertex);
                            backtrack[neighbourEdge.Destination] = vertex;
                        }
                    }
                }
            }

            // Back track to get the path
            List <Cell>             path          = new List <Cell>();
            GraphVertexWithDistance currentVertex = destination;

            while (currentVertex != source)
            {
                if (backtrack.ContainsKey(currentVertex))
                {
                    if (currentVertex != destination)
                    {
                        path.Add(currentVertex.Id);
                    }
                    currentVertex = backtrack[currentVertex];
                }
                else
                {
                    break;
                }
            }
            path.Reverse();
            return(path);
        }