1 importjava.io.BufferedReader;2 importjava.io.FileNotFoundException;3 importjava.io.FileReader;4 importjava.io.IOException;5 importjava.util.ArrayList;6 importjava.util.Arrays;7 importjava.util.Collections;8 importjava.util.Scanner;9
10 @SuppressWarnings("rawtypes")11 public class EightPuzzle implementsComparable{12 private int[] num = new int[9];13 private int depth; //当前的深度即走到当前状态的步骤
14 private int evaluation; //从起始状态到目标的最小估计值
15 private int misposition; //到目标的最小估计
16 private EightPuzzle parent; //当前状态的父状态
17 public int[] getNum() {18 returnnum;19 }20 public void setNum(int[] num) {21 this.num =num;22 }23 public intgetDepth() {24 returndepth;25 }26 public void setDepth(intdepth) {27 this.depth =depth;28 }29 public intgetEvaluation() {30 returnevaluation;31 }32 public void setEvaluation(intevaluation) {33 this.evaluation =evaluation;34 }35 public intgetMisposition() {36 returnmisposition;37 }38 public void setMisposition(intmisposition) {39 this.misposition =misposition;40 }41 publicEightPuzzle getParent() {42 returnparent;43 }44 public voidsetParent(EightPuzzle parent) {45 this.parent =parent;46 }47
48 /**
49 * 判断当前状态是否为目标状态50 *@paramtarget51 *@return
52 */
53 public booleanisTarget(EightPuzzle target){54 returnArrays.equals(getNum(), target.getNum());55 }56
57 /**
58 * 求f(n) = g(n)+h(n);59 * 初始化状态信息60 *@paramtarget61 */
62 public voidinit(EightPuzzle target){63 int temp = 0;64 for(int i=0;i<9;i++){65 if(num[i]!=target.getNum()[i])66 temp++;67 }68 this.setMisposition(temp);69 if(this.getParent()==null){70 this.setDepth(0);71 }else{72 this.depth = this.parent.getDepth()+1;73 }74 this.setEvaluation(this.getDepth()+this.getMisposition());75 }76
77 /**
78 * 求逆序值并判断是否有解79 *@paramtarget80 *@return有解:true 无解:false81 */
82 public booleanisSolvable(EightPuzzle target){83 int reverse = 0;84 for(int i=0;i<9;i++){85 for(int j=0;jnum[i])87 reverse++;88 if(target.getNum()[j]>target.getNum()[i])89 reverse++;90 }91 }92 if(reverse % 2 == 0)93 return true;94 return false;95 }96 @Override97 public intcompareTo(Object o) {98 EightPuzzle c =(EightPuzzle) o;99 return this.evaluation-c.getEvaluation();//默认排序为f(n)由小到大排序
100 }101 /**
102 *@return返回0在八数码中的位置103 */
104 public intgetZeroPosition(){105 int position = -1;106 for(int i=0;i<9;i++){107 if(this.num[i] == 0){108 position =i;109 }110 }111 returnposition;112 }113 /**
114 *115 *@paramopen 状态集合116 *@return判断当前状态是否存在于open表中117 */
118 public int isContains(ArrayListopen){119 for(int i=0;i
127 *128 *@return小于3的不能上移返回false129 */
130 public booleanisMoveUp() {131 int position =getZeroPosition();132 if(position<=2){133 return false;134 }135 return true;136 }137 /**
138 *139 *@return大于6返回false140 */
141 public booleanisMoveDown() {142 int position =getZeroPosition();143 if(position>=6){144 return false;145 }146 return true;147 }148 /**
149 *150 *@return0,3,6返回false151 */
152 public booleanisMoveLeft() {153 int position =getZeroPosition();154 if(position%3 == 0){155 return false;156 }157 return true;158 }159 /**
160 *161 *@return2,5,8不能右移返回false162 */
163 public booleanisMoveRight() {164 int position =getZeroPosition();165 if((position)%3 == 2){166 return false;167 }168 return true;169 }170 /**
171 *172 *@parammove 0:上,1:下,2:左,3:右173 *@return返回移动后的状态174 */
175 public EightPuzzle moveUp(intmove){176 EightPuzzle temp = newEightPuzzle();177 int[] tempnum = (int[])num.clone();178 temp.setNum(tempnum);179 int position = getZeroPosition(); //0的位置
180 int p=0; //与0换位置的位置
181 switch(move){182 case 0:183 p = position-3;184 temp.getNum()[position] =num[p];185 break;186 case 1:187 p = position+3;188 temp.getNum()[position] =num[p];189 break;190 case 2:191 p = position-1;192 temp.getNum()[position] =num[p];193 break;194 case 3:195 p = position+1;196 temp.getNum()[position] =num[p];197 break;198 }199 temp.getNum()[p] = 0;200 returntemp;201 }202 /**
203 * 按照八数码的格式输出204 */
205 public voidprint(){206 for(int i=0;i<9;i++){207 if(i%3 == 2){208 System.out.println(this.num[i]);209 }else{210 System.out.print(this.num[i]+" ");211 }212 }213 }214 /**
215 * 反序列的输出状态216 */
217 public voidprintRoute(){218 EightPuzzle temp = null;219 int count = 0;220 temp = this;221 while(temp!=null){222 temp.print();223 System.out.println("----------分割线----------");224 temp =temp.getParent();225 count++;226 }227 System.out.println("步骤数:"+(count-1));228 }229 /**
230 *231 *@paramopen open表232 *@paramclose close表233 *@paramparent 父状态234 *@paramtarget 目标状态235 */
236 public void operation(ArrayList open,ArrayListclose,EightPuzzle parent,EightPuzzle target){237 if(this.isContains(close) == -1){238 int position = this.isContains(open);239 if(position == -1){240 this.parent =parent;241 this.init(target);242 open.add(this);243 }else{244 if(this.getDepth()
254 @SuppressWarnings("unchecked")255 public static voidmain(String args[]){256 //定义open表
257 ArrayList open = new ArrayList();258 ArrayList close = new ArrayList();259 EightPuzzle start = newEightPuzzle();260 EightPuzzle target = newEightPuzzle();261
262 //BufferedReader br = new BufferedReader(new FileReader("./input.txt") );
263 String lineContent = null;264 int stnum[] = {2,1,6,4,0,8,7,5,3};265 int tanum[] = {1,2,3,8,0,4,7,6,5};266 int order = 0;267 try{268 BufferedReader br;269 br = new BufferedReader(new FileReader("input.txt") );270 while((lineContent=br.readLine())!=null){271 String[] str = lineContent.split(",");272 for(int i = 0 ;i
276 tanum[i] =Integer.parseInt(str[i]);277 }278 order++;279 }280 } catch(NumberFormatException e) {281 System.out.println("请检查输入文件的格式,例如:2,1,6,4,0,8,7,5,3 换行 1,2,3,8,0,4,7,6,5");282 e.printStackTrace();283 } catch(IOException e) {284 System.out.println("当前目录下无input.txt文件。");285 e.printStackTrace();286 }287 start.setNum(stnum);288 target.setNum(tanum);289 long startTime=System.currentTimeMillis(); //获取开始时间
290 if(start.isSolvable(target)){291 //初始化初始状态
292 start.init(target);293 open.add(start);294 while(open.isEmpty() == false){295 Collections.sort(open); //按照evaluation的值排序
296 EightPuzzle best = open.get(0); //从open表中取出最小估值的状态并移除open表
297 open.remove(0);298 close.add(best);299 if(best.isTarget(target)){300 //输出
301 best.printRoute();302 long end=System.currentTimeMillis(); //获取结束时间
303 System.out.println("程序运行时间: "+(end-startTime)+"ms");304 System.exit(0);305 }306 intmove;307 //由best状态进行扩展并加入到open表中308 //0的位置上移之后状态不在close和open中设定best为其父状态,并初始化f(n)估值函数
309 if(best.isMoveUp()){310 move = 0;311 EightPuzzle up =best.moveUp(move);312 up.operation(open, close, best, target);313 }314 //0的位置下移之后状态不在close和open中设定best为其父状态,并初始化f(n)估值函数
315 if(best.isMoveDown()){316 move = 1;317 EightPuzzle up =best.moveUp(move);318 up.operation(open, close, best, target);319 }320 //0的位置左移之后状态不在close和open中设定best为其父状态,并初始化f(n)估值函数
321 if(best.isMoveLeft()){322 move = 2;323 EightPuzzle up =best.moveUp(move);324 up.operation(open, close, best, target);325 }326 //0的位置右移之后状态不在close和open中设定best为其父状态,并初始化f(n)估值函数
327 if(best.isMoveRight()){328 move = 3;329 EightPuzzle up =best.moveUp(move);330 up.operation(open, close, best, target);331 }332
333 }334 }else
335 System.out.println("没有解,请重新输入。");336 }337
338 }