7

I want to make a code giving the shortest route when given a labyrinth as a matrix.

enter image description here

In this case, the matrix representation of this labyrinth is as follows.

## [,1] [,2] [,3] [,4]
## [1,] 2 0 0 0
## [2,] 1 1 0 1
## [3,] 0 1 0 0
## [4,] 1 1 1 3
 , where  0 denotes inaccessible points, 1 denotes accessible points.
          2 denotes the starting point, and 3 denotes the destination.

And, the desired result is this : c(4,1,4,4,1,1), where 1 denotes East, 2 denotes North, 3 denotes West, and 4 denotes South.

I guess that one possible code might be a function giving the shortest route as a vector when it is given the matrix representation of a labyrinth.

In addition to this case, I want to know if the coverage could be extended to general cases, though it seems rather redundant. I would like to know whether a desirable code can be made so that it covers arbitrary n by m size matrix, although just 4 by 4 case suffices. And I wonder if the start point and the destination could be located at arbitrary points other than vertices, though vertices case is sufficient.

kmee
  • 151
  • 7
  • 2
    i am not sure it is a programming question -- you need to have the search algorithm in place first before you even start pondering about how to code it. – stas g Oct 22 '15 at 16:52
  • 2
    I'm not sure that a matrix is the appropriate data structure to represent this problem. A graph would be better. You then have an ILP / QP problem where you aim to find the shortest distance between two points with equal distances between each vertex. – alexwhitworth Oct 22 '15 at 16:55
  • 2
    This isn't a problem with one right answer. There are many ways to find find paths. Check out: https://qiao.github.io/PathFinding.js/visual/ You need to decide which method is most appropriate for your data. – MrFlick Oct 22 '15 at 17:10
  • I think you could be looking for an implementation of Dijkstra's algorithm. Although I have never seen an output like that for those graphs – erasmortg Oct 22 '15 at 17:23
  • 1
    @stasg there is high-volume algorithms tag dedicated entirely to questions about what algorithm to use for a programming problem. Algorithms questions are not necessarily off-topic. I also don't understand the close votes for "too broad" here -- this can likely be implemented in 5 or fewer lines with igraph... – josliber Oct 22 '15 at 17:43

3 Answers3

9

You could construct a graph to represent the valid moves between positions in the matrix:

# Construct nodes and edges from matrix
(nodes <- which(m == 1 | m == 2 | m == 3, arr.ind=TRUE))
#       row col
#  [1,]   1   1
#  [2,]   2   1
#  [3,]   4   1
#  [4,]   2   2
#  [5,]   3   2
#  [6,]   4   2
#  [7,]   4   3
#  [8,]   2   4
#  [9,]   4   4
edges <- which(outer(seq_len(nrow(nodes)),seq_len(nrow(nodes)), function(x, y) abs(nodes[x,"row"] - nodes[y,"row"]) + abs(nodes[x,"col"] - nodes[y,"col"]) == 1), arr.ind=T)
(edges <- edges[edges[,"col"] > edges[,"row"],])
#      row col
# [1,]   1   2
# [2,]   2   4
# [3,]   4   5
# [4,]   3   6
# [5,]   5   6
# [6,]   6   7
# [7,]   7   9

library(igraph)
g <- graph.data.frame(edges, directed=FALSE, vertices=seq_len(nrow(nodes)))

Then you could solve the shortest path problem between the specified start and end location:

start.pos <- which(m == 2, arr.ind=TRUE)
start.node <- which(paste(nodes[,"row"], nodes[,"col"]) == paste(start.pos[,"row"], start.pos[,"col"]))
end.pos <- which(m == 3, arr.ind=TRUE)
end.node <- which(paste(nodes[,"row"], nodes[,"col"]) == paste(end.pos[,"row"], end.pos[,"col"]))
(sp <- nodes[get.shortest.paths(g, start.node, end.node)$vpath[[1]],])
#      row col
# [1,]   1   1
# [2,]   2   1
# [3,]   2   2
# [4,]   3   2
# [5,]   4   2
# [6,]   4   3
# [7,]   4   4

Finally, you could determine the direction (1: east; 2: north; 3: west; 4: south) as a simple manipulation of the final set of nodes selected:

dx <- diff(sp[,"col"])
dy <- -diff(sp[,"row"])
(dirs <- ifelse(dx == 1, 1, ifelse(dy == 1, 2, ifelse(dx == -1, 3, 4))))
# [1] 4 1 4 4 1 1

This code will work for arbitrarily sized input matrices.

Data:

