欧美性猛交黑人xxxx,成人毛片一区二区三区,久久综合九色综合精品,男的把j放进女人下面视频免费

VC中利用人工智能解決八迷宮問題

  • 發(fā)布于:2023-09-06
  • 189 人圍觀
 前言

  隨著計算機技術(shù)的發(fā)展,人工智能(Artificial intelligence,下文簡稱"AI")已經(jīng)成為世界各國一個熱門的研究方向。對于這一領(lǐng)域的內(nèi)容,國內(nèi)起步較晚,目前雖然網(wǎng)絡(luò)上各種編程文章很多,但是關(guān)于如何編程解決人工智能問題的文章和資料少之又少。近日,筆者有幸在國外網(wǎng)站上發(fā)現(xiàn)了這一篇精彩文章,該文通過VC實例來說明如何解決及實現(xiàn)人工智能問題,例子程序雖然相對來說比較簡單,但有一定的代表性,對有興趣研究這一領(lǐng)域的朋友們有借鑒意義。

  一、"八迷宮"游戲簡介

  在大學(xué)進行AI模塊開發(fā)的時候,我就開始著手寫這篇文章,目的是介紹我所了解到的一些讓人感興趣的問題。對于什么是人工智能,我想沒有任何人愿意花費大量時間進行爭論。

  當(dāng)你讀到這里的時候,推薦你下源代碼,因為粘貼和拷貝的代碼與源代碼的作用相比是遠遠不及的。在本文中,我將使用一個單人游戲"八迷宮"作為一個例子,這個游戲的規(guī)則如下:

  有一個3X3的網(wǎng)格,包含1到8這幾個數(shù)(因此,有一個格子是空的),最初這8個數(shù)的排列是隨機的,例如,下面的排列是一種可能情況:

6 1 7
3 4
5 8 2

  游戲玩家可以向東、南、西、北等方向移動這個空格,移動空格時,空格所占位置的數(shù)字將填補到原來空格的位置。例如,對于上圖來說,如果向北移動空格,游戲的狀態(tài)將如下圖所示:

6 1
3 4 7
5 8 2


  當(dāng)游戲狀態(tài)實現(xiàn)如下所示的狀態(tài)時,游戲結(jié)束。

1 2 3
8 4
7 6 5

  二、解決"八迷宮"問題的方法

  解決上述問題的方法主要有以下幾種:

  1、Breadth First Search(按照"橫向"原則搜索).

  2、Depth First Search(按照"深度"原則搜索).

  3、Heuristic Search(啟發(fā)式搜索).

  4、A* search.

  實現(xiàn)這些方法的代碼非常相似,但是它們工作的方式是截然不同的。所有的上述方法都要使用一個鏈表,而且最初的鏈表都只有一個成員,它對應(yīng)著游戲網(wǎng)格的最初狀態(tài)。這個成員向它所有可能的子狀態(tài)進行膨脹(每種移動所產(chǎn)生的結(jié)果都被考慮了進去),然后所有這些子狀態(tài)都被添加到鏈表中。這種處理將在一個循環(huán)中進行持續(xù)處理,直到實現(xiàn)目標狀態(tài),也就是說直到游戲結(jié)束為止。

  實現(xiàn)"八迷宮"單人游戲的偽代碼如下:
Do
  Current_Item = Remove_Item_From_List
  Child_State_Array = Expand (Current_State)
  Add_to_List(Child_State_Array)
  If child_State_Array Holds the solution then IsGameOver = true
