Thanks for the fun little batch game. I played it for awhile (looks great, quick and fun to play, challenging when the mazes get big) and was checking out neorobin's code... so now I've got mazes on my mind! I've been examining the different algorithms and decided to attempt the easiest depth-first
maze generator I could muster. It's super simple, finitely iterative, totally stack-less, can produce mazes of any dimensions up to a maximum of ~2096 cells, and I've designed it as a direct replacement for
amaze.exe. Simply substitute
amaze.bat and make the following change to line# 14 of the file
mazeit.bat:
Code: Select all
>%_filename% CALL amaze %lines% %cols% #
I was able to increase the maximum number of cells from ~1992 to ~2096 by removing the exterior walls from the
maze string (adding them back during output). I eliminated the stack by storing the back-tracking information in the
maze itself... leaving bread crumbs, Hansel und Gretel style! It was already checking in each direction for closed cells, so I added a check for crumbs. Bingo, no stack. I've added some other stuff to the version I'm currently playing with (retention of longest path, animated display) but I'm posting this version now since it's a ready-to-go command-line replacement (I've also posted it at
Rosetta Code).
Code: Select all
:amaze Rows Cols [wall char]
:: A stack-less, iterative, depth-first maze generator in native WinNT batch.
:: Rows and Cols must each be >1 and Rows*Cols cannot exceed 2096.
:: Default wall character is #, [wall char] is used if provided.
:: 2017/09/27 v0.1 by CirothUngol
@ECHO OFF
SETLOCAL EnableDelayedExpansion
:: check for valid input, else GOTO :help
IF /I "%~2" EQU "" GOTO :amaze_help
FOR /F "tokens=* delims=0123456789" %%A IN ("%~1%~2") DO IF "%%~A" NEQ "" GOTO :amaze_help
SET /A "rows=%~1, cols=%~2, mTmp=rows*cols"
IF !rows! LSS 2 GOTO :amaze_help
IF !cols! LSS 2 GOTO :amaze_help
IF !mTmp! GTR 2096 GOTO :amaze_help
:: set map characters and use 1st character of %3 for wall, if defined
SET "wall=#"
SET "hall= "
SET "crumb=."
IF "%~3" NEQ "" SET "wall=%~3"
SET "wall=!wall:~0,1!"
:: assign width, height, cursor position, loop count, and offsets for NSEW
SET /A "cnt=0, wide=cols*2-1, high=rows*2-1, size=wide*high, N=wide*-2, S=wide*2, E=2, W=-2"
:: different random entrance points
:: ...on top
:: SET /A "start=(!RANDOM! %% cols)*2"
:: ...on bottom
:: SET /A "start=size-(!RANDOM! %% cols)*2-1"
:: ...on top or bottom
:: SET /A ch=cols*2, ch=!RANDOM! %% ch
:: IF !ch! GEQ !cols! ( SET /A "start=size-(ch-cols)*2-1"
:: ) ELSE SET /A start=ch*2
:: random entrance inside maze
SET /A "start=(!RANDOM! %% cols*2)+(!RANDOM! %% rows*2)*wide"
SET /A "curPos=start, cTmp=curPos+1, loops=cols*rows*2+1"
:: fill the maze with 8186 wall characters, clip to size, and open 1st cell
SET "mz=!wall!"
FOR /L %%A IN (1,1,6) DO SET mz=!mz!!mz!!mz!!mz!
SET bdr=!mz:~-%wide%!
SET mz=!mz:~3!!mz:~3!
SET mz=!mz:~-%size%!
SET mz=!mz:~0,%curPos%!!hall!!mz:~%cTmp%!
:: iterate #cells*2+1 steps of random depth-first search
FOR /L %%@ IN (1,1,%loops%) DO (
SET "rand=" & SET "crmPos="
REM set values for NSEW cell and wall positions
SET /A "rCnt=rTmp=0, cTmp=curPos+1, np=curPos+N, sp=curPos+S, ep=curPos+E, wp=curPos+W"
SET /A "wChk=curPos/wide*wide, eChk=wChk+wide, nw=curPos-wide, sw=curPos+wide, ew=curPos+1, ww=curPos-1"
REM examine adjacent cells, build direction list, and find last crumb position
FOR /F "tokens=1-8" %%A IN ("!np! !sp! !ep! !wp! !nw! !sw! !ew! !ww!") DO (
IF !np! GEQ 0 IF "!mz:~%%A,1!" EQU "!wall!" ( SET /A rCnt+=1 & SET "rand=n !rand!"
) ELSE IF "!mz:~%%E,1!" EQU "!crumb!" SET /A crmPos=np, cw=nw
IF !sp! LEQ !size! IF "!mz:~%%B,1!" EQU "!wall!" ( SET /A rCnt+=1 & SET "rand=s !rand!"
) ELSE IF "!mz:~%%F,1!" EQU "!crumb!" SET /A crmPos=sp, cw=sw
IF !ep! LEQ !eChk! IF "!mz:~%%C,1!" EQU "!wall!" ( SET /A rCnt+=1 & SET "rand=e !rand!"
) ELSE IF "!mz:~%%G,1!" EQU "!crumb!" SET /A crmPos=ep, cw=ew
IF !wp! GEQ !wChk! IF "!mz:~%%D,1!" EQU "!wall!" ( SET /A rCnt+=1 & SET "rand=w !rand!"
) ELSE IF "!mz:~%%H,1!" EQU "!crumb!" SET /A crmPos=wp, cw=ww
)
IF DEFINED rand ( REM adjacent unvisited cell is available
SET /A rCnt=!RANDOM! %% rCnt
FOR %%A IN (!rand!) DO ( REM pick random cell + wall
IF !rTmp! EQU !rCnt! SET /A "curPos=!%%Ap!, cTmp=curPos+1, mw=!%%Aw!, mTmp=mw+1"
SET /A rTmp+=1
)
REM write the 2 new characters into the maze
FOR /F "tokens=1-4" %%A IN ("!mw! !mTmp! !curPos! !cTmp!") DO (
SET "mz=!mz:~0,%%A!!crumb!!mz:~%%B!"
SET "mz=!mz:~0,%%C!!hall!!mz:~%%D!"
)
) ELSE IF DEFINED crmPos ( REM follow the crumbs backward
SET /A mTmp=cw+1
REM erase the crumb character and set new cursor position
FOR /F "tokens=1-2" %%A IN ("!cw! !mTmp!") DO SET "mz=!mz:~0,%%A!!hall!!mz:~%%B!"
SET "curPos=!crmPos!"
)
)
SET /A open=cols/2*2, mTmp=open+1
ECHO !wall!!bdr:~0,%open%!!hall!!bdr:~%mTmp%!!wall!
FOR /L %%A IN (0,!wide!,!size!) DO IF %%A LSS !size! ECHO !wall!!mz:~%%A,%wide%!!wall!
ECHO !wall!!bdr:~0,%open%!!hall!!bdr:~%mTmp%!!wall!
ENDLOCAL
EXIT /B 0
:amaze_help
ECHO Usage: %~0 Rows Cols [wall char]
ECHO Rows^>1, Cols^>1, and Rows*Cols^<=2096
ECHO Example: %~0 11 39 @
ENDLOCAL
EXIT /B 0
Next up is a
maze-solving algorithm (simple depth-first search) and then I want to try to implement a couple more (Hunt and Kill, Growing Tree, recursive division, and Eller's especially) before I attempt to do anything useful with them. Check out
Think Labyrinth if mazes interest you at all, it's the Grand PooBah of
maze algorithm sites!
Edit 1: fixed link to Rosetta Code.