Skip to content

Commit 93a6253

Browse files
committed
Create recmaze.r
Another maze function. This one uses recursive backtracking to build the maze. You'll need some of the functions in 'maze.r' to do plotting and solving.
1 parent eaa0f77 commit 93a6253

File tree

1 file changed

+114
-0
lines changed

1 file changed

+114
-0
lines changed

recmaze.r

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
### recursive division maze
2+
3+
# Begin with an empty field.
4+
# Bisect the field with a wall, either horizontally or vertically. Add a single passage through the wall.
5+
# Repeat step #2 with the areas on either side of the wall.
6+
# Continue, recursively, until the maze reaches the desired resolution.
7+
# Recommended: look at aspect ratio of each new "field" and choose vert or horiz
8+
# wall to avoid long skinny passages.
9+
# http://weblog.jamisbuck.org/2011/1/12/maze-generation-recursive-division-algorithm
10+
# likes following one
11+
# 'sequence' of subdivisions until a field is at the cell level, then backing to
12+
# some other field.
13+
14+
15+
16+
## recursive backtracking maze
17+
18+
# Make the initial cell the current cell and mark it as visited
19+
# While there are unvisited cells
20+
# If the current cell has any neighbours which have not been visited
21+
# Choose randomly one of the unvisited neighbours
22+
# Push the current cell to the stack
23+
# Remove the wall between the current cell and the chosen cell
24+
# Make the chosen cell the current cell and mark it as visited
25+
# Else if stack is not empty
26+
# Pop a cell from the stack
27+
# Make it the current cell
28+
# Else
29+
# Pick a random unvisited cell, make it the current cell and mark it as visited
30+
31+
rbmaze<-function( dimx, dimy, slowly=FALSE, tcols, ...) {
32+
require(reshape2)
33+
mardef<-par()$mar
34+
par(mar=c(.1,.1,.1,.1))
35+
#build init matrices; remember cells are ID'd by "top left" coord
36+
scell<-matrix(0,nrow=(dimy),ncol=(dimx) )
37+
icell<-melt(scell)
38+
walls <- NULL #store indices of removed walls
39+
dewall<-vector(length=4)
40+
# select starting cell -- rumor has it that the starting cell
41+
# should be at 0,0; dunno why, tho.
42+
initx<-sample(1:dimx,1)
43+
inity<-sample(1:dimy,1)
44+
icell[icell[,1]==inity & icell[,2]==initx,3] <- 1
45+
# let's build my stack. set scell[i,j] to -1 when all neighbors are visited
46+
stackcount<-1
47+
scell[inity,initx]<-stackcount
48+
stackcount<-stackcount + 1
49+
# now loop until all cells have been visited... I think
50+
while( any(0%in% icell[,3] )) {
51+
# pick a wall to remove; for initial cell, don't need to check whether
52+
# neighbor has been visited. BUT need to check for boundary
53+
# 1234= NESW
54+
##watch for index crash at edges -- gotta be a smoother way
55+
neighborx <- initx+c(-1,1)
56+
neighborx <- neighborx[neighborx>0 & neighborx <=dimx]
57+
neighbory <- inity+c(-1,1)
58+
neighbory <- neighbory[neighbory>0 & neighbory <=dimy]
59+
# find out how many neighborxy
60+
# values showed up and sample amongst them.
61+
visith <- icell[(icell[,1]==inity & abs(icell[,2]-initx)==1 &icell[,3]==0),]
62+
visitv <- icell[(abs(icell[,1]-inity)==1 & icell[,2]==initx &icell[,3]==0),]
63+
visits<-rbind(visith,visitv)
64+
# in case all neighbors are already visited, skip the "build"
65+
if( nrow(visits) ) {
66+
pickit <- sample(1:nrow(visits),1)
67+
newy <- visits[pickit,1]
68+
newx <- visits[pickit,2]
69+
scell[newy,newx]<-stackcount
70+
##see same-ish algorithm for "dewall" in pmaze
71+
kwall<- c(max(initx,newx), max(newy,inity), max(newx,initx)+1*(initx==newx), max(newy,inity) + 1*(inity==newy) )
72+
walls<-rbind(walls, kwall)
73+
#Finished off the work when visits[] had rows
74+
} else {
75+
# just pick a new place to start; new approach is to back up the stackcount
76+
scell[inity,initx]<- -1 #no nonvisited neighbors; removes current
77+
# "stack count" value from array
78+
newcoord<-which(scell==max(scell),arr.ind=TRUE)
79+
newx<-newcoord[2]
80+
newy<-newcoord[1]
81+
} # end of if else
82+
stackcount<-stackcount+1
83+
initx <- newx
84+
inity <- newy
85+
icell[icell[,1]==inity & icell[,2]==initx,3] <- 1
86+
scell[inity,initx]<-stackcount
87+
} #end of while any 0
88+
#
89+
## now plot the maze, using same techniques as in pmaze.
90+
# modify limits to make it easier to plot in/out labels
91+
plot( c(1,(dimx+1),(dimx+1),1,1), c(1,1,(dimy+1),dimy+1,1),t='l',axes=F,xlab='',ylab='',xlim=c(0,dimx+2),ylim=c(0,dimy+2) )
92+
df = as.matrix(expand.grid( xvert= seq_len(dimx),yvert= seq_len(dimy)))
93+
dfv <- cbind(df,df[,1],df[,2]+1)
94+
df2 <- as.matrix(expand.grid(yvert= seq_len(dimy), xvert= seq_len(dimx)))
95+
dfh <- cbind(df2[,2],df2[,1],df2[,2]+1,df2[,1])
96+
# concatenate each row w/ delimiter (so that 2_13 is not same as 21_3 )
97+
#nb alternative methods as found on SO turn out to be much slower
98+
allwalls<-rbind(dfv,dfh)
99+
allrows<-unlist(sapply(1:nrow(allwalls),function(j) paste(allwalls[j,],collapse='_')) )
100+
# the maze walls:
101+
allfoo <- unlist(sapply(1:nrow(walls),function(j) paste(walls[j,],collapse='_')))
102+
thewalls<-setdiff(allrows,allfoo)
103+
dowalls<-allwalls[allrows%in%thewalls,]
104+
# original method, since I'm not sure "trees" exist in this maze yet.
105+
dowalls <- dowalls[order(rowSums(dowalls[,1:2])),]
106+
# timng is kinda cruddy here. Experiment with (if(slowly & !j%%10)) sort of thing
107+
for(j in 1:nrow(dowalls) ) {
108+
lines(dowalls[j,c(1,3)],dowalls[j,c(2,4)],...)
109+
if(slowly) Sys.sleep(slowly)
110+
}
111+
#cleanup
112+
par(mar=c(mardef))
113+
return(invisible(walls))
114+
}

0 commit comments

Comments
 (0)