Loop while (IsGameOver = false)


   這個結(jié)構(gòu)的代碼可以在上述所有的人工智能方法中看到,各種方法的區(qū)別僅僅在于它們是如何在鏈表中進行排序。

   1、在 breadth first search方法中,各個成員都是按照某一固定的方向被添加到鏈表中,刪除時按相反方向進行。

   2、在 depth first search方法中,各個成員的添加和刪除都是在鏈表的同一個方向進行。

   3、在heuristic search方法中,各個成員可以在鏈表的任意方向進行添加,然而,在從鏈表中刪除一個成員時,每一個成員被"heuristic"函數(shù)進行打分(對于狀態(tài)來說,分數(shù)越高越接近于最終狀態(tài)),得分最高的項目將被從鏈表中刪除。

   4、A*方法使用兩個heuristic函數(shù),并將最終的兩個得分加在一起。使用兩個heuristics函數(shù)極大地提高了程序發(fā)現(xiàn)下步最佳狀態(tài)的能力,但是卻降低了程序的運行速度。

   其實,三、四方法是第二種方法的延伸和變種,區(qū)別僅在于啟發(fā)式搜索的方式不同罷了,這一點讀者朋友們可以在后面的代碼中細細體味。實際上"八迷宮"這種游戲的heuristic函數(shù)的可以是這么一個函數(shù),它計算擁有正確位置的網(wǎng)格個數(shù),或是100-狀態(tài)深度。

   使用啟發(fā)式的搜索有利有弊,在這個例子中,使用啟發(fā)式可能使程序的主循環(huán)降低10倍速度,然而,它降低了循環(huán)的次數(shù),可能從6百萬次降低到了4000次,這節(jié)省了內(nèi)存的負荷,以及例子程序的運行時間。(這提醒了我,我使用的最初的狀態(tài)使用了25步解決了問題),這看起來不是很多,但如果沒有啟發(fā)式搜索,搜索將1秒鐘處理300兆的內(nèi)存,除非你使用功能強大的處理機器,(我使用的是1.3G,256兆的機器),否則你可能需要減少結(jié)束游戲所需要的移動次數(shù),要低于10。

  三、程序代碼

  首先,要聲明的是,游戲網(wǎng)格在程序中對應(yīng)著一個擁有10個成員變量的數(shù)組,網(wǎng)格每個位置按照從左到右、從上到下的位置排序。對于網(wǎng)格狀態(tài),可實現(xiàn)一個狀態(tài)類,它對應(yīng)著網(wǎng)格的各種狀態(tài),并擁有所有操作網(wǎng)格時所需要的代碼和變量,這個類命名為CState,代碼如下:

/* 聲明網(wǎng)格中空格所有可能移動的方向,至于為什么要包括"NONE"將在后面的代碼中顯現(xiàn)出來;*/
enum DIRECTION { NONE, NORTH, EAST, SOUTH, WEST };

// 聲明CState類
class CState {
  private:
   // 使用1 to 9號索引來對應(yīng)網(wǎng)格的每個位置, 定義為 char類型是為了節(jié)省內(nèi)存;
   char Grid[10];
   char Depth; //Depth變量對游戲的最初原始狀態(tài)演變到當(dāng)前狀態(tài)所經(jīng)歷的步數(shù);
   //我們需要記錄下父狀態(tài)是如何進行移動而得到當(dāng)前狀態(tài)的;
   DIRECTION OperatorApplyed;
   // 父狀態(tài)指針,當(dāng)程序結(jié)束時,我們可以利用它跟蹤所經(jīng)歷的狀態(tài),從而給出答案;
   CState *PrevState;

   // 尋找當(dāng)前網(wǎng)格中的空格位置或某一個具體數(shù)字的位置,默認狀態(tài)是尋找空格位置;
   inline int FindBlank(char Search=0) {
    int Blank=1;
    while (Grid[Blank] != Search) {
     Blank++;
    }
    return Blank;
   }

   // 按照規(guī)定的方向移動空格;
   void MoveBlank(DIRECTION Direction) {
    int Blank = FindBlank();
    // 我們需要記住本次操作所移動的方向;
    OperatorApplyed = Direction;
    switch (Direction) {
     case NORTH:
      Grid[Blank] = Grid[Blank - 3];
      Grid[Blank - 3] = 0;
      break;
     case EAST:
      Grid[Blank] = Grid[Blank + 1];
      Grid[Blank + 1] = 0;
      break;
     case SOUTH:
      Grid[Blank] = Grid[Blank + 3];
      Grid[Blank + 3] = 0;
      break;
     case WEST:
      Grid[Blank] = Grid[Blank - 1];
      Grid[Blank - 1] = 0;
      break;
    }
   }

