Tuesday, June 20, 2017

Monkey-X - Closest Point in Line Segment - code example


This can be turned into a collision function. Circle to line segment. Use a 
distance function for that.


' Example on how to get the closest point in a line segment
' to another point.
'
'

Import mojo

Class point
    Field x:Float
    Field y:Float
    Method New(x:Float,y:Float)
        Self.x = x
        Self.y = y
    End Method
End Class

Class MyGame Extends App

    Method OnCreate()
        SetUpdateRate(30)        
    End Method
    Method OnUpdate()        
    End Method
    Method OnRender()
        Cls 0,0,0 
        SetColor 255,255,255        
        DrawText "Mouse the mouse around to see the closest point",0,0
        DrawText "of the line segment..",0,20
        Local mypoint:point = New point(0,0)
        ' the mouse location for point x and y closest to line point
        Local cx:Float=MouseX(),cy:Float=MouseY()
        ' line coordinates
        Local lx1:Float=100
        Local ly1:Float=100
        Local lx2:Float=200
        Local ly2:Float=200
        ' draw the line
        SetColor 100,100,100
        DrawLine lx1,ly1,lx2,ly2
        ' get the closest point on the line segment
        mypoint = getclosestpointonsegment(lx1,ly1,lx2,ly2,cx,cy)
        ' draw this point
           SetColor 255,255,0
           DrawCircle mypoint.x,mypoint.y,10

    End Method
End Class

Function getclosestpointonsegment:point(sx1:Int, sy1:Int, sx2:Int, sy2:Int, px:Int, py:Int)
    Local xDelta:Float = sx2 - sx1
    Local yDelta:Float = sy2 - sy1
    Local u:Float

    If ((xDelta = 0) And (yDelta = 0))    
      Error("Segment start equals segment end")
    End If

    u = ((px - sx1) * xDelta + (py - sy1) * yDelta) / (xDelta * xDelta + yDelta * yDelta)

       Local closestPoint:point = New point(0,0)
    If (u < 0)
      closestPoint = New point(sx1, sy1)
    Else If (u > 1)
      closestPoint = New point(sx2, sy2)
    Else
      closestPoint = New point(Int(Floor(sx1 + u * xDelta)), Int(Floor(sy1 + u * yDelta)))
    End If
    
    Return closestPoint
End Function


Function Main()
    New MyGame()
End Function

Friday, June 9, 2017

Monkey-X - Interface Data in array - code example


'
' When building an interface on the screen it might
' be useful to put the data of it and store it elsewhere.
' Sometimes you might use the coordinates more then once
' and for other things like collision(mouse click) 
'
  
Import mojo

' Here we create 1 array with the coordinates 
' and width and height and 1 string for the
' text. Ends with c and s.
Global label1c:Int[] = [10,10,50,15] ' coordinates x,y,w,h
Global label1s:String = "Label1" ' text
Global label2c:Int[] = [10,30,50,15]
Global label2s:String = "Label2"

Class MyGame Extends App

    Method OnCreate()
        SetUpdateRate(1)
    End Method
    Method OnUpdate()        
    End Method
    Method OnRender()
        Cls 0,0,0 
        ' Here we call the drawlabel function.
        ' We put one string and a array in it.
        drawlabel(label1s,label1c)
        drawlabel(label2s,label2c)
    End Method
End Class

' this function takes a string and a int array
' into the function.
Function drawlabel:Void(a:String,b:Int[])
    SetColor 255,55,55
    ' draw a rect x,y,w,h
    DrawRect b[0],b[1],b[2],b[3]
    SetColor 255,255,255
    DrawText a,b[0]+b[2]/2,b[1]+b[3]/2,.5,.5
End Function

Function Main()
    New MyGame()
End Function

Friday, April 14, 2017

Monkey-X - Maze - Recursive Division with Rooms - code example


#rem
Recursive Division with Rooms - Maze

From the book - Mazes for programmers -

#end


Import mojo


Class cell
    Field x:Int,y:Int
    Field north:Bool,east:Bool
    Field south:Bool,west:Bool
    Field visited:Bool=False
    Field value:Int
    Method New(x:Int,y:Int)
        Self.x = x
        Self.y = y
    End Method
