_TITLE "PathFinder 2, prepping maze as you read this."  
'started 2018-08-11 when Colbalt asked about A* pathfinder
' He has now 2018-08-12 posted a QB64 version that is nice!
 
' 2018-08-11 started PathFinder 1
' 2018-08-12 almost working but buggy backtract to point A after point B is found.
' 2018-08-13 PathFinder 1a.bas I think I have a fix for buggy path BackTrack but major surgery so this new version
' 2018-08-14 Pathfinder 2:  2 parts
' Part 1: creates a map, a random Home point and backtracts all the points available to move over.
' Part 2: allows clicking variaous points of map to see if path is found.
 
' 2019-12-19 add Maze Generator code that converts 2 arrays for walls and ceilings to a map for PathFinder 2
 
 
'generator
 
 
 
DIM y
, x
, parentF
, tick
, parentx
, changes$
, ystart
, ystop
, xStart
, xStop
, xxStart
, xxStop
, yyStart
, yyStop
, cf
, xx
, yy
 DIM new$
, newxy$
, newParent$
, u
, v
, mx
, my
, ps$
, parenty
  
    'this part sets up a sample map and get's the Backtracking build into map
 
    FOR y 
= 1 TO maph 
'clear and initialize map             map(x, y) = " "
    'maze generator
    init_walls
    generate_maze
    fillMap 'convert walls to map and outline borders
 
    ax = 2 * W: ay = 2 * H ' here is the target, a for anchor that all paths must go
    map(ax, ay) = "A"
    parentF = 1: tick = 0: parentx = 0
        parentF = 0: tick = tick + 1: changes$ = ""
        ystart = max(ay - tick, 1): ystop = min(ay + tick, maph)
            xStart = max(ax - tick, 1): xStop = min(ax + tick, mapw)
                'check out the neighbors
                IF x 
- 1 >= 1 THEN xxStart 
= x 
- 1 ELSE xxStart 
= x
                 IF x 
+ 1 <= mapw 
THEN xxStop 
= x 
+ 1 ELSE xxStop 
= x
                 IF y 
- 1 >= 1 THEN yyStart 
= y 
- 1 ELSE yyStart 
= y
                 IF y 
+ 1 <= maph 
THEN yyStop 
= y 
+ 1 ELSE yyStop 
= y
                     cf = 0
                    FOR yy 
= yyStart 
TO yyStop
                         FOR xx 
= xxStart 
TO xxStop
                                     parentF = 1 'so will continue looping
        'update map with cells assigned parents
            new$ = leftOf$(changes$, "}")
            changes$ = rightOf$(changes$, "}")
            newxy$ = leftOf$(new$, "{")
            newParent$ = rightOf$(new$, "{")
            u 
= VAL(leftOf$
(newxy$
, ",")): v 
= VAL(rightOf$
(newxy$
, ","))            map(u, v) = leftOf$(newParent$, ",") + "," + rightOf$(newParent$, ",")
 
 
    'this parts displays the ability to find a path to blue square anywhere in the maze
 
    _TITLE "Click maze to find a path to blue square (if any), c = clear, n = new map, esc = quit"     displayM
            bx = mx / sq + 1: by = my / sq + 1
                LINE ((bx 
- 1) * sq 
+ 2, (by 
- 1) * sq 
+ 2)-STEP(sq 
- 4, sq 
- 4), &HFFFFFF000, BF
                 ps$ = map(bx, by)
                parentx 
= VAL(leftOf$
(ps$
, ","))                parenty 
= VAL(rightOf$
(ps$
, ","))                IF parentx 
THEN 'backtrack to A   note: B could be right next to A!!!                     LINE ((parentx 
- 1) * sq 
+ 3, (parenty 
- 1) * sq 
+ 3)-STEP(sq 
- 6, sq 
- 6), &HFFFFFFFF, BF
                     WHILE parentx 
'trace the path back                         ps$ = map(parentx, parenty)
                        parentx 
= VAL(leftOf$
(ps$
, ","))                        parenty 
= VAL(rightOf$
(ps$
, ","))                        LINE ((parentx 
- 1) * sq 
+ 3, (parenty 
- 1) * sq 
+ 3)-STEP(sq 
- 6, sq 
- 6), &HFFFFFFFF, BF
                     displayM
 
                CASE "A": k 
= &HFF0000FF 'target                 CASE "B": k 
= &HFFFFBB00 'border                 CASE "O": k 
= &HFF008800 'maze wall             LINE ((x 
- 1) * sq
, (y 
- 1) * sq
)-STEP(sq
, sq
), k
, BF
  
    rand% 
= INT(RND * (hi% 
- lo% 
+ 1)) + lo%
 
 
 
    posOf 
= INSTR(source$
, of$
)    IF posOf 
> 0 THEN leftOf$ 
= MID$(source$
, 1, posOf 
- 1)  
    posOf 
= INSTR(source$
, of$
) 
            v_walls(x, y) = 1
            h_walls(x, y) = 1
 