   /* 下面的函數(shù)將被用于第一種方法的heuristics函數(shù)的一部分,它得到兩個索引位置的直角距離,它還用于確定一個數(shù)字當(dāng)前位置與其應(yīng)該所在位置的直角距離;
   int GetDistanceBetween(int Tile1, int Tile2) {
    int X1, X2;
    int Y1, Y2;
    int temp=0;
    // 將grid位置轉(zhuǎn)換為X,Y坐標;
    Y1 = 1;
    Y2 = 2;
    X1 = Tile1;
    X2 = Tile2;
    if(Tile1 > 3) { Y1 = 2; X1 = Tile1 - 3; }
    if(Tile1 > 6) { Y1 = 3; X1 = Tile1 - 6; }
    if(Tile2 > 3) { Y2 = 2; X2 = Tile2 - 3; }
    if(Tile2 > 6) { Y2 = 3; X2 = Tile2 - 6; }
    //為了確保距離值為正說,進行必要的換位處理;
    if(Y1 - Y2 < 0) {
     temp = Y1;
     Y1 = Y2;
     Y2 = temp;
    }
    if(X1 - X2 < 0) {
     temp = X1;
     X1 = X2;
     X2 = temp;
    }
    return ((Y1 - Y2) + (X1 - X2));
   }

  public:
   // 異常處理;
   class ERROR_ILLEGAL_MOVE{};
   class ERROR_NO_MORE_DIRECTIONS{};
   class ERROR_OUT_OF_BOUNDS{};
   //用于heuristic函數(shù);它代表了當(dāng)前狀態(tài)與前一狀態(tài)的距離;這個數(shù)值越小越好。
   int GetDepth() {
    return Depth;
   }

   // CState類構(gòu)造函數(shù);
   CState() {
    Depth = 0;
    Grid[1] = 6; // for slower machines use 4
    Grid[2] = 1; // for slower machines use 1
    Grid[3] = 7; // for slower machines use 3
    Grid[4] = 3; // for slower machines use 2
    Grid[5] = 0; // for slower machines use 0
    Grid[6] = 4; // for slower machines use 5
    Grid[7] = 5; // for slower machines use 8
    Grid[8] = 8; // for slower machines use 7
    Grid[9] = 2; // for slower machines use 6
    PrevState = 0;
    /*由于還沒有以前移動的操作,所以這就是為什么我們需要聲明NONE 變量的原因。*/
    OperatorApplyed = NONE;
   }

   void SetPrevState(CState *Set) {
    PrevState = Set;
   }

   CState* GetPrevState() {
    return PrevState;
   }

   // 用于確定移動操作是否合法
   bool CanBlankMove(DIRECTION Direction) {
    int Blank = FindBlank();
    switch (Direction) {
     case NORTH:
      if (Blank > 3) {
       return true;
      }
      else {
       return false;
      }
      break;
     case EAST:
      if (Blank != 3 && Blank != 6 && Blank != 9) {
       return true;
      }
      else {
       return false;
      }
      break;
     case SOUTH:
      if (Blank < 7) {
       return true;
      }
      else {
       return false;
      }
      break;
     case WEST:
      if (Blank != 1 && Blank != 4 && Blank != 7) {
       return true;
      }
      else {
       return false;
      }
      break;
     default:
      return false;
      break;
    }
   }

   void setgrid(int index, int value) {
    Grid[index] = value;
   }

   /*該函數(shù)如果返回"true", 當(dāng)前狀態(tài)將是最終狀態(tài),以前的狀態(tài)指針可以用來回退,從而得到解決問題的答案。*/
   bool Solution() {
     if (Grid[1] == 1 && Grid[2] == 2 && Grid[3] == 3 && Grid[4] == 8 && Grid[5]
== 0 && Grid[6] == 4 && Grid[7] == 7 && Grid[8] == 6 && Grid[9] == 5)
     {
      return true;
     }
     else {
      return false;
     }
   }

   char GetGridValue(int Index) {

    if (Index < 1 || Index > 9) {
     throw ERROR_OUT_OF_BOUNDS();
    }
    else {
     return Grid[Index];
    }
   }

   // 含一個參數(shù)的構(gòu)造函數(shù);
   CState(CState* Init) {
    Depth = (Init->GetDepth());
    OperatorApplyed = Init->GetLastOperator();
    PrevState = Init->GetPrevState();
    for (int n=1; n<=9; n++) {
     Grid[n] = Init->GetGridValue(n);
    }
   }

   DIRECTION GetLastOperator() {
    return OperatorApplyed;
  }

  // 兩個參數(shù)的構(gòu)造 函數(shù);
  CState(CState* Init, DIRECTION Direction) {
   int n;
   PrevState = Init;
   Depth = (Init->GetDepth() + 1);
   for (n=1; n<=9; n++) {
    Grid[n] = Init->GetGridValue(n);
   }
   MoveBlank(Direction);
  }

  // 另外一個heuristic函數(shù),它計算錯誤網(wǎng)格的數(shù)量;
  int GetWrongTiles() {
   return ((Grid[1] != 1) +
   (Grid[2] != 2) +
   (Grid[3] != 3) +
   (Grid[4] != 3) +
   (Grid[5] != 3) +
   (Grid[6] != 3) +
   (Grid[7] != 3) +
   (Grid[8] != 3) +
   (Grid[9] != 3) +
   (Depth )); // 也用于第二種heuristic (A*)的depth
  }

  /* ManhattanDistance是一個技術(shù)術(shù)語,它代表了所有當(dāng)前位置數(shù)字與其應(yīng)該處于的位置的直角距離之和*/

  int GetManhattanDistance() {
   int Result=0;
   Result = GetDistanceBetween(1, FindBlank(1));
   Result = Result + GetDistanceBetween(2, FindBlank(2));
   Result = Result + GetDistanceBetween(3, FindBlank(3));
   Result = Result + GetDistanceBetween(4, FindBlank(8));
   Result = Result + GetDistanceBetween(5, FindBlank(0));
   Result = Result + GetDistanceBetween(6, FindBlank(4));
   Result = Result + GetDistanceBetween(7, FindBlank(7));
   Result = Result + GetDistanceBetween(8, FindBlank(6));
   Result = Result + GetDistanceBetween(9, FindBlank(5));
   Result = Result + Depth;// 也用于第二種heuristic (A*)的depth;
   return Result;
  }
};


   正如你所看到的,這是一個很"巨大"的類,但是,它一點都不復(fù)雜,僅僅是一些簡單的數(shù)據(jù)操作。比較難的部分是跟蹤各種狀態(tài),并按照正確的順序操作它們,這將是我們下面要做的。

   這部分與人工智能關(guān)系不大,但是人工智能程序不能沒有它。如果你不了解為什么我們使用鏈表而不用數(shù)組,那末這里告訴你原因,數(shù)組在設(shè)計時有固定的尺寸,在運行時不能改變,所以如果程序一開始,你就擁有一個含有6 百萬個Cstates類對象的數(shù)組的話,而且這時你還不需要它,那將浪費大量的內(nèi)存。

  鏈表僅在需要時才為新的對象申請空間,至于它是如何工作的就不詳細介紹了,到處都有此類的例子,你只要知道它確實在工作,它是一個可變尺寸的數(shù)組。鏈表實際上并不保存狀態(tài),而保存指向各個狀態(tài)的指針,這是因為,鏈表將是一個等待膨脹的狀態(tài)隊列,當(dāng)一個狀態(tài)膨脹時,它將從鏈表中刪除,然而,我們需要在內(nèi)存中保存這個狀態(tài),用于可能發(fā)生的回退或是用于報告從最初狀態(tài)到解決問題時的解決路徑。

   當(dāng)我們實際編寫主循環(huán)代碼時,我們將把膨脹狀態(tài)放入到第二個隊列中,這樣我們才能跟蹤它們在那里,什么時候從內(nèi)存中刪除狀態(tài)(防止內(nèi)存泄露) 。

   好了,從現(xiàn)在起回到C++代碼,生成一個新的頭文件"Llist.h",輸入如下代碼:

//列舉鏈表的兩個末端;
enum SIDE { LEFT, RIGHT };
// 鏈表由下面的Link結(jié)構(gòu)對象組成;
struct Link {
  Link *LeftLink; // 指向鏈表中左端LINK對象的指針;
  Link *RightLink; //指向鏈表中右端LINK對象的指針;
  CState *Data; // 指向狀態(tài)數(shù)據(jù)的指針;
};

// 鏈表類;
class CLList {
private:
  Link* LeftPointer; // 指向一個永遠是空的,并且是末端的link對象;
  Link* RightPointer; //與上面的指針一樣,但方向相反;
  double ListLen; // 鏈表的長度;
  // 清空內(nèi)存;
  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);
  }

  //從鏈表中彈出數(shù)據(jù);
  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;
  }

  //向鏈表中壓入數(shù)據(jù)
  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;
   }
  }

  //啟發(fā)式搜索過程中,從鏈表中搜尋最佳狀態(tài);
  CState* PopBestByHeuristics(HEURISTIC heuristic) {
   int BestValue=9999;
   int Temp=0;
   Link* BestState = 0;
   Link* Current = LeftPointer;
   CState* ForReturn = 0;
   if(!IsListEmpty()) {
    //啟發(fā)式搜索可以使用MANHATTAN_DISTANCE或WrongTile方式來搜尋最佳狀態(tài)
    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;
     }
    }
    //從鏈表中刪除最佳狀態(tài);
    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;
  }

  接下來,創(chuàng)建另外一個頭文件"Eightpuzz.h",這里,除了main(),我將放入所有的東西,這些代碼閱讀起來有一定的難度,所以你要堅持住:

void gotoxy(int x, int y); //函數(shù)原型,使用光標的xy坐標;
// 枚舉搜索的類型;
enum TYPE {BREADTH_FIRST, DEPTH_FIRST };

// 類舉可能的A* 啟發(fā)式方法,第二種啟發(fā)式使用深度;
enum HEURISTIC {NOT_USED, MANHATTAN_DISTANCE, WRONG_TILES};
// include the header files we are going to need
#include<iostream.h> // for console i/o
#include<windows.h> // for sleep() and gotoxy()
#include"State.h" // for game state class
#include"Llist.h" // for a linked list class

CLList PrevStates; /* 用于跟蹤以前的狀態(tài),程序結(jié)束時要及時刪除,以免內(nèi)存泄露*/
CLList MainQue; // 等待主隊列;
SIDE PushSide;
SIDE PopSide;
// 膨脹函數(shù);
CState* GeneralExpand(int DepthLimit, HEURISTIC heuristic);
// 膨脹的步數(shù);
double Expanded = 0;

// 當(dāng)發(fā)現(xiàn)解決方法后,該函數(shù)將結(jié)果顯示在屏幕上;
void ShowSolution(CState* Solution) {
// 結(jié)果是回退得到的,所以實際結(jié)果應(yīng)該是與之反向的,這時候可以使用后入先出的方法;
CLList Reverse;
bool EndLoop=false;
while(!EndLoop) {
  Reverse.Push(LEFT, Solution);
  if(Solution->GetPrevState() != 0) {
   Solution = Solution->GetPrevState();
  }
  else {
   EndLoop = true;
  }
}
int NewLine = 0;
CState *Temp;
cout << "\n";
while(!Reverse.IsListEmpty()) {
  Temp = Reverse.Pop(LEFT);
  NewLine++;
  if(NewLine > 10) { cout << "\n"; NewLine=0;}
  switch(Temp->GetLastOperator()) {
   case NORTH:
    cout << "North, ";
    break;
   case EAST:
    cout << "East, ";
    break;
   case SOUTH:
    cout << "South, ";
    break;
   case WEST:
    cout << "West, ";
    break;
  }
}
cout << "\n\n" << "Expanded: " << Expanded << endl;
}
}

// 設(shè)置控制臺i/o x,y坐標
void gotoxy(int x, int y) {
  // SET CONSOLE CURSOR POSITION.
  COORD coord = {x,y};
  HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
  SetConsoleCursorPosition(handle,coord);
}

// 為主循環(huán)做準備;
void GeneralSearch(TYPE Type, HEURISTIC heuristic) {
  CState *Solution;
  int DepthLimit=0;
  switch(heuristic) {
   case NOT_USED:
    // Breadth First Queing Type
    if(Type == BREADTH_FIRST) {
     PushSide = RIGHT;
     PopSide = LEFT;
    }
    else {
     // Depth First Search
     cout << "Enter a Depth Limit :";
     cin >> DepthLimit;
     PushSide = RIGHT;
     PopSide = RIGHT;
    }
    break;
   case MANHATTAN_DISTANCE:
    PushSide = RIGHT;
    PopSide = RIGHT;
    break;
   case WRONG_TILES:
    PushSide = RIGHT;
    PopSide = RIGHT;
  }

  //將最初的狀態(tài)放入鏈表中;
  MainQue.Push(PushSide, new CState());
  //調(diào)用主循環(huán)
  Solution = GeneralExpand(DepthLimit, heuristic);
  // returns pointer to soution.
  // or null pointer (failure)
  if(Solution != 0) {
   cout << "FOUND SOLUTION!" << endl;
   ShowSolution(Solution);
   cout << "DONE" << endl;
  }
  else {
   //Fail
   cout << "FAIL" << endl;
  }
}