End Class

Class recursivedivisionrmaze
    Field width:Int,height:Int
    Field tilewidth:Float,tileheight:Float
    Field map:cell[][]
    Method New(mazewidth:Int,mazeheight:Int,sw:Int,sh:Int)
        Self.width = mazewidth
        Self.height = mazeheight
        map = New cell[width][]
        For Local i=0 Until width
            map[i] = New cell[height]
        Next
        For Local y=0 Until height
        For Local x=0 Until width
            map[x][y] = New cell
        Next
        Next
        tilewidth = Float(sw)/Float(mazewidth)
        tileheight = Float(sh)/Float(mazeheight)
        recursivedivisionrmaze
    End Method
    '
    ' This method creates the maze
    '
     ' We set every cell connection to true. Then
     ' we recursively split the grid in half by adding 
     ' walls back in. Every wall we add has one passage.
     '
     ' We add walls with a few lines in the divide 
     ' function. It basically skips recursion at random
     ' at a smaller then <size.
     '
    Method recursivedivisionrmaze()
        ' Set all wall connections to true
        For Local y=0 Until height
        For Local x=0 Until width
            map[x][y].north = True
            map[x][y].east = True
            map[x][y].south = True
            map[x][y].west = True
        Next
        Next
        ' Here we recursivly create the maze
        divide(0,0,width,height)
        ' Here we add walls to the outer edge of the 
        ' map.
        For Local y=0 Until height
            map[0][y].west = False
            map[width-1][y].east = False
        Next
        For Local x=0 Until width
            map[x][0].north = False
            map[x][height-1].south = False
        Next
    End Method
    ' Here we divide the grid vertically and
    ' horizontally. We exit it if the cell size
    ' is <=1
    Method divide(x:Int,y:Int,w:Int,h:Int)
        If h <= 1 Or w <= 1 Then Return
        ' Here we add the rooms        
        Local roomw:Int=Rnd(3,8)
        Local roomh:Int=Rnd(3,8)
        If w<roomw And h<roomh And Int(Rnd(6)) = 0 Then Return
        ' Here we select to either do a horizontal 
        ' or vertical wall.
        If h>w
            divide_horizontally(x,y,w,h)
        Else
            divide_vertically(x,y,w,h)
        End If
    End Method
    ' Here we create a horizontal line in the map
    Method divide_horizontally(x:Int,y:Int,w:Int,h:Int)
        ' Get the y location where we create the wall
        Local divide_south_of:Int = Rnd(h-1)
        ' Here we set the location of the door
        Local passage_at:Int = Rnd(w)
        ' Loop through the width of the map
        For Local x1=0 Until w
            ' If not on the open door area
            If passage_at <> x1 Then
                ' if not out of bounds
                If x+x1 < width And y+divide_south_of < height
                ' Get the cell location
                Local x2:Int = x+x1
                Local y2:Int = y+divide_south_of
                ' Unlink the walls
                map[x2][y2].south = False
                If y2+1<height 
                map[x2][y2+1].north = False
                End If
                End If
            End If
        Next
        ' Recurse - Make a new wall horizontally
        ' and vertically in the area we just did.
        divide(x,y,w,divide_south_of+1)
        divide(x,y+divide_south_of+1,w,h-divide_south_of-1)
    End Method    
    ' Here we create a vertical wall
    Method divide_vertically(x:Int,y:Int,w:Int,h:Int)
        ' get the location where we create the walls
        Local divide_east_of:Int = Rnd(w-1)
        ' One location where we create an open door(passage)
        Local passage_at:Int = Rnd(h)
        ' Loop from top to bottom of the map
        For Local y1=0 Until h
            ' If not on a passage
            If passage_at <> y1 Then
            ' If not out of bounds
            If y+y1<height And x+divide_east_of < width
                ' Get the current cell to carve into
                Local x2:Int = x+divide_east_of
                Local y2:Int = y+y1
                ' Disconnect(carve) the wall
                map[x2][y2].east = False
                If x2+1<width
                map[x2+1][y2].west = False
                End If
            End If
            End If
        Next
        ' Divide in this area again
        divide(x,y,divide_east_of+1,h)
        divide(x+divide_east_of+1,y,w-divide_east_of-1,h)
    End Method
    '
    ' Draw the maze
    '
    Method draw()
        For Local y=0 Until height
        For Local x=0 Until width
            Local x1:Int=x*tilewidth
            Local y1:Int=y*tileheight
            SetColor 255,255,255
            If map[x][y].north = False
                DrawLine x1,y1,x1+tilewidth,y1
            End If
            If map[x][y].east = False
                DrawLine x1+tilewidth,y1,x1+tilewidth,y1+tileheight
            End If
            If map[x][y].south = False
                DrawLine x1,y1+tileheight,x1+tilewidth,y1+tileheight
            End If
            If map[x][y].west = False
                DrawLine x1,y1,x1,y1+tileheight
            End If
        Next
        Next
    End Method
