一。空指针异常问题
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; }
}
“`