'===========================================================================
' Subject: MAZES                              Date: 07-19-92 (00:00:00)    
'  Author: Jean Crepeau                       Code: QB, QBasic             
'  Origin: MAZES                            Packet: ALGOR.ABC
'===========================================================================
'        I was reading  a message a  while ago asking  about a maze
'drawing algorithm.  I've been  working on this  algorithm since last
'night and it's now ready to be sent. It draws a one-solution two-exits
'maze.  From one of the to exit/entrance, you can reach any 'square' in
'the maze.
'
'        It works in three phases. First it draws the paths and waits for
'a key. This is the main drawing  algorithm. Then it clears the screen,
'draws the walls (outlined paths),  and waits for a  key. Finally, the
'third part finds and draws the unique solution of  the maze and then
'waits for a key. You can exit at any time by pressing [Esc].

' Maze
' By Jean Cr*peau

DEFINT A-Z
DECLARE FUNCTION num (x, y)
DECLARE SUB vdctr (x$)
RANDOMIZE TIMER
DO
    SCREEN 0, 0: CLS
    COLOR 15: vdctr "Maze": COLOR 7
    vdctr "By Jean Cr*peau"
    PRINT
    INPUT "X,Y: ", nx, ny
    nx = nx - 1: ny = ny - 1
    IF nx <= 0 THEN nx = 31
    IF ny <= 0 THEN ny = 31
' Initialization
   SCREEN 1, 0: CLS : wx = 320 - 1: wy = 200 - 1' CGA4
    'SCREEN 2, 0: CLS : wx = 640 - 1: wy = 200 - 1' CGA2
    'SCREEN 3, 0: CLS : wx = 720 - 1: wy = 348 - 1' HERC
    xi = wx \ nx: yi = wy \ ny
    mx = (wx - xi * nx) / 2: my = (wy - yi * ny) / 2
    REDIM SHARED ar(nx, ny), avl(3), bit(7)
    bit(0) = 1: bit(1) = 2: bit(2) = 4: bit(3) = 8
    bit(4) = 1: bit(5) = 3: bit(6) = 7: bit(7) = 15
' Maze computation
    tt = (nx + 1) * (ny + 1): t = 0: ox = 0: oy = 0
    DO
        IF t = 0 THEN
            t = tt: cx = 0: cy = RND * ny
            sy0 = cy
        ELSE
            cx = ox: cy = oy: DO
                IF ar(cx, cy) THEN
                    IF num(cx, cy) > 0 THEN EXIT DO
                END IF
                cy = cy + 1: IF cy > ny THEN : cy = 0: cx = cx + 1: IF cx = nx THEN cx = 0
            LOOP
            ox = cx: oy = cy
        END IF
        DO
            px = cx * xi: py = cy * yi
            n = 4
            avl(0) = 1: avl(1) = 2: avl(2) = 3: avl(3) = 4
            IF cx = nx THEN avl(0) = 0 ELSE IF ar(cx + 1, cy) THEN avl(0) = 0
            IF cy = ny THEN avl(1) = 0 ELSE IF ar(cx, cy + 1) THEN avl(1) = 0
            IF cx = 0 THEN avl(2) = 0 ELSE IF ar(cx - 1, cy) THEN avl(2) = 0
            IF cy = 0 THEN avl(3) = 0 ELSE IF ar(cx, cy - 1) THEN avl(3) = 0
            DO
                IF avl(0) = 0 AND n > 0 THEN
                    n = n - 1: SWAP avl(0), avl(n)
                ELSEIF avl(1) = 0 AND n > 1 THEN
                    n = n - 1: SWAP avl(1), avl(n)
                ELSEIF avl(2) = 0 AND n > 2 THEN
                    n = n - 1: SWAP avl(2), avl(n)
                ELSEIF avl(3) = 0 AND n > 3 THEN
                    n = n - 1: SWAP avl(3), avl(n)
                ELSE
                    EXIT DO
                END IF
            LOOP UNTIL n = 0
            IF n = 0 THEN EXIT DO
            q = avl(INT(RND * n)) - 1
            IF ar(cx, cy) = 0 THEN t = t - 1
            ar(cx, cy) = ar(cx, cy) OR bit(q)
            SELECT CASE q
            CASE 0: cx = cx + 1
            CASE 1: cy = cy + 1
            CASE 2: cx = cx - 1
            CASE 3: cy = cy - 1
            END SELECT
            ar(cx, cy) = ar(cx, cy) OR bit(q XOR 2): t = t - 1
            LINE (mx + px, my + py)-(mx + cx * xi, my + cy * yi)

            IF cx = nx THEN sy1 = cy
        LOOP
        IF INKEY$ = CHR$(27) THEN GOTO quit
    LOOP UNTIL t = 0
    ar(nx, sy1) = ar(nx, sy1) OR bit(0)
    ar(0, sy0) = ar(0, sy0) OR bit(2)
    a$ = INPUT$(1)
