Monday, April 1, 2013

Petit Computer Journal #14

Petit Computer Journal#14
Amazing Mazes!

It has been a long time, hasn't it? I took one month sabbatical. It became 3 months. How time flies! I got jolted into action by the bugs on my windshield! It's spring! Time to get moving!

Haha, joking aside, it IS time for me to get up and do something.

I have been working on this maze generation program that I planned to use on D&D type of game. The eventual code will create "rooms" out of the maze.

And here is the whole program

'MAZE
'APRIL 2013
'HARRY HARDJONO
CLS:CLEAR
DIM XDIR[5]
DIM YDIR[5]


'ROOM: MAKE ROOMS
'PATH: DRAW PATH
'CHOICE: CHOOSE PATH
'INIT: SET PARAMS
'MAZE: MAKE MAZE

GOTO @INIT
So far, so good. I'm allocating memory in the beginning of the program. I also map out the structure of the program in terms of subroutines.
@ROOM
'I'M SKIPPING THIS FOR NOW. TOO LAZY.
'LOOK IT UP ON QR CODE
RETURN
You're probably wondering what goes on here. All it does is scan the maze for straight walls, and removing them. Any bend in the wall and it will be left alone. The resulting "rooms" are unique. Setting the LINK variable to 0 will render this subroutine useless. For lots of spaces, I find LINK=8 is a good value to use. Higher values means less room.
@PATH
LOCATE CX,CY:?CHR$(32);
FOR PC=1 TO LEN(M$)-1
PDX=XDIR[INSTR(CIDX$,MID$(M$,PC,1))]
PDY=YDIR[INSTR(CIDX$,MID$(M$,PC,1))]
CX=CX+PDX:CY=CY+PDY
LOCATE CX,CY:?CHR$(32);
CX=CX+PDX:CY=CY+PDY
LOCATE CX,CY:?CHR$(32);
NEXT
RETURN
Path really draws the path of the maze. It goes by "UDLR" values of XDIR,YDIR arrays. I have the idea of making the subroutine generic by using string and draws all the path. No error checking here, so be careful when using this subroutine as-is.
@CHOICE
CS$=""
FOR CI=0 TO 3
CJ$=MID$(CIDX$,CI,1)
CPX=CX+(2*XDIR[CI])
CPY=CY+(2*YDIR[CI])
IF LEN(M$)>250 THEN CJ$=""
IF CPX<SCXMIN THEN CJ$=""
IF CPX>SCXMAX THEN CJ$=""
IF CPY<SCYMIN THEN CJ$=""
IF CPY>SCYMAX THEN CJ$=""
IF LINK==0 OR RND(LINK) THEN IF CHKCHR(CPX,CPY)!=151 THEN CJ$=""
CS$=CS$+CJ$
NEXT
C$=MID$(CS$,RND(LEN(CS$)),1)
RETURN
This subroutine merely take the current cursor position and looks at 4 different directions. Valid direction gets added to CS$. Invalid directions are those that are nested too deep, out-of-bounds, and dead-ended in a maze.
@INIT
CIDX$="UDLR"
XDIR(0)=0:YDIR(0)=-1
XDIR(1)=0:YDIR(1)=1
XDIR(2)=-1:YDIR(2)=0
XDIR(3)=1:YDIR(3)=0
SCXMIN=1:SCXMAX=29
SCYMIN=1:SCYMAX=21
SCXCUR=RND(SCXMAX/2)*2+1
SCYCUR=RND(SCYMAX/2)*2+1
LINK=88:'CHANGE THIS FOR CONNECTEDNESS
ROOM=FALSE

CLS:M$=""
FOR II=SCYMIN-1 TO SCYMAX+1:?CHR$(151)*31:NEXT
@INIT subroutine establishes the parameters of the program. The maze characteristics, other than SCXMAX,SCYMAX which defines the size of the maze would be LINK and ROOM=(TRUE/FALSE). Set ROOM to TRUE if you want open areas in the maze.

Also draws the initial background.

@MAZE
'HEAVY WIZARDRY
CX=SCXCUR:CY=SCYCUR
GOSUB @PATH
GOSUB @CHOICE
M$=M$+C$+C$
M$=LEFT$(M$,LEN(M$)-1)
IF LEN(M$) GOTO @MAZE
BEEP:IF ROOM THEN GOSUB @ROOM
This is the heart of the program. Traditionally, this is implemented by a recursive function. Obviously, BASIC has no recursion. I managed to flattened the whole algorithm. This used to be a double FOR-LOOP. Now, it's a single REPEAT-LOOP. Very clean and simple. I like it.
@END
IF BUTTON(0) GOTO @INIT
GOTO @END
Press any key to continue...

And there you have it. A short, simple and sweet maze generator routine. Feel free to use it on your games! I'm looking forward to see what you can come up with. Happy coding!