End Class

Global maze:recursivedivisionrmaze

Class MyGame Extends App
    Method OnCreate()
        SetUpdateRate(1)
        maze = New recursivedivisionrmaze(20,20,500,400)
    End Method
    Method OnUpdate()        
        If MouseHit(MOUSE_LEFT)
            Seed = Millisecs
            maze = New recursivedivisionrmaze(20,20,500,400)
        End If
    End Method
    Method OnRender()
        Cls 0,0,0 
        SetColor 255,255,255
        maze.draw
        DrawText "Recursive Division mazes with rooms.",0,480-40
        DrawText "Press Mouse or Touch to create new maze",0,480-20
    End Method
End Class


Function Main()
    New MyGame()
End Function

Monkey-X - Maze - Recursive Division Algorithm - code example


#rem
Recursive Division Algorithm - Maze

From the book - Mazes for programmers -

#end


Import mojo


Class cell
    Field x:Int,y:Int
    Field north:Bool,east:Bool
    Field south:Bool,west:Bool
    Field visited:Bool=False
    Field value:Int
    Method New(x:Int,y:Int)
        Self.x = x
        Self.y = y
    End Method
End Class

Class recursivedivisionmaze
    Field width:Int,height:Int
    Field tilewidth:Float,tileheight:Float
    Field map:cell[][]
    Method New(mazewidth:Int,mazeheight:Int,sw:Int,sh:Int)
        Self.width = mazewidth
        Self.height = mazeheight
        map = New cell[width][]
        For Local i=0 Until width
            map[i] = New cell[height]
        Next
        For Local y=0 Until height
        For Local x=0 Until width
            map[x][y] = New cell
        Next
        Next
        tilewidth = Float(sw)/Float(mazewidth)
        tileheight = Float(sh)/Float(mazeheight)
        recursivedivisionmaze
    End Method
    '
    ' This method creates the maze
    '
     ' We set every cell connection to true. Then
     ' we recursively split the grid in half by adding 
     ' walls back in. Every wall we add has one passage.
     '
    Method recursivedivisionmaze()
        ' Set all wall connections to true
        For Local y=0 Until height
        For Local x=0 Until width
            map[x][y].north = True
            map[x][y].east = True
            map[x][y].south = True
            map[x][y].west = True
        Next
        Next
        ' Here we recursivly create the maze
        divide(0,0,width,height)
        ' Here we add walls to the outer edge of the 
        ' map.
        For Local y=0 Until height
            map[0][y].west = False
            map[width-1][y].east = False
        Next
        For Local x=0 Until width
            map[x][0].north = False
            map[x][height-1].south = False
        Next
    End Method
    ' Here we divide the grid vertically and
    ' horizontally. We exit it if the cell size
    ' is <=1
    Method divide(x:Int,y:Int,w:Int,h:Int)
        If h <= 1 Or w <= 1 Then Return
        If h>w
            divide_horizontally(x,y,w,h)
        Else
            divide_vertically(x,y,w,h)
        End If
    End Method
    ' Here we create a horizontal line in the map
    Method divide_horizontally(x:Int,y:Int,w:Int,h:Int)
        ' Get the y location where we create the wall
        Local divide_south_of:Int = Rnd(h-1)
        ' Here we set the location of the door
        Local passage_at:Int = Rnd(w)
        ' Loop through the width of the map
        For Local x1=0 Until w
            ' If not on the open door area
            If passage_at <> x1 Then
                ' if not out of bounds
                If x+x1 < width And y+divide_south_of < height
                ' Get the cell location
                Local x2:Int = x+x1
                Local y2:Int = y+divide_south_of
                ' Unlink the walls
                map[x2][y2].south = False
                If y2+1<height 
                map[x2][y2+1].north = False
                End If
                End If
            End If
        Next
        ' Recurse - Make a new wall horizontally
        ' and vertically in the area we just did.
        divide(x,y,w,divide_south_of+1)
        divide(x,y+divide_south_of+1,w,h-divide_south_of-1)
    End Method    
    ' Here we create a vertical wall
    Method divide_vertically(x:Int,y:Int,w:Int,h:Int)
        ' get the location where we create the walls
        Local divide_east_of:Int = Rnd(w-1)
        ' One location where we create an open door(passage)
        Local passage_at:Int = Rnd(h)
        ' Loop from top to bottom of the map
        For Local y1=0 Until h
            ' If not on a passage
            If passage_at <> y1 Then
            ' If not out of bounds
            If y+y1<height And x+divide_east_of < width
                ' Get the current cell to carve into
                Local x2:Int = x+divide_east_of
                Local y2:Int = y+y1
                ' Disconnect(carve) the wall
                map[x2][y2].east = False
                If x2+1<width
                map[x2+1][y2].west = False
                End If
            End If
            End If
        Next
        ' Divide in this area again
        divide(x,y,divide_east_of+1,h)
        divide(x+divide_east_of+1,y,w-divide_east_of-1,h)
    End Method
    '
    ' Draw the maze
    '
    Method draw()
        For Local y=0 Until height
        For Local x=0 Until width
            Local x1:Int=x*tilewidth
            Local y1:Int=y*tileheight
            SetColor 255,255,255
            If map[x][y].north = False
                DrawLine x1,y1,x1+tilewidth,y1
            End If
            If map[x][y].east = False
                DrawLine x1+tilewidth,y1,x1+tilewidth,y1+tileheight
            End If
            If map[x][y].south = False
                DrawLine x1,y1+tileheight,x1+tilewidth,y1+tileheight
            End If
            If map[x][y].west = False
                DrawLine x1,y1,x1,y1+tileheight
            End If
        Next
        Next
    End Method
