Linked Lists

By: Kevin Picone




About


      The following was written to take the user through the basic usage and concepts associated with managing linked lists of Types. The article mostly follows in a top down nature. With the most advanced concepts located towards the bottom. There's various key headings all the way through, so if your already familiar with types then you should be able to skim the headings to brush up on PlayBASIC's implementation.

      In a previous tutorial about types, we had running example about storing peoples information (name/address etc). First individuals, then groups of people in a typed array. So in this tutorial, we'll use the same premise, but this time we'll use linked type list rather than array.


I N D E X:






Type's, What are they?

     In order to understand Linked Lists, we'll first need to be familiar with User Defined Types. So it's highly recommended that you read through the Types tutorial, before continuing on with linked lists.

Top





What's a Linked List all about ?


      In programming, one of the biggest hurdles is often managing information, as typically the more information we have to handle, the more important code design becomes. Moreover, different types of programs tend to require different approaches for managing information.

      In game programming, we're typically processing groups of the Characters (I.e. Players, Badguys / Aliens, Bullets, etc), where we'll be frequently adding (When a new character is spawned) and deleting characters when they've died.

      Immediately, this sounds like a perfect situation for a typed array (See ArrayBasics), where we'd create various arrays to store the different character types in. This means to add/delete items we need to write our code to manage the size of the array. While this is perfectly fine approach, and one that I often use myself, but there's another way.

      A linked List is a mechanism PlayBASIC can embed into type variables. What this mechanism does, is it allows us to hold a series of typed variables all connected (linked) together and access through the single type variable. The beauty of the Linked List is that we no longer have to concern ourselves about the size of the list. Nor do we generally have to worry about manually providing indexes to reference each individual character within our list, like we would when using an array for example. Since it's all handled transparently to the user.

Top





Declaration of a Linked Type List


      Before we get the declaration part, first we need to setup a type. So for the sake of simplicity, Lets imagine we wish to store the personal information about a group friends. The collected information might cover the persons first, middle, surname (family) name, home address, phone number, type of employment etc etc. This information will be bound together into a user defined type that we'll called Person

I.e.,

      The following code is declaring a type called "Person". This type will hold all of the relevant information about a single person in one place.

  
; Declare the "Person" user defined type.
  Type Person
   ; These Fields will hold this persons full name
     FirstName$
     MiddleName$
     SurName$
     
   ; Phone Number
     PhoneNumber$
  EndType
  


      The code above purely shows the declaration of our "Person" type. We can see the type has four string fields FirstName$,MiddleName$,SurName$ and PhoneNumber$ are contained within this type. At this point we can't really do much with it, we need to create a variable of this type, in order store and retrieve information about our friends.

      To declare a type variable with Linked List Support we append the List keyword to end of your variable dimension.

E.G

  
;  Dimension the Friends variable of type Person,
; with linked list support
  Dim  Friends As Person List
  



      So far we've our code doesn't really do anything that we can see. All we've done is declared our user defined type (Person) and declared our Friends list. So at this point the list is empty, so there's nothing to see until learnr how to add people to the list. Which we do via the NEW operator.

Top






Adding New Types to the LIST (the NEW operator)


      When we deal with UDT (User Defined types) link lists. The dimensioning process declares the type variable container, but at this point it's empty. To add new types to our list we must use the NEW operator.

      What the NEW operator does, is it allocates some memory to hold this type, which we can then assign to our list variable. If you're read the types tutorial this is nothing new, if not, you might want to go back and read the types tutorial first.

E.G

  
;  Dimension the Friends variable of type Person, with linked list support
  Dim Friends As Person List
  
; Explicitly create a NEW person and ADD it to the Friends list.
  Friends = New Person
  

(Sample code only)


      You're probably no doubt wondering by now, just what all the fuss is about ? - as so far the code is identical to a regular Type Variables. Which is true, but the unlike type variables, when we assign a linked list a new type data, this new type gets added to the head of the list. It doesn't replace whatever was there (if anything), but it is added to the list. So if we assign the a list two new items, the list now contains two individual items. Which you can see in the following example.


      In this (Cut and past friendly) example we're declaring our person type, making your Friends list and adding two people to the list.

  
  
