继上周实现了C++控制台版的五子棋之后,这周开始学习Java,顺便花了两三天时间,做出了一直想做的图形化界面的五子棋小游戏。同时在原来C++控制台程序的基础上对AI的算法进行了一定修正,修复了一些bug,并加入了悔棋的功能
C++五子棋系列传送门:
C++之简单五子棋的设计思路
C++之简单五子棋的语言设计实现
C++简单五子棋的AI设计及实现
五子棋的算法规则和类的设计在C++相关中讲过了,所以现在主要总结一下如何转成图形化界面。由于第一次接触java,顶层设计做的不是很好,还是带有浓厚的面向过程的设计风格,勉强合格吧。
效果如下
界面主要使用swing组件搭建,具体如下:
MyChessBoard :面板类,继承JPanel类。主要用来实现存储棋盘信息,记录下棋过程和显示棋局。考虑到各个组件都要对棋盘进行操作,所以对棋局进行记录操作的相关函数和变量均设为静态类成员。具体包括:
- 存储棋盘信息的15*15二维数组chess[][],用0代表空,1代表白,2代表黑;
- 记录最近两步走棋信息的2*2二维数组lastChess[][],用于悔棋;
- 悔棋操作函数reDo(),将lastChess数组中存储的坐标处的棋子标记为空,然后调用repaint()进行重绘;
- 标志棋盘是否为空的布尔变量isEmpty
- 负责接收坐标,更新棋盘信息的函数record(int,int);
- clearBoard()函数负责对棋盘进行清除,并初始化相关变量;
除此之外,在构造函数中对各变量进行初始化,lastChess[][]初始化为全变量-1,有棋子落子时在record函数里对其进行更新,采用队列的数据结构,存储落子的坐标。
重写父类的paintComponent用来完成棋盘和棋子的绘制。
setChess(int,int,int)函数用来接收鼠标点击的坐标和当前所下的棋子颜色,通过点击坐标计算出落子坐标,调用record函数进行记录,调用repaint函数进行重绘。
//面板,用来打印15*15的棋盘和当前在棋盘上的棋子,提供一个15*15的int数组,标记每个节点处的棋子状态
class MyChessBoard extends JPanel{
protected BufferedImage bg = null;
static public int[][] chess ;//0为空,1为白,2为黑
static protected int [][] lastChess = {
{-1,-1},{-1,-1}};
static protected boolean isEmpty = true;
static public void record(int x,int y) {
lastChess[1][0] = lastChess[0][0];
lastChess[1][1] = lastChess[0][1];
lastChess[0][0] = x;
lastChess[0][1] = y;
ChessGame.reserve();
MyControlBoard.redo = false;
MyControlBoard.undo.setText("Undo");
isEmpty = false;
}
// default constructor
public MyChessBoard(){
super();
lastChess[0][0] = -1;
lastChess[0][1] = -1;
lastChess[1][0] = -1;
lastChess[1][1] = -1;
chess = new int[15][15];
for(int i =0;i < 15;i++) {
for(int j = 0;j < 15;j++) {
chess[i][j] = 0;
}
}
try {
bg = ImageIO.read(new File("D:\\administrator-\\Documents\\eclipse-workspace\\practice\\src\\Windows\\renju.png"));
}catch(Exception e) {
e.printStackTrace();
}
repaint();
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(new Color(222,184,135));
Graphics2D g1 = (Graphics2D)g;
//add background
g1.drawImage(bg, 0, 0,getWidth(),getHeight(), null);
//draw chess board
g1.setColor(Color.red);
BasicStroke seg = new BasicStroke(2,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
g1.setStroke(seg);
int width = getWidth();
int height = getHeight();
int vgap = height/16;
int hgap = width/16;
for(int i = 1;i<16;i++) {
g1.drawLine(hgap, i*vgap, 15*hgap, i*vgap);
g1.drawLine(i*hgap,vgap , i*hgap, 15*vgap);
}
//draw chess
int chessWidth = hgap*3/4;
int chessHeight = vgap*3/4;
for(int i = 0;i < 15;i++) {
for(int j = 0;j < 15;j++) {
if(chess[i][j] == 2) {
g1.setColor(Color.BLACK);
g1.fillOval((1+j)*hgap-chessWidth/2,(1+i)*vgap-chessHeight/2,chessWidth, chessHeight);