TGC Codebase Backup



A* Pathfinding by Phaelax

23rd Jun 2013 21:40
Summary

IanM's path finding code ported over to AGK.



Description

Read the thread for full details:
http://forum.thegamecreators.com/?m=forum_view&t=206280&b=41

Attached is main.agc which is a demo showing how to use this library.



Code
                                    ` This code was downloaded from The Game Creators
                                    ` It is reproduced here with full permission
                                    ` http://www.thegamecreators.com
                                    
                                    /* *************************************************
 * Original Author: IanM (DBP)
 * Ported to AGK: Phaelax
 * Date: June 22, 2013
 *
 *
 *                     COMMANDS
 *      ----------------------------------------
 *
 * CreateSearchMap(width, height)
 * CreateSearchPathList(NumberOfPaths)
 * SetSearchMap(x, y, value) (values greater than 0 are not walkable)
 * GetSearchMap(x, y)
 * GetSearchPathX(path, move)
 * GetSearchPathY(path, move)
 * GetSearchPathSize(path)
 * SetSearchRestrictDiagonals(mode) (1 will avoid diagonals between blocked cells)
 * SetMaximumCost(cost)
 *
 * SearchMapAStar4(path, startX, startY, finishX, finishY)
 * SearchMapAStar8(path, startX, startY, finishX, finishY)
 * SearchMapFlood4(path, startX, startY, finishX, finishY)
 * SearchMapFlood8(path, startX, startY, finishX, finishY)
 *
 * GetFloodCost(finishX, finishY) (Uses previous Flood4 search to identify cost of specified target)
 * *************************************************
*/



// ===================================================
// Must call this sub-routine first
// ===================================================
SEARCH_Declare_UDT:
    type SEARCH_Position_t
        x as integer
        y as integer
    endtype

    type SEARCH_TileInformation_t
        status  as integer
        G       as integer
        H       as integer
        F       as integer
        parentX as integer
        parentY as integer
        O       as integer
    endtype

    type SEARCH_OpenListItem_t
        F as integer
        x as integer
        y as integer
    endtype
RETURN




// ===================================================
// Initialize search variables
// ===================================================
function initPathfinder()

    global SEARCH_MapWidth          as integer
    global SEARCH_MapHeight         as integer
    global SEARCH_MaxPaths          as integer
    global SEARCH_CurrentPosition   as SEARCH_Position_t


    // Used for HEAP format used in A*
    global SEARCH_OpenListSize   as integer
    // Used for flood4 search
    global SEARCH_OpenListTop    as integer
    global SEARCH_OpenListBottom as integer

    // Optimization for flood4 search
    global SEARCH_PreviousStart as SEARCH_Position_t

    // General search parameters
    global SEARCH_RestrictedDiagonals as integer
    global SEARCH_MaximumCost         as integer
    global SEARCH_ParametersChanged   as integer
    global SEARCH_LastSearch          as integer

    // Initialize flags
    global SEARCH_PathsInitialized  as integer
    global SEARCH_MapInitialized    as integer


    dim SEARCH_Map[SEARCH_MapWidth, SEARCH_MapHeight] as integer
    dim SEARCH_TileInfo[SEARCH_MapWidth, SEARCH_MapHeight]  as SEARCH_TileInformation_t
    dim SEARCH_OpenList[SEARCH_MapWidth * SEARCH_MapHeight] as SEARCH_OpenListItem_t
    dim SEARCH_SearchPath[SEARCH_MaxPaths, SEARCH_MapWidth * SEARCH_MapHeight] as SEARCH_Position_t
    dim SEARCH_PathSize[SEARCH_MaxPaths] as integer

endfunction




// ===================================================
//
// ===================================================
function CreateSearchMap(X as integer, Y as integer)
    SEARCH_MapWidth = X
    SEARCH_MapHeight = Y

    SEARCH_PreviousStart.X = -9999
    SEARCH_PreviousStart.Y = -9999

    undim SEARCH_Map[]
    undim SEARCH_TileInfo[]
    undim SEARCH_OpenList[]

    global dim SEARCH_Map[X, Y] as integer
    global dim SEARCH_TileInfo[X, Y] as SEARCH_TileInformation_t
    global dim SEARCH_OpenList[X * Y] as SEARCH_OpenListItem_t

    SEARCH_MapInitialized = 1
endfunction



// ===================================================
//
// ===================================================
function CreateSearchPathLists(Paths as integer)
    SEARCH_MaxPaths = Paths

    undim SEARCH_SearchPath[]
    undim SEARCH_PathSize[]

    global dim SEARCH_SearchPath[SEARCH_MaxPaths, SEARCH_MapWidth * SEARCH_MapHeight] as SEARCH_Position_t
    global dim SEARCH_PathSize[SEARCH_MaxPaths] as integer

    SEARCH_PathsInitialized = 1
endfunction



// ===================================================
//
// ===================================================
function SetSearchMap(X as integer, Y as integer, Value as integer)
    if SEARCH_MapInitialized = 0 then exitfunction
    if X < 0 or X >= SEARCH_MapWidth then exitfunction
    if Y < 0 or Y >= SEARCH_MapHeight then exitfunction
    SEARCH_PreviousStart.X = -9999
    SEARCH_Map[X,Y] = Value
endfunction



// ===================================================
//
// ===================================================
function GetSearchMap(X as integer, Y as integer)
    if SEARCH_MapInitialized = 0 then exitfunction
    if X < 0 or X >= SEARCH_MapWidth then exitfunction 0
    if Y < 0 or Y >= SEARCH_MapHeight then exitfunction 0
    v = SEARCH_Map[X,Y]
    exitfunction v
endfunction 0



// ===================================================
//
// ===================================================
function GetSearchPathX(Path as integer, Move as integer)
    if SEARCH_PathsInitialized = 0 then exitfunction -1
    if Path < 0 or Path > SEARCH_MaxPaths then exitfunction -1
    if Move < 0 or Move > SEARCH_PathSize[Path] then exitfunction -1
    x = SEARCH_SearchPath[Path, SEARCH_PathSize[Path]-Move].X
    exitfunction x
endfunction -1



// ===================================================
//
// ===================================================
function GetSearchPathY(Path as integer, Move as integer)
    if SEARCH_PathsInitialized = 0 then exitfunction -1
    if Path < 0 or Path > SEARCH_MaxPaths then exitfunction -1
    if Move < 0 or Move > SEARCH_PathSize[Path] then exitfunction -1
    y = SEARCH_SearchPath[Path, SEARCH_PathSize[Path]-Move].Y
    exitfunction y
endfunction -1



// ===================================================
//
// ===================================================
function GetSearchPathSize(Path as integer)
    if SEARCH_PathsInitialized = 0 then exitfunction -1
    p = SEARCH_PathSize[Path]
    if Path >= 0 or Path <= SEARCH_MaxPaths then exitfunction p
endfunction -1



// ===================================================
//
// ===================================================
function SetSearchRestrictDiagonals(Mode as integer)
    if SEARCH_RestrictedDiagonals <> Mode
        SEARCH_RestrictedDiagonals = Mode
        SEARCH_ParametersChanged = 1
    endif
endfunction



// ===================================================
//
// ===================================================
function SetSearchMaximumCost(Cost as integer)
    if SEARCH_MaximumCost <> Cost*10
        SEARCH_MaximumCost = Cost * 10
        SEARCH_ParametersChanged = 1
    endif
endfunction



// ===================================================
//
// ===================================================
function GetFloodCost(TX as integer, TY as integer)
    if SEARCH_MapInitialized = 0 then exitfunction -1
    if SEARCH_PathsInitialized = 0 then exitfunction -1
    F = SEARCH_TileInfo[TX,TY].F
    if SEARCH_PreviousStart.X <> -9999 then exitfunction F
endfunction -1



// ===================================================
//
// ===================================================
function SEARCH_SingleStepCost(X as integer, Y as integer)
    if X = 0 or Y = 0 then exitfunction 10
endfunction 14



// ===================================================
//
// ===================================================
function SEARCH_EstimateDistance(X as integer, Y as integer, TX as integer, TY as integer)
    Distance as integer
    Distance = (abs(X - TX) + abs(Y - TY))*10
endfunction Distance



// ===================================================
//
// ===================================================
function SEARCH_InitializeTileInfo(SX as integer, SY as integer)
    SEARCH_OpenListSize=0

    SEARCH_PopulateTileInfo()

    SEARCH_TileInfo[SX, SY].G = 0
    SEARCH_TileInfo[SX, SY].H = SEARCH_EstimateDistance(SX, SY, TX, TY)
    SEARCH_TileInfo[SX, SY].F = SEARCH_TileInfo[SX, SY].H
    SEARCH_TileInfo[SX, SY].Status = 1
    SEARCH_TileInfo[SX, SY].ParentX = SX
    SEARCH_TileInfo[SX, SY].ParentY = SY

    SEARCH_AddToOpenList(SX, SY)
endfunction



// ===================================================
//
// ===================================================
function SEARCH_PopulateTileInfo()
    for X = 0 to SEARCH_MapWidth
        for Y = 0 to SEARCH_MapHeight
            SEARCH_TileInfo[X,Y].F = 0
            if SEARCH_Map[X,Y] > 0
                SEARCH_TileInfo[X,Y].Status = 2
            else
                SEARCH_TileInfo[X,Y].Status = 0
            endif
        next Y
    next X
endfunction



// ===================================================
//
// ===================================================
function SEARCH_AddToOpenList(X as integer, Y as integer)
    Parent as integer
    Child as integer
    Cost as integer

    Child = SEARCH_OpenListSize
    inc SEARCH_OpenListSize

    Cost = SEARCH_TileInfo[X,Y].F

    do
        if Child <= 0 then exit

        Parent = (Child - 1)/2

        if SEARCH_OpenList[Parent].F < Cost then exit


        SEARCH_OpenList[Child].F = SEARCH_OpenList[Parent].F
        SEARCH_OpenList[Child].X = SEARCH_OpenList[Parent].X
        SEARCH_OpenList[Child].Y = SEARCH_OpenList[Parent].Y


        Child = Parent
    loop

    SEARCH_OpenList[Child].F = Cost
    SEARCH_OpenList[Child].X = X
    SEARCH_OpenList[Child].Y = Y
endfunction



// ===================================================
//
// ===================================================
function SEARCH_GetLowestCostOpen()
    Parent as integer
    Child as integer
    Cost as integer

    if SEARCH_OpenListSize <= 0 then exitfunction 0

    dec SEARCH_OpenListSize

    SEARCH_CurrentPosition.X = SEARCH_OpenList[0].X
    SEARCH_CurrentPosition.Y = SEARCH_OpenList[0].Y

    Cost = SEARCH_OpenList[SEARCH_OpenListSize].F


    X = SEARCH_OpenList[SEARCH_OpenListSize].X
    Y = SEARCH_OpenList[SEARCH_OpenListSize].Y


    Parent = 0
    do
        Child = (2 * Parent) + 1
        if Child >= SEARCH_OpenListSize then exit

        if Child+1 < SEARCH_OpenListSize
            if SEARCH_OpenList[Child].F > SEARCH_OpenList[Child + 1].F then inc Child
        endif

        if SEARCH_OpenList[Child].F < Cost

            SEARCH_OpenList[Parent].F = SEARCH_OpenList[Child].F
            SEARCH_OpenList[Parent].X = SEARCH_OpenList[Child].X
            SEARCH_OpenList[Parent].Y = SEARCH_OpenList[Child].Y

            Parent = Child
        else
            exit
        endif
    loop


    SEARCH_OpenList[Parent].F = Cost
    SEARCH_OpenList[Parent].X = X
    SEARCH_OpenList[Parent].Y = Y


    if SEARCH_TileInfo[SEARCH_CurrentPosition.X,SEARCH_CurrentPosition.Y].Status = 2 then exitfunction SEARCH_GetLowestCostOpen()

    SEARCH_TileInfo[SEARCH_CurrentPosition.X,SEARCH_CurrentPosition.Y].Status = 2
endfunction 1



// ===================================================
//
// ===================================================
function SEARCH_QueueOntoOpen(X as integer, Y as integer)
    inc SEARCH_OpenListTop
    SEARCH_OpenList[SEARCH_OpenListTop].X = X
    SEARCH_OpenList[SEARCH_OpenListTop].Y = Y
endfunction



// ===================================================
//
// ===================================================
function SEARCH_UnqueueFromOpen()
    if SEARCH_OpenListBottom => SEARCH_OpenListTop then exitfunction 0

    inc SEARCH_OpenListBottom
    SEARCH_CurrentPosition.X = SEARCH_OpenList[SEARCH_OpenListBottom].X
    SEARCH_CurrentPosition.Y = SEARCH_OpenList[SEARCH_OpenListBottom].Y
endfunction 1



// ===================================================
//
// ===================================================
function SEARCH_BuildPath(Path as integer, SX as integer, SY as integer, TX as integer, TY as integer)
    Moves = 0
    X = TX
    Y = TY
    SEARCH_SearchPath[Path, Moves].X = X
    SEARCH_SearchPath[Path, Moves].Y = Y

    repeat
        inc Moves
        SEARCH_SearchPath[Path, Moves].X = SEARCH_TileInfo[X,Y].ParentX
        SEARCH_SearchPath[Path, Moves].Y = SEARCH_TileInfo[X,Y].ParentY
        X = SEARCH_SearchPath[Path, Moves].X
        Y = SEARCH_SearchPath[Path, Moves].Y
    until X = SX and Y = SY

    SEARCH_PathSize[Path] = Moves
endfunction Moves



// ===================================================
//
// ===================================================
function SEARCH_ClearPath(Path as integer, SX as integer, SY as integer)
    SEARCH_SearchPath[Path, 0].X = SX
    SEARCH_SearchPath[Path, 1].Y = SY
    SEARCH_PathSize[Path] = 0
endfunction 0












// ****************************************************************************
// ****************************************************************************
//
// ****************************************************************************
// ****************************************************************************
function SearchMapAStar8(Path as integer, SX as integer, SY as integer, TX as integer, TY as integer)
    X as integer
    Y as integer
    XOffset as integer
    YOffset as integer
    NewCost as integer

    if SEARCH_MapInitialized = 0 then exitfunction -1
    if SEARCH_PathsInitialized = 0 then exitfunction -1
    if Path < 0 or Path > SEARCH_MaxPaths then exitfunction -1

    SEARCH_LastSearch = 1
    SEARCH_InitializeTileInfo(SX,SY)

    while SEARCH_GetLowestCostOpen() > 0

        for XOffset = -1 to 1

            X = SEARCH_CurrentPosition.X + XOffset
            if X >= 0 and X < SEARCH_MapWidth

                for YOffset = -1 to 1

                    if (XOffset || YOffset) <> 0
                        Y = SEARCH_CurrentPosition.Y + YOffset

                        if (XOffset || YOffset) = 0
                            Y = -1
                        else
                            ` Restrict diagonals
                            if SEARCH_RestrictedDiagonals
                                if XOffset <> 0 and YOffset <> 0
                                    if SEARCH_TileInfo[X, SEARCH_CurrentPosition.Y].Status = 2
                                        ` This bit depends on Y *not* being set to -1
                                        if SEARCH_TileInfo[SEARCH_CurrentPosition.X, Y].Status = 2
                                            Y = -1
                                        endif
                                    endif
                                endif
                            endif
                        endif

                        if Y >= 0 and Y < SEARCH_MapHeight

                            if SEARCH_TileInfo[X,Y].Status = 0
                                SEARCH_TileInfo[X,Y].ParentX = SEARCH_CurrentPosition.X
                                SEARCH_TileInfo[X,Y].ParentY = SEARCH_CurrentPosition.Y
                                if X = TX and Y = TY then exitfunction SEARCH_BuildPath(Path,SX,SY,TX,TY)
                                SEARCH_TileInfo[X,Y].G = SEARCH_TileInfo[SEARCH_CurrentPosition.X,SEARCH_CurrentPosition.Y].G + SEARCH_SingleStepCost(XOffset,YOffset)
                                SEARCH_TileInfo[X,Y].H = SEARCH_EstimateDistance(X,Y,TX,TY)
                                SEARCH_TileInfo[X,Y].F = SEARCH_TileInfo[X,Y].G + SEARCH_TileInfo[X,Y].H
                                if SEARCH_MaximumCost = 0 or SEARCH_TileInfo[X,Y].G < SEARCH_MaximumCost
                                    SEARCH_AddToOpenList(X,Y)
                                    SEARCH_TileInfo[X,Y].Status = 1
                                endif
                            else
                                if SEARCH_TileInfo[X,Y].Status = 1
                                    NewCost = SEARCH_TileInfo[SEARCH_CurrentPosition.X,SEARCH_CurrentPosition.Y].G + SEARCH_SingleStepCost(XOffset,YOffset)
                                    if SEARCH_TileInfo[X,Y].G > NewCost
                                        SEARCH_TileInfo[X,Y].ParentX = SEARCH_CurrentPosition.X
                                        SEARCH_TileInfo[X,Y].ParentY = SEARCH_CurrentPosition.Y
                                        SEARCH_TileInfo[X,Y].G = NewCost
                                        SEARCH_TileInfo[X,Y].F = NewCost + SEARCH_TileInfo[X,Y].H
                                        SEARCH_AddToOpenList(X,Y)
                                    endif
                                endif
                            endif
                        endif
                    endif

                next YOffset
            endif

        next XOffset
    endwhile

    n = SEARCH_ClearPath(Path,SX,SY)
    exitfunction n
endfunction 0









// ****************************************************************************
// ****************************************************************************
//
// ****************************************************************************
// ****************************************************************************
function SearchMapAStar4(Path as integer, SX as integer, SY as integer, TX as integer, TY as integer)
    X as integer
    Y as integer
    XOffset as integer
    YOffset as integer
    NewCost as integer

    if SEARCH_MapInitialized = 0 then exitfunction -1
    if SEARCH_PathsInitialized = 0 then exitfunction -1
    if Path < 0 or Path > SEARCH_MaxPaths then exitfunction -1

    SEARCH_LastSearch = 0
    SEARCH_InitializeTileInfo(SX,SY)

    while SEARCH_GetLowestCostOpen() > 0

        for XOffset = -1 to 1

            X = SEARCH_CurrentPosition.X + XOffset
            if X >= 0 and X < SEARCH_MapWidth

                for YOffset = -1 to 1

                    if (XOffset && YOffset) = 0
                        Y = SEARCH_CurrentPosition.Y + YOffset

                        if Y >= 0 and Y < SEARCH_MapHeight

                            if SEARCH_TileInfo[X,Y].Status = 0
                                SEARCH_TileInfo[X,Y].ParentX = SEARCH_CurrentPosition.X
                                SEARCH_TileInfo[X,Y].ParentY = SEARCH_CurrentPosition.Y
                                if X = TX and Y = TY then exitfunction SEARCH_BuildPath(Path,SX,SY,TX,TY)
                                SEARCH_TileInfo[X,Y].G = SEARCH_TileInfo[SEARCH_CurrentPosition.X,SEARCH_CurrentPosition.Y].G  + 10
                                SEARCH_TileInfo[X,Y].H = SEARCH_EstimateDistance(X,Y,TX,TY)
                                SEARCH_TileInfo[X,Y].F = SEARCH_TileInfo[X,Y].G + SEARCH_TileInfo[X,Y].H
                                if SEARCH_MaximumCost = 0 or Cost < SEARCH_MaximumCost
                                    SEARCH_AddToOpenList(X,Y)
                                    SEARCH_TileInfo[X,Y].Status = 1
                                endif
                            else
                                if SEARCH_TileInfo[X,Y].Status = 1
                                    NewCost = SEARCH_TileInfo[SEARCH_CurrentPosition.X,SEARCH_CurrentPosition.Y].G + 10
                                    if SEARCH_TileInfo[X,Y].G > NewCost
                                        SEARCH_TileInfo[X,Y].ParentX = SEARCH_CurrentPosition.X
                                        SEARCH_TileInfo[X,Y].ParentY = SEARCH_CurrentPosition.Y
                                        SEARCH_TileInfo[X,Y].G = NewCost
                                        SEARCH_TileInfo[X,Y].F = NewCost + SEARCH_TileInfo[X,Y].H
                                        SEARCH_AddToOpenList(X,Y)
                                    endif
                                endif
                            endif
                        endif
                    endif
                next YOffset
            endif
        next XOffset
    endwhile

    n = SEARCH_ClearPath(Path,SX,SY)
    exitfunction n
endfunction 0










// ****************************************************************************
// ****************************************************************************
//
// ****************************************************************************
// ****************************************************************************
function SearchMapFlood8(Path as integer, SX as integer, SY as integer, TX as integer, TY as integer)
    XOffset as integer
    YOffset as integer
    X as integer
    Y as integer
    Cost as integer

    if SEARCH_MapInitialized = 0 then exitfunction -1
    if SEARCH_PathsInitialized = 0 then exitfunction -1
    if Path < 0 or Path > SEARCH_MaxPaths then exitfunction -1

    if SEARCH_ParametersChanged = 1 or SEARCH_LastSearch <> 3
        SEARCH_ParametersChanged = 0
        SEARCH_PreviousStart.X = -9999
        SEARCH_LastSearch = 3
    endif

    if SX <> SEARCH_PreviousStart.X or SY <> SEARCH_PreviousStart.Y
        SEARCH_PreviousStart.X = SX
        SEARCH_PreviousStart.Y = SY

        SEARCH_PopulateTileInfo()

        SEARCH_TileInfo[SX, SY].Status = 1
        SEARCH_TileInfo[SX, SY].ParentX = SX
        SEARCH_TileInfo[SX, SY].ParentY = SY
        SEARCH_TileInfo[SX, SY].F = 0
        SEARCH_AddToOpenList(SX,SY)

        SEARCH_SearchMode = 0

        while SEARCH_GetLowestCostOpen() > 0
            for XOffset = -1 to 1

                X = SEARCH_CurrentPosition.X + XOffset

                if X >= 0 and X < SEARCH_MapWidth

                    for YOffset = -1 to 1

                        Y = SEARCH_CurrentPosition.Y + YOffset

                        ` Not the current cell (offsets both zero)
                        if (XOffset || YOffset) = 0
                            Y = -1
                        else
                            ` Restrict diagonals
                            if SEARCH_RestrictedDiagonals
                                if XOffset <> 0 and YOffset <> 0
                                    if SEARCH_TileInfo[X, SEARCH_CurrentPosition.Y].Status = 2
                                        ` This bit depends on Y *not* being set to -1
                                        if SEARCH_TileInfo[SEARCH_CurrentPosition.X, Y].Status = 2
                                            Y = -1
                                        endif
                                    endif
                                endif
                            endif
                        endif

                        if Y >= 0 and Y < SEARCH_MapHeight
                            if SEARCH_TileInfo[X,Y].Status = 0
                                SEARCH_TileInfo[X, Y].Status = 1
                                SEARCH_TileInfo[X, Y].ParentX = SEARCH_CurrentPosition.X
                                SEARCH_TileInfo[X, Y].ParentY = SEARCH_CurrentPosition.Y
                                Cost = SEARCH_TileInfo[SEARCH_CurrentPosition.X, SEARCH_CurrentPosition.Y].F + SEARCH_SingleStepCost(XOffset,YOffset)
                                SEARCH_TileInfo[X, Y].F = Cost
                                if SEARCH_MaximumCost = 0 or Cost < SEARCH_MaximumCost
                                    SEARCH_AddToOpenList(X,Y)
                                endif
                            endif
                        endif
                    next YOffset
                endif
            next XOffset
        endwhile
    endif

    if SEARCH_TileInfo[TX,TY].Status > 0 then exitfunction SEARCH_BuildPath(Path,SX,SY,TX,TY)

    n = SEARCH_ClearPath(Path,SX,SY)
    exitfunction n
