这一期讲一讲我五子棋的互动部分代码设计。做为准备,我们先写一个接口文件DataConfig来存储一些静态数据,如下所示:
// 静态资源
public interface DataConfig{
int LEFT_X = 50;//棋盘左边缘宽度
int LEFT_Y = 50;//棋盘右边缘宽度
int SIZE = 35;//网格的间距 棋子的直径
int ROW = 15;//行数
int CLOUM= 15;//列数
}
随后,我构建了一个交互类GoListener来汇总所有点击方法及情况。先设置一些参数,Graphics g 为绘图必须的图像对象,ifRecord是是否在录制,isPlayback为是否在回放, isAutoversus为是否在人机对战,isAutoturn为在人机对战中是否轮到机器下。将它们设为私有变量,并写点获取方法。
与此同时,设置二维数组 chessArray用于存储棋盘,同时设置下棋标变量chessFlag与之对应,其中0为未下棋或不能下棋状态,1为黑棋,2为白棋。
public class GoListener extends MouseAdapter implements ActionListener, DataConfig{
private Graphics g = null;
private GoBangPanel goPanel;
public void setGraphics(Graphics g){
this.g = g;
}
private int chessFlag = 0;// 0禁止下棋 1黑 2白
private boolean ifRecord = false;
private boolean isPlayback = false;
private boolean isAutoversus = false;
private boolean isAutoturn = false;
public boolean getPlayback(){return isPlayback;};
public boolean getAutoversus(){return isAutoversus;};
public boolean getisAutoturn(){return isAutoturn;};
private int[][] chessArray = new int[ROW + 1][CLOUM + 1];
public int[][] getChessArray(){
return chessArray;
}
public void setChessArray(int[][] newArray){
chessArray=newArray;
}
public void resetChessArray(){
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < CLOUM; j++) {
chessArray[i][j] = 0;
}
}
}
}
接下来,在继承集成书包动作的类MouseAdapter的基础上改写它actionPerformed的方法,即点击按钮后调用的方法。使用e.getActionCommand ()方法可以获取当前按钮的文本,针对每个按钮修改对于的变量,如下所示。
public class GoListener extends MouseAdapter implements ActionListener, DataConfig{
@Override
public void actionPerformed(ActionEvent e){
String action = e.getActionCommand ();
System.out.println ();
JButton btn = (JButton) e.getSource ();
if(action.equals ("开始对局")){
chessFlag = 1;
btn.setText ("结束对局");
} else if(action.equals ("结束对局")){
chessFlag = 0;
btn.setText ("开始对局");
}else if(action.equals ("悔棋")){
goPanel.repaint(g);
}else if(action.equals ("录制")){
ifRecord = true;
goPanel.setChessbefore();//记录当前棋局
}else if(action.equals ("回放")){
isPlayback=true;
goPanel.playback(g);
isPlayback = false;
goPanel.paint(g);
}else if(action.equals ("人机对战")){
// chessFlag = 1;
// resetChessArray();
isAutoversus=true;
}
}
public void setGoPanel(GoBangPanel goPanel){
this.goPanel = goPanel;
}
}
再使通过mousePressed(MouseEvent e)来撰写鼠标点击后使用的方法。通过e.getX ()、e.getY ()可以获取鼠标点击处的横纵坐标,可以通过取余来确定它们要下的位置r、c。这里可以创建一个ChessCheck类,调用vscheck用于判断棋局是否输赢。
public void mousePressed(MouseEvent e){
ChessCheck presentCheck=new ChessCheck(chessArray,chessFlag);
int x = e.getX ();
int y = e.getY ();
int r = (y - LEFT_Y + SIZE / 2) / SIZE;
int c = (x - LEFT_X + SIZE / 2) / SIZE;
// 获取坐标
System.out.println (x + " " + y);
// 检查是否可以下棋
if(!presentCheck.goCheck (x, y)){//若当前棋局已有输赢
return;
}
if(isAutoturn == true){
JOptionPane.showMessageDialog (null, "电脑正在下棋,请等待!");
return;
}
//存储棋子
goPanel.laststep(r,c);
chessArray[r][c] = chessFlag;
if(ifRecord==true){goPanel.record(chessFlag);}
//检查当前落子结果
if(presentCheck.vsCheck (r, c,chessFlag)!=0){
if(chessFlag == 1){
goPanel.paint(g);
JOptionPane.showMessageDialog (null, "比赛结束,黑棋胜!");
} else{
goPanel.paint(g);
JOptionPane.showMessageDialog (null, "比赛结束,白棋胜!");
}
return;
}
if(chessFlag == 1){
// g.setColor (Color.BLACK);
chessFlag = 2;
} else{
// g.setColor (Color.WHITE);
chessFlag = 1;
}
goPanel.paint(g);
}
如果当前状态为人机对战,则可以创建一个ManmachChess类用于电脑自动下棋,如下所示。
//人机对战模式打开,如果人下好,则轮到机器下,机器下:
// 修改chessarray(运行paint绘图)
// 机器下后改轮次变量,改颜色变量,完成。
if(isAutoversus==true){
isAutoturn = true;
try {
ManmachVersus presentVersus=new ManmachVersus(chessArray,chessFlag);
presentVersus.autoVersus();
goPanel.AutoChessarray=presentVersus.getAutoChessarray();
ChessCheck presentautoCheck=new ChessCheck(chessArray,chessFlag);
if(presentautoCheck.vsCheck (presentVersus.maxr, presentVersus.maxc,chessFlag)!=0){
if(chessFlag == 1){
Thread.sleep(1000);
goPanel.paint(g);
Thread.sleep(500);
JOptionPane.showMessageDialog (null, "比赛结束,黑棋胜!");
} else{
Thread.sleep(1000);
goPanel.paint(g);
Thread.sleep(500);
JOptionPane.showMessageDialog (null, "比赛结束,白棋胜!");
}
return;
}
if(chessFlag == 1){
chessFlag = 2;
} else{
chessFlag = 1;
}
Thread.sleep(1000);
goPanel.paint(g);
} catch (InterruptedException i) {
i.printStackTrace();
}
isAutoturn = false;
}
// // 根据行列值 还原标准坐标
// int cx = c * SIZE + LEFT_X - SIZE / 2;
// int cy = r * SIZE + LEFT_Y - SIZE / 2;
// g.fillOval (cx, cy, 35, 35);
综上,该类全代码为:
public class GoListener extends MouseAdapter implements ActionListener, DataConfig{
private Graphics g = null;
private GoBangPanel goPanel;
public void setGraphics(Graphics g){
this.g = g;
}
private int chessFlag = 0;// 0禁止下棋 1黑 2白
private boolean ifRecord = false;
private boolean isPlayback = false;
private boolean isAutoversus = false;
private boolean isAutoturn = false;
public boolean getPlayback(){return isPlayback;};
public boolean getAutoversus(){return isAutoversus;};
public boolean getisAutoturn(){return isAutoturn;};
private int[][] chessArray = new int[ROW + 1][CLOUM + 1];
public int[][] getChessArray(){
return chessArray;
}
public void setChessArray(int[][] newArray){
chessArray=newArray;
}
public void resetChessArray(){
for (int i = 0; i < ROW; i++) {
for (int j = 0; j < CLOUM; j++) {
chessArray[i][j] = 0;
}
}
}
@Override
public void actionPerformed(ActionEvent e){
String action = e.getActionCommand ();
System.out.println ();
JButton btn = (JButton) e.getSource ();
if(action.equals ("开始对局")){
chessFlag = 1;
btn.setText ("结束对局");
} else if(action.equals ("结束对局")){
chessFlag = 0;
btn.setText ("开始对局");
}else if(action.equals ("悔棋")){
goPanel.repaint(g);
}else if(action.equals ("录制")){
ifRecord = true;
goPanel.setChessbefore();//记录当前棋局
}else if(action.equals ("回放")){
isPlayback=true;
goPanel.playback(g);
isPlayback = false;
goPanel.paint(g);
}else if(action.equals ("人机对战")){
// chessFlag = 1;
// resetChessArray();
isAutoversus=true;
}
}
public void mousePressed(MouseEvent e){
ChessCheck presentCheck=new ChessCheck(chessArray,chessFlag);
int x = e.getX ();
int y = e.getY ();
int r = (y - LEFT_Y + SIZE / 2) / SIZE;
int c = (x - LEFT_X + SIZE / 2) / SIZE;
// 获取坐标
System.out.println (x + " " + y);
// 检查是否可以下棋
if(!presentCheck.goCheck (x, y)){
return;
}
if(isAutoturn == true){
JOptionPane.showMessageDialog (null, "电脑正在下棋,请等待!");
return;
}
//存储棋子
goPanel.laststep(r,c);
chessArray[r][c] = chessFlag;
if(ifRecord==true){goPanel.record(chessFlag);}
//检查当前落子结果
if(presentCheck.vsCheck (r, c,chessFlag)!=0){
if(chessFlag == 1){
goPanel.paint(g);
JOptionPane.showMessageDialog (null, "比赛结束,黑棋胜!");
} else{
goPanel.paint(g);
JOptionPane.showMessageDialog (null, "比赛结束,白棋胜!");
}
return;
}
if(chessFlag == 1){
// g.setColor (Color.BLACK);
chessFlag = 2;
} else{
// g.setColor (Color.WHITE);
chessFlag = 1;
}
goPanel.paint(g);
//人机对战模式打开,如果人下好,则轮到机器下,机器下:
// 修改chessarray(运行paint绘图)
// 机器下后改轮次变量,改颜色变量,完成。
if(isAutoversus==true){
isAutoturn = true;
try {
ManmachVersus presentVersus=new ManmachVersus(chessArray,chessFlag);
presentVersus.autoVersus();
goPanel.AutoChessarray=presentVersus.getAutoChessarray();
ChessCheck presentautoCheck=new ChessCheck(chessArray,chessFlag);
if(presentautoCheck.vsCheck (presentVersus.maxr, presentVersus.maxc,chessFlag)!=0){
if(chessFlag == 1){
Thread.sleep(1000);
goPanel.paint(g);
Thread.sleep(500);
JOptionPane.showMessageDialog (null, "比赛结束,黑棋胜!");
} else{
Thread.sleep(1000);
goPanel.paint(g);
Thread.sleep(500);
JOptionPane.showMessageDialog (null, "比赛结束,白棋胜!");
}
return;
}
if(chessFlag == 1){
chessFlag = 2;
} else{
chessFlag = 1;
}
Thread.sleep(1000);
goPanel.paint(g);
} catch (InterruptedException i) {
i.printStackTrace();
}
isAutoturn = false;
}
// // 根据行列值 还原标准坐标
// int cx = c * SIZE + LEFT_X - SIZE / 2;
// int cy = r * SIZE + LEFT_Y - SIZE / 2;
// g.fillOval (cx, cy, 35, 35);
}
public void setGoPanel(GoBangPanel goPanel){
this.goPanel = goPanel;
}
}