前两天才接触到了这个游戏,高级难度的迷题快把我逼疯了.错综复杂的逻辑关系像蜘蛛网一样.所心干脆编个解迷的程序..... 这个解迷的思路完全是线性的,等想到好的算法再贴一版....... package queen.ght.shudu.core; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Stack; import java.util.TreeMap; public class NumPanel implements NumChangedListener{ private Grid[][] grids=new Grid[9][9]; /**记录最近的一次操作是从计数集合中的哪个键值取的*/ private int recordCache; private int immutableGridNum=0; /**标识出错误状态,如果按照某种可能性走到某一步发现 * 一个未填数的格子的剩余数字为零,则将此变量置为真*/ private boolean error; /**以格子中剩余数字的指标,对grid进行分类记录的Map*/ private Map<Integer,ArrayList<Grid>> countMap; public NumPanel(int[][] initial){ for(int row=0;row<9;row++){ for(int col=0;col<9;col++){ //Grid grid=new Grid(initial[row][col],new Position(row,col)); Grid grid=new Grid(0,new Position(row,col)); grid.regiesterListener(this); grids[row][col]=grid; } } for(int row=0;row<9;row++){ for(int col=0;col<9;col++){ int value=initial[row][col]; // Position pos=new Position(row,col); Grid grid=grids[row][col]; if(value!=0) grid.putNum(value); //grids[row][col]=grid; //grid.removeNum(value); // initMap(row,value,RowLay); // initMap(col,value,ColLay); // initMap(grid.getPos().getArea(),value,AreaLay); } } countMap=new TreeMap<Integer,ArrayList<Grid>>(); for(int row=0;row<9;row++){ for(int col=0;col<9;col++){ recordCountMap(-1,grids[row][col]); } } printMiddleResult(); } public int[][] puzzle(){ Stack<Grid> runner=new Stack<Grid>(); //Grid last=null; Grid minGrid=pickMinGrid(); while(havantWon()){ runner.push(minGrid); //if(minGrid.getRemainNum()>1) //last=minGrid; minGrid.fillIn(); minGrid.mark(); if(isError()){ printMiddleResult(); minGrid=backToLast(runner); continue; } else printMiddleResult(); minGrid=pickMinGrid(); } printMiddleResult(); return null; } /** * 从计数集合中选取剩余数字最小的一个list,并且 * 从中挑选出一个格子进行填数操作 * @return */ private Grid pickMinGrid() { if(recordCache!=0){ for(int key=recordCache;key<=countMap.keySet().size();key++){ if(countMap.get(key)==null) continue; for(Grid grid:countMap.get(key)){ if(!grid.isImmutable()) return grid; } } }else{ //获取计数集合中的第一个子集合的第一个元素 recordCache=countMap.keySet().iterator().next(); return countMap.get(recordCache).get(0); } return null; } private void printMiddleResult() { for(int i=0;i<9;i++){ for(int j=0;j<9;j++){ System.out.print(grids[i][j].printNumStr()); if(j!=8) System.out.print(","); } System.out.println("/n"); } System.out.println("------------------------昏割线["+immutableGridNum+"]---------------------------"); } private Grid backToLast(Stack<Grid> runner) { Grid top=runner.pop(); if(!top.isMark()){ top.back(); printMiddleResult(); return backToLast(runner); } else{ //minGrid=last; //top.clear(); top.back(); setError(false); return top; } //return top; } private boolean havantWon() { if(immutableGridNum<81) return true; return false; } /** * 根据grid的剩余数字,将grid统计进Map中。剩余数字 * 相同的格子们会被放入一个list中,并且与数字值做成 * 映射 * * @param org 原始计数值 * @param grid 需要被记录的格子 */ private void recordCountMap(int org,Grid grid){ if(countMap==null) return; int key=grid.getRemainNum(); if(org!=-1){ ArrayList<Grid> grids=countMap.get(org); grids.remove(grid); } if(countMap.containsKey(key)){ ArrayList<Grid> grids=countMap.get(key); //不允许重复添加格子 if(!grids.contains(grid)) grids.add(grid); }else{ ArrayList<Grid> grids=new ArrayList<Grid>(); grids.add(grid); countMap.put(key,grids); } } public class Grid { private int value; private Position pos; private List<Integer> nums; private List<Integer> hasBeenTried=new ArrayList<Integer>(); private boolean immutable; /**标志某个格子是否是回滚点*/ private boolean mark=false; /**记录'可能性数字'被移除的轨迹*/ private Stack<Integer> trace=new Stack<Integer>(); //private boolean Error; private List<NumChangedListener> listeners=new ArrayList<NumChangedListener>(); public Grid(int value,Position pos){ this.value=value; this.pos=pos; if(value==0) this.setImmutable(false); else this.setImmutable(true); initNums(); } /** * 判断一个格子是否需要被标记,当格子里的 * 剩余数字大于一个,并且还没有被完全尝试 * 过的情况下,格子才被标记 * @return */ public boolean isRemarkable() { return (getRemainNum()>1)&&(nums.size()>hasBeenTried.size()); } public void removeNum(Integer value) { //如果格子处于未填数的状态,做减少数字处理 if(getValue()==0){ if(nums.remove(value)) trace.push(value); else trace.push(-1); //触发侦听器,重新调整计数map fireListener2(nums.size()+1,this); } //如果发现某个未填数的格子的剩余数字个数为零。 //则说明出现了错误,需要置一下状态 if(nums.size()==0&&!isImmutable()){ setError(true); return; } //每次都判断一下剩余数字最小的格子,对于已经有数的 //的格子就直接跳过去trace // if(minGrid==null) // minGrid=this; // else if(getRemainNum()<=minGrid.getRemainNum()&& // !isImmutable()) // minGrid=this; } private void fireListener2(int org,Grid grid) { for(NumChangedListener listener:listeners){ listener.recount(org,grid); } } public void putNum(Integer value){ this.value=value; setImmutable(true); fireListener(); } private void initNums(){ nums=new ArrayList<Integer>(); nums.addAll(Arrays.asList(1,2,3,4,5,6,7,8,9)); } public int getValue() { return value; } public Position getPos(){ return pos; } public void setImmutable(boolean immutable) { this.immutable = immutable; if(immutable) immutableGridNum++; } public boolean isImmutable() { return immutable; } public void regiesterListener(NumChangedListener listener){ listeners.add(listener); } public void fireListener(){ for(NumChangedListener listener:listeners){ listener.numChanged(pos,value); } } public int getRemainNum(){ return nums.size(); } public void fillIn(){ if(hasBeenTried.size()==0){ putNum(nums.get(0)); hasBeenTried.add(nums.get(0)); return; } //对于已经试完所有数值的格子,下面的代码检测时会 //报错,需要注掉 modified by ganht else if(hasBeenTried.size()==nums.size()){ //setError(true); hasBeenTried.clear(); //如果发现所有数字都已经试过,则需要清除格 //子尝试过的数集.从头来过 add by ganht putNum(nums.get(0)); hasBeenTried.add(nums.get(0)); return; //clear(); } else { for(Integer v:nums){ if(hasBeenTried.contains(v)) continue; else{ putNum(v); hasBeenTried.add(v); return; } } } } // public void setError(boolean error) { // Error = error; // } // // public boolean isError() { // return Error; // } public void clear(){ setError(false); //hasBeenTried.clear(); } public void back(){ //hasBeenTried.remove(Integer.valueOf(value)); for(NumChangedListener listener:listeners){ listener.backToLast(pos,value); } //作撤消处理的时候,需要将格子值清零 //然后再将可变状态置为假 this.value=0; setImmutable(false); //每次回退的时候,都需要对棋局的固定 //棋子数参数作一个调整 immutableGridNum--; if(nums.size()==hasBeenTried.size()) hasBeenTried.clear(); } public void addNum(Integer value){ if(isImmutable()) return; int last=trace.pop(); if(last!=-1){ //这里需要控制,不可以填加重复的数字 if(!nums.contains(value)) nums.add(value); fireListener2(nums.size()-1,this); //需要将该值重新压入轨迹栈 //trace.push(value); } } public String printNumStr(){ if(value==0) return nums.toString(); else return "[*"+value+"]"; } public String toString() { return pos.getRow()+"-"+pos.getCol()+"-"+ pos.getArea()+"-"+value; } /** * */ public void mark() { if(isRemarkable()) this.mark = true; else this.mark=false; } public boolean isMark() { return mark; } } public class Position{ private String row; private String col; private String area; public Position(String row,String col){ this.row=row; this.col=col; this.area=getArea(row,col); } public Position(int row,int col){ this.row=String.valueOf(row); this.col=String.valueOf(col); this.area=getArea(this.row,this.col); } public int getArea(){ return Integer.parseInt(area); } private String getArea(String row, String col) { int _col=Integer.parseInt(col); int _row=Integer.parseInt(row); int area=(_row)/3*3+(_col)/3; return String.valueOf(area); } public boolean equals(Object pos){ if(!(pos instanceof Position)) return false; else{ Position _pos=(Position)pos; if(_pos.area.equals(area)&& _pos.col.equals(col)&& _pos.row.equals(row)) return true; else return false; } } public int hashCode(){ return row.hashCode()+col.hashCode()+area.hashCode(); } public int getRow(){ return Integer.parseInt(row); } public int getCol(){ return Integer.parseInt(col); } } @Override public void numChanged(Position pos,Integer value) { int row=pos.getRow(); int col=pos.getCol(); for(int i=0;i<=8;i++){ grids[row][i].removeNum(value); } for(int i=0;i<=8;i++){ grids[i][col].removeNum(value); } int _row=row/3; int _col=col/3; for(int i=_row*3;i<(_row*3+3);i++){ for(int j=_col*3;j<(_col*3+3);j++){ //对于之前已经移除过的格子就不再做处理 if(i!=row&&j!=col) grids[i][j].removeNum(value); } } } @Override public void backToLast(Position pos, Integer value) { int row=pos.getRow(); int col=pos.getCol(); for(int i=0;i<=8;i++){ grids[row][i].addNum(value); } for(int i=0;i<=8;i++){ grids[i][col].addNum(value); } int _row=row/3; int _col=col/3; for(int i=_row*3;i<(_row*3+3);i++){ for(int j=_col*3;j<(_col*3+3);j++){ //对于之前已经移除过的格子就不再做处理 if(row!=i&&col!=j) grids[i][j].addNum(value); } } } public static void main(String[] args){ int[][] mission=new int[][] {{0,6,0,2,0,0,0,0,8}, {9,3,0,0,5,0,0,0,0}, {0,0,2,0,0,1,3,0,0}, {0,7,0,0,3,0,0,5,6}, {6,0,0,1,0,5,0,0,9}, {5,1,0,0,2,0,0,8,0}, {0,0,6,5,0,0,4,0,0}, {0,0,0,0,1,0,0,6,2}, {3,0,0,0,0,2,0,9,0}}; NumPanel np=new NumPanel(mission); np.puzzle(); } public void setError(boolean error) { this.error = error; } public boolean isError() { return error; } @Override public void recount(int org, Grid grid) { recordCountMap(org, grid); } }