endfunction 0






// ****************************************************************************
// ****************************************************************************
//
// ****************************************************************************
// ****************************************************************************
function SearchMapFlood4(Path as integer, SX as integer, SY as integer, TX as integer, TY as integer)
    XOffset as integer
    YOffset as integer
    X as integer
    Y as integer

    if SEARCH_MapInitialized = 0 then exitfunction -1
    if SEARCH_PathsInitialized = 0 then exitfunction -1
    if Path < 0 or Path > SEARCH_MaxPaths then exitfunction -1

    if SEARCH_ParametersChanged = 1 or SEARCH_LastSearch <> 2
        SEARCH_ParametersChanged = 0
        SEARCH_PreviousStart.X = -9999
        SEARCH_LastSearch = 2
    endif

    if SX <> SEARCH_PreviousStart.X or SY <> SEARCH_PreviousStart.Y
        SEARCH_PreviousStart.X = SX
        SEARCH_PreviousStart.Y = SY

        SEARCH_PopulateTileInfo()

        SEARCH_OpenListTop=-1
        SEARCH_OpenListBottom=-1

        SEARCH_TileInfo[SX, SY].Status = 1
        SEARCH_TileInfo[SX, SY].ParentX = SX
        SEARCH_TileInfo[SX, SY].ParentY = SY
        SEARCH_TileInfo[SX, SY].F = 0
        SEARCH_QueueOntoOpen(SX, SY)

        while SEARCH_UnqueueFromOpen() > 0
            for XOffset = -1 to 1

                X = SEARCH_CurrentPosition.X + XOffset
                if X >= 0 and X < SEARCH_MapWidth

                    for YOffset = -1 to 1

                        if (XOffset && YOffset) = 0
                            Y = SEARCH_CurrentPosition.Y + YOffset

                            if Y >= 0 and Y < SEARCH_MapHeight

                                if SEARCH_TileInfo[X, Y].Status = 0
                                    SEARCH_TileInfo[X, Y].Status = 1
                                    SEARCH_TileInfo[X, Y].ParentX = SEARCH_CurrentPosition.X
                                    SEARCH_TileInfo[X, Y].ParentY = SEARCH_CurrentPosition.Y
                                    SEARCH_TileInfo[X, Y].F = SEARCH_TileInfo[SEARCH_CurrentPosition.X, SEARCH_CurrentPosition.Y].F + 10
                                    if SEARCH_MaximumCost = 0 or SEARCH_TileInfo[X, Y].F < SEARCH_MaximumCost
                                        SEARCH_QueueOntoOpen(X, Y)
                                    endif
                                endif

                            endif
                        endif
                    next YOffset
                endif
            next XOffset
        endwhile
    endif

    if SEARCH_TileInfo[TX,TY].Status > 0 then exitfunction SEARCH_BuildPath(Path,SX,SY,TX,TY)
    n = SEARCH_ClearPath(Path,SX,SY)
    exitfunction n
endfunction 0