; Declare the "Person" user defined type.
  Type Person
   ; These Fields will hold this persons full name
     FirstName$
     MiddleName$
     SurName$
     
   ; Phone Number
     PhoneNumber$
  EndType
  
  
;  Dimension the Friends variable of type Person,
; with linked list support
  Dim  Friends As Person List
  
  
; Add a person to Friends list
  Friends= New Person
  
; The Friends list is now pointing at the newly added
; Person, so lets assign this persons name
  
  Friends.FirstName$ ="Billy"
  Friends.MiddleName$ ="Bob"
  Friends.Surname$ ="Citizen"
  
  
; Add another person to Friends list
  Friends= New Person
  
; The Friends list is now pointing at the newly
; added person, so assign this persons name also
  Friends.FirstName$      ="Sally"
  Friends.MiddleName$      ="Anne"
  Friends.Surname$           ="Stevens"
  
; Display size of this list
  Print GetListSize(Friends())
  
; display the screen and wait for a key press
  Sync
  WaitKey
  



      If you run this code, you'll see that PlayBASIC returns that there are 2 Person types store in our Friends


      This is one of major fundamental difference between working with regular type variables are typed variable lists. As if we assign a regular typed variable a NEW type more than once, the second/third etc times we assign it, PB will overwrite the existing data it's holding.

Top






Retrieving Information From a Linked List


      Retrieving information from a linked list type variable is just the same as regular typed variables. So we
simply enter our type name with field in our expression, and PlayBASIC will retrieve this information for you.


e.g. (Cut and past friendly)
  
; Declare the "Person" user defined type.
  Type Person
   ; These Fields will hold this persons full name
     FirstName$
     MiddleName$
     SurName$
     
   ; Phone Number
     PhoneNumber$
  EndType
  
  
; Dimension the Friends variable of type Person,
; with linked list support
  Dim  Friends As Person List
  
  
; Add a person to Friends list
  Friends= New Person
  
; The Friends list is now pointing at the newly added
; Person, so lets assign this persons name
  
  Friends.FirstName$ ="Billy"
  Friends.MiddleName$ ="Bob"
  Friends.Surname$ ="Citizen"
  
  
; Add another person to Friends list
  Friends= New Person
  
; The Friends list is now pointing at the newly
; added person, so assign this persons name also
  Friends.FirstName$      ="Sally"
  Friends.MiddleName$      ="Anne"
  Friends.Surname$           ="Stevens"
  
  
; Display the current Friends name
  Print Friends.FirstName$
  Print Friends.MiddleName$
  Print Friends.Surname$
  
  
; display the screen and wait for a key press
  Sync
  WaitKey
  



      If you run this example, you'll notice that it only displays one of the two people (Sally) that were added to the list. Why ? - This is because inside the friends list, PB stores a pointer to the 'current' person. So each time we read/write to a friends properties within the list, PB is effectively redirectingly us to the current person. Therefore, In order to display all of the different people contained within our list, we need a method for moving the current pointer through all of the people. For this, we use the For Each /Next looping structure.

Top






Looping Through Lists (For Each / Next)



      The For Each /next loop structure is a variation of the For/Next designed for iterating through linked type lists. What this structure does is handles the current pointer within the list. Upon enter the For Each/Next loop the Current Pointer of the list you pass it reset to it's Head position. Each time the loop iterates, the lists current pointer is stepped through the list of available items, until reaching the end of the list where it'll exit and continue on.


e.g. (Cut and Past friendly)

  
  
  
; Declare the "Person" user defined type.
  Type Person
   ; These Fields will hold this persons full name
     FirstName$
     MiddleName$
     SurName$
     
   ; Phone Number
     PhoneNumber$
  EndType
  
  
;  Dimension the Friends variable of type Person,
; with linked list support
  Dim  Friends As Person List
  
  
; Add a person to Friends list
  Friends= New Person
  
; The Friends list is now pointing at the newly added
; Person, so lets assign this persons name
  
  Friends.FirstName$ ="Billy"
  Friends.MiddleName$ ="Bob"
  Friends.Surname$ ="Citizen"
  
  
; Add another person to Friends list
  Friends= New Person
  
; The Friends list is now pointing at the newly
; added person, so assign this persons name also
  Friends.FirstName$      ="Sally"
  Friends.MiddleName$      ="Anne"
  Friends.Surname$           ="Stevens"
  
  
; Display all of the people in our friends list
; When PB hits the opening For EACH statement it
; reset the current item pointer in Friends()
; to it's head object.
  For Each Friends()
     Print Friends.FirstName$
     Print Friends.MiddleName$
     Print Friends.Surname$
     Print ""
   ; Each time the loop hits next, PB Moves
   ; the Friends() current pointer to the next item
   ; until there's no more items left. Then it exits
  Next
  
; display the screen and wait for a key press
  Sync
  WaitKey
  
  



      If you run this example it'll display Sally and Billies names. Sally will be the first, since she was last added to the list.

Top






How Do I Delete Items from Linked Lists ?


      There are two ways to remove items of a linked list. Which are,


1) Assign the List a NULL - Assigning a list a NULL will tell PB that you wish to the remove the Current object that the list is pointing too. After the object has been deleted, the list pointer will move back to the previous object in the list.

2) You can use the FreeCell command with the index of any cell you wish to delete/free. See the Manual List Processing topic bellow for more information how on that.




      e.g. This example deletes the current list item by assigning NULL (Cut and Past friendly)


  
; Declare the "Person" user defined type.
  Type Person
   ; These Fields will hold this persons full name
     FirstName$
     MiddleName$
     SurName$
  EndType
  
  
;  Dimension the Friends variable of type Person,
; with linked list support
  Dim  Friends As Person List
  
  
; Add a person (Billy) to Friends list
  Friends= New Person
  Friends.FirstName$ ="Billy"
  Friends.MiddleName$ ="Bob"
  Friends.Surname$ ="Citizen"
  
  
; Add another person (Sally) to Friends list
  Friends= New Person
  Friends.FirstName$      ="Sally"
  Friends.MiddleName$      ="Anne"
  Friends.Surname$           ="Stevens"
  
; Display the number of people in the friends list
  Print "ListSize="+Str$(GetListSize(Friends()))
  
  
; DELETE the current person from friends list
  Friends = null
  
; Show the Friends list after the delete
  For Each Friends()
     Print Friends.FirstName$
     Print Friends.MiddleName$
     Print Friends.Surname$
     Print ""
  Next
  
; Display the number of people in the friends list
  Print "ListSize="+Str$(GetListSize(Friends()))
  
  
; display the screen and wait for a key press
  Sync
  WaitKey
  



      If you run this example, you'll see it only displays Billies name. This occurs because Sally was the last person added to our friends list, as such, she was current person in the friends list. So when we assigned our Friends list a Null, PB will remove whom-ever the Friends list is currently pointing at. In this case Sally. After the delete, the current pointer will be pointing at Billy

Top






How do I know where I am ?



      While most of the time knowing our position within the list isn't important to us, since we're not really concerned with what's in the list, we just want to drop objects onto it and process them all individually in a FOR EACH/Next loop.

      However, it can sometimes be helpful to get the current position of an object. To do this, we use the GetListPos() function. This this returns the list current index. Moreover, since the objects are linked together we can also look ahead at the next and previous objects, using the GetListPrevious(), GetListNext() functions. You can change the current position using the SetListPos() command.


      e.g. This example create a list of two people and then runs through and display the persons names and their list position. (Cut and Past friendly)

  
; Declare the "Person" user defined type.
  Type Person
   ; These Fields will hold this persons name
     FirstName$
     SurName$
  EndType
  
;  Dimension the Friends variable of type Person,
; with linked list support
  Dim  Friends As Person List
  
  
; Add a person (Billy) to Friends list
  Friends= New Person
  Friends.FirstName$ ="Billy"
  Friends.Surname$ ="Citizen"
  
  
; Add another person (Sally) to Friends list
  Friends= New Person
  Friends.FirstName$      ="Sally"
  Friends.Surname$           ="Stevens"
  
  
; Show the Friends list
  For Each Friends()
   ; Display current position in the list
     Print "List Position="+Str$(GetListPos(Friends()))
     Print Friends.FirstName$+" "+Friends.Surname$
     Print ""
  Next
  
; display the screen and wait for a key press
  Sync
  WaitKey
  
  



      If you run this example, you'll see it displays Sally has a list position of 2 and that Billy has a list position of 1. The positions of objects (within the list) will never change until these people are deleted. After deletion PlayBASIC will re-use any freed cells the next time a new object is added to a list.

Top







How do I change my current list position ?


      So we now know from the previous section, that we can read the current position from a list using the GetListPos() function, so it stands to reason that we can also change to a new position via the SetListPos() function.



  
; Declare the "Person" user defined type.
  Type Person
   ; These Fields will hold this persons name
     FirstName$
     SurName$
  EndType
  
;  Dimension the Friends variable of type Person,
; with linked list support
  Dim  Friends As Person List
  
  
; Add a person (Billy) to Friends list
  Friends= New Person
  Friends.FirstName$ ="Billy"
  Friends.Surname$ ="Citizen"
  
; Get the position of the BILL within the list
  BillsPosition = GetListPos(Friends())
  
  
  
; Add another person (Sally) to Friends list
  Friends= New Person
  Friends.FirstName$      ="Sally"
  Friends.Surname$           ="Stevens"
  
; Get the position of the SAlly within the list
  SallysPosition = GetListPos(Friends())
  
  
; Call the show friend function with the
; Position of the person we wish to display
; in this case we're passing it the position
; of BILLY
  ShowFriend(BillsPosition)
  
  
; Next we pass the show friend function
; sallys position
  ShowFriend(SallysPosition)
  
  
; display the screen and wait for a key press
  Sync
  WaitKey
  
  
; Show Friend function is use show a persons name
Function ShowFriend(ThisListPosition)
; Change the current link in the friends() list
; this person
  SetListPos Friends(),ThisListPosition
; Show this persons name
  Print Friends.FirstName$+" "+Friends.Surname$
  Print ""
EndFunction
  
  
  


Top






How do I find the First Item In the List ?


      You can retrieve first item using the GetListFirst() function. If the list is empty, GetListFirst will return a -1. Moreover if you're adding/deleting objects to the list then it's important not to assume what the first item is. So it's highly recommended that if you call GetListFirst(), rather than just assume some object is still at the heads of the list.



      e.g. This example create a list of two people and returns the display the then persons names and their list position. (Cut and Past friendly)

  
  
; Declare the "Person" user defined type.
  Type Person
   ; These Fields will hold this persons name
     FirstName$
     SurName$
  EndType
  
;  Dimension the Friends variable of type Person,
; with linked list support
  Dim  Friends As Person List
  
  
  
; Add a person (Billy) to Friends list
  Friends= New Person
  Friends.FirstName$ ="Billy"
  Friends.Surname$ ="Citizen"
  
  Print "Billies List Position="+Str$GetListPos(Friends()))
  
  
; Add another person (Sally) to Friends list
  Friends= New Person
  Friends.FirstName$      ="Sally"
  Friends.Surname$           ="Stevens"
  
; Get the position of the BILL within the list
  Print "Sallies List Position="+Str$GetListPos(Friends()))
  
  
; Display
  Print "First Item In List ="+Str$GetListFirst(Friends()))
  
  
  
; display the screen and wait for a key press
  Sync
  WaitKey
  
  
  


Top







Manual List Processing


      While generally we'll only need to the use the basic list controls mentioned above. However, there will most list come times where you might just want some more hands on functionality, as such PlayBASIC has various extra list processing functions at your disposal.

      Such commands include,


NewList MyList() ; Allocate List for this type variable
ResetList MyList() ; Reset current object index to first object in list
StepList MyList() ; Move the list index to the next item in the list
result=EndOfList(MyList()) ; check if we've hit the end of the list
FreeCell MyList(),Index ; The link you wish to delete



      These function can used to replicate the For Each / Next behavior like so.

Example #1

  
; Declare the "Person" user defined type.
  Type Person
   ; These Fields will hold this persons name
     FirstName$
     SurName$
  EndType
  
;  Dimension the Friends variable of type Person,
; with linked list support
  Dim  Friends As Person List
  
; Add a person (Billy) to Friends list
  Friends= New Person
  Friends.FirstName$      ="Billy"
  Friends.Surname$           ="Citizen"
  
; Add another person (Sally) to Friends list
  Friends= New Person
  Friends.FirstName$      ="Sally"
  Friends.Surname$           ="Stevens"
  
  
; Process the List Manually
; Set the Lists Current Index to the FIRST link
  ResetList Friends()
  
; USe a While/EndWhile to process the list
  While Not EndOfList(Friends())
     
   ; Show this persons name
     Print Friends.FirstName$+" "+Friends.Surname$
     
   ; Move to the next link in the list
     StepList Friends()
  EndWhile
  
  
; display the screen and wait for a key press
  Sync
  WaitKey
  
  
  
  





Example #2

      You can also use the GetListFirst() / SetListPos() & GetListNext() functions to replicate the same behavior..

  
; Declare the "Person" user defined type.
  Type Person
   ; These Fields will hold this persons name
     FirstName$
     SurName$
  EndType
  
;  Dimension the Friends variable of type Person,
; with linked list support
  Dim  Friends As Person List
  
; Add a person (Billy) to Friends list
  Friends= New Person
  Friends.FirstName$      ="Billy"
  Friends.Surname$           ="Citizen"
  
; Add another person (Sally) to Friends list
  Friends= New Person
  Friends.FirstName$      ="Sally"
  Friends.Surname$           ="Stevens"
  
  
; Process the List Manually.
  
; Ask this list for the First LINK
  ThisLInk=GetListFirst(Friends())
  
; USe a While/EndWhile to process the list
  While ThisLink>0
     
   ; Set Friends current to ThisLink
     SetListPos Friends(),ThisLink
     
   ; Show this persons name
     Print Friends.FirstName$+" "+Friends.Surname$
     
   ; Ask our list object what the next list is
     ThisLink=GetListNext(Friends())
  EndWhile
  
  
; display the screen and wait for a key press
  Sync
  WaitKey
  
  
  



Top






Manual List Deletion




  
  
; Declare the "Person" user defined type.
  Type Person
   ; These Fields will hold this persons name
     FirstName$
     SurName$
  EndType
  
;  Dimension the Friends variable of type Person,
; with linked list support
  Dim  Friends As Person List
  
  
; Add a person (Billy) to Friends list
  Friends= New Person
  Friends.FirstName$ ="Billy"
  Friends.Surname$ ="Citizen"
  
; Get the position of the BILL within the list
  BillsPosition = GetListPos(Friends())
  
  
  
; Add another person (Sally) to Friends list
  Friends= New Person
  Friends.FirstName$      ="Sally"
  Friends.Surname$           ="Stevens"
  
; Get the position of the SAlly within the list
  SallysPosition = GetListPos(Friends())
  
  
; USe FreeCell to remove Bill from the list by bills position
  FreeCell Friends(),BillsPosition
  
  
; Display the People in the friends list
  For Each Friends()
     Print Friends.FirstName$+" "+Friends.Surname$
  Next
  
  
; display the screen and wait for a key press
  Sync
  WaitKey
  
  



Top






Lets put that knowledge to good use


      So that's a crash course in PlayBASIC's Linked List controls. The following is a simple game frame work built around list processing. The frame work doesn't include a player, only a simple object handler for manging the aliens. Which in this case, are going to be some randomly coloured circles.

      The example includes object spawning, deletion and even inter object collision. This is where each object in the list checks for impacts against all other objects in the list. Which is one of circumstance where manual list processing can come in very handy. When an impact occurs the objects just randomly flashes and changes direction. Which means some will get stuck on each other.



  
  
; Tell PlayBASIC to limit this programs speed to 60 frames
; per second or less.
  SetFPS 60
  
; Declare tObject type to hold the information about our object
  Type tObject
     x#,y#          ; position
     Angle#     ; Direction object is moving in
     Speed#     ; speed object is moving at
     Size          ; Size of this object
     Colour     ; colour
  EndType
  
  
; Declare Alien variable as type tObject with linked list support
  Dim Alien As tObject List
  
  
  
; Start of Do /loop
  Do
   ; Clear the Screen
     Cls RGB(20,30,40)
     
   ; Check if the Space Bar was press ?
     If SpaceKey()=true
        
        Alien = New tobject
        
      ; init it's position
        Alien.x#=Rnd(GetScreenWidth())
        Alien.y#=Rnd(GetScreenHeight())
        
      ; init it's size
        Alien.Size=RndRange(10,30)
        
      ; init the direction and speed
        Alien.Angle#=Rnd#(360)
        Alien.Speed#=RndRange#(5,10)
        
      ; init it's colour
        Alien.Colour=RndRGB()
        
     EndIf
     
     
     
   ; use FOR EACH to iterate through
   ; Alien() list and move them.
     For Each Alien()
        
      ; Get the Speed and direction this alien is moving
        Size          =Alien.Size
        
        ThisColour=Alien.Colour
        
        Angle#     =Alien.Angle#
        Speed#     =Alien.Speed#
        
      ; Calc New X & Y coordinates of this alien
        x#=Alien.x#     +CosRadius(Angle#,Speed#)
        y#=Alien.y#     +SinRadius(Angle#,Speed#)
        
        
      ; Check if the Alien has left the screen ?
        If PointInBox(x#,y#,-Size,-Size,GetScreenWidth()+size,GetScreenHeight()+size)=true
           
         ; Remember the list position of the current alien
           CurrentListPOs=GetListPos(Alien())
           
         ; Run through the Aliens list and check if we hit another alien
           While Not EndOfList(Alien())
              
            ; Move to the next alien
              StepList Alien()
              
            ; Check if our position over laps another alien
              If CirclesIntersect(x#,y#,Size,Alien.x,Alien.y,Alien.Size)=true
                 
               ; if it does change colours and size
                 ThisColour=RndRGB()
                 Alien.Colour=ThisColour
                 
               ; Randomly change he hit aliens direction
                 Alien.Angle#=Rnd(360)
                 
               ; Randomly my angle, so object
                 Angle#=Rnd(360)
                 
              EndIf
              
            ; Contine the While loop
           EndWhile
           
         ; restore our original position in the list
           SetListPos Alien(),CurrentListPos
           
           
         ; draw a circle to represent this alien
           CircleC x#,y#,Size,true,ThisColour
           
         ; record the aliens new position/Colour and angle
           Alien.x#=x#
           Alien.y#=y#
           Alien.Colour=ThisColour
           Alien.Angle#=Angle#
           
           
        Else
           
         ; This alien is no longer inside the screen bounds
         ; and has thus moved off the screen.  So lets delete it
         ; from the Alien list.
           Alien = null
           
        EndIf
        
      ; Continue processing all of the aliens in the list
     Next
     
     
     Print "Number Of Aliens:"+Str$(GetListSize(Alien()))
     Print "Press Space To Spawn Aliens"
     
   ;refresh the screen
     Sync
     
   ; Jump back to the DO statement, to keep program running
  Loop
  
  


Top







Where to from here ?


      If you've made it all the way through that, then you might want brush over Variables, ArrayBasics, loops, Types, Functions&Psub's & the Images and Sprites tutorial.

Top




 
Related Info: ArrayBasics | Functions&Psub | Loops | NamingConventions | Operators | ProgramLayout | Types | Variables :
 


(c) Copyright 2002 - 2024 - Kevin Picone - PlayBASIC.com