%import textio %import math ; Even though prog8 only has support for extremely limited recursion, ; you can write recursive algorithms with a bit of extra work by building your own explicit stack structure. ; This program shows a depth-first maze generation algorithm (1 possible path from start to finish), ; and a depth-first maze solver algorithm, both using a stack to store the path taken. ; Note: this program can be compiled for multiple target systems. maze { uword score sub bench(uword max_time) -> uword { txt.nl() score=0 math.rndseed(2345,44332) cbm.SETTIM(0,0,0) while cbm.RDTIM16() bool { ubyte cx = startCx ubyte cy = startCy stackptr = 0 @(celladdr(cx,cy)) &= ~STONE drawCell(cx, cy) uword cells_to_carve = numCellsHoriz * numCellsVert - 1 while cbm.RDTIM16() { cy-- @(celladdr(cx,cy)) |= DOWN } RIGHT -> { cx++ @(celladdr(cx,cy)) |= LEFT score++ } DOWN -> { cy++ @(celladdr(cx,cy)) |= UP } LEFT -> { cx-- @(celladdr(cx,cy)) |= RIGHT } } @(celladdr(cx,cy)) &= ~STONE cells_to_carve-- drawCell(cx, cy) } } return false sub repath() -> bool { ; repath: try to find a new start cell with possible directions. ; we limit our number of searches so that the algorith doesn't get stuck ; for too long on bad rng... just accept a few unused cells in that case. repeat 255 { do { cx = math.rnd() % numCellsHoriz cy = math.rnd() % numCellsVert } until @(celladdr(cx, cy)) & STONE ==0 if available_uncarved()!=0 return true } return false } sub available_uncarved() -> ubyte { ubyte candidates = 0 if cx>0 and @(celladdr(cx-1, cy)) & STONE !=0 candidates |= LEFT if cx0 and @(celladdr(cx, cy-1)) & STONE !=0 candidates |= UP if cy ubyte { ubyte candidates = available_uncarved() if candidates==0 return 0 repeat { ubyte choice = candidates & directionflags[math.rnd() & 3] if choice!=0 return choice } } } sub openpassages() { ; open just a few extra passages, so that multiple routes are possible in theory. ubyte numpassages ubyte cx ubyte cy do { do { cx = math.rnd() % (numCellsHoriz-2) + 1 cy = math.rnd() % (numCellsVert-2) + 1 } until @(celladdr(cx, cy)) & STONE ==0 ubyte direction = directionflags[math.rnd() & 3] if @(celladdr(cx, cy)) & direction == 0 { when direction { LEFT -> { if @(celladdr(cx-1,cy)) & STONE == 0 { @(celladdr(cx,cy)) |= LEFT drawCell(cx,cy) numpassages++ } } RIGHT -> { if @(celladdr(cx+1,cy)) & STONE == 0 { @(celladdr(cx,cy)) |= RIGHT drawCell(cx,cy) numpassages++ } } UP -> { if @(celladdr(cx,cy-1)) & STONE == 0 { @(celladdr(cx,cy)) |= UP drawCell(cx,cy) numpassages++ } } DOWN -> { if @(celladdr(cx,cy+1)) & STONE == 0 { @(celladdr(cx,cy)) |= DOWN drawCell(cx,cy) numpassages++ } } } } } until numpassages==10 } sub solve(uword max_time) -> bool { ubyte cx = startCx ubyte cy = startCy const uword max_path_length = 1024 ; the path through the maze can be longer than 256 so doesn't fit in a regular array.... :( uword pathstack = memory("pathstack", max_path_length, 0) uword pathstackptr = 0 @(celladdr(cx,cy)) |= WALKED ; txt.setcc(cx*2+1, cy*2+1, 81, 1) while cbm.RDTIM16() { ;txt.setcc(cx*2+1, cy*2+2, 81, 9) cy++ } DOWN -> { ;txt.setcc(cx*2+1, cy*2, 81, 9) cy-- } LEFT -> { ;txt.setcc(cx*2+2, cy*2+1, 81, 9) cx++ } RIGHT -> { ;txt.setcc(cx*2, cy*2+1, 81, 9) cx-- score++ } } goto solve_loop } pathstackptr++ if pathstackptr==max_path_length { txt.print("stack overflow, path too long\n") return true } @(celladdr(cx,cy)) |= WALKED ;txt.setcc(cx*2+1, cy*2+1, 81, 1) } return false } sub celladdr(ubyte cx, ubyte cy) -> uword { return cells+(numCellsHoriz as uword)*cy+cx } sub drawCell(ubyte cx, ubyte cy) { return ; ubyte x = cx * 2 + 1 ; ubyte y = cy * 2 + 1 ; ubyte doors = @(celladdr(cx,cy)) ; if doors & UP !=0 ; txt.setcc(x, y-1, ' ', EMPTYCOLOR) ; if doors & RIGHT !=0 ; txt.setcc(x+1, y, ' ', EMPTYCOLOR) ; if doors & DOWN !=0 ; txt.setcc(x, y+1, ' ', EMPTYCOLOR) ; if doors & LEFT !=0 ; txt.setcc(x-1, y, ' ', EMPTYCOLOR) ; if doors & STONE !=0 ; txt.setcc(x, y, 160, WALLCOLOR) ; else ; txt.setcc(x, y, 32, EMPTYCOLOR) ; ; if doors & WALKED !=0 ; txt.setcc(x, y, 81, 1) ; if doors & BACKTRACKED !=0 ; txt.setcc(x, y, 81, 2) } sub initialize() { sys.memset(cells, numCellsHoriz*numCellsVert, STONE) ; txt.fill_screen(160, WALLCOLOR) drawStartFinish() } sub drawStartFinish() { ; txt.setcc(startCx*2+1,startCy*2+1,sc:'s',5) ; txt.setcc(finishCx*2+1, finishCy*2+1, sc:'f', 13) } }