练习八数码的一些体会

一。空指针异常问题
1.在工程中,我定义了几个自定义类的数组,在使用数组前,没有实例化,导致应用数组空指针异常
2.直接使用数组加下标代替引用变量,调用类的方法,而没有将引用变量指向某个对象,也没有实例化,导致变量使用异常
3.原来计划是,在进行空格试探性移动时,将动作保留在Num类中,即保证谁的动作归谁,但是在实现是,出现很多问题,导致很小的程序调试时间很长,最终妥协,使用 了一些面向结构的思想来实现

二。构思程序时,片面的希望能完全是面向对象思想的产物,但是个人能力所累,设计的逻辑有很大漏洞,
本来一个数组就解决的事,却被面向对象所累,好多函数共同作用才实现。

编码习惯也存在很多毛病,switch语句中,case快中没有break;
使用太多while语句,导致多次出现无法跳出循环
变成耦合性太强,不注意降低,编程思路是以功能驱动,导致代码又长又乱,修改很费劲

    ``
    package homework.ai;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Iterator;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
/*
 * 八数码入口
 */
public class EightPuzzle implements ActionListener{
    private static int count=0,x=5,y=5; //统计路径输出时已经输出Grid的个数
    JFrame frame ;
    JPanel jPanel;
    JButton ensureButton;
    JButton resetButton;
    JButton fillButton;
    JTextField[][] jTextFields ;
    private void initFrame(){
        //初始化面板
                frame = new JFrame("八数码");
                Toolkit tool = frame.getToolkit();
                Dimension dimension = tool.getScreenSize();
                frame.setBounds( (((int)dimension.getWidth()-200)/2) , (((int)dimension.getHeight()-200)/2) ,200, 200);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                //创建布局管理器
                GridLayout gridLayout = new GridLayout(4,3);
                //初始化面板
                jPanel = new JPanel(gridLayout);
                frame.add(jPanel);
                //在面板中加入文本框,并将文本框保存在一个二维数组中
                jTextFields = new JTextField[4][3];
                for(int i=0; i<3;i++){
                    for(int j=0; j<3; j++){
                        jTextFields[i][j] = new JTextField();
                        jTextFields[i][j].setFont(new Font("楷体",Font.PLAIN,20));
                        jPanel.add(jTextFields[i][j]);
                    }
                }//for
                ensureButton = new JButton("确定");
                ensureButton.addActionListener(this);
                resetButton = new JButton("重置");
                resetButton.addActionListener(this);
                fillButton = new JButton("填充");
                fillButton.addActionListener(this);
                jPanel.add(ensureButton);
                jPanel.add(resetButton);
                jPanel.add(fillButton);
                    frame.setVisible(true);
    }//initFrame    
    //实现按钮监听
    @Override
    public void actionPerformed(ActionEvent e) {
        if(e.getSource()==ensureButton){
            Num[][] nums = new Num[3][3];   //创建nums数组,放置从屏幕中得到的九个数字
            for(int i=0; i<3;i++){
                for(int j=0; j<3; j++){
                        Pattern pattern = Pattern.compile("[1-8]");     //确定每个位置输入的是数字
                        String str = jTextFields[i][j].getText();
                        Matcher isNum = pattern.matcher(str);
                        if( isNum.matches() ){   
                            nums[i][j] = new Num(i, j, Integer.parseInt(str));  //实例化一个Num对象,存入nums数组中
                        }else{   
                            nums[i][j] = new Num(i, j, 0);
                        }
                }
            }//for
            //创建第一个八数码对象,深度为1,得到的方式为空,数组信息是从屏幕获得
            Grid firstGrid = new Grid(1,"", nums,null);
            this.done(firstGrid);   //对八数码进行处理,并将路径输出           
        }else if(e.getSource()==resetButton){   //重置bashuma
            for(int i=0; i<3;i++){
                for(int j=0; j<3; j++){
                    jTextFields[i][j].setText("");              
                }
            }//for
        }else if(e.getSource()==fillButton){//填充八数码
            jTextFields[0][0].setText("1"); 
            jTextFields[0][1].setText("0");
            jTextFields[0][2].setText("3");
            jTextFields[1][0].setText("7");
            jTextFields[1][1].setText("2");
            jTextFields[1][2].setText("4");
            jTextFields[2][0].setText("6");
            jTextFields[2][1].setText("8");
            jTextFields[2][2].setText("5");
        }
    }//actionPerformed  
    //对八数码进行处理
    public void done(Grid fgrid){   
        int steps=0;
        Grid minFnGrid = fgrid;
        Grid gr = fgrid;//临时变量
        boolean equation = true;    
        Vector<Grid> grids = new Vector<Grid>();    //存放所有八数码
        grids.add(fgrid);   //将第一个八数码存放在数组中
        boolean whi=true;
        while(whi){
            steps++;        
            equation = true;    //允许每次遍历,进行一次等于上次最小Fn 的复制
            Iterator<Grid> itr = grids.iterator();
            while(itr.hasNext()){//遍历数组 
                gr = itr.next();    
                if(gr.isLeaf){//如果当前节点是叶子节点
                    minFnGrid = gr; //获取第一个叶子节点
                    break;
                }
            }
            while(itr.hasNext()){//从第一个叶子节点之后遍历数组
                gr = itr.next();
                if(gr.isLeaf){//如果当前节点是叶子节点
                    if(gr.getFn() < minFnGrid.getFn()){
                        minFnGrid = gr; //将当前八数码设置为最小Fn的节点
                    }
                }   
            }//while(itr.hasNext())
            if(minFnGrid.getPn()!=0){//如果不是结果
                //当前所有叶子节点Fn最小的那个节点进行操作
                minFnGrid.move();
                for(int i=0;i<4;i++){   //将移动后得到的新的八数码放在数组中
                    if(minFnGrid.grid4[i]!=null){
                        grids.add(minFnGrid.grid4[i]);
                    }
                }
                            }else{
                //输出结果
                printFrame(minFnGrid);
                JFrame jf = new JFrame();
                //提示结束程序
                int f = JOptionPane.showConfirmDialog(jf, "结果输出完成!!\n"+ "请结束程序","系统提示",
                        JOptionPane.YES_NO_OPTION);
                if( (f==JOptionPane.YES_OPTION)||(f == JOptionPane.NO_OPTION )){
                    System.out.println("\n===================就结束吧!!!=======================");
                }
                whi = false;
            }//else
            //如果操作进行一万步没有得到答案,结束操作
            if(steps>100){
                System.out.println("操作步骤大于步,程序已自动结束,请输入别的八数码!!");
                whi = false;
            }
        }//while
    }//done 
    //输出八数码
    public void printFrame(Grid grid){
        if(grid.fatherCode != null){
                printFrame(grid.fatherCode);
        }
        if(grid != null){
            count=count+1;
            if(count%6==0){ //如果输出框有三十,就换一行
                x=x+200;
                y=5;
            }else if(count==1) {
                y=5;//输出框右移
            }else{
                y+=200;
            }
            JFrame frame1 = new JFrame(String.valueOf(count));
            frame1.setBounds( x ,y  ,200, 200);
            //创建布局管理器
            GridLayout gridLayout = new GridLayout(3,3);
            //初始化面板
            JPanel jPanel1 = new JPanel(gridLayout);
            frame1.add(jPanel1);
            //在面板中加入文本框,并将文本框保存在一个二维数组中
            jTextFields = new JTextField[3][3];
            JTextField ff = new JTextField();
            for(int i=0; i<3;i++){
                for(int j=0; j<3; j++){
                    if(grid.nums[i][j]!=null)
                    ff = new JTextField(String.valueOf(grid.nums[i][j].getValue()));
                    jTextFields[i][j] = ff  ;
                    jPanel1.add(ff);
                    jTextFields[i][j].setFont(new Font("楷体",Font.PLAIN,20));    //设置显示文本样式
                }
            }//for
            frame1.setVisible(true);
        }
    }//printFrame
    public static void main(String[] args) {
        EightPuzzle eightPuzzle = new EightPuzzle();
        eightPuzzle.initFrame();
    }//main 
}
    package homework.ai;
