最近在写五子棋,悔棋部分遇到了点问题,本来想的是落子以后趁此时在鼠标监听器中得到的坐标 x = e.getX(); y = e.getY();
还没被覆盖,点击悔棋按钮后,再把储存坐标的二维数组中这个坐标的值清零,然后调用重绘方法处理。没错这个确实可以实现,但是就不能多次悔棋。比如我想悔两步,就不能实现了,因为我不知道上上步下在哪个地方。
没错,我还得用某个方法储存每一步的落子位置才行。我就必须知道第几步有哪两个坐标,要有顺序,还要有坐标。
对象数组方法
首先就想起可以用以前用过的对象数组。
先建一个 Position 类,有两个坐标属性:
public class Position {
int listi;
int listj;
}
在主界面获取一个大于总格子数的对象数组防止溢出:
public class chessUI extends JPanel {
public Position[] ps = new Position[300];
int counti; //计数
}
在落子步骤后,每落一个棋子,将坐标按顺序存入对象数组:
Position p = new Position(); //如果不先创建Position对象会报空指针
ui.ps[ui.counti]=p;
ui.ps[ui.counti].listi = xp;
ui.ps[ui.counti].listj = yp;
ui.counti++; //每存一次计数+1
这样每一步的坐标都按顺序存入这个对象数组了,悔棋的时候只要把最后存入的那个数组坐标取出,然后在存坐标的二维数组中将该坐标位置清零,调用重绘方法就行了。
if(counti>0){ //判断是否有棋子
int x = ui.ps[ui.counti-1].listi;//取出前一步的x
int y = ui.ps[ui.counti-1].listj;//取出前一步的y
ui.point[x][y]=0; //让二维数组这个坐标清零
ui.counti--; //计数-1
if (turn==1){turn++;} //回到上一轮
else {turn--;}
ui.repaint(); //重绘
}
else{
JOptionPane.showMessageDialog(null, "不能悔棋!");
}
总体上看和我之前写的画图板通过存入取出对象数组中的数据,实现图形大小调节重绘的方法差不多。
数组队列方法
其实我刚开始就用的数组队列的方法写的,因为前两天刚刚接触这个东西,用到这里也刚刚好。
数组队列(ArrayList)类也是用来储存对象, 与数组不同,数组一旦创建,长度固定,但是数组队列的长度是动态的,不受限制,可以存储任意多的对象,但是只能存储对象,不能存储原生数据类型例如int
。
因为数组队列存入多少个数据长度就是多少,所以就不用专门弄个计数器。直接用list.size();
方法就能得到长度了。
建一个 ChessPosition 类,里面有两个坐标属性(这里用的构造器传入坐标,用其他方法也行):
public class ChessPosition {
public int Listi,Listj;
public ChessPosition() {
}
public ChessPosition(int Listi,int Listj) {
this.Listi=Listi;
this.Listj=Listj;
}
}
在主界面获取一个 ArrayList 类的对象 ChessPositonList:
public class chessUI extends JPanel {
public ArrayList<ChessPosition> ChessPositonList=new ArrayList<ChessPosition>();
}
<ChessPosition>
是泛型,表示这个数组队列只能存储 ChessPosition 类的对象。
在落子步骤后,每落一个棋子,将棋子坐标存入 ChessPosition 类然后用list.add();
方法存入数组队列:
ui.ChessPositonList.add(new ChessPosition(xp,yp));
悔棋的时候,通过 list.remove();
方法,取出前一步的对象的同时将它从数组队列里移除。然后在存坐标的二维数组中将该坐标位置清零,调用重绘方法就行了。
这里如果用list.get();
方法,那么只将它取出来却没有移除,再次悔棋就不起作用了。
if (ui.ChessPositonList.size() >0){ //判断是否有棋子
//取出前一步的 ChessPositon
ChessPosition cp = new ChessPosition();
cp = ui.ChessPositonList.remove(ui.ChessPositonList.size()-1);
//让二维数组这个坐标清零
ui.point[cp.Listi][cp.Listj]=0;
if (turn==1){turn++;} //回到上一轮
else {turn--;}
ui.repaint(); //重绘
}
else{
JOptionPane.showMessageDialog(null, "不能悔棋!");
}
我觉得这种时候用 ArrayList 比较好吧,因为落子数量不一定,数组队列可以动态变化长度,增删都比较方便。
刚开始写这篇博客是想通过悔棋操作来归纳总结 ArrayList 用法的,结果自己试着又把通过对象数组悔棋写出来了(虽然觉得可以,但是开始写这篇博客的时候没想过要真的来实现的)。
那就干脆把这篇写成了两种方法的对比和实现了(捂脸