'this takes the generted maze and loads the Map string array
                map(2 * x + 1, 2 * y + 1) = "O": map(2 * x + 2, 2 * y + 1) = "O": map(2 * x + 3, 2 * y + 1) = "O"
                map(2 * x + 1, 2 * y + 1) = "O": map(2 * x + 1, 2 * y + 2) = "O": map(2 * x + 1, 2 * y + 3) = "O"
        map(2 * x + 1, 1) = "B": map(2 * x + 2, 1) = "B": map(2 * x + 3, 1) = "B"
        map(2 * x + 1, 2 * H + 1) = "B": map(2 * x + 2, 2 * H + 1) = "B": map(2 * x + 3, 2 * H + 1) = "B"
        map(1, 2 * y + 1) = "B": map(1, 2 * y + 2) = "B": map(1, 2 * y + 3) = "B"
        map(2 * W + 1, 2 * y + 1) = "B": map(2 * W + 1, 2 * y + 2) = "B": map(2 * W + 1, 2 * y + 3) = "B"
 
'   Maze Generator Code
'
' 2019-09-02 isolated and updated generator code for OPTION _EXPLICIT
' from trans 2018-06-15 for Amazing Rat.bas (QB64)
' From SmallBASIC code written by Chris WS developer
' Backtracking maze generator by chrisws 2016-06-30 now found at
' https://github.com/smallbasic/smallbasic.github.io/blob/5601c8bc1d794c5b143d863555bb7c15a5966a3c/samples/node/1623.bas
'
' Chris notes:
' https://en.wikipedia.org/wiki/Maze_generation_algorithm
' - Starting from a random cell,
' - Selects a random neighbouring cell that has not been visited.
' - Remove the wall between the two cells and marks the new cell as visited,
'   and adds it to the stack to facilitate backtracking.
' - Continues with a cell that has no unvisited neighbours being considered a dead-end.
'   When at a dead-end it backtracks through the path until it reaches a cell with an
'   unvisited neighbour, continuing the path generation by visiting this new,
'   unvisited cell (creating a new junction).
'   This process continues until every cell has been visited, backtracking all the
'   way back to the beginning cell. We can be sure every cell is visited.
'
 
'B+ notes for using:
' The most important item is that the maze uses 2 arrays one for vertical walls the other for horizontal
' CONST xmax, ymax is pixel size used in maze coder, using SW, SH for screen dimensions
' Maze should mount in top left corner of screen with min border space around it at left and top at least.
' CONST W, H - number of cells Wide and High you can specify.
' CONST wallThk - adjusts thickness of walls
' CONST mazeClr - colors walls made with BF in LINE statement
' CONST border - will create a space around the maze
' SHARED cellW, cellH - are pixels sizes for cell, see calcs before SCREEN command
' SHARED  h_walls(W, H) AS INTEGER, v_walls(W, H) AS INTEGER - these are your Maze, 0 no wall, 1 = wall
' When player occupies cell x, y that cell may v_wall that blocks player going left;
' a cell v_wall(x+1, y) = 1 will block a player going right;
' cell (x, y) may have an h_wall that stops player from going up;
' cell (x, y+1) may have h_wall that stops player at x, y from going down.
' Cells at (W, y) should not be occupied with W cells wide and array base 0 only W-1 can be occupied
' unless game needs something special.
' Likewise cells at (x, H) should only provide wall to stop player from going out of box.
 
 
 
    x = current.x
    y = current.y
    uvi = 0
            uvi = uvi + 1
            unvisited(uvi).x = x - 1
            unvisited(uvi).y = y
            uvi = uvi + 1
            unvisited(uvi).x = x + 1
            unvisited(uvi).y = y
            uvi = uvi + 1
            unvisited(uvi).x = x
            unvisited(uvi).y = y - 1
            uvi = uvi + 1
            unvisited(uvi).x = x
            unvisited(uvi).y = y + 1
 
    DIM curr_cell 
AS cell
, next_cell 
AS cell
, cur_cell 
AS cell
  
    rand_cell cur_cell.x, cur_cell.y
    visited(curr_cell.x, curr_cell.y) = 1
    num_visited = 1
    num_cells = W * H
    si = 0
    WHILE num_visited 
< num_cells
         cnt = 0
        get_unvisited visited(), curr_cell, cells(), cnt
 
            ' choose randomly one of the current cell's unvisited neighbours
            next_cell.x = cells(rc).x
            next_cell.y = cells(rc).y
 
            ' push the current cell to the stack
            si = si + 1
            stack(si).x = curr_cell.x
            stack(si).y = curr_cell.y
 
            ' remove the wall between the current cell and the chosen cell
            IF next_cell.x 
= curr_cell.x 
THEN                 x = next_cell.x
                y = max(next_cell.y, curr_cell.y)
                h_walls(x, y) = 0
                x = max(next_cell.x, curr_cell.x)
                y = next_cell.y
                v_walls(x, y) = 0
 
            ' make the chosen cell the current cell and mark it as visited
            curr_cell.x = next_cell.x
            curr_cell.y = next_cell.y
            visited(curr_cell.x, curr_cell.y) = 1
            num_visited = num_visited + 1
 
 
            ' pop a cell from the stack and make it the current cell
            curr_cell.x = stack(si).x
            curr_cell.y = stack(si).y
            si = si - 1