' "Outline" maze
    CLS
    xi = wx \ (nx + 1): yi = wy \ (ny + 1)
    mx = (wx - (nx + 1) * xi) / 2: my = (wy - (ny + 1) * yi) / 2
    LINE (mx, my)-(mx, my + yi * (ny + 1))
    py = (sy0 + 1) * yi: LINE (mx, my + py)-(mx, my + py - yi), 0
    LINE (mx, my)-(mx + xi * (nx + 1), my)
    FOR y = 0 TO ny
        FOR x = 0 TO nx
            px = mx + (x + 1) * xi: py = my + (y + 1) * yi
            IF (ar(x, y) AND bit(0)) = 0 THEN LINE (px, py)-(px, py - yi)
            IF (ar(x, y) AND bit(1)) = 0 THEN LINE (px, py)-(px - xi, py)
        NEXT
        IF INKEY$ = CHR$(27) THEN GOTO quit
    NEXT
    a$ = INPUT$(1)
' Solution computation
    cx = 0: cy = sy0: t = 1: ld = 2: d = 0: u$ = "0"
    DO
        q = ar(cx, cy) AND NOT bit(ld)
        IF q = bit(0) THEN
            d = 0
        ELSEIF q = bit(1) THEN
            d = 1
        ELSEIF q = bit(2) THEN
            d = 2
        ELSEIF q = bit(3) THEN
            d = 3
        ELSEIF t = 1 THEN
            IF q AND bit(0) THEN
                u$ = u$ + CHR$(48 + d): d = 0
            ELSEIF q AND bit(1) THEN
                u$ = u$ + CHR$(48 + d): d = 1
            ELSEIF q AND bit(2) THEN
                u$ = u$ + CHR$(48 + d): d = 2
            ELSEIF q AND bit(3) THEN
                u$ = u$ + CHR$(48 + d): d = 3
            ELSE
                d = ld: t = 0
            END IF
        ELSE
            nd = ASC(RIGHT$(u$, 1)) AND 3
            q = ar(cx, cy) AND NOT bit(nd XOR 2) AND NOT bit(ld + 4)
            IF q AND bit(1) THEN
                t = 1: d = 1
            ELSEIF q AND bit(2) THEN
                t = 1: d = 2
            ELSEIF q AND bit(3) THEN
                t = 1: d = 3
            ELSE
                u$ = LEFT$(u$, LEN(u$) - 1)
                d = nd XOR 2
            END IF
        END IF
        px = mx + cx * xi: py = my + cy * yi
        LINE (px + 2, py + 2)-(px + xi - 2, py + yi - 2), t, BF
        SELECT CASE d
        CASE 0: cx = cx + 1: LINE (px + xi - 2, py + 2)-(px + xi + 2, py + yi - 2), t, BF
        CASE 1: cy = cy + 1: LINE (px + 2, py + yi - 2)-(px + xi - 2, py + yi + 2), t, BF
        CASE 2: cx = cx - 1: LINE (px - 2, py + 2)-(px + 2, py + yi - 2), t, BF
        CASE 3: cy = cy - 1: LINE (px + 2, py - 2)-(px + xi - 2, py + 2), t, BF
        END SELECT
        ld = d XOR 2
        IF INKEY$ = CHR$(27) THEN GOTO quit
    LOOP UNTIL cx = nx AND cy = sy1
    px = mx + cx * xi: py = my + cy * yi: LINE (px + 2, py + 2)-(px + xi - 2, py + yi - 2), t, BF
LOOP UNTIL INPUT$(1) = CHR$(27)
quit: SCREEN 0
END

FUNCTION num (x, y)
  SHARED nx, ny
  n = 4
  IF x >= nx THEN n = n - 1 ELSE IF ar(x + 1, y) THEN n = n - 1
  IF y >= ny THEN n = n - 1 ELSE IF ar(x, y + 1) THEN n = n - 1
  IF x <= 0 THEN n = n - 1 ELSE IF ar(x - 1, y) THEN n = n - 1
  IF y <= 0 THEN n = n - 1 ELSE IF ar(x, y - 1) THEN n = n - 1
  num = n
END FUNCTION

SUB vdctr (x$)
    PRINT SPACE$(40 - LEN(x$) / 2); x$
END SUB

