'===========================================================================
' Subject: A-MAZING! V1.0 (MAZE SOLVER)       Date: 10-16-99 (19:56)       
'  Author: David Szafranski                   Code: LB                     
'  Origin: digital_paris@csi.com            Packet: LIBERTY.ABC
'===========================================================================
'A-Mazing! 1.0    David Szafranski 1998   digital_paris@csi.com
'Program in Public Domain. Feel free to modify/use/copy in any way!
'I was curious about drawing mazes so I created a program which draws a
'one-solution two-exits maze. From one of the two exit/entrance, you can
'reach any 'cell' in the maze. It first calculates a maze and then uses
'the 'right-hand' rule to find the solution. Optional crumbs are available
'in order to help solve the more difficult mazes.
'This program requires Liberty Basic V1.41
'Liberty Basic can be found at http://world.std.com/~carlg/basic.html

    nomainwin
    WindowWidth = 798
    WindowHeight = 598

    dim cellarray(10,10) 'based on ncellsx, ncellsy  'array for keeping no of walls
    dim visitarray(10,10) 'based on ncellsx, ncellsy  'array for keeping track of visited cells 1=visited 0= not visited
    dim visit2(10,10) 'array for keeping track of 2nd visit to cell
    dim solvearray(10,10) ' array for keeping track of visited cells while finding maze solution

    UpperLeftX = int((DisplayWidth - WindowWidth) / 2)
    UpperLeftY = int((DisplayHeight - WindowHeight) / 2)

    graphicbox #main.back, 0, 0, 790, 570
    graphicbox #main.statusBar, 0, 522, 790, 30
    menu #main, "&File", "&Quit", [quit]
    menu #main, "&Select Maze", "&Medium", [medium], "Lar&ge", [large], "&XL", [xlarge], "XX&L", [xxlarge]
    menu #main, "Solve &Maze", "Solve It", [solveMaze]
    menu #main, "&About", "&About A-Mazing!", [about]
    open "A-Mazing! 1.0" for window as #main

    open "gdi" for dll as #gdi
    open "user" for dll as #user
    hWnd=hwnd(#main.statusBar)

    calldll #user, "GetDC",_
        hWnd AS short,_
        hDC AS short

    print #main, "trapclose [quit]";
    print #main, "resizehandler [redrawStatbar]"
    print #main.back, "when mouseMove [main.back.MM]"    'routine to show current location
    print #main.statusBar, "when leftButtonDown [offButtonDown]"
    print #main.statusBar, "when leftButtonUp [offButtonUp]"

    print #main.back, "fill black; color green; backcolor black; down; flush";

    print #main.statusBar, "fill lightgray; flush"
    print #main.statusBar, "font Arial_Bold 0 15";

    gosub [drawStatusBar]     'create statusbar

[mainLoop]
    input aVar$
    goto [mainLoop]

[main.back.MM]  'draw selection box
    if cellarray(0,0) = 0 then goto [mainLoop]
    if solveFlag = 1 then goto [mainLoop]

    nextCellx = int((MouseX-startx)/cellwidth)    'x direction box number
    nextCelly = int((MouseY-starty)/cellheight)   'y direction box number

    if nextCellx = currentCellx and nextCelly = currentCelly then goto [mainLoop]

    gosub [nextBox]   'check valid moves

    if currentCellx <> nextCellx or currentCelly <> nextCelly then
        gosub [nextRedBox]
        gosub [currentRedBox]
        if crumbFlag = 1 then gosub [drawCrumbs]
        gosub [swap]
    end if

'    print #main.back, "flush"

    if endFlag = 0 and currentCellx = ncellsx-1 and currentCelly = exit then
        endFlag = 1
'        playwave "nolife.wav",async
        notice "Way to Go!"
    end if

    goto [mainLoop]


[solveMaze]
    solveFlag = 1
    text$ = "Solution to Maze"
    gosub [setStatusText]
    gosub [solveIt]
    gosub [drawSolution]
    goto [mainLoop]

[medium]
'   input number of cells in maze width ncellsx and height ncellsy
    ncellsx = 30
    ncellsy = 20
    text$ = "Medium Maze 20 x 30"
    gosub [setStatusText]
    radius = 5     'radius of crumb circle
    goto [draw1]

[large]
'   input number of cells in maze width ncellsx and height ncellsy
    ncellsx = 45
    ncellsy = 30
    text$ = "Large Maze 30 x 40"
    gosub [setStatusText]
    radius = 4     'radius of crumb circle
    goto [draw1]

[xlarge]
'   input number of cells in maze width ncellsx and height ncellsy
    ncellsx = 60
    ncellsy = 40
    text$ = "X-Large Maze 40 x 60"
    gosub [setStatusText]
    radius = 3     'radius of crumb circle
    goto [draw1]

[xxlarge]
'   input number of cells in maze width ncellsx and height ncellsy
    ncellsx = 75
    ncellsy = 50
    text$ = "XX-Large Maze 50 x 75"
    gosub [setStatusText]
    radius = 3     'radius of crumb circle
    goto [draw1]


[draw1]
    cursor hourglass
    print #main.back, "cls; fill black; color green; backcolor black; down";

    solveFlag = 0
    endFlag = 0

'drawing area of screen is approx 770 x 530

    dwidth = 750
    dheight = 500

    cellheight = int(dheight / ncellsy)
    cellwidth = int(dwidth / ncellsx)

    redim cellarray(ncellsx, ncellsy)
    redim visitarray(ncellsx, ncellsy)
    redim visit2(ncellsx, ncellsy)
    dim bit(15)  'number for wall assignments

'   assignments for cell walls for cellarray() as follows:
'   North = 1, East = 2, South = 4, West = 8
'   N+E wall = 3, N+S wall = 5, N+W walls = 9, E+S = 6, E+W = 10, S+W = 12
'   N+E+S = 7, N+E+W=11, N+S+W = 13, E+S+W = 14
'   All = 15
    bit(0) = 1  'north
    bit(1) = 2  'east
    bit(2) = 4  'south
    bit(3) = 8  'west
    bit(4) = 3
    bit(5) = 5
    bit(6) = 9
    bit(7) = 6
    bit(8) = 10
    bit(9) = 12
    bit(10) = 7
    bit(11) = 11
    bit(12) = 13
    bit(13) = 14
    bit(14) = 15

'total no of cells
    totalCells = ncellsx * ncellsy

    incr = 0                    'initialize increment counter for progress bar
    onePercent = 0.01 * totalCells    '1% step for progress bar update
    leap = onePercent


'initiate all cells to have all four walls (=15 or bit(14))
    for i = 0 to ncellsx-1
        for j = 0 to ncellsy -1
            cellarray(i,j) = bit(14)
        next j
    next i

'pick an entrance and exit cell by random from first and last row
    enter = int(rnd(1)*ncellsy)
    exit = int(rnd(1)*ncellsy)

'modify entrance and exit cells to remove exterior wall

    cellarray(0,enter) = cellarray(0,enter)-bit(3)
    cellarray(ncellsx-1,exit) = cellarray(ncellsx-1,exit) - bit(1)

'start to create maze - according to Judson McClendon try the following:
'Start a 'random walk' from the entry point, removing walls along the path.
'Do not 'break into' a previously visited cell.  If you encounter a dead-end,
'select at random a previously visited cell and start another random
'walk.  When you encounter the exit, remove that wall, though you can
'continue that random walk.  Repeat this process until every cell has
'been visited.  PS. Don't try this at home...

'keep track of current location in grid, start at entrance, go thru first random walk

    currentCellx = 0
    currentCelly = enter
    visitarray(currentCellx,currentCelly) = 1 'mark first cell as visited

    cellCount = totalCells

    gosub [initFlag]
    deadend = 0
    lastDirection = -1


        while deadend = 0       'if deadend detected then stop loop

[pickAnother]

            if flag(0)=1 and flag(1) = 1 and flag(2)=1 and flag(3) = 1 then
                deadend = 1
                goto [jump]
            end if

            gosub [pickWall]    'pick a direction

            'if nextCell is out of maze, then pick another cell, keep track of rejected directions with flags

            if nextCellx > ncellsx-1 then flag(1)=1: goto [pickAnother]
            if nextCellx < 0 then flag(3)=1: goto [pickAnother]
            if nextCelly > ncellsy-1 then flag(2)=1: goto [pickAnother]
            if nextCelly < 0 then flag(0)=1 :goto [pickAnother]

            ' if cell has already been visited, then skip it, find another, set direction rejection flag
            if visitarray(nextCellx,nextCelly) = 1 then flag(direction) = 1 : goto [pickAnother]

            ' if the same direction has been selected more than three times in a row, try new direction
            if direction = lastDirection then
                dirCount = dirCount + 1
            else
                dirCount = 0
            end if
            if dirCount > 2 then dirCount = 0: lastDirection = -1: goto [pickAnother]
            lastDirection = direction

            gosub [removeWall]  'remove wall between two cells
            gosub [cellVisited] 'mark cell visited
            gosub [swap]        'swap currentCell and nextCell
            gosub [initFlag]    'reinitialize flag()
            cellCount = cellCount - 1
            gosub [progressBar]

[jump]
        wend


    while cellCount <> 1    'now continue random walks from previously visited cells until all cells visited

        if cellCount < totalCells * 0.01 then   'choose next cell using list if < 1% remain

            'make a list of visited cells that have unvisited neighbors
            gosub [cellList2]

            'find a new starting point on current path of visited cells
            gosub [findNewCell]
        else
[tryAnother]
            gosub [selectNewCell]   'select next visited cell randomly
            if visitarray(currentCellx,currentCelly) = 0 then [tryAnother]
            if visit2(currentCellx,currentCelly) = 1 then [tryAnother]
            if currentCellx > 0 and currentCellx < ncellsx-1 and _
                currentCelly > 0 and currentCelly < ncellsy-1 then

                if visitarray(currentCellx+1,currentCelly) = 1 and _
                    visitarray(currentCellx-1,currentCelly) = 1 and _
                    visitarray(currentCellx,currentCelly+1) = 1 and _
                    visitarray(currentCellx,currentCelly-1) = 1 then [tryAnother]
            end if
        end if
        visit2(currentCellx,currentCelly) = 1

        gosub [initFlag]  'initiate all flag() to 0
        deadend = 0       'set deadend flag
        lastDirection = -1


        while deadend = 0       'if deadend detected then stop loop

[getAnother]   'pick another cell direction

            if flag(0)=1 and flag(1) = 1 and flag(2)=1 and flag(3) = 1 then
                deadend = 1
                goto [jumpout]
            end if
[goAgain]
            gosub [pickWall]    'pick a direction
            if flag(direction) = 1 then goto [goAgain]

            'if nextCell is out of maze, then pick another cell, keep track of rejected directions with flags

            if nextCellx > ncellsx-1 then flag(1)=1: goto [getAnother]
            if nextCellx < 0 then flag(3)=1: goto [getAnother]
            if nextCelly > ncellsy-1 then flag(2)=1: goto [getAnother]
            if nextCelly < 0 then flag(0)=1 :goto [getAnother]

            ' if cell has already been visited, then skip it, find another, set direction rejection flag
            if visitarray(nextCellx,nextCelly) = 1 then flag(direction) = 1 : goto [getAnother]

            ' if the same direction has been selected more than three times in a row, try new direction
            if direction = lastDirection then
                dirCount = dirCount + 1
            else
                dirCount = 0
            end if
            if dirCount > 2 then dirCount = 0: lastDirection = -1: goto [getAnother]
            lastDirection = direction

            gosub [removeWall]  'remove wall between two cells
            gosub [cellVisited] 'mark cell visited

            gosub [swap]        'swap currentCell and nextCell
            gosub [initFlag]    'reinitialize flag()
            cellCount = cellCount - 1
            gosub [progressBar]

[jumpout]
        wend

    wend
    cursor normal
    gosub [clearPBar]
    gosub [drawMaze]

    currentCellx = 0       'initiate starting point for selection box
    currentCelly = enter   'initiate starting point for selection box
    gosub [currentRedBox]  'draw first entrance selection box

    goto [mainLoop]

[redrawStatbar]
    hstatbar = 30
    newWidth = WindowWidth
    newHeight = WindowHeight

    print #main.statusBar, "locate "; 0; " "; newHeight-hstatbar; " "; newWidth; " "; hstatbar
    print #main.back, "locate 0 0 "; newWidth; " "; newHeight
    print #main, "refresh"
   goto [mainLoop]

[offButtonDown]
    'redraw box in recessed format
    if MouseX < 363 or MouseX > 430 then goto [mainLoop]   'check to see if button was pushed

    x = 4*gap + 350   'redraw as a recessed3D pushbutton
    y = 2*gap
    boxWidth = 67
    boxHeight = statusBoxHeight
    gosub [recessedStatBarBox]
    if buttonFlag = 0 then
        print #main.statusBar, "color yellow; backcolor green"
        print #main.statusBar, "place 363 20"      'print button title
        print #main.statusBar, "\       Off!        "
    end if
    if buttonFlag = 1 then
        print #main.statusBar, "color red; backcolor yellow"
        print #main.statusBar, "place 363 20"      'print button title
        print #main.statusBar, "\        On!       "
    end if
'    print #main.statusBar, "flush"
    goto [mainLoop]

[offButtonUp]
    'redraw box in recessed format
    if MouseX < 363 or MouseX > 420 then goto [mainLoop]   'check to see if button was pushed
    x = 4*gap + 350    'redraw as a raised3D pushbutton
    y = 2*gap
    boxWidth = 67
    boxHeight = statusBoxHeight
    gosub [raisedStatBarBox]
    if buttonFlag = 1 then
        print #main.statusBar, "color yellow; backcolor green"
        print #main.statusBar, "place 363 20"      'print button title
        print #main.statusBar, "\       Off!        "
        buttonFlag = 0
        crumbFlag = 0
        goto [mainLoop]
    end if
    if buttonFlag = 0 then
        print #main.statusBar, "color red; backcolor yellow"
        print #main.statusBar, "place 363 20"      'print button title
        print #main.statusBar, "\        On!       "
        buttonFlag = 1
        crumbFlag = 1
    end if
'    print #main.statusBar, "flush"
    goto [mainLoop]

[about]
    h=hwnd(#main)
    message$ = "A-Mazing! 1.0 "+ chr$(13) _
             +"December 1998"+ chr$(13) _
             +"David Szafranski"+ chr$(13) _
             +"digital_paris@csi.com"
    title$ = "A-Mazing! 1.0"
    gosub [dialogBox]
    goto [mainLoop]

[quit]
    calldll #user, "ReleaseDC",_
        hWnd AS short,_
        hDC AS short,_
        RESULT AS short
    close #user
    close #gdi
    close #main
    END


[cellList2]   'create a list of visited cells with at least one un-visited neighbor
    list$ = ""
    listcount = 0

    for i = 0 to ncellsx-1
        for j = 0 to ncellsy-1
        if visitarray(i,j) = 0 then     'stop at only unvisited cells

            if i = ncellsx-1 and j = 0 then
                gosub [left]
                gosub [down]
            goto [skip]
            end if

            if i = 0 and j = ncellsy-1 then
                gosub [right]
                gosub [up]
            goto [skip]
            end if

            if i = ncellsx-1 and j = ncellsy-1 then
                gosub [left]
                gosub [up]
            goto [skip]
            end if

            if i = 0 and j = 0 then
                gosub [right]
                gosub [down]
            goto [skip]
            end if

            if i = 0 then
                gosub [right]
                gosub [down]
                gosub [up]
            goto [skip]
            end if

            if j = 0 then
                gosub [right]
                gosub [left]
                gosub [down]
            goto [skip]
            end if

            if i = ncellsx-1 then
                gosub [left]
                gosub [down]
                gosub [up]
            goto [skip]
            end if

            if j = ncellsy-1 then
                gosub [right]
                gosub [left]
                gosub [up]
            goto [skip]
            end if


            gosub [right]
            gosub [left]
            gosub [down]
            gosub [up]

        end if
[skip]
        next j
    next i
return


[dupes]  'make sure there are no duplicates in list
    if instr(list$, temp$) <> 0 then temp$ = "" else listcount = listcount+1
return

[right]  'check cell to right
                if visitarray(i+1,j)= 1 then
                    temp$ = " " + str$(i+1) + "," + str$(j)
                    gosub [dupes]
                    list$ = list$ + temp$
                end if
return

[left]   'check cell to left
                if visitarray(i-1,j) = 1 then
                    temp$ = " " + str$(i-1) + "," + str$(j)
                    gosub [dupes]
                    list$ = list$ + temp$
                end if
return

[down]   'check cell below
                if visitarray(i,j+1) = 1 then
                    temp$ = " " + str$(i) + "," + str$(j+1)
                    gosub [dupes]
                    list$ = list$ + temp$
                end if
return

[up]    'check cell above
                if visitarray(i,j-1) = 1 then
                    temp$ = " " + str$(i) + "," + str$(j-1)
                    gosub [dupes]
                    list$ = list$ + temp$ 
                end if
return


[swap]
        'swap contents of nextCell with currentCell
        currentCellx = nextCellx
        currentCelly = nextCelly
return

[initFlag]
    for i = 0 to 3: flag(i) = 0: next i
return



[pickWall]
'pick a random wall 0 = N, 1 = E, 2 = S, 3 = W  oppWall = opposite wall for nextCell
    gosub [RandomN]
    direction = int(RandomN.RN*4)

    if direction = 0 then nextCelly = currentCelly - 1 : nextCellx = currentCellx : oppWall = 2
    if direction = 1 then nextCellx = currentCellx + 1 : nextCelly = currentCelly : oppWall = 3
    if direction = 2 then nextCelly = currentCelly + 1 : nextCellx = currentCellx : oppWall = 0
    if direction = 3 then nextCellx = currentCellx - 1 : nextCelly = currentCelly : oppWall = 1
return

[cellVisited]
'update vistarray to keep track of which valid next cells that have been visited
    visitarray(nextCellx,nextCelly) = 1        '1=visited 0=unvisited
return



[findNewCell]
'choose a cell from approved list
     gosub [RandomN]
     cellPick = int(RandomN.RN*listcount)+1
     choice$ = trim$(word$(list$, cellPick))
     comma = instr(choice$, ",")
     currentCellx = val(left$(choice$, comma))
     currentCelly = val(right$(choice$, len(choice$)-comma))

'    print "cellpick= "; cellPick
'    print "cellx= ";currentCellx; " celly= "; currentCelly
return


[selectNewCell]
'choose a cell that has already been visited and then pick another new wall/direction

    gosub [RandomN]
    currentCellx = int(RandomN.RN*ncellsx)
    gosub [RandomN]
    currentCelly = int(RandomN.RN*ncellsy)
return



[removeWall]
'remove wall between currentCell and nextCell
    cellarray(currentCellx,currentCelly) = cellarray(currentCellx,currentCelly) - bit(direction)
    cellarray(nextCellx,nextCelly) = cellarray(nextCellx,nextCelly) - bit(oppWall)
return




[drawMaze]
'draw current maze

    startx = 20   'location of UL corner of maze
    starty = 10

    for i = 0 to ncellsx-1
        for j = 0 to ncellsy-1

'   assignments for cell walls as follows:
'   North = 1, East = 2, South = 4, West = 8
'   N+E wall = 3, N+S wall = 5, N+W walls = 9, E+S = 6, E+W = 10, S+W = 12
'   N+E+S = 7, N+E+W=11, N+S+W = 13, E+S+W = 14
'   all = 15
        if cellarray(i,j) = 1 then gosub [north]
        if cellarray(i,j) = 2 then gosub [east]
        if cellarray(i,j) = 4 then gosub [south]
        if cellarray(i,j) = 8 then gosub [west]
        if cellarray(i,j) = 3 then gosub [north] : gosub [east]
        if cellarray(i,j) = 5 then gosub [north] : gosub [south]
        if cellarray(i,j) = 9 then gosub [north] : gosub [west]
        if cellarray(i,j) = 6 then gosub [east]  : gosub [south]
        if cellarray(i,j) = 10 then gosub [east] : gosub [west]
        if cellarray(i,j) = 12 then gosub [south] : gosub [west]
        if cellarray(i,j) = 7 then gosub [north]  : gosub [east] : gosub [south]
        if cellarray(i,j) = 11 then gosub [north] : gosub [east] : gosub [west]
        if cellarray(i,j) = 13 then gosub [north] : gosub [south] : gosub [west]
        if cellarray(i,j) = 14 then gosub [east] : gosub [south] : gosub [west]
        if cellarray(i,j) = 15 then gosub [north] : gosub [east] : gosub [south]: gosub [west]
        next j
    next i

    'mark entrance and exit points of maze
    print #main.back, "place "; 2; " "; enter*cellheight+starty+int(cellheight/2)+4
    print #main.back, "color red; backcolor black"
    print #main.back, "\>>"
    print #main.back, "place "; ncellsx*cellwidth+startx+1 ; " "; exit*cellheight+starty+int(cellheight/2) + 4
    print #main.back, "\<<"

    print #main.back, "flush";

return


[north]
    print #main.back, "line "; i*cellwidth+startx; " "; j*cellheight+starty; " "; (i+1)*cellwidth+startx; _
     " "; j*cellheight+starty
return

[east]
    print #main.back, "line "; (i+1)*cellwidth+startx; " "; j*cellheight+starty; " "; (i+1)*cellwidth+startx; _
    " "; (j+1)*cellheight+starty
return

[south]
    print #main.back, "line "; (i)*cellwidth+startx; " "; (j+1)*cellheight+starty; " "; (i+1)*cellwidth+startx; _
    " "; (j+1)*cellheight+starty
return

[west]
    print #main.back, "line "; i*cellwidth+startx; " "; j*cellheight+starty; " "; i*cellwidth+startx; _
    " "; (j+1)*cellheight+starty
return



[RandomN]     'random number generator by Brosco!
            if RandomN.Seed = 0 then gosub [RandomN.SeedRNG]
            RandomN.C1=24298
            RandomN.C2=99991
            RandomN.C3=199017
            RandomN.SeedTmp = RandomN.C1 * RandomN.Seed + RandomN.C2
            RandomN.Seed = RandomN.SeedTmp - _
            int( RandomN.SeedTmp / RandomN.C3 ) * RandomN.C3
            RandomN.RN = RandomN.Seed / RandomN.C3
return

[RandomN.SeedRNG]
            RandomN.Seed = rnd(1) * 199017
return


[drawStatusBar]
    wstatbar = 798
    hstatbar = 30
    gap = 3          'border width for status bar

    x = gap-1           'draw outside raisedd3D box
    y = gap-1
    boxWidth = wstatbar-(2*(gap-1))-12
    boxHeight = hstatbar-(2*(gap-1))-2
    outsideBoxWidth=boxWidth
    outsideBoxHeight=boxHeight
    gosub [raisedStatBarBox]

    x = 2*gap          'draw first recessed3D status bar box for text status
    y = 2*gap
    boxWidth = 200
    boxHeight = outsideBoxHeight-(2*gap)
    statusBoxHeight = boxHeight
    gosub [recessedStatBarBox]

    x = 3*gap + 200     'draw box for crumbs
    y = 2*gap
    boxWidth = 150
    boxHeight= statusBoxHeight
    gosub [recessedStatBarBox]

    text$ = "Turn Crumbs On/Off"
    print #main.statusBar, "color black; backcolor lightgray"
    print #main.statusBar, "place 220 20"      'print new text
    print #main.statusBar, "\ "; text$ 

    x = 4*gap + 350    'draw on/off pushbutton
    y = 2*gap
    boxWidth = 67
    boxHeight = statusBoxHeight
    gosub [raisedStatBarBox]
    print #main.statusBar, "color yellow; backcolor green"
    print #main.statusBar, "place 363 20"      'print button title
    print #main.statusBar, "\       Off!        "
    buttonFlag = 0

    x = 6*gap + 414    'draw recessed3D status box for progress bar example
    y = 2*gap
    boxWidth = 150
    boxHeight = statusBoxHeight
    gosub [recessedStatBarBox]

    print #main.statusBar, "flush"
return


[raisedStatBarBox]
     ' x is the x position to start drawing box
    ' y is the y position to start drawing box
    ' boxWidth is the desired box width
    ' boxHeight is the desired box height
    print #main.statusBar, "color white ; down"
    print #main.statusBar, "place "; x; " "; y
    print #main.statusBar, "line "; x; " "; y; " "; x; " "; y+boxHeight
    print #main.statusBar, "place "; x; " "; y
    print #main.statusBar, "line "; x; " "; y; " "; x + boxWidth; " "; y
    print #main.statusBar, "color darkgray"
    print #main.statusBar, "place "; x; " "; y+boxHeight
    print #main.statusBar, "line "; x; " "; y+boxHeight; " "; x+boxWidth; " "; y+boxHeight
    print #main.statusBar, "place "; x+boxWidth; " "; y
    print #main.statusBar, "line "; x+boxWidth; " "; y; " "; x+boxWidth; " "; y+boxHeight
    print #main.statusBar, "flush"

return

[recessedStatBarBox]
    ' x is the x position to start drawing box
    ' y is the y position to start drawing box
    ' boxWidth is the desired box width
    ' boxHeight is the desired box height
    print #main.statusBar, "color darkgray ; down"
    print #main.statusBar, "place "; x; " "; y
    print #main.statusBar, "line "; x; " "; y; " "; x; " "; y+boxHeight
    print #main.statusBar, "place "; x; " "; y
    print #main.statusBar, "line "; x; " "; y; " "; x + boxWidth; " "; y
    print #main.statusBar, "color white"
    print #main.statusBar, "place "; x; " "; y+boxHeight
    print #main.statusBar, "line "; x; " "; y+boxHeight; " "; x+boxWidth; " "; y+boxHeight
    print #main.statusBar, "place "; x+boxWidth; " "; y
    print #main.statusBar, "line "; x+boxWidth; " "; y; " "; x+boxWidth; " "; y+boxHeight
    print #main.statusBar, "flush"

return


[progressBar]
    if incr = int(leap) then
        percent = (totalCells-cellCount)/totalCells*100
        percent$ = str$(int(percent+1))
        proBarCount = int(percent * 147 / 100)
        x1 = 434
        print #main.statusBar, "color green; backcolor green"
        print #main.statusBar, "up; goto 434 8"
        print #main.statusBar, "down; boxfilled "; x1 + proBarCount; " "; 23
        print #main.statusBar, "up"

        print #main.statusBar, "color lightgray; backcolor lightgray"
        print #main.statusBar, "up; goto "; x1 + proBarCount; " "; 8
        print #main.statusBar, "down; boxfilled "; 581; " "; 23
        print #main.statusBar, "up"

        calldll #gdi, "SetBkMode",_
            hDC AS short,_
            1 AS short,_
            RESULT AS short

        print #main.statusBar, "backcolor white; color red"  'transparent text
        print #main.statusBar, "place 495 20"
        print #main.statusBar, "\ "; percent$ + "%"

        leap = leap + onePercent
    end if
    incr = incr + 1
return

[clearPBar]
      'redraw box and start over
        print #main.statusBar, "color lightgray; backcolor lightgray"
        print #main.statusBar, "up; goto 434 8"
        print #main.statusBar, "down; boxfilled 581 23; up"
return


[setStatusText]
    'set text in first recessed3D status box
'    text$ = "XXXXXXXXXXXXXXXXXXXXXXXX"       'test for max chars
    if len(text$) > 24 then text$ = left$(text$,24)

        calldll #gdi, "SetBkMode",_
            hDC AS short,_
            2 AS short,_
            RESULT AS short

    print #main.statusBar, "color black; backcolor lightgray"
    print #main.statusBar, "place 7 20"       'erase previous text
    print #main.statusBar, "\ "; space$(60)
    print #main.statusBar, "place 7 20"      'print new text
    print #main.statusBar, "\ "; text$
    print #main.statusBar, "flush"

return

'According to Lou's Maze algorithm, solve the maze using the "right-hand rule":
'Start at the entrance, keeping your right hand on the wall at all times,
'and following your nose.  This will get you to the exit.
'To implement the right-hand rule, try the following:
'First, always keep track of what direction you're walking.
'Now to simulate the right hand on the wall: check the grid
'location in the direction just clockwise to the direction you're walking.
'In other words, if you're walking to the right, check the downward
'direction.  Is there a wall there?  If not, go in that direction.  But if
'there is a wall there, keep checking directions going counter-clockwise
'until you find a direction that doesn't have a wall. For example, if you
'couldn't go down, check right, then up, then left until you find a
'non-wall. As soon as you find a non-wall, go in that direction.
'------------------------------------------------------------------------

'In order to keep track of the solution, you will need to associate another
'boolean variable with each maze location, indicating whether or not
'you've passed that spot already while trying to solve the maze.  (Think
'of leaving a trail of bread crumbs and you have the right idea.)  Set
'all your "bread crumbs" to false.  Now start at the beginning of the
'maze, and walk the maze via the right-hand rule.  Whenever you move to
'a new location, check to see if there's a bread crumb there already.  If
'there is not, put one there, *and also in the location you were just at*.
'If there is already a bread crumb there, remove it, *and also remove the
'bread crumb from the location you were just at*.  When you finally reach
'the exit, the only bread crumbs remaining, will comprise the solution.
'(All that bit about "the location you were just at", keeps bread crumbs
'from appearing improperly at corners and dead ends.)

[solveIt]

    redim solvearray(ncellsx, ncellsy)   'if solvearray() = 1 then cell has been visited
    if cellarray(0,0) = 0 then return
    cursor hourglass

'   assignments for cell walls for cellarray() as follows:
'   North = 1, East = 2, South = 4, West = 8
'   N+E wall = 3, N+S wall = 5, N+W walls = 9, E+S = 6, E+W = 10, S+W = 12
'   N+E+S = 7, N+E+W=11, N+S+W = 13, E+S+W = 14

    currentCellx = 0
    currentCelly = enter
    nextCellx = 0
    direction = 2
    solvearray(currentCellx,currentCelly) = 1
    dummy = 0

    while dummy <> 1
        if nextCellx = ncellsx-1 and nextCelly = exit then
            dummy = 1
            goto [bottom]
        end if

        'check down, then right, then up, then left to see if there is a wall

        if direction = 2 then gosub [checkDir2] : goto [skipover]
        if direction = 4 then gosub [checkDir4] : goto [skipover]
        if direction = 1 then gosub [checkDir1] : goto [skipover]
        if direction = 8 then gosub [checkDir8]

[skipover]
        if solvearray(nextCellx,nextCelly) = 0 then
            solvearray(nextCellx,nextCelly) =1
            solvearray(currentCellx,currentCelly) = 1
        else
            solvearray(nextCellx,nextCelly) =0
            solvearray(currentCellx,currentCelly) = 0
        end if

'        print #main.back, "backcolor yellow"
'        print #main.back, "place "; currentCellx*cellwidth+startx; " "; currentCelly*cellheight+starty
'        print #main.back, "boxfilled "; currentCellx*cellwidth+startx+cellwidth; " "; currentCelly*cellheight+starty+cellheight

        gosub [swap]
[bottom]
    wend

    cursor normal
return


[checkDir2]   'direction east

   'check for south wall
    gosub [swall]

    if sw = 0 then
       nextCellx = currentCellx
       nextCelly = currentCelly+1
       direction = 4
       return
    end if

   'check for east wall
    gosub [ewall]

    if ew = 0 then
       nextCellx = currentCellx+1
       nextCelly = currentCelly
       direction = 2
       return
    end if

   'check for north wall
    gosub [nwall]

    if nw = 0 then
       nextCellx = currentCellx
       nextCelly = currentCelly-1
       direction = 1
       return
    end if

   'check for west wall
    gosub [wwall]

    if ww = 0 then
       nextCellx = currentCellx-1
       nextCelly = currentCelly
       direction = 8
       return
    end if

return

[checkDir4]   'south

   'check for west wall
    gosub [wwall]
    if ww = 0 then
            nextCellx = currentCellx-1
            nextCelly = currentCelly
            direction = 8
            return
    end if

   'check for south wall
    gosub [swall]

    if sw = 0 then
            nextCellx = currentCellx
            nextCelly = currentCelly+1
            direction = 4
            return
    end if

   'check for east wall
    gosub [ewall]
    if ew = 0 then
            nextCellx = currentCellx+1
            nextCelly = currentCelly
            direction = 2
            return
    end if

   'check for north wall
    gosub [nwall]
    if nw = 0 then
            nextCellx = currentCellx
            nextCelly = currentCelly-1
            direction = 1
            return
    end if

return


[checkDir8]   'west

   'check for north wall
    gosub [nwall]
    if nw = 0 then
            nextCellx = currentCellx
            nextCelly = currentCelly-1
            direction = 1
            return
    end if

   'check for west wall
    gosub [wwall]
    if ww = 0 then
            nextCellx = currentCellx-1
            nextCelly = currentCelly
            direction = 8
            return
    end if

   'check for south wall
    gosub [swall]
    if sw = 0 then
            nextCellx = currentCellx
            nextCelly = currentCelly+1
            direction = 4
            return
    end if

   'check for east wall
    gosub [ewall]
    if ew = 0 then
            nextCellx = currentCellx+1
            nextCelly = currentCelly
            direction = 2
            return
    end if

return


[checkDir1]   'north

   'check for east wall
    gosub [ewall]
    if ew = 0 then
            nextCellx = currentCellx+1
            nextCelly = currentCelly
            direction = 2
            return
    end if

   'check for north wall
    gosub [nwall]
    if nw = 0 then
            nextCellx = currentCellx
            nextCelly = currentCelly-1
            direction = 1
            return
    end if

   'check for west wall
    gosub [wwall]
    if ww = 0 then
            nextCellx = currentCellx-1
            nextCelly = currentCelly
            direction = 8
            return
    end if

   'check for south wall
    gosub [swall]
    if sw = 0 then
            nextCellx = currentCellx
            nextCelly = currentCelly+1
            direction = 4
            return
    end if

return

[swall]
    if cellarray(currentCellx,currentCelly) = 4 or _
       cellarray(currentCellx,currentCelly) = 5 or _
       cellarray(currentCellx,currentCelly) = 6 or _
       cellarray(currentCellx,currentCelly) = 12 or _
       cellarray(currentCellx,currentCelly) = 7 or _
       cellarray(currentCellx,currentCelly) = 13 or _
       cellarray(currentCellx,currentCelly) = 14 then sw = 1 else sw = 0
return

[ewall]
    if cellarray(currentCellx,currentCelly) = 2 or _
       cellarray(currentCellx,currentCelly) = 3 or _
       cellarray(currentCellx,currentCelly) = 6 or _
       cellarray(currentCellx,currentCelly) = 10 or _
       cellarray(currentCellx,currentCelly) = 7 or _
       cellarray(currentCellx,currentCelly) = 11 or _
       cellarray(currentCellx,currentCelly) = 14 then ew = 1 else ew = 0
return

[nwall]
    if cellarray(currentCellx,currentCelly) = 1 or _
       cellarray(currentCellx,currentCelly) = 3 or _
       cellarray(currentCellx,currentCelly) = 5 or _
       cellarray(currentCellx,currentCelly) = 9 or _
       cellarray(currentCellx,currentCelly) = 7 or _
       cellarray(currentCellx,currentCelly) = 11 or _
       cellarray(currentCellx,currentCelly) = 13 then nw = 1 else nw = 0
return

[wwall]
    if cellarray(currentCellx,currentCelly) = 8 or _
       cellarray(currentCellx,currentCelly) = 9 or _
       cellarray(currentCellx,currentCelly) = 10 or _
       cellarray(currentCellx,currentCelly) = 12 or _
       cellarray(currentCellx,currentCelly) = 11 or _
       cellarray(currentCellx,currentCelly) = 13 or _
       cellarray(currentCellx,currentCelly) = 14 then ww = 1 else ww = 0
return

[drawSolution]
    print #main.back, "color pink; backcolor pink"
    for i = 0 to ncellsx-1
        for j = 0 to ncellsy-1

            if solvearray(i,j) = 1 then
                print #main.back, "place "; i*cellwidth+startx+4; " "; j*cellheight+starty+4
                print #main.back, "boxfilled "; i*cellwidth+startx+cellwidth-3; " "; j*cellheight+starty+cellheight-3
            end if
        next j
    next i

return





[currentRedBox]
        x0 = (currentCellx)*cellwidth+startx+1
        y0 = (currentCelly)*cellheight+starty+1

        print #main.back, "rule XOR"
        print #main.back, "place "; x0; " "; y0
        print #main.back, "color cyan";
        print #main.back, "box "; x0+cellwidth-1; " "; y0+cellheight-1
        print #main.back, "line "; x0+1; " "; y0+1; " "; x0+cellwidth-2; " "; y0+cellheight-2
        print #main.back, "line "; x0+1; " "; y0+cellheight-2; " "; x0+cellwidth-2; " "; y0+1
        print #main.back, "rule OVER"

return

[nextRedBox]
        x0 = (nextCellx)*cellwidth+startx+1
        y0 = (nextCelly)*cellheight+starty+1
        print #main.back, "rule XOR"
        print #main.back, "place "; x0; " "; y0
        print #main.back, "color cyan";
        print #main.back, "box "; x0+cellwidth-1; " "; y0+cellheight-1
        print #main.back, "line "; x0+1; " "; y0+1; " "; x0+cellwidth-2; " "; y0+cellheight-2
        print #main.back, "line "; x0+1; " "; y0+cellheight-2; " "; x0+cellwidth-2; " "; y0+1
        print #main.back, "rule OVER"

return

[nextBox]  'only allow a move into a valid cell
    moves$ = ""
    gosub [nwall]
    if nw = 0 then moves$ = moves$ + " " + str$(currentCellx) + "," + str$(currentCelly-1)
    gosub [ewall]
    if ew = 0 then
        if currentCellx+1 <= ncellsx-1 then moves$ = moves$ + " " + str$(currentCellx+1) + "," + str$(currentCelly)
    end if
    gosub [wwall]
    if ww = 0 then
        if currentCellx-1 >= 0 then moves$ = moves$ + " " + str$(currentCellx-1) + "," + str$(currentCelly)
    end if
    gosub [swall]
    if sw = 0 then moves$ = moves$ + " " + str$(currentCellx) + "," + str$(currentCelly+1)

    nextmove$ = str$(nextCellx) + "," + str$(nextCelly)
    if instr(moves$,nextmove$) = 0 then
        nextCellx = currentCellx
        nextCelly = currentCelly
    end if
return


[drawCrumbs]
    x0 = currentCellx*cellwidth+startx+1+int((cellwidth/2))
    y0 = currentCelly*cellheight+starty+1+int((cellheight/2))
    print #main.back, "place "; x0; " "; y0
    print #main.back, "color yellow; backcolor yellow"
    print #main.back, "circlefilled "; radius
return


[dialogBox]

    wtype = 4160

    calldll #user, "Messagebox", _
        h as word, _
        message$ as ptr, _
        title$ as ptr, _
        wtype as word, _
        RESULT as short

    input a$ 

return