End Class

Global maze:recursivedivisionmaze

Class MyGame Extends App
    Method OnCreate()
        SetUpdateRate(1)
        maze = New recursivedivisionmaze(20,20,500,400)
    End Method
    Method OnUpdate()        
        If MouseHit(MOUSE_LEFT)
            Seed = Millisecs
            maze = New recursivedivisionmaze(20,20,500,400)
        End If
    End Method
    Method OnRender()
        Cls 0,0,0 
        SetColor 255,255,255
        maze.draw
        DrawText "Recursive Division Algorithm Maze",0,480-40
        DrawText "Press Mouse or Touch to create new maze",0,480-20
    End Method
End Class


Function Main()
    New MyGame()
End Function

Thursday, April 13, 2017

Monkey-X - Maze - Growing Tree Algorithm - code example


#rem
Growing Tree Algorithm - Maze

From the book - Mazes for programmers -

#end


Import mojo


Class cell
    Field x:Int,y:Int
    Field north:Bool,east:Bool
    Field south:Bool,west:Bool
    Field visited:Bool=False
    Field value:Int
    Method New(x:Int,y:Int)
        Self.x = x
        Self.y = y
    End Method
End Class

Class growingtreemaze
    Field width:Int,height:Int
    Field tilewidth:Float,tileheight:Float
    Field map:cell[][]
    Method New(mazewidth:Int,mazeheight:Int,sw:Int,sh:Int)
        Self.width = mazewidth
        Self.height = mazeheight
        map = New cell[width][]
        For Local i=0 Until width
            map[i] = New cell[height]
        Next
        For Local y=0 Until height
        For Local x=0 Until width
            map[x][y] = New cell
        Next
        Next
        tilewidth = Float(sw)/Float(mazewidth)
        tileheight = Float(sh)/Float(mazeheight)
        growingtreemaze
    End Method
    '
    ' This method creates the maze
    '
     ' The growing tree algorithm is like the prim's
     ' algorithm. It has a list with cells and either
     ' picks one out randomly or the last one. This
     ' cell location is used to carve to a neighbor.
     ' If the list is empty then the maze is done.
     '
     '
     '
    Method growingtreemaze()
        'This variable is used to select more or less
        'variation. Lower is longer paths
        Local variation:=Rnd(1,5)
        ' This is the list with neighbor cells
        Local availneighbors:Stack<cell> = New Stack<cell>
        ' pick a random cell position
        Local x:Int=Rnd(0,width)
        Local y:Int=Rnd(0,height)
        ' push to the neighbor list
        availneighbors.Push(New cell(x,y))
        ' mark visited
        map[x][y].visited = True
        ' loop until the list is emtpy
        While availneighbors.IsEmpty = False
            ' variable that holds the position we are
            ' on in the stack(deletion)
            Local p:Int
            ' Chose between random and last
            If Int(Rnd(variation)) = 0 'last
                p = availneighbors.Length-1
                x = availneighbors.Get(p).x
                y = availneighbors.Get(p).y
            Else'random
                'get random position from list
                p = Rnd(availneighbors.Length)
                x = availneighbors.Get(p).x
                y = availneighbors.Get(p).y
            End If
            ' make list for positions around the current cell
            Local dirs:Stack<Int> = New Stack<Int>
            ' put cells on the dirs list if unvisited and 
            ' on the map.
            If y-1 >= 0 And map[x][y-1].visited = False Then dirs.Push(0)
            If x+1 < width And map[x+1][y].visited = False Then dirs.Push(1)
            If y+1 < height And map[x][y+1].visited = False Then dirs.Push(2)
            If x-1 >= 0 And map[x-1][y].visited = False Then dirs.Push(3)
            ' if there are directions we can go into
            If dirs.Length > 0
                ' from all positions around the current cell
                ' select one direction.
                Local s:Int=dirs.Get(Rnd(0,dirs.Length))
                ' carve into direction and set x,y with new value
                Select s
                    Case 0'north
                    map[x][y].north = True
                    y-=1                    
                    map[x][y].south = True                    
                    Case 1'east
                    map[x][y].east = True
                    x+=1
                    map[x][y].west = True
                    Case 2'south
                    map[x][y].south = True
                    y+=1
                    map[x][y].north = True
                    Case 3'west
                    map[x][y].west = True
                    x-=1
                    map[x][y].east = True
                End Select
                ' mark new position as visited
                map[x][y].visited = True
                ' push new position to the availneighbors 
                ' list
                availneighbors.Push(New cell(x,y))                    
            Else ' if no neighbors then remove from 
                 ' availneighbors list
                availneighbors.Remove(p)
            End If
        Wend
    End Method
    '
    ' Draw the maze
    '
    Method draw()
        For Local y=0 Until height
        For Local x=0 Until width
            Local x1:Int=x*tilewidth
            Local y1:Int=y*tileheight
            SetColor 255,255,255
            If map[x][y].north = False
                DrawLine x1,y1,x1+tilewidth,y1
            End If
            If map[x][y].east = False
                DrawLine x1+tilewidth,y1,x1+tilewidth,y1+tileheight
            End If
            If map[x][y].south = False
                DrawLine x1,y1+tileheight,x1+tilewidth,y1+tileheight
            End If
            If map[x][y].west = False
                DrawLine x1,y1,x1,y1+tileheight
            End If
        Next
        Next
    End Method