import java.util.Collection;
/*
 * 放置Num的九宫格
 * @cq_cai
 * @11.07.2016
 */
public class Grid {
    int deep=0; //用于指示九宫格所在深度
    String moveType = null; //指示该九宫格是其父节点通过怎样的移动得到的他。防止其在move时变成其父类,造成重复
    boolean isLeaf=true;    //是否是叶子节点   初创的对象默认为叶子节点
    protected Num[][] nums = new Num[3][3] ;    //存放九宫格内的九个Num
    protected Grid[] grid4  ;   //存放由该Grid经过move后得到的Grid
    //辅助型变量
    protected Num[][] exnums ;  //创建新的Grid对象是过渡数组
    private int pRow,pCol;//复制过渡数组exnums时候定位空格坐标
    private int minN=0,maxN=2;//确定Grid大小是3*3
    Grid fatherCode;    
    public Grid() {
        super();
    }
    public Grid(int deep, String moveType, Num[][] nums,Grid fatherCode) {
        super();
        this.deep = deep;
        this.moveType = moveType;
        this.fatherCode = fatherCode;
        this.isLeaf = true;
        this.nums = new Num[3][3];
        for(int i=0; i<3;i++)
            for(int j=0; j<3; j++){
                if(nums[i][j] != null){                 
                    this.nums[i][j] = new Num(i, j, nums[i][j].getValue());
                }
            }
    }//Grid 
    //获取P(n)
    public int getPn(){
        int pn = 0;
        for(int i=0; i<3;i++){
            for(int j=0; j<3; j++){
                switch (this.nums[i][j].getValue()) {
                case 1:{
                        pn+= i + j;
                        break;
                    }
                case 2:{
                        pn +=  i + Math.abs(j-1);
                        break;                  }
                case 3:{
                        pn +=  i + Math.abs(j-2);
                        break;                  }
                case 4:{
                        pn +=  Math.abs(i-1) + Math.abs(j-2);
                        break;              }
                case 5:{
                        pn +=  Math.abs(i-2) + Math.abs(j-2);
                        break;                  }
                case 6:{
                        pn +=  Math.abs(i-2) + Math.abs(j-1);
                        break;
                    }
                case 7:{
                        pn +=  Math.abs(i-2) + j;
                        break;                  }
                case 8:{
                        pn +=  Math.abs(i-1) + j;
                        break;                  }
                default:{
                        pn +=  0;
                        break;                  }
                }//switch
            }
        }//for
        return pn;
    }//getPn
    //获取F(n)
    public int getFn(){
        return this.getPn()+this.deep;  }
    //获取节点属性
    public boolean getIsLeaf(){
        return this.isLeaf; }
    //九宫格进行移动
    public void move(){
        this.isLeaf = false;    //更改为非叶子节点
        //复制过渡数组exnums,并确定空格所在位置
        this.exnums = new Num[3][3];
        this.grid4 = new Grid[4];
        this.deep=this.deep+1;      //深度增加
        for(int i=0; i<3;i++){  
            for(int j=0; j<3; j++){
                if(this.nums[i][j].getValue()==0){  //如果是空格,复制其坐标
                    this.pRow =  i;
                    this.pCol = j;              }
                this.exnums[i][j] = this.nums[i][j];    //复制过渡数组
                            }
        }//for
        /*
         * 对空格的位置进行尝试性移动
         * 根据存留的上一级的移动方式 movetype,避免返回式移动
         */
        //左移空格
        if(this.pCol>this.minN && (this.moveType!= "right")){
            //如果空格不是在最左边界,即它的左边有对象,那他就左移,相当于其左对象右移. 如果它不是由其父节点右移得到,就进行左移
            Num n = this.exnums[this.pRow][this.pCol];
            this.exnums[this.pRow][this.pCol] = this.exnums[this.pRow][this.pCol-1];
            this.exnums[this.pRow][this.pCol-1] =n;
            this.grid4[0] = new Grid(this.deep, "left", this.exnums,this);      }
        /*******************************************************************/
        //每次都要重新复制nums,防止各次i尝试互相影响
        for(int i=0; i<3;i++){
            for(int j=0; j<3; j++){
                this.exnums[i][j] = this.nums[i][j];    //复制过渡数组
            }
        }//for
        //上移空格
        if(this.pRow>this.minN && (this.moveType!= "down")){
            //如果空格不是在最上边界,即它的上边有对象,那他就上移,相当于其上边对象下移.    如果它不是由其父节点下移得到,就进行上移
//          this.nums[this.pRow][this.pCol].moveUp();
//          this.nums[this.pRow-1][this.pCol].moveDown();
            Num n = this.exnums[this.pRow][this.pCol];
            this.exnums[this.pRow][this.pCol] = this.exnums[this.pRow-1][this.pCol];
            this.exnums[this.pRow-1][this.pCol] =n;
            this.grid4[2] = new Grid(this.deep, "up", this.exnums,this);
        }
        /*******************************************************************/
        for(int i=0; i<3;i++){
            for(int j=0; j<3; j++){
                this.exnums[i][j] = this.nums[i][j];    //复制过渡数组
            }
        }//for
        //右移空格
        if(this.pCol<this.maxN && (this.moveType!= "left")){
            //如果空格不是在最右边界,即它的右边有对象,那他就右移,相当于其右边对象左移.    如果它不是由其父节点左移得到,就进行右边
//          this.nums[this.pRow][this.pCol].moveRight();
//          this.nums[this.pRow][this.pCol+1].moveLeft();
            Num n = this.exnums[this.pRow][this.pCol];
            this.exnums[this.pRow][this.pCol] = this.exnums[this.pRow][this.pCol+1];
            this.exnums[this.pRow][this.pCol+1] =   n;
            this.grid4[1] = new Grid(this.deep, "right", this.exnums,this);
        }
        /*******************************************************************/
        for(int i=0; i<3;i++){
            for(int j=0; j<3; j++){
                this.exnums[i][j] = this.nums[i][j];    //复制过渡数组
            }
        }//for
        //下移空格
        if(this.pRow<this.maxN && (this.moveType!= "up")){
//          this.nums[this.pRow][this.pCol].moveDown();
//          this.nums[this.pRow+1][this.pCol].moveUp();
            Num n = this.exnums[this.pRow][this.pCol];
            this.exnums[this.pRow][this.pCol] = this.exnums[this.pRow+1][this.pCol];
            this.exnums[this.pRow+1][this.pCol] =n;
            this.grid4[3] = new Grid(this.deep, "down", this.exnums,this);
        }
    }//move
}//Grid
    package homework.ai;
/*
 * 定义数字块,相当于八数码的数
 */
public class Num {  

    private int value;
    private int maxRow=2,maxCol=2;
    private int minRow=0,minCol=0;  
    public Num( int value) {
        super();
        this.value = value; }   
    //得到数字值
    public int getValue() {
        return value;   }           
    //设置数字值
    public void setValue(int value) {
        this.value = value; }
}

“`

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值