人工智能之八數碼難題

推薦閱讀:web

八數碼難題:33的9個方格中有1到8的整數,並用0表示空白格。非0數字能夠向與之相鄰的空白格(即0的位置)移動,同時空白格向這個數字原來的位置移動。經過若干步的移動,將33方格中的數字排列在指定的位置。用prolog寫代碼,求解八數碼難題。app

題目中的意思咱們用數學的方式表示出來:svg

初始狀態爲:
1 2 3
4 5 6
0 7 8編碼

目標狀態爲:
2 3 0
1 4 5
7 8 6.net

對於這個問題咱們來做以下分析:
(1)能夠用列表來表達一個八數碼狀態,例如[0 1 2 3 4 5 6 7 8 ]表示的數碼狀態是:0 1 2 是第一行,3 4 5是第二行,6 7 8是第三行。33的方格序號(即位置)按照行編碼,因此列表[0 1 2 3 4 5 6 7 8 ]中數的序號分別是1 2 3 4 5 6 7 8 9。用謂詞write_array_list(integer)輸出列表形式的狀態爲3*3形式,即每輸出3個數就換行。設計

(2)用謂詞list_same(integer*,integer*)來比較2個列表是否相同,用來判斷狀態轉移是否到達最終目標code

(3)用謂詞swap(integer*,integer,integer, integer*)來實現0(即空格)和某個相鄰數字的交換。Swap的第1個參數是交換前的列表,第4個參數是交換後的列表,第二、3個參數表明要交換的2個數的序號(即位置)。例如[0 1 2 3 4 5 6 7 8 ]中,序號一、 2的數0和1能夠交換;序號1 、4的數0和3能夠交換;由於沒有空格,序號二、3的數1和2不能交換;由於不相鄰,序號一、7的數0和6不能交換。xml

(4) 爲了實現swap,要設計根據序號對列表進行取值、賦值的謂詞。blog

(5)設計謂詞findZeroPosition,找到列表中空格的序號(0的位置),已知空格序號後,其周圍哪些位置的數能夠交換就肯定了。例如當空格序號爲5時,空格能夠和序號爲二、四、六、8的數進行交換。遞歸

(6)核心規則是move(linelist,linelist,integer):-…swap…move ….
規則左邊的move第1個參數爲列表表達的當前狀態,第2個參數爲列表表達的目標狀態,第3個參數是深度,move規則每遞歸1次,深度減1,要求深度大於等於0。設置深度是爲了不無心義的狀態轉移,例如在[0 1 2 3 4 5 6 7 8 ]中,序號一、2對應的數0和1能夠交換,交換後1和0又能夠交換,這種無盡交換沒有價值,經過設置深度來淘汰這種交換。規則的右邊move是左邊move的下一個狀態。右邊的move以前,應該檢測空格序號(0的位置),隨後肯定空格能夠與哪些序號交換,而後調用swap進行交換,最後是對交換後的列表(即新狀態)遞歸move。

(7)設置move遞歸的終止條件。寫一條move規則判斷是否已經到達最終目標,即判斷move中的第一、2個參數表明的列表是否相等。
move(linelist,linelist,integer)

(8)到達目標後設計輸出狀態序列的輸出。

代碼實現以下:

DOMAINS
  integerlist=integer*
PREDICATES
	write_array_list(integerlist)%輸出序列
	list_same(integerlist,integerlist)%比較兩個狀態是否相等
	nondeterm findZeroPosition(integerlist,integer)%找出0的位置
	swap(integerlist,integer,integer,integerlist)%交換兩個位置的值,併成爲一個新的表
	get(integerlist,integer,integer)%得到要交換的位置的值
	set(integerlist,integer,integer,integerlist)%給要交換的位置復賦值
	nondeterm move(integerlist,integerlist,integer,integerlist)%與0位置交換,併成爲新的表
	nondeterm value(integer,integer)%獲取能夠與0交換的位置
	compareSL(integerlist,integerlist)%判斷當前狀態是否在狀態序列中
	append(integerlist,integerlist,integerlist)%將兩個表合成一個新的表	
	writeSL(integerlist)%輸出狀態序列
CLAUSES
	append([], List, List).  
	append([X|L1], List2, [X|L3]) :-
	append(L1, List2, L3).
	
	writeSL([]):-!.
	writeSL([X1,X2,X3,X4,X5,X6,X7,X8,X9|SL]):-write(X1),write(""),write(X2),write(""),write(X3),write(""),nl,
						write(X4),write(""),write(X5),write(""),write(X6),write(""),nl,
						write(X7),write(""),write(X8),write(""),write(X9),write(""),nl,nl,writeSL(SL).


	compareSL(L,[]).
	compareSL([X1,X2,X3,X4,X5,X6,X7,X8,X9],[Y1,Y2,Y3,Y4,Y5,Y6,Y7,Y8,Y9|_]):-X1=Y1,X2=Y2,X3=Y3,X4=Y4,X5=Y5,X6=Y6,X7=Y7,X8=Y8,X9=Y9,!,fail.
	compareSL(L,[X1,X2,X3,X4,X5,X6,X7,X8,X9|SL]):-compareSL(L,SL).
	
	write_array_list([]).%輸出列表
	write_array_list([X,Y,Z|L]):-write(X),write(""),write(Y),write(""),write(Z),nl,write_array_list(L).
	
	list_same([],[]):-!.
	list_same([X|L1],[Y|L2]):-X=Y,list_same(L1,L2).%比較列表是否相同
	
	findZeroPosition([0|L],X):-X=1,!.
	findZeroPosition([H|L],X):-findZeroPosition(L,X1),X=X1+1.
		
	value(1,2).value(1,4).
	value(2,1).value(2,3).value(2,5).
	value(3,2).value(3,6).
	value(4,1).value(4,5).value(4,7).
	value(5,2).value(5,4).value(5,6).value(5,8).
	value(6,3).value(6,5).value(6,9).
	value(7,4).value(7,8).
	value(8,5).value(8,7).value(8,9).
	value(9,6).value(9,8).
	
	swap(L1,X,Y,L2):-get(L1,X,X1),get(L1,Y,Y1),set(L1,X,Y1,L22),set(L22,Y,X1,L2).
	
	get([X|_],1,X):-!.
	get([X|Y],A,B):-A1=A-1,get(Y,A1,B).
	
	set([X|Y],1,B,[B|Y]):-!.
	set([X|L1],A,B,[X|L2]):-A1=A-1,set(L1,A1,B,L2).
	
	move(L1,L2,X,SL):-list_same(L1,L2),
			writeSL(SL),!.
	move(L1,L2,X,SL):- X>=0,
			findZeroPosition(L1,ZERO),
			value(ZERO,Y),
			swap(L1,ZERO,Y,L11),
			compareSL(L11,SL),append(SL,L11,SL2),
			X1=X-1,			
			move(L11,L2,X1,SL2).
	
GOAL
	move([1,2,3,4,5,6,0,7,8],[2,3,0,1,4,5,7,8,6],7,[1,2,3,4,5,6,0,7,8]).