End Class

Global maze:growingtreemaze

Class MyGame Extends App
    Method OnCreate()
        SetUpdateRate(1)
        maze = New growingtreemaze(20,20,500,400)
    End Method
    Method OnUpdate()        
        If MouseHit(MOUSE_LEFT)
            Seed = Millisecs
            maze = New growingtreemaze(20,20,500,400)
        End If
    End Method
    Method OnRender()
        Cls 0,0,0 
        SetColor 255,255,255
        maze.draw
        DrawText "Growing Tree Algorithm Maze",0,480-40
        DrawText "Press Mouse or Touch to create new maze",0,480-20
    End Method
End Class


Function Main()
    New MyGame()
End Function

Monkey-X - Maze - True Prim's Algorithm - code example


#rem
True Prim's Algorithm - Maze

From the book - Mazes for programmers -

#end

Import mojo


Class cell
    Field x:Int,y:Int
    Field north:Bool,east:Bool
    Field south:Bool,west:Bool
    Field visited:Bool=False
    Field value:Int
    Method New(x:Int,y:Int)
        Self.x = x
        Self.y = y
    End Method
End Class

Class trueprimsmaze
    Field width:Int,height:Int
    Field tilewidth:Float,tileheight:Float
    Field map:cell[][]
    Method New(mazewidth:Int,mazeheight:Int,sw:Int,sh:Int)
        Self.width = mazewidth
        Self.height = mazeheight
        map = New cell[width][]
        For Local i=0 Until width
            map[i] = New cell[height]
        Next
        For Local y=0 Until height
        For Local x=0 Until width
            map[x][y] = New cell
        Next
        Next
        tilewidth = Float(sw)/Float(mazewidth)
        tileheight = Float(sh)/Float(mazeheight)
        trueprimsmaze
    End Method
    '
    ' This method creates the maze
    '
    ' You have a list for neighbors. You put
    ' a start position in the list from the map.
    ' On the map each cell has a random value.
    ' We pick a cell from the neighbor list with the lowest
    ' value. We then create a list with the directions around 
    ' the current position if they are unvisited.
    ' We select to carve into this new direction. The one
    ' With the lowest value. Put the new position on the neighbor
    ' list.
    ' If there was no direction to go around the current cell
    ' then remove this position from the neighbor list.
    ' When the list is empty then the maze is done.
    ' 
    Method trueprimsmaze()
        ' This is the list with neighbor cells
        Local availneighbors:Stack<cell> = New Stack<cell>
        ' Put a random value on each of the cells in the map.
        For Local y=0 Until height
        For Local x=0 Until width
            map[x][y].value = Rnd(0,100)
        Next
        Next
        ' These hold the start position
        Local x:Int,y:Int
        ' Find start position. The position on the map
        ' with the lowest value
        Local lowest:Int=100
        For Local y1=0 Until height
        For Local x1=0 Until width
            If map[x1][y1].value < lowest Then
                x = x1
                y = y1
                lowest = map[x1][y1].value
            End If
        Next
        Next
        ' push to the neighbor list
        availneighbors.Push(New cell(x,y))
        availneighbors.Top.value = map[x][y].value
        ' mark visited
        map[x][y].visited = True
        ' loop until the list is emtpy
        While availneighbors.IsEmpty = False
            ' get the position on the map with the lowest
            ' value.
            Local lowest:Int=100
            ' We need to remember the item position on the list
            ' we select. So we can delete it later on.
            Local itemtodelete:Int
            For Local i = 0 Until availneighbors.Length
                If availneighbors.Get(i).value < lowest
                    lowest = availneighbors.Get(i).value
                    x = availneighbors.Get(i).x
                    y = availneighbors.Get(i).y
                    itemtodelete = i
                End If
            Next

            ' make list for positions around the current cell
            Local dirs:Stack<Int> = New Stack<Int>
            ' put cells on the dirs list if unvisited and 
            ' on the map.
            If y-1 >= 0 And map[x][y-1].visited = False Then dirs.Push(0)
            If x+1 < width And map[x+1][y].visited = False Then dirs.Push(1)
            If y+1 < height And map[x][y+1].visited = False Then dirs.Push(2)
            If x-1 >= 0 And map[x-1][y].visited = False Then dirs.Push(3)
            ' if there are directions we can go into
            If dirs.Length > 0
                ' from all positions around the current cell
                ' select the direction with the lowest value
                Local s:Int=-1
                Local lowest:Int=500
                For Local i = 0 Until dirs.Length
                    If dirs.Get(i) = 0
                    If map[x][y-1].value < lowest Then
                        lowest = map[x][y-1].value
                        s = 0
                    End If
                    End If
                    If dirs.Get(i) = 1
                    If map[x+1][y].value < lowest Then
                        lowest = map[x+1][y].value
                        s = 1
                    End If
                    End If
                    If dirs.Get(i) = 2
                    If map[x][y+1].value < lowest Then
                        lowest = map[x][y+1].value
                        s = 2
                    End If
                    End If
                    If dirs.Get(i) = 3
                    If map[x-1][y].value < lowest Then
                        lowest = map[x-1][y].value
                        s = 3
                    End If
                    End If
                Next
                ' carve into direction and set x,y with new value
                Select s
                    Case 0'north
                    map[x][y].north = True
                    y-=1                    
                    map[x][y].south = True                    
                    Case 1'east
                    map[x][y].east = True
                    x+=1
                    map[x][y].west = True
                    Case 2'south
                    map[x][y].south = True
                    y+=1
                    map[x][y].north = True
                    Case 3'west
                    map[x][y].west = True
                    x-=1
                    map[x][y].east = True
                End Select
                ' mark new position as visited
                map[x][y].visited = True
                ' push new position to the availneighbors 
                ' list
                availneighbors.Push(New cell(x,y))
                ' Set the value of the item
                availneighbors.Top.value = map[x][y].value                    
            Else ' if no neighbors then remove active item from 
                 ' availneighbors list
                availneighbors.Remove(itemtodelete)
            End If
        Wend
    End Method
    '
    ' Draw the maze
    '
    Method draw()
        For Local y=0 Until height
        For Local x=0 Until width
            Local x1:Int=x*tilewidth
            Local y1:Int=y*tileheight
            SetColor 255,255,255
            If map[x][y].north = False
                DrawLine x1,y1,x1+tilewidth,y1
            End If
            If map[x][y].east = False
                DrawLine x1+tilewidth,y1,x1+tilewidth,y1+tileheight
            End If
            If map[x][y].south = False
                DrawLine x1,y1+tileheight,x1+tilewidth,y1+tileheight
            End If
            If map[x][y].west = False
                DrawLine x1,y1,x1,y1+tileheight
            End If
        Next
        Next
    End Method
