1. 程式人生 > >Programming Assignment 4: 8 Puzzle

Programming Assignment 4: 8 Puzzle

img 節點數 分析 boa 二維數組 人工智 流行 處理 resource

題目:Programming Assignment 4: 8 Puzzle

1. 問題翻譯

這回讀題讀的頭大~~(英語差吃虧了)~~,我就先按照自己的理解寫下題目的翻譯,再寫重述性質的內容。

使用A*算法編寫一個程序解決各種類型的數字推盤遊戲。

問題。數字推盤遊戲是Noyes Palmer Chapman在1870年發明的一個十分流行的謎題。遊戲在一個3×3的網格上進行,包括擁有有1到8標簽的8個方塊和一個空白塊。你的目標時用最小的移動,重排這些方塊,使得方塊有序。你被允許橫向或縱向滑動方塊到空白快。下圖展示了一個從初始推盤(左側)到目標推盤(右側)的合法移動序列。

技術分享圖片

最優搜索。現在我們描述一種叫做A*搜索算法的通用人工智能方法。我們定義一個推盤為搜索節點,到達此推盤所要經歷的移動數目和其前一個搜索節點。首先,插入初始搜索節點(初始搜索節點,0移動,前一個搜索節點為null)進入優先隊列。然後,刪除優先隊列中優先權最低的節點,然後將這個優先權最低的節點的所有鄰居節點(從此節點通過一次移動可以到達的搜索節點)插入到優先隊列中。重復這個步驟,直到從優先隊列中刪除的節點為目標節點是停止。這個方法的成功取決於如何為搜索節點選擇優先函數。我們考慮兩種優先函數。

  • Hamming優先函數。在錯誤位置的塊加上到目前塊位置所經歷的移動。直觀上,一個擁有少的錯誤位置塊的搜索節點將更靠近目標,並且我們期望一個搜索節點能用少的移動到達目的。
  • Manhattan優先函數。從當前推盤到目標推盤各個塊的曼哈頓距離(到達目標點的橫向和縱向距離和)距離和,加上到當前搜索節點的移動距離。

例如,下圖初始搜索節點的Hamming和Manhattan優先權分別為5和10。

技術分享圖片

讓我們來看一看。一個給定的搜索點優先隊列求解這個問題,我們需要去移動的總的移動數目(包括已經走的)至少是使用Hamming或Manhattan計算的優先權(對於Hamming優先權,因為錯誤的塊至少需要一次移動才能到達目標位置,所以是對的。對於Manhattan優先權,因為沒有個塊必須移動曼哈頓距離才能到達目標位置,所以是對的。註意,我們計算Hamming和Manhattan優先權是不計算空白塊)。因此,當目標塊出隊時,我們找到的不僅僅是從初始塊到目標塊的路線,也是最短移動路線。(挑戰:數學證明)

關鍵優化。最有搜索喲路一個惱人的特性:搜索節點和其相同的節點被入隊許多次。為了減少不必要的無用搜索節點,當考慮搜索節點的鄰居時,不要將與前一次搜索節點相同的鄰居節點入隊。

技術分享圖片

第二個優化。為了避免在許多優先隊列操作中重新計算搜索節點的Manhattan優先權,在構造搜索節點時就計算,將他保存在一個實例變量中,然後在需要時返回保存的值。這項緩存技術是官方使用的:當你需要重新大量計算相同的數和計算量是瓶頸是可以使用。

博弈樹。博弈樹是觀看計算過程的一個方法。在博弈樹中,每一個搜索節點是一個博弈樹節點,並且其子節點和其鄰居搜索節點相同。博弈樹的跟節點是初始搜索節點;內部節點已經被處理;葉節點被加入到優先隊列;每一步,A*算法將從優先隊列中移出最小優先權的節點並且處理它(通過將它的子節點加入到博弈樹和優先級隊列中)。

技術分享圖片

檢測不可解謎題。並不是所有的初始節點都可以通過一系列的合法移動求出目標節點,包括以下兩種情況。

技術分享圖片

為了檢測這些情況,使用以下兩個事實,推盤被分為兩個等價的種類(use the fact that boards are divided into two equivalence classes with respect to reachability: )。其一,通向目標節點的,其二,那些通過交換初始節點任何塊(不包括空白塊)通向目標節點的。(挑戰:數學上證明)。為了應用這個事實,在兩個謎題實例上運行A*算法,一個初始推盤,一個在初始推盤上交換過塊的推盤(one with the initial board modified by swapping a pair of blocks—in lockstep (alternating back and forth between exploring search nodes in each of the two game trees).)。其中一個將會到達目標。

剩下的都是關於如何代碼API、性能需求、邊角案例等的,就不翻譯了。

2. 問題重述

自己重新寫一下翻譯之後,發現基本如何實現已經寫清楚了。。當時英語看的迷迷糊糊的,挺多實現還是自己想的。哎。

通過程序實現一個數字推盤遊戲,推盤有n*n個塊,其中有一個空白塊,其他塊擁有1到n^2-1的編號。空白塊邊上的塊可以通過水平或垂直移動移到空白塊,最終使推盤內部編號有序排列。

具體實現方法如題目中所說,首先,建立一個搜索節點的數據結構,其中包含當前塊,移動到當前塊的上一個塊,移動到當前塊總共經歷的移動次數。其次,每次列出當前搜索節點能夠變化的鄰居節點,然後將其中與前一次搜索節點不同的鄰居塊加入到一個優先隊列。最後,將優先隊列中優先權最小的搜索節點移出優先塊,作為搜索節點。循環直到找到目標有序推盤。

這裏優先權的計算有兩種方法,具體見題目。

分析

有兩個類需要實現,Board類和Solver。

1. Board類

Board類用來表示一個推盤。推盤包括一些重要的數據,推盤的維數、推盤的hamming,Manhattan、推盤是否到達目標。這裏為了記錄空白塊位置,還加入了兩個整形來記錄空白塊。

Board構造函數,為了記錄傳遞過來的二維數組,這裏建立了一個二維數組成員,期望拷貝傳遞的二維數組。但是發現java的clone函數不能的拷貝二維數組,所以就自己實現了一個函數,用來拷貝二維數組。

計算hamming,就是遍歷整個推盤,如果所在位置的數值和預想值不同,則hamming加一。

計算Manhattan,遍歷整個推盤,計算推盤所在位置數值的行和列與預想的行和列的差值。這裏記得差值要取絕對值。

生成雙胞胎推盤,按照題目的要求,這裏需要生成一個只交換兩個塊的雙胞胎推盤。翻譯的時候發現,好像題目是期望你將推盤第一個和最後一個非空給交換。我采用的方法是將推盤左上角,右上角,左下角其中非空的兩個交換。最開始是將第一行的前三個交換,但是如果維度小於3就失敗了,然後選擇了這個交換方法。

判斷相等函數。參考書上的例子,首先判斷輸入是不是自己,是的話相等。第二,判斷輸入是否為空,為空則不等。第三,判斷兩個對象是不是同一種類,如果不是則不等。第四,將輸入對象朱鹮為Board類,判斷類中的維度,hamming,Manhattan是否相等。我本來以為這種情況就相等了,但是仔細想了想,這些相等也不一定等,下圖的例子就是不等的。如果這三個值有不等的,則認為不等。最後,將兩個Board類的塊一個一個比較,判斷是否相等。

技術分享圖片

2.Solver類

SearchNode類。這個類記錄搜索節點數據,按照題目要求,應該包含當前塊,移動到當前塊的上一個塊,移動到當前塊總共經歷的移動次數。我還添加了優先級的記錄。

構造函數中,根據初始節點構造兩個搜索節點,一個使用初始節點,一個使用初始節點的雙胞胎節點。然後按照問題重述中的循環搜索目標節點,直到這兩個節點其中一個找到目標節點為止。若可解,根據當前搜索節點向前搜索,構造求解順序,最後記得將初始節點加上。

Programming Assignment 4: 8 Puzzle