N-Puzzle Game
N-Puzzle 是一種滑塊類推盤游戲,常見的有15-puzzle和8-puzzle。
如下圖所示,由15個方塊和一個空位組成,規則很簡單,移動方塊,讓所有的方塊按照數字的順序排列。
使用Silverlight實現如下:
那么如何使用算法來解決15-puzzle,已得到一個在任意狀態下到達最終按順序排列的一個路徑呢?
IDA*(Iterative Deepening A*) 算法
IDA*是迭代加深的A*算法,深度優先,一次只記錄一條路徑,減少空間需求。
簡單來說,給定一個限定值limit,開始深度優先搜索,當前節點的F()(估值函數)值超過limit時結束,然后每次增加limit,循環迭代搜索直到找到最終路徑。
1. GoalState : 最終按數字順序排列的狀態
2. StartState : 任意打亂順序的開始狀態
3. IsResolved : 判斷當前狀態是否已達到GoalState
4. Manhattan Distance : 對於當前狀態的任一點 P1(X1,Y1),到其值在目標狀態的位置 P2(X2,Y2)的距離, D= Abs(X1-X2) + Abs(Y1-Y2)
算法如下:

1 public class PuzzleNode 2 { 3 public PuzzleNode(int[] state, int blank, PuzzleNode node) 4 { 5 this.state = state; 6 this.BlankPosition = blank; 7 this.parent = node; 8 if (parent != null) 9 cost = parent.Cost + 1; 10 } 11 12 /// <summary> 13 /// The current state 14 /// </summary> 15 /// <returns></returns> 16 public int[] CurrentState() 17 { 18 return state; 19 } 20 21 /// <summary> 22 /// Total cost 23 /// </summary> 24 public int Cost { get { return cost; } } 25 26 /// <summary> 27 /// The position of blank 28 /// </summary> 29 public int BlankPosition { get; set; } 30 31 /// <summary> 32 /// The move from parent to the current node 33 /// </summary> 34 public Direction Direction { get; set; } 35 36 private int[] state; 37 private int cost; 38 private PuzzleNode parent; 39 }

1 public List<PuzzleNode> IDAStar(int[] startboard) 2 { 3 int limit = SearchHelper.Heuristic(root); 4 5 List<PuzzleNode> solution = null; 6 List<PuzzleNode> path = new List<PuzzleNode>(); 7 path.Add(root); 8 while (solution == null) 9 { 10 solution = DepthLimitSearch(limit, path); 11 limit += 1; 12 } 13 14 return solution; 15 } 16 17 private List<PuzzleNode> DepthLimitSearch(int cost, List<PuzzleNode> path) 18 { 19 if (cost >= Int32.MaxValue) 20 throw new ArgumentException("cost over flow"); 21 22 var node = path.Last(); 23 if (IsSolved(node)) 24 { 25 return path; 26 } 27 28 foreach (var child in GetSuccessors(node)) 29 { 30 if (((int)child.Direction + (int)node.Direction != 0) && (SearchHelper.Heuristic(child) + child.Cost) <= cost) 31 { 32 var nextpath = new List<PuzzleNode>(path); 33 nextpath.Add(child); 34 var solution = DepthLimitSearch(cost, nextpath); 35 if (solution != null) 36 { 37 return solution; 38 } 39 } 40 } 41 return null;
我們將數字換成圖片,變成一個拼圖游戲。大家來試一下吧。