(m <- matrix(c(2, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 3), nrow=4))
#      [,1] [,2] [,3] [,4]
# [1,]    2    0    0    0
# [2,]    1    1    0    1
# [3,]    0    1    0    0
# [4,]    1    1    1    3
josliber
  • 43,891
  • 12
  • 98
  • 133
  • Thank you for your kind answer. In your advice, I would like to ask if it is possible for the code to be manipulated to a code of the form "f=function(m){ .....}" , where m is a given matrix of a maze so that the function f gives the result as a vector whenever an arbitrary 4 by 4 sized matrix m is given. And, I would like to ask if it is possible to use codes without using any package, so that I might complete a self-sufficient code without any help of packages. – kmee Oct 23 '15 at 02:58
  • 1
    @kmee You can get your function by just adding `f <- function(m) {` before all my code and `}` afterwards. As for your second question, of course you could implement a shortest path algorithm without a library (google "Dijkstra's algorithm"), but I will not do it here because it would really be reimplementing the wheel. Note that if you have requirements about packages you can or can't use, those really belong in the question and shouldn't be mentioned as afterthoughts. – josliber Oct 23 '15 at 03:38
  • Thank you for your answer. I feel it very difficult to contain all the factors that I must consider before I post my question, possibly due to my inexperience. I will bear it in mind. And I think that I should take some time before posting questions in order not to omit any condition which is indispensable. Is it permissible for me to post again a question concerning this problem with added conditions? Thank you. – kmee Oct 23 '15 at 05:33
  • 1
    @kmee at this point your indeed do have a new coding problem -- you want to implement a shortest path algorithm instead of using the one from a library. Note that just asking for others to implement this for you is probably too broad a question to ask and will likely be downvoted and closed. It would be best to try implementing a shortest path algorithm yourself and post a question if you run into an issue with the implementation. – josliber Oct 23 '15 at 05:36
  • OK, I will try it myself. but I feel now that everything in R is very obscure and I seem ignorant of what to do in almost all examples, just as a student feel distressed when he study mathematical analysis first time in college. This is just a childish grumble, so ignore it. Thank you. – kmee Oct 23 '15 at 05:58
9

I'd likely use functions from the gdistance package, demonstrated in another setting here:

library(gdistance) ## A package to "calculate distances and routes on geographic grids"

## Convert sample matrix to a spatial raster
m = matrix(c(2, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 3), nrow=4)
R <- raster(m)

## Convert start & end points to SpatialPoints objects
startPt <- SpatialPoints(xyFromCell(R, Which(R==2, cells=TRUE)))
endPt   <- SpatialPoints(xyFromCell(R, Which(R==3, cells=TRUE)))

## Find the shortest path between them
## (Note: gdistance requires that you 1st prepare a sparse "transition matrix"
##  whose values give the "conductance" of movement between pairs of cells)
tr1 <- transition(R, transitionFunction=mean, directions=4)
SPath <- shortestPath(tr1, startPt, endPt, output="SpatialLines")

## Extract your direction codes from the steps taken in getting from 
## one point to the other. 
## (Obfuscated, but it works. Use some other method if you prefer.)
steps <- sign(diff(coordinates(SPath)[[1]][[1]]))
(t(-steps)+c(2,3))[t(steps!=0)]
## [1] 4 1 4 4 1 1

## Graphical check that this works
plot(R>0)
plot(rBind(startPt, endPt), col=c("yellow", "orange"), pch=16, cex=2, add=TRUE)
plot(SPath, col="red", lwd=2, add=TRUE)

enter image description here

Community
  • 1
  • 1
Josh O'Brien
  • 159,210
  • 26
  • 366
  • 455
7

One possibility consists in setting up a matrix with value 1 at the target and a decrease of the value at the rate of 0.9 for each square, as a function of the Manhattan distance from the destination. The obstacles would have the value zero, the starting point is arbitrary.

Once such a matrix is defined, the shortest path is obtained by iteratively going to the neighboring square with the largest increase in value.

This method is described, e.g., in the first chapter of the book "Statistical Reinforcement Learning" by M. Sugiyama.

So your matrix could look like this:

     [,1]  [,2]  [,3] [,4]
[1,] 0.53  0.00  0.0  0.00
[2,] 0.59  0.66  0.0  0.81
[3,] 0.00  0.73  0.0  0.00
[4,] 0.73  0.81  0.9  1.00

And the algorithm would be:

  • Choose a starting square with non-zero value
  • Move to the square that has the highest value among those squares that are one step away from you.
  • Repeat the previous step until you reach the square with value 1

Note that the value [2,4] is de facto not accessible and should therefore be excluded as a possible starting point. The destination does not need to be at a corner.

RHertel
  • 23,412
  • 5
  • 38
  • 64
  • Step 2 of the algorithm is "Move to the square that has the highest value among those squares that are one step away from you." How do you choose between neighboring cells with the same values? – Robert Hijmans Oct 22 '15 at 19:51
  • @RobertH There's no need to choose in that case, one can pick an arbitrary one as long as it is the highest value. If two cells have the same value the resulting path will have the same the length (like, e.g., turning first left and then up as opposed to first moving up and then turning left). – RHertel Oct 22 '15 at 20:22