// 主循環(huán)函數(shù)(YEP, it BITES !)
CState* GeneralExpand(int DepthLimit, HEURISTIC heuristic) {
  CState *CurrentState = 0;
  CState *TempState = 0;
  int LastDepth=-1;
  if(PushSide == PopSide) {cout << "THINKING...please wait." << endl;}
   // Main loop
   while(!MainQue.IsListEmpty()) {
    if(heuristic == NOT_USED) {
     CurrentState = MainQue.Pop(PopSide);
    }
    else {
     CurrentState = MainQue.PopBestByHeuristics(heuristic);
    }
    PrevStates.Push(RIGHT, CurrentState);
    //對取出的狀態(tài)保持跟蹤(需要防止內(nèi)存)
    /*可以讓用戶規(guī)定結(jié)束游戲所需要移動的最大步數(shù),這僅限于"breadth first only"方法*/
    if(LastDepth < CurrentState->GetDepth() && PushSide != PopSide) {
      LastDepth = CurrentState->GetDepth();
      cout << "EXPANDING LEVEL " << LastDepth << endl;
    }

    // 如果當(dāng)前節(jié)點沒有超出depth限制
    if((CurrentState->GetDepth() < DepthLimit) || (DepthLimit == 0 )) {
     if((CurrentState->CanBlankMove(NORTH)) && (CurrentState->GetLastOperator() != SOUTH)) {
      TempState = new CState(CurrentState, NORTH);
      MainQue.Push(PushSide, TempState);
      Expanded++;
      if(TempState->Solution()) {
       return TempState;
      }
     }

     if((CurrentState->CanBlankMove(EAST)) && (CurrentState->GetLastOperator() != WEST)) {
      TempState = new CState(CurrentState, EAST);
      MainQue.Push(PushSide, TempState);
      Expanded++;
      if(TempState->Solution()) {
       return TempState;
      }
     }

    if((CurrentState->CanBlankMove(SOUTH)) && (CurrentState->GetLastOperator() != NORTH)) {
     TempState = new CState(CurrentState, SOUTH);
     MainQue.Push(PushSide, TempState);
     Expanded++;
     if(TempState->Solution()) {
      return TempState;
     }
    }

    if((CurrentState->CanBlankMove(WEST)) && (CurrentState->GetLastOperator() != EAST)) {
     TempState = new CState(CurrentState, WEST);
     MainQue.Push(PushSide, TempState);
     Expanded++;
     if(TempState->Solution()) {
      return TempState;
     }
    }
   }
  }
  return 0;
}

  下面是主文件"EightPuzz.cpp" 的代碼:

#include"Eightpuzz.h"
int main() {
  char Choice=0;
  cout << "Choose Search Method...\n"
 << " [1] Blind Breadth First Search\n"
 << " [2] Blind Depth First Search\n"
 << " [3] A*(Tiles in the wrong position)\n"
 << " [4] A*(Manhattan Distance)\n" << endl;
  cin >> Choice;
  switch(Choice) {
   case ’1’:
    // call Blind Breadth First Search
    GeneralSearch(BREADTH_FIRST, NOT_USED);
    break;
   case ’2’:
    // call Blind Depth First Search
    GeneralSearch(DEPTH_FIRST, NOT_USED);
    break;
   case ’3’:
    // call A* with wrong tiles heuristic
    GeneralSearch(DEPTH_FIRST, WRONG_TILES);
    break;
   case ’4’:
    // call A* with manhatten heuristic
    GeneralSearch(DEPTH_FIRST, MANHATTAN_DISTANCE);
    break;
  }
  return 0;
}

  正如我前面所說的,還是推薦你看完本文中的代碼,下載程序的源代碼,并用VC打開,仔細看一看整個程序的結(jié)構(gòu)及流程。通過這個例子程序,你應(yīng)該明白,編寫一個AI程序,所需要做的是:

  1、 一個存儲狀態(tài)的方法;

  2、 一個膨脹狀態(tài)的方法;

  3、 一個回退到原始狀態(tài)的方法;

  4、 一個排序狀態(tài)的方法;

  5、 一個給狀態(tài)評分的函數(shù);

  6、 一個主循環(huán),將一個狀態(tài)從鏈表中移出,并將其所有的子狀態(tài)添加到鏈表中;

  上面的每個步驟都很簡單,但將它們組合在一起,并使它易讀易懂卻不那么容易了。
萬企互聯(lián)
標簽: