我们分3个大步骤来实现:
1. 在窗体上画棋盘、画棋子(棋子在网格交点、交替落子)
2. 判断输赢,即寻找是否在同一直线上有5子相邻
3. 人机大战
前2个步骤就可以实现基础的人人对战,让我们开始吧
1.在窗体上画棋盘、画棋子
首先,我们需要一个窗体,设置好名称,合适的大小,添加鼠标的监听器,之后设置其可见。
然后再画棋盘,我们可以根据棋盘的行列数、间隔,算出棋盘大小。你想让棋盘显示在什么位置,就算好每一根线的起止点的坐标,使用g.drawRect将其画出就好了。当然,一根根画肯定很麻烦,也可以使用循环来添加所有的线(将在源码中演示这种做法)。
最后实现绘制棋子。我们使用g.fillOval很容易的实现在鼠标按下位置绘制棋子。但是绘制的棋子怎么在交点上,还有在后面判断输赢中和重绘中都需要再次使用棋子坐标该怎么办呢。
在此我们将整个棋盘的交点集,看成一个二维数组或者矩阵。每下一颗棋,就将棋子的颜色信息,保存到矩阵对应的位置中去。之后再将矩阵中的每一个棋子画在棋盘上。
还有一些小细节,比如黑白棋子要交替落子,不能在同个地方重复落子等,一起在代码中讲解吧。
public class FiveChessFrame extends JFrame implements MouseListener {
//棋子坐标
int x = 0;
int y = 0;
//演示棋盘为16*16,所以需要16*16的二维数组来保存所有棋子的颜色信息
//0表示没有棋子,1表示黑子,2表示白子,默认为0没有棋子
int[][] allChess = new int [16][16];
//标识下一步黑白棋,black or white,true为黑棋
boolean b_w = true ;
//设置窗体
public FiveChessFrame() {
this.setTitle("五子棋");
this.setSize(1600,1400);
this.setLocationRelativeTo(null);
this.setResizable(false);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.addMouseListener(this);
this.setVisible(true);
}
//重写JFrame中的paint方法
public void paint(Graphics g) {
super.paint;//调用JFrame中的paint方法,继承原有功能
Graphics2D g2d=(Graphics2D)g;将画笔转换为2D,可以设置划线粗细
//使用for循环绘制棋盘,根据窗体的大小设置棋盘大小
//演示中棋盘左上角x,y为275,175,右下角1325,1225,间距70
for(int i = 0;i<16;i++) {
g2d.setColor(Color.BLACK);
g2d.setStroke(new BasicStroke(3));//调整画笔粗细
g2d.drawLine(275, 175+70*i, 1325, 175+70*i);
g2d.drawLine(275+70*i, 175, 275+70*i, 1225);
}
//画棋子的部分建议先看下文鼠标按下如何保存坐标
//根据保存在二维数组中的棋子颜色信息,画出棋子
//使用for循环,遍历二维数组中的每一个数的颜色信息
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 16; j++) {
if (allChess[i][j]== 1) {
//根据数组保存坐标时相反的运算,算出棋子在棋盘上的坐标
int X = i * 70 + 275;
int Y = j * 70 + 175;
g2.fillOval(X-30, Y-30, 60, 60);//椭圆工具以x y 坐标为原点绘制,如果想使绘制的图形出现在鼠标点击的地方,x需要偏移半个宽度,y需要偏移半个高度
}
if (allChess[i][j]== 2) {
int X = i * 70 + 275;
int Y = j * 70 + 175;
g2.setColor(Color.WHITE);
g2.fillOval(X-30, Y-30, 60, 60);//白色棋子为白底黑边
g2.setColor(Color.BLACK);
g2.drawOval(X-30, Y-30, 60, 60);
}
}
}
}
public void mouseClicked (MouseEvent e) {
}
public void mousePressed (MouseEvent e) {
System.out.println("X "+e.getX());
System.out.println("Y "+e.getY());
//鼠标按下获取xy坐标
x = e.getX();
y = e.getY();
//限制仅在棋盘上按下有效
if (x >= 275 && x <= 1325 && y >= 175 && y <= 1225 ) {
//在数组中x坐标 = (x按下坐标-左边与窗体的距离)/ 线间隔
//得到的小数会自动转成整数,对应棋盘图中0,1,2……
//因为小数部分会被截断,而不会四舍五入,所以x按下坐标再向右偏移半个线间隔
//x坐标 = (x按下坐标+半个线间隔-左边与窗体的距离)/ 线间隔
x = (x - 240) / 70;
y = (y - 140) / 70;
//先判断此处有没有棋子
if(allChess[x][y]== 0) {
//判断棋子颜色 如果是黑方在落子,就在对应数组的xy坐标上保存颜色信息1
if(b_w == true) {
allChess[x][y] = 1;
//然后改变为白方落子,实现双方交替落子
b_w = false;
}else {
allChess[x][y] = 2;
b_w = true;
}
}
}
this.repaint();//每次落子后,需要调用重绘,将所有棋子画在棋盘上。
}
小结 第一步的核心思想:先将棋子颜色信息保存在二维数组对应的坐标中,再遍历数组,将所有的棋子绘制出。
2.判断输赢
五子棋的判断输赢很简单,就是判断在一条线上有么有相邻的5个同颜色的棋子
如图所示,每个棋子都有横、竖、左