Library tutorials & articles

AI 1 - Problem Solving (Artificial intelligence)

Linked List

This part doesn’t have much to do with AI, but, you cant code a AI program without one, so we have to do it. If you don’t know, a linked list is used to replace an array. Why don’t we use an array ? Well, because as array’s size is set at design time, and cannot be changed during run time, so, as soon as the program starts you would have an array of 6 million Cstates, wasting all that memory when you don't need it.

A linked list makes space for new states as and when it is used. I won't bother telling you how it works, there are plenty of examples all over the place. You just need to know that it does work, and its just a variable sized array! nothing more. The linked list will not actually hold the states, just pointers to states, this is because, the list will act as a queue for states waiting to be expanded, when a state is expanded, it is removed from the list. However, we need to keep expanded states in memory for when it comes to tracing back and reporting the path from initial state to solution state.

When we actually start coding the main loop, we will place expanded states on a second que, so that we keep track of where they are when its time to delete the states from memory (prevent memory leaks)

OKAY,, from now on, were back to C++ code, Make a new header file “Llist.h” and put the following in there.

// enum the ends of the list
enum SIDE { LEFT, RIGHT };

// the list is made up of the following Links.
struct Link {
   Link   *LeftLink; // pointer to link on left
   Link   *RightLink; // pointer to link on right
   CState *Data; // pointer to actual data, the state.
};

// the main list
class CLList {

private:

   Link* LeftPointer; // pointer to a perminant and BLANK link
   Link* RightPointer; // same as above, opposite end.
   double ListLen; // number of non-blank lists in list.
   
   // Removes EVERYTHING from memory
//(Links, AND the state data they point to)
   void EmptyUsedMemory() {
       CState *temp;
       while(!IsListEmpty()) {
           temp = Pop(LEFT);
           delete temp;
       }
   }

public:
   
   class ERROR_CANT_POP_EMPTY_LIST{}; // Error Exception

   CLList() {
       // initialise all private variables
       LeftPointer  = new Link;
       RightPointer = new Link;
       ListLen      = 0;

       LeftPointer->LeftLink = 0;
       LeftPointer->RightLink = RightPointer;
       RightPointer->RightLink = 0;
       RightPointer->LeftLink = LeftPointer;
   }

   ~CLList() {
       EmptyUsedMemory();
   }

   inline double GetListLen() {
       return ListLen;
   }
   
   inline bool IsListEmpty() {
       return (LeftPointer->RightLink == RightPointer);
   }

   CState* Pop(SIDE Side) {

       Link  ForReturn;
       Link* ForDelete;
           
       if (!IsListEmpty()) {

           ListLen--;
           if (Side == LEFT) {

               ForReturn                      = *(LeftPointer->RightLink);
               ForDelete                      = LeftPointer->RightLink;
               LeftPointer->RightLink         = ForReturn.RightLink;
               ForReturn.RightLink->LeftLink  = LeftPointer;

           }
           else {

               ForReturn                      = *(RightPointer->LeftLink);
               ForDelete                      = RightPointer->LeftLink;
               RightPointer->LeftLink         = ForReturn.LeftLink;
               ForReturn.LeftLink->RightLink  = RightPointer;
           }

           delete ForDelete;
           return ForReturn.Data;
       }
       return 0;
   }

   void Push(SIDE Side, CState* What) {
       Link* NewLink = new Link;
       NewLink->Data = What;
       ListLen++;

       if (Side == LEFT) {

           NewLink->RightLink           = LeftPointer->RightLink;
           NewLink->LeftLink            = LeftPointer;
           LeftPointer->RightLink       = NewLink;
           NewLink->RightLink->LeftLink = NewLink;
       }
       else {

           NewLink->RightLink           = RightPointer;
           NewLink->LeftLink            = RightPointer->LeftLink;
           RightPointer->LeftLink       = NewLink;
           NewLink->LeftLink->RightLink = NewLink;
       }
   }

   CState* PopBestByHeuristics(HEURISTIC heuristic) {

       int   BestValue=9999;
       int   Temp=0;
       Link* BestState = 0;
       Link* Current = LeftPointer;
       CState* ForReturn = 0;
       
       if(!IsListEmpty()) {

       // Find BEST State By Wrong tile number heuristic
           while(Current->RightLink != RightPointer) {

               Current = Current->RightLink;
               
               if(heuristic == MANHATTAN_DISTANCE) {
                   Temp = Current->Data->GetManhattanDistance();
               }
               else {
                   Temp = Current->Data->GetWrongTiles();
               }

               if(Temp < BestValue) {
                   BestValue = Temp;
                   BestState = Current;
               }
           }

           // POP the value out the List.
           // Make the link to the right's left pointer point to the link on the left.
           BestState->RightLink->LeftLink = BestState->LeftLink;
           BestState->LeftLink->RightLink = BestState->RightLink;

           ForReturn = BestState->Data;
           delete BestState;

           return ForReturn;
       }
       return 0;
   }

   CState* PeekByBestHueristics(HEURISTIC heuristic) {
   

       int   BestValue=9999;
       int   Temp=0;
       Link* BestState = 0;
       Link* Current = LeftPointer;
       CState* ForReturn = 0;
       
       if(!IsListEmpty()) {

       // Find BEST State By Wrong tile number heuristic
           while(Current->RightLink != RightPointer) {

               Current = Current->RightLink;
               
               if(heuristic == MANHATTAN_DISTANCE) {
                   Temp = Current->Data->GetManhattanDistance();
               }
               else {
                   Temp = Current->Data->GetWrongTiles();
               }

               if(Temp < BestValue) {
                   BestValue = Temp;
                   BestState = Current;
               }
           }

           ForReturn = BestState->Data;

           return ForReturn;
       }
       return 0;
   }

So, like I said. Hopefully you will know how linked lists work, if you don’t, here is a little explanation of what each function does…

  • GetListLen() returns the number of NON blank links in the list
  • IsListEmpty() returns true if there is no data in the list
  • Pop(SIDE) removes a Cstate pointer from the list side, and returns it.
  • Push(SIDE, WHAT) pushes the WHAT pointer onto the SIDE side of the list.
  • PopBestByHeuristics(HEURISTIC heuristic) pops the link that scored highest using Heuristic HEURISTC, (which will be enumberated later)
  • PeekByBestHueristics(HEURISTIC heuristic) does the same as above, except the data is not removed from the list, just returned.

OKAY… Now that we have the 2 main class’ here is the hard part. Writing the main loop !

Comments

  1. 27 Jul 2005 at 20:11

    i need help with an error im recieving.


    i have a template linked list class


    template <class LT>
    class LList
    {
    private:
     class LNode
       {
       public:
         LNode ();
         LT data;
         LNode * next;
       };


    public:
     LList();
     LList( const LList & other);
     ~LList ();
     LList & operator = (const LList & other);
     bool operator == (const LList & other);
     int Size() const;
     friend ostream & operator << <> (ostream & outs, const LList<LT> & L);
     bool InsertFirst (const LT & value);
     bool InsertLast (const LT & value);
     bool DeleteFirst ();
     bool DeleteLast ();
    private:
     LNode * first;
     int size;
    };


    and the friend function is giving me an error:


    template <class LT>
    ostream & operator << (ostream & outs, const LList<LT> & L)
    {
     if (L.first == NULL)
       return outs;


     outs << L.first -> data;


     for (LList<LT>::LNode * n = L.first -> next; n != NULL; n = n -> next)
      {
        outs << ' ' << n -> data;
      }
     return outs;
    }


    i get an error at the for loop... the error is :


    LLIST.tmp: In function std:<img src="images/smilies/redface.gif" width=15>stream& operator&lt;&lt;(std:<img src="images/smilies/redface.gif" width=15>stream&, const LList&lt;LT&gt;&)': <br> LLIST.tmp:111: error: n' undeclared (first use this function)
    LLIST.tmp:111: error: (Each undeclared identifier is reported only once for each function it appears in.)
    LLIST.tmp:33: error: LList&lt;int&gt;::LNode*LList&lt;int&gt;::first' is private <br> LLIST.tmp:106: error: within this context <br> LLIST.tmp:33: error: LList<int>::LNode*LList<int>::first' is private
    LLIST.tmp:109: error: within this context
    application.cpp:19:   instantiated from here
    LLIST.tmp:33: error: LList&lt;int&gt;::LNode*LList&lt;int&gt;::first' is private <br> LLIST.tmp:111: error: within this context <br> LLIST.tmp:111: error: dependent-name LList<LT>::LNode' is parsed as a non-type, but instantiation yields a type
    LLIST.tmp:111: note: say `typename  LList<LT>::LNode' if a type is meant


    i know these all have to do with friend and being private, what do i do?!?!

  2. 01 Jan 1999 at 00:00

    This thread is for discussions of AI 1 - Problem Solving (Artificial intelligence).

Leave a comment

Sign in or Join us (it's free).

AddThis

Related discussion

Events coming up

  • Dec 6

    Developing AJAX Web Applications with Castle Monorail

    London, United Kingdom

    Monorail is the model-view-controller engine of the Castle Project, bringing many of the best ideas of Ruby on Rails to the .NET world. In this talk, David De Florinier and Gojko Adzic show how Monorail makes it easy to develop .NET based AJAX applications, and how to use the Castle Project to build Web 2.0 applications effectively. Come to this session if you are a .NET web developer. Everyone is welcome!