用Java写一个简易五子棋游戏

 一. 程序基本思路:

1.写窗口、棋盘面板、控制面板;

2.绘制棋盘;

3.绘制棋子;

4.添加组件功能;

5.判断输赢;

6.悔棋;

7.复盘。

二.实际操作

1.创建窗口、添加面板

package teachGoBang;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class GoBang {
	public void drawUI() {
		JFrame jf = new JFrame("五子棋");//创建窗口
		jf.setSize(980,900);//设置窗口大小
		jf.setLocationRelativeTo(null);//居中显示
		jf.setDefaultCloseOperation(3);//设置窗口后台关闭
		jf.setLayout(new BorderLayout());//将窗体设为边框布局
		
		JPanel chesspanel = new JPanel();//创建棋盘对象
		jf.setBackground(Color.WHITE);//设置棋盘颜色
		jf.add(chesspanel,BorderLayout.CENTER);//将面板添加到窗体中间
		Mouse mouse = new Mouse();//创建鼠标对象
		//直接在面板后创建鼠标对象便于对象在类之间的传递
		
		JPanel buttonpanel = new JPanel();//创建操控面板
		buttonpanel.setBackground(Color.GRAY);//设置棋盘颜色
		buttonpanel.setPreferredSize(new Dimension(180,900));//设置控制面板大小
		jf.add(buttonpanel,BorderLayout.EAST);//将面板添加到窗体右侧布局
		
		String[] button = {"开始","人机","悔棋","认输","复盘"};//创建按钮数组
		for(int i=0;i<button.length;i++) {
			JButton jbu = new JButton(button[i]);//创建按钮对象,并赋给其数组值
			jbu.setPreferredSize(new Dimension(160,100));//设置按钮大小
			jbu.setFont(new Font("思源宋体",Font.BOLD,18));//设置按钮字体
			buttonpanel.add(jbu);//给操控面板添加按钮组件
			jbu.addActionListener(mouse);//给按钮添加鼠标监听器
			
		}
		jf.setVisible(true);//设置窗体课件
		mouse.setGraphics(chesspanel.getGraphics());//创建画笔对象并传递给Mouse类
		chesspanel.addMouseListener(mouse);//给棋盘添加鼠标监听器
	}
	public static void main(String[]args) {
		GoBang go = new GoBang();
		go.drawUI();
	}

}

效果图:

 2.绘制棋盘

  为了棋盘线在窗体刷新后仍能保存,我们直接重写chesspanel的paint方法,将棋盘绘制写在paint方法中。为了调用方便,我们先写一个接口,用于保存绘制棋盘要用的数据。

package teachGoBang;

public interface Basic {
	public int x0 = 50, y0 = 50, size = 50, line = 15;
	//x0,y0围棋盘线的起始点,size为行距,line为行数
}
package teachGoBang;

import java.awt.Graphics;

import javax.swing.JPanel;
//写一个MyPanel类继承类,重写paint方法
public class MyPanel extends JPanel implements Basic{
	public void paint(Graphics g) {
		super.paint(g);//先将父类自带的paint方法再写一遍
		for (int i = 0; i < line; i++) {
			g.drawLine(x0, y0 + i * size, x0 + (line - 1) * size, y0 + i * size);
			g.drawLine(x0 + i * size, y0, x0 + i * size, y0 + (line - 1) * size);
		}
	}
}

同时要记得将先前的chesspanel对象的类名改为MyPanel

MyPanel chesspanel = new MyPanel();//创建棋盘对象

效果图

 3.绘制棋子

  棋子绘制写在鼠标类中,通过鼠标点击位置获取棋子坐标。绘制后的棋子要保存到数组中,然后在MyPanel类的paint方法中再绘制一次棋子,完成已绘制棋子的保存。

package teachGoBang;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import lqz3.Chess;

//在鼠标类中直接去继承MouseAdapter类而不是使用接口可以不用重写所有方法
public class Mouse extends MouseAdapter implements ActionListener, Basic {
	private Graphics g;// 定义画笔
	private int x, y, x1, y1;
	private int[][] chessArr = new int[line][line];// 定义二维数组,用于保存棋盘坐标对应的棋子颜色
	private int count = 0;// 定义计数器记录棋子个数
	private Color color;

	public void setGraphics(Graphics g) {
		this.g = g;
	}
    public int[][] getchessArr(){
		return chessArr;
	}

	public void actionPerformed(ActionEvent e) {

	}

	public void mouseClicked(MouseEvent e) {
		int x = e.getX();// 鼠标点击处获取x、y坐标
		int y = e.getY();
		// 获取落子坐标,此处进行判断让获取的坐标位于棋盘线交点处
		if ((x - x0) % size > size / 2) {
			x1 = (x - x0) / size + 1;

		} else if ((x - x0) % size <= size / 2) {
			x1 = (x - x0) / size;

		}

		if ((y - y0) % size > size / 2) {
			y1 = (y - y0) / size + 1;

		} else if ((y - y0) % size <= size / 2) {
			y1 = (y - y0) / size;

		}

		// 判断棋子是否会越出棋盘界
		if (0 <= x1 && x1 <= 14 && 0 <= y1 && y1 <= 14) {
			// 判断只有空位置才能下棋
			if (chessArr[y1][x1] == 0) {
				// 加for循环是为了给棋子添加3D效果
				for (int i = 0; i < 50; i++) {
					// count为双数下黑棋,为单数下白棋
                    //下完黑棋在数组中存入1,白棋存入-1
					if (count % 2 == 0) {
						color = new Color(5 * i, 5 * i, 5 * i);// 3d效果
						g.setColor(color);// 设置画笔颜色
						g.fillOval(x1 * size + x0 + i / 2 - 25, y1 * size + y0 + i / 2 - 25, 50 - i, 50 - i);
						chessArr[y1][x1] = 1;// 记录棋盘上每颗棋子的颜色(实际是记入1、-1)

					} else {
						color = new Color(155 + 2 * i, 155 + 2 * i, 155 + 2 * i);
						g.setColor(color);
						g.fillOval(x1 * size + x0 + i / 2 - 25, y1 * size + y0 + i / 2 - 25, 50 - i, 50 - i);
						chessArr[y1][x1] = -1;

					}

				}
				count++;//每下完一颗棋,计数器加1
			} 
		}else {
				System.out.print("超出棋盘边界");
		}

	}

}

接下来要在MyPanel的paint方法中重绘棋子。先在两个类中写set和get方法,再将chessArr数组传递到MyPanel类中,由于GoBang类中同时出现chesspanel和mouse对象,因此在GoBang中传递该数组。为了防止MyPanel中出现重绘棋盘时要用到chessArr数组而chessArr数组还没传过来的情况发生,我们直接在创建chesspanel对象后就把数组传过去

  Mouse mouse = new Mouse();//创建鼠标对象
  chesspanel.setchseeArr(mouse.getchessArr());//传递数组
public void paint(Graphics g) {
		super.paint(g);// 先将父类自带的paint方法再写一遍
		//绘制棋盘
		for (int i = 0; i < line; i++) {
			g.drawLine(x0, y0 + i * size, x0 + (line - 1) * size, y0 + i * size);
			g.drawLine(x0 + i * size, y0, x0 + i * size, y0 + (line - 1) * size);
		}
		//绘制棋子
		for (int i = 0; i < chessArr.length; i++) {
			for (int j = 0; j < chessArr[0].length; j++) {
				int chesscolor = chessArr[i][j];//取出棋子颜色对应的值
				if (chesscolor != 0) {
					if (chesscolor == 1) {//下黑棋
						for (int a = 0; a < 50; a++) {
							g.setColor(new Color(5 * a, 5 * a, 5 * a));
							g.fillOval(j * size + x0 + a / 2 - 25, i * size + y0 + a / 2 - 25, 50 - a, 50 - a);
						}
					} else {//下白棋
						for (int a = 0; a < 50; a++) {
							g.setColor(new Color(155 + 2 * a, 155 + 2 * a, 155 + 2 * a));
							g.fillOval(j * size + x0 + a / 2 - 25, i * size + y0 + a / 2 - 25, 50 - a, 50 - a);

						}
					}

				}

			}
		}

	}

效果图

 此步骤重点有:用计数器单双决定棋色、棋子要下在交点处、用二维数组保存棋色对应值、传递二维数组、实现棋子重绘。

4.添加组件功能

   我们先写“开始”和“认输”这两个功能。

开始:

在鼠标类中

private String button;
private boolean start=false;//定义布尔值,点击开始后start=true,判断输赢后start=false

在下棋前加入判断条件 

//下棋前添加判断条件:是否按了“开始”
if (start == true) {
	// 判断棋子是否会越出棋盘界
	if (0 <= x1 && x1 <= 14 && 0 <= y1 && y1 <= 14) {

点击开始后要要清空棋盘,因此我们在Mouse类中写一个清空棋盘的方法。

为此我们要将chesspanel对象传入Mouse类中:

private boolean start = false;// 定义布尔值,点击开始后start=true,判断输赢后start=false
private MyPanel chesspanel;
//通过构造方法,传入chesspanel
public Mouse(MyPanel chesspanel) {
    this.chesspanel = chesspanel;
}

在GoBang类创建mouse对象时传入chesspanel

Mouse mouse = new Mouse(chesspanel);//创建鼠标对象,并传入chesspanel

接着在Mouse中写一个clean方法:

public void clean() {
//遍历二维数组,让所有棋子颜色归零
	for(int i=0;i<chessArr.length;i++) {
		for(int j=0;j<chessArr[i].length;j++) {
			chessArr[i][j] = 0;
		}
	}
	//执行重绘方法,除去所有棋子
	chesspanel.paint(g);
}

最后对应按钮功能

public void actionPerformed(ActionEvent e) {
	button = e.getActionCommand();// 按钮内容对应鼠标点击信息
	switch (button) {
	case "开始"://点击开始
		clean();// 清空棋盘
		count = 0;//计数器清零
		start = true;// 允许开始
        break;
	}
}

认输:

这里的“认输”功能我们采用点击按钮后弹出窗口显示游戏结束的做法,并且点击“认输”按钮后不能再下棋。我们直接写一个end方法。


// 输出游戏结束面板
public void end() {
    //创建窗体    
	JFrame jy = new JFrame();
	jy.setSize(500, 500);
	jy.setLocationRelativeTo(null);
	jy.setDefaultCloseOperation(3);
    //设置流动布局
	jy.setLayout(new FlowLayout());
    //添加标签,载入图片
	JLabel jla = new JLabel(new ImageIcon("D:\java\java\10.16五子棋(游戏结束.png"));
    //设置标签大小
	jla.setPreferredSize(new Dimension(500, 500));
	jy.add(jla);
	jy.setVisible(true);

}
case "认输":
    end();//弹出面板
	start = false;//不能再下棋
	break;

5.判断输赢

由于判断输赢代码量较大,我们直接新建一个Win类,在该类中写判断输赢的方法。

同样需要把chessArr传入Win类

public class Win {
	private int[][] chessArr;//定义chessArr数组
	//构造方法初始化chessArr数组
	public Win(int[][] chessArr) {
		this.chessArr = chessArr;
	}
}
private boolean start = false;// 定义布尔值,点击开始后start=true,判断输赢后start=false
private MyPanel chesspanel;
Win win = new Win(chessArr);//创建win对象并传入chessArr

判断输赢的思路是:分为水平、竖直、左上-右下、右上-左下四条轴写四个方法,每条轴又分正负两个方向;每条轴设定一个计数器,通过for循环遍历同方向棋子,当棋子同色,计数器+1,最后返回计数器的值,当计数器大于等于5时,决出胜负。

// 判断水平方向
	public int countchessX(int x1, int y1) {
		int chess = 1;// 设置计数器记录同色棋子
		// 往右侧方向
		for (int i = x1 + 1; i < chessArr.length; i++) {
			if (chessArr[y1][x1] == chessArr[y1][i]) {
				chess++;// 如果右侧棋子同色,则计数器加1

			} else {// 不同色则退出循环
				break;
			}
		}
		// 往左侧方向
		for (int i = x1 - 1; i >= 0; i--) {
			if (chessArr[y1][x1] == chessArr[y1][i]) {
				chess++;

			} else {
				break;
			}
		}

		return chess;// 返回chess值用于判断输赢

	}

	// 判断竖直方向
	public int countchessY(int x1, int y1) {
		int chess = 1;

		for (int i = y1 + 1; i < chessArr.length; i++) {
			if (chessArr[y1][x1] == chessArr[i][x1]) {
				chess++;

			} else {
				break;
			}
		}
		for (int i = y1 - 1; i >= 0; i--) {
			if (chessArr[y1][x1] == chessArr[i][x1]) {
				chess++;

			} else {
				break;
			}
		}

		return chess;

	}

	// 判断左上、右下方向
	public int countchessM(int x1, int y1) {
		int chess = 1;
		// 右下方向
		for (int i = x1 + 1, j = y1 + 1; i < chessArr.length && j < chessArr.length; i++, j++) {
			if (chessArr[y1][x1] == chessArr[j][i]) {
				chess++;

			} else {
				break;
			}
		}
		// 左上方向
		for (int i = x1 - 1, j = y1 - 1; i >= 0 && j >= 0; i--, j--) {
			if (chessArr[y1][x1] == chessArr[j][i]) {
				chess++;

			} else {
				break;
			}

		}

		return chess;

	}

	// 判断右上、左下方向
	public int countchessN(int x1, int y1) {
		int chess = 1;
		// 右上方向
		for (int i = x1 + 1, j = y1 - 1; i < chessArr.length && j >= 0; i++, j--) {
			if (chessArr[y1][x1] == chessArr[j][i]) {
				chess++;
			} else {
				break;
			}
		}
		// 左下方向
		for (int i = x1 - 1, j = y1 + 1; i >= 0 && j < chessArr.length; i--, j++) {
			if (chessArr[y1][x1] == chessArr[j][i]) {
				chess++;
			} else {
				break;
			}
		}

		return chess;

	}

	// 判断输赢
	public int checkwin(int x1, int y1) {

		if (countchessX(x1, y1) >= 5 || countchessY(x1, y1) >= 5 || countchessM(x1, y1) >= 5
				|| countchessN(x1, y1) >= 5) {

			// 用最后下的棋子的颜色判断谁输谁赢。
			if (chessArr[y1][x1] == 1) {//最后下黑棋

				return 1;//返回1

			} else if (chessArr[y1][x1] == -1) {//最后下白棋
				return -1;//返回-1

			}

		}

		return 0;
	}

在Mouse类中写一个判断输赢的方法,每下完一颗棋执行一次该方法。

    public void checkwin() {
		//如果以满足胜负条件
		if(win.checkwin(x1, y1)==1||win.checkwin(x1, y1)==-1) {
			end();//执行结束游戏方法
		}
	}

		}
		count++;// 每下完一颗棋,计数器加1
		checkwin();//每下完一颗棋,判断一次输赢
	} 

6.悔棋

悔棋思路:先创建一个棋子类存入棋子对象的坐标、颜色,再创建一个一维数组按顺序存入一个个棋子对象,接着写一个悔棋方法:每点击一次悔棋,就找出数组中最末位棋子对应的坐标,取出该坐标带入chessArr并令其等于0,然后刷新面板出去该棋子。

package teachGoBang;

import java.awt.Color;
//创建棋子类
public class ChessR {
	public int x1,y1;
	public Color color;
//构造方法初始化参数
	public ChessR(int x1,int y1,Color color) {
		this.x1 = x1;
		this.y1 = y1;
		this.color = color;
	}

}
private int[][] chessArr = new int[line][line];// 定义二维数组,用于保存棋盘坐标对应的棋子颜色
private ChessR[] chessB =new ChessR[line*line]; //定义一维数组存入棋子对象
        ChessR chess = new ChessR(x1,y1,color);//创建棋子对象存入棋子数值
        chessB[count] = chess;//以count为下标存入棋子对象
        count++;// 每下完一颗棋,计数器加1
        checkwin();//每下完一颗棋,判断一次输赢
   
    } 
// 悔棋方法
	public void regret() {
		if (count > 0) {//添加判断,有棋子时才能悔棋
			ChessR chessR = chessB[--count];// 取出数组中最后一颗棋子
			int x = chessR.x1;// 取出该棋子对应的x、y值
			int y = chessR.y1;
			chessArr[y][x] = 0;// 清空该棋子对应位置
			chesspanel.paint(g);
		}
	}

7.复盘

复盘的本质是棋子的重绘,我们在复盘前先清空前,然后设置时间间隔,通过paint方法依次绘出所下的棋子。

// 复盘方法
	public void repeat() {
		for (int i = 0; i < count; i++) {
			ChessR chess = chessB[i];// 通过循环,正序取出棋子
			// 设置棋子重绘时间间隔
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {

				e.printStackTrace();
			}
			//顺序双数绘黑棋,单数绘白棋
			if(i%2==0) {
				chessArr[chess.y1][chess.x1] = 1;
			}else {
				chessArr[chess.y1][chess.x1] = -1;
			}
            chesspanel.paint(g);//绘制棋子
		}
	     count = 0;//计数器清零
	}

以上就是用java写一个简单的五子棋程序的全过程,下一章将在五子棋中加入人机对战的功能。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>