fb:porticula NoPaste
myMaze (Pathfind)
| Uploader: |  Eternal_Pain | 
| Datum/Zeit: | 23.03.2013 10:57:19 | 
#Define Distance2(X1,Y1,X2,Y2) sqr(((X1-X2)*(X1-X2))+((Y1-Y2)*(Y1-Y2)))
#Define MazeFloor     &h00
#Define MazeStart     &h01
#Define MazeGoal      &h02
#Define MazeWall      &h70
Randomize Timer
Type tListNode
    NextEntry  as tListNode ptr
    PrevEntry  as tListNode ptr
    EntryValue as Integer
End Type
Type tList
    Declare Sub AddEntry(byval Value as Integer)
    Declare Sub DelEntry(byval ListNode as tListNode ptr)
    Declare Sub DestroyList()
    FirstEntry as tListNode ptr
    LastEntry  as tListNode ptr
End Type
Sub tList.AddEntry(byval Value as Integer)
    Dim NewEntry as tListNode ptr = NEW tListNode
    NewEntry -> EntryValue = Value
    If (LastEntry = 0) Then
        FirstEntry = NewEntry
        LastEntry  = NewEntry
        Exit Sub
    End If
    NewEntry -> PrevEntry = LastEntry
    LastEntry -> NextEntry = NewEntry
    LastEntry = NewEntry
End Sub
Sub tList.DestroyList()
    while FirstEntry
        LastEntry = FirstEntry -> NextEntry
        Delete FirstEntry
        FirstEntry = LastEntry
    wend
End Sub
Sub tList.DelEntry(byval ListNode as tListNode ptr)
    If (ListNode = 0) Then Exit Sub
    If ListNode -> NextEntry Then ListNode -> NextEntry -> PrevEntry = ListNode -> PrevEntry
    If ListNode -> PrevEntry Then ListNode -> PrevEntry -> NextEntry = ListNode -> NextEntry
    If ListNode = FirstEntry Then FirstEntry = FirstEntry -> NextEntry
    If ListNode = LastEntry  Then LastEntry  = LastEntry -> PrevEntry
    Delete ListNode
End Sub
Type Vector2
    X as Integer
    Y as Integer
End Type
Function getRandom(Byval imin as Integer, Byval imax as Integer) as Integer
    Dim rndnum as Integer
    Dim as Integer min, max
    min = imin : max = imax
    If min>max then swap min,max
    rndnum = min + int( rnd*( max - (min-1) ) )
    return rndnum
End Function
Type tMaze
    Private:
    'if goal reachable from start
    Declare Function fillPath(byval posX as Integer, byval posY as Integer) as Integer
    Public:
    MazeP as ubyte ptr 'Map (pointer)
    MazeW as integer   'width
    MazeH as integer   'height
    MazeS as Vector2   'start position
    MazeG as Vector2   'goal position
    Declare Function genMaze(Byval sizeW as integer, byval sizeH as integer) as Integer
    Declare Function delMaze() as Integer 'destroy/memfre
    Declare Function getPath(byval fromX as Integer, byval fromY as Integer, byval targetX as Integer, byval targetY as Integer) as Integer ptr
End Type
Function tMaze.fillPath(byval posX as Integer, byval posY as Integer) as Integer
    Dim fillmap  as byte ptr = NEW byte[MazeW*MazeH]
    Dim fillList as tList
    Dim mappos as Integer = posX+(posY*MazeW)
    Dim as Integer fX, fY
    fillList.AddEntry(mappos)
    fillmap[mappos] = 1
    While fillList.FirstEntry
        mappos = fillList.FirstEntry -> EntryValue
        fillList.DelEntry(fillList.FirstEntry)
        if (MazeP[mappos] = MazeGoal) Then Function = 1 : Exit While
        fX = mappos mod MazeW : fY = mappos \ MazeW
        If (fX > 0)         andalso ( (fillmap[mappos-1]     = 0) and (MazeP[mappos-1]     < MazeWall) ) Then fillList.AddEntry(mappos-1)     : fillmap[mappos-1]     = 1
        If (fY > 0)         andalso ( (fillmap[mappos-MazeW] = 0) and (MazeP[mappos-MazeW] < MazeWall) ) Then fillList.AddEntry(mappos-MazeW) : fillmap[mappos-MazeW] = 1
        If (fX < (MazeW-1)) andalso ( (fillmap[mappos+1]     = 0) and (MazeP[mappos+1]     < MazeWall) ) Then fillList.AddEntry(mappos+1)     : fillmap[mappos+1]     = 1
        If (fY < (MazeH-1)) andalso ( (fillmap[mappos+MazeW] = 0) and (MazeP[mappos+MazeW] < MazeWall) ) Then fillList.AddEntry(mappos+MazeW) : fillmap[mappos+MazeW] = 1
    Wend
    Delete[] fillmap
    fillList.DestroyList()
End Function
Function tMaze.genMaze(Byval sizeW as integer, byval sizeH as integer) as Integer
    Dim granularity  as Integer
    Dim randomLength as Integer
    Dim minLength    as Integer
    Dim maxLength    as Integer
    Dim numWalls     as Integer
    Dim rndWallPosX  as Integer
    Dim rndWallPosY  as Integer
    Dim rndDest      as Integer
    Dim dX           as Integer
    Dim dY           as Integer
    Dim mappos       as Integer
    Dim minDist      as Integer
    Do
        If MazeP Then delMaze()
        MazeW = sizeW : MazeH = sizeH
        If (MazeW mod 2) = 0 Then MazeW -= 1
        If (MazeH mod 2) = 0 Then MazeH -= 1
        If (MazeW < 9) Then MazeW = 9
        If (MazeH < 9) Then MazeH = 9
        MazeP = NEW ubyte[MazeW*MazeH]
        'gen outwalls
        For WallW as Integer = 0 to MazeW-1
            MazeP[WallW] = MazeWall
            MazeP[((MazeH-1)*MazeW)+WallW] = MazeWall
        Next WallW
        For WallH as Integer = 0 to MazeH-1
            MazeP[WallH*MazeW] = MazeWall
            MazeP[(MazeW-1)+(WallH*MazeW)] = MazeWall
        Next WallH
        minDist = sqr(sqr(MazeW*MazeH))
        'gen random start position
        Do : MazeS.X = getRandom(1,MazeW-2) : Loop while ((MazeS.X mod 2) = 0)
        Do : MazeS.Y = getRandom(1,MazeH-2) : Loop while ((MazeS.Y mod 2) = 0)
        'gen random goal position (with minimal distance)
        Do
            Do : MazeG.X = getRandom(1,MazeW-2) : Loop while ((MazeG.X mod 2) = 0)
            Do : MazeG.Y = getRandom(1,MazeH-2) : Loop while ((MazeG.Y mod 2) = 0)
        Loop while (Distance2(MazeS.X,MazeS.Y,MazeG.X,MazeG.Y) < minDist)
        MazeP[MazeS.X+(MazeS.Y*MazeW)]=MazeStart
        MazeP[MazeG.X+(MazeG.Y*MazeW)]=MazeGoal
        For G as Integer = 4 to 1 step -1
            granularity = 2 ^ G '...16,8,4,2
            numWalls = (MazeW*MazeH)/G
            For W as Integer = 1 to numWalls '1 to...
                rndWallPosX = granularity * (getRandom(1,MazeW-1) \ granularity)
                rndWallPosY = granularity * (getRandom(1,MazeH-1) \ granularity)
                minLength   = getRandom(1,4)
                maxLength   = getRandom(2,10)
                rndDest     = getRandom(0,3)
                Select Case rndDest
                    Case 0 'North/Up
                        dX =  0 : dY = -1
                    Case 1 'East/Right
                        dX =  1 : dY =  0
                    Case 2 'South/Down
                        dX =  0 : dY =  1
                    Case 3 'West/Left
                        dX = -1 : dY =  0
                End Select
                randomLength = granularity * (getRandom(minLength,maxLength)+1)
                For L as Integer = 1 to randomLength
                    mappos = (rndWallPosX + (rndWallPosY*MazeW))
                    If MazeP[mappos] <> MazeFloor Then Exit For
                    MazeP[mappos] = MazeWall
                    rndWallPosX += dX : rndWallPosY += dY
                Next L
            Next W
        Next G
    Loop until fillPath(MazeS.X,MazeS.Y) 'if goal not reachable, then repeat
    'replace Start to Floor
    MazeP[MazeS.X+(MazeS.Y*MazeW)]=MazeFloor
    Return -1'TRUE
End Function
Function tMaze.delMaze() as Integer
    If MazeP Then Delete[] MazeP
    MazeP       = 0
    MazeW       = 0
    MazeH       = 0
    return -1'TRUE
End Function
Function tMaze.getPath(byval fromX as Integer, byval fromY as Integer, byval targetX as Integer, byval targetY as Integer) as Integer ptr
    Dim PathMap    as Integer ptr
    Dim PathList   as Integer ptr
    Dim PathLength as Integer
    Dim frompos    as Integer     = fromX+(fromY*MazeW)
    Dim targetpos  as Integer     = targetX+(targetY*MazeW)
    Dim mappos     as Integer
    Dim nearestpos as Integer
    Dim distance   as Single
    Dim distanceL  as Single      = MazeW*MazeH
    Dim fillList   as tList
    Dim as integer tX,tY
    If (frompos < 0) or (frompos > ((MazeW*MazeH)-1)) Then return 0
    fillList.AddEntry(frompos)
    PathMap = NEW Integer[MazeW*MazeH]
    While fillList.FirstEntry
        mappos = fillList.FirstEntry -> EntryValue
        fillList.DelEntry(fillList.FirstEntry)
        PathMap[mappos] += 1 'Set PathCost
        tX = mappos mod MazeW : tY = mappos \ MazeW
        distance = Distance2(tX,tY,targetX,targetY)
        If (distance < distanceL) Then
            distanceL  = distance
            nearestpos = mappos
        End If
        If (mappos = targetpos) then exit while
        If (tX > 0)         andalso ( (MazeP[mappos-1]     < MazeWall) and PathMap[mappos-1]     = 0 ) Then fillList.AddEntry(mappos-1)     : PathMap[mappos-1]     = PathMap[mappos]
        If (tY > 0)         andalso ( (MazeP[mappos-MazeW] < MazeWall) and PathMap[mappos-MazeW] = 0 ) Then fillList.AddEntry(mappos-MazeW) : PathMap[mappos-MazeW] = PathMap[mappos]
        If (tX < (MazeW-1)) andalso ( (MazeP[mappos+1]     < MazeWall) and PathMap[mappos+1]     = 0 ) Then fillList.AddEntry(mappos+1)     : PathMap[mappos+1]     = PathMap[mappos]
        If (tY < (MazeH-1)) andalso ( (MazeP[mappos+MazeW] < MazeWall) and PathMap[mappos+MazeW] = 0 ) Then fillList.AddEntry(mappos+MazeW) : PathMap[mappos+MazeW] = PathMap[mappos]
    Wend
    fillList.DestroyList()
    PathLength                    = PathMap[nearestpos]
    PathList                      = New Integer[PathLength+1]
    PathList[0]                   = PathMap[nearestpos]
    PathList[PathMap[nearestpos]] = nearestpos
    Do
        mappos               = nearestpos
        PathLength           = PathMap[mappos]
        PathList[PathLength] = mappos
        If (PathLength = 1) Then Exit Do
        tX = mappos mod MazeW : tY = mappos \ MazeW
        If (tX > 0)         andalso PathMap[mappos-1]     = PathLength-1 Then nearestpos -= 1     : continue do
        If (tY > 0)         andalso PathMap[mappos-MazeW] = PathLength-1 Then nearestpos -= MazeW : continue do
        If (tX < (MazeW-1)) andalso PathMap[mappos+1]     = PathLength-1 Then nearestpos += 1     : continue do
        If (tY < (MazeW-1)) andalso PathMap[mappos+MazeW] = PathLength-1 Then nearestpos += MazeW : continue do
        exit do
    Loop
    Delete[] PathMap
    return PathList
End Function
Sub DrawMaze(byref Maze as tMaze, byval size as Integer=10)
    Dim mappos as Integer
    Dim dcolor as UInteger
    For Y as Integer = 0 to Maze.MazeH-1
        For X as Integer = 0 to Maze.MazeW-1
            mappos = X + (Y*Maze.MazeW)
            Select Case Maze.MazeP[mappos]
                Case MazeFloor
                    dcolor = &h000000
                Case MazeWall
                    dcolor = &hFFFFFF
                Case MazeGoal
                    dcolor = &hFF0000
                Case Else
                    dColor = &hFF8800
            End Select
            line(X*size,Y*size)-((size-1)+(X*size),(size-1)+(Y*size)),dcolor,bf
        Next X
    Next Y
End Sub
Sub PlayerMove(byref Maze as tMaze, byref Player as Vector2, byval dx as integer, byval dy as integer)
    Dim playerpos as Integer = Player.X + (Player.Y * Maze.MazeW)
    Dim destpos   as Integer = playerpos + dx + (dy * Maze.MazeW)
    If (Maze.MazeP[destpos] < MazeWall) Then Player.X += dx : Player.Y += dy
End Sub
screenres 800,600,32
Dim myMaze as tMaze
myMaze.genMaze(80,60)
''MAIN:
Dim Player   as Vector2 = myMaze.MazeS
Dim KeyTimer as Double = Timer
Dim size     as Integer = 10
Dim as Integer MX,MY,MB
Dim PathList as Integer ptr
Dim PathMove as Integer
    Do
        Screenlock
            cls
            DrawMaze(myMaze,size)
            line(Player.X*size,Player.Y*size)-((size-1)+(Player.X*size),(size-1)+(Player.Y*size)),&hFFFF00,bf
        Screenunlock
        If PathList Then
            If PathMove = PathList[0]+1 Then
                Delete[] PathList : PathList = 0
            Else
                Player.X = PathList[PathMove] mod myMaze.MazeW
                Player.Y = PathList[PathMove] \ myMaze.MazeW
                PathMove += 1
            End If
        End If
        If ((Timer-KeyTimer) > 0.025) Then
            getMouse MX,MY,,MB
            If (MB > 0) Then
                If PathList Then Delete[] PathList : PathList = 0
                PathList = myMaze.getPath(Player.X,Player.Y,fix(MX/size),fix(MY/size))
                PathMove = 1
            End If
            If multikey(&h48) Then PlayerMove(myMaze, Player, 0,-1) 'UP
            If multikey(&h4B) Then PlayerMove(myMaze, Player,-1, 0) 'LEFT
            If multikey(&h4D) Then PlayerMove(myMaze, Player, 1, 0) 'RIGHT
            If multikey(&h50) Then PlayerMove(myMaze, Player, 0, 1) 'DOWN
            KeyTimer=Timer
        End if
        If multikey(&h01) Then exit do'ESC
        sleep 1
    Loop
    If PathList Then Delete[] PathList
    myMaze.delMaze()
	
 Wer ist online?
 Wer ist online? Buchempfehlung
 Buchempfehlung
 FreeBASIC-Chat
 FreeBASIC-Chat
 FreeBASIC-Nachrichten jetzt auch über Twitter erhalten. Follow us!
			FreeBASIC-Nachrichten jetzt auch über Twitter erhalten. Follow us!