End Class

Global maze:trueprimsmaze

Class MyGame Extends App
    Method OnCreate()
        SetUpdateRate(1)
        maze = New trueprimsmaze(10,10,500,400)
    End Method
    Method OnUpdate()        
        If MouseHit(MOUSE_LEFT)
            maze = New trueprimsmaze(10,10,500,400)
        End If
    End Method
    Method OnRender()
        Cls 0,0,0 
        SetColor 255,255,255
        maze.draw
        DrawText "True Prim's Algorithm Maze",0,480-40
        DrawText "Press Mouse or Touch to create new maze",0,480-20
    End Method
End Class


Function Main()
    New MyGame()
End Function

Monkey-X - Maze - Simplified Prim's Algorithm - code example

#rem
Simplified Prim's Algorithm - Maze

From the book - Mazes for programmers -

#end


Import mojo


Class cell
    Field x:Int,y:Int
    Field north:Bool,east:Bool
    Field south:Bool,west:Bool
    Field visited:Bool=False
    Field value:Int
    Method New(x:Int,y:Int)
        Self.x = x
        Self.y = y
    End Method
End Class

Class simplifiedprimsmaze
    Field width:Int,height:Int
    Field tilewidth:Float,tileheight:Float
    Field map:cell[][]
    Method New(mazewidth:Int,mazeheight:Int,sw:Int,sh:Int)
        Self.width = mazewidth
        Self.height = mazeheight
        map = New cell[width][]
        For Local i=0 Until width
            map[i] = New cell[height]
        Next
        For Local y=0 Until height
        For Local x=0 Until width
            map[x][y] = New cell
        Next
        Next
        tilewidth = Float(sw)/Float(mazewidth)
        tileheight = Float(sh)/Float(mazeheight)
        simplifiedprimsmaze
    End Method
    '
    ' This method creates the maze
    '
    ' What the algorithm does is: It starts with 
    ' a list with a start location on it. We take
    ' a random location from the list and see if there
    ' are neighbors cells that have not been visited.
    ' We select one of those neighbors and carve towards
    ' it. We add that new cell to the list. 
    ' If there are no neighbors then we remove that cell
    ' from the list.
    ' The maze is finished if the list is empty.
    ' 
    ' The method is somewhat like a flood(seed) fill.
    ' 
    Method simplifiedprimsmaze()
        ' This is the list with neighbor cells
        Local availneighbors:Stack<cell> = New Stack<cell>
        ' pick a random cell position
        Local x:Int=Rnd(0,width)
        Local y:Int=Rnd(0,height)
        ' push to the neighbor list
        availneighbors.Push(New cell(x,y))
        ' mark visited
        map[x][y].visited = True
        ' loop until the list is emtpy
        While availneighbors.IsEmpty = False
            'get random position from list
            Local p:Int=Rnd(availneighbors.Length)
            x = availneighbors.Get(p).x
            y = availneighbors.Get(p).y
            ' make list for positions around the current cell
            Local dirs:Stack<Int> = New Stack<Int>
            ' put cells on the dirs list if unvisited and 
            ' on the map.
            If y-1 >= 0 And map[x][y-1].visited = False Then dirs.Push(0)
            If x+1 < width And map[x+1][y].visited = False Then dirs.Push(1)
            If y+1 < height And map[x][y+1].visited = False Then dirs.Push(2)
            If x-1 >= 0 And map[x-1][y].visited = False Then dirs.Push(3)
            ' if there are directions we can go into
            If dirs.Length > 0
                ' from all positions around the current cell
                ' select one direction.
                Local s:Int=dirs.Get(Rnd(0,dirs.Length))
                ' carve into direction and set x,y with new value
                Select s
                    Case 0'north
                    map[x][y].north = True
                    y-=1                    
                    map[x][y].south = True                    
                    Case 1'east
                    map[x][y].east = True
                    x+=1
                    map[x][y].west = True
                    Case 2'south
                    map[x][y].south = True
                    y+=1
                    map[x][y].north = True
                    Case 3'west
                    map[x][y].west = True
                    x-=1
                    map[x][y].east = True
                End Select
                ' mark new position as visited
                map[x][y].visited = True
                ' push new position to the availneighbors 
                ' list
                availneighbors.Push(New cell(x,y))                    
            Else ' if no neighbors then remove from 
                 ' availneighbors list
                availneighbors.Remove(p)
            End If
        Wend
    End Method
    '
    ' Draw the maze
    '
    Method draw()
        For Local y=0 Until height
        For Local x=0 Until width
            Local x1:Int=x*tilewidth
            Local y1:Int=y*tileheight
            SetColor 255,255,255
            If map[x][y].north = False
                DrawLine x1,y1,x1+tilewidth,y1
            End If
            If map[x][y].east = False
                DrawLine x1+tilewidth,y1,x1+tilewidth,y1+tileheight
            End If
            If map[x][y].south = False
                DrawLine x1,y1+tileheight,x1+tilewidth,y1+tileheight
            End If
            If map[x][y].west = False
                DrawLine x1,y1,x1,y1+tileheight
            End If
        Next
        Next
    End Method
End Class

Global maze:simplifiedprimsmaze

Class MyGame Extends App
    Method OnCreate()
        SetUpdateRate(1)
        maze = New simplifiedprimsmaze(10,10,500,400)
    End Method
    Method OnUpdate()        
        If MouseHit(MOUSE_LEFT)
            maze = New simplifiedprimsmaze(10,10,500,400)
        End If
    End Method
    Method OnRender()
        Cls 0,0,0 
        SetColor 255,255,255
        maze.draw
        DrawText "Simplified Prim's Algorithm Maze",0,480-40
        DrawText "Press Mouse or Touch to create new maze",0,480-20
    End Method
End Class


Function Main()
    New MyGame()
End Function