小游戏?来做个五子棋玩玩

五子棋应该是所有棋类游戏中规则最简单的一种了,对应着我们写代码,也是最简单,我们今天就来根据学过的知识,写一个五子棋玩一玩。

基本界面

五子棋首先要画出界面,界面其实并不麻烦,但是在画出界面之前,肯定首先需要计算一下,不然脑子里面会完全是乱的.

首先,我们约定整个棋盘是 15 * 15 的大小

其次,棋盘格子和格子之间肯定是有距离的,我们约定,每个格子之间的距离是35

当然为了让棋盘稍微美观一点,我们可以为棋盘加上一点背景色.为了让大家看到的更加直观,整个棋盘的布局,如下图:

1.整个Swing界面的大小

2.棋盘的大小

这里要稍微注意的一点是,这个棋盘是 15 * 15的大小,但是棋盘的格子其实只有14个,所以有线框的部分实际只有 490 * 490 的大小

3.棋盘和Swing边框周围的计算

所以,根据上面的图像,先来编写代码

编写代码

根据面向对象的思想,将代码划分了3个类去编写:
BoardPanel类专门负责画出棋盘
Board类负责画出旗子以及判定胜负
GameFrame类画出主面板

首先来看画出棋盘的类BoardPanel.java,既然专门负责画出棋盘,所以让这个类直接去继承Panel类,然后paint出相应的图像就ok

BoardPanel.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.fivechess;
import javax.swing.*;
import java.awt.*;
public class BoardPanel extends JPanel{
@Override
public void paint(Graphics g) {
g.setColor(new Color(165,185,75));
g.fillRect(35,35,525,525);
g.setColor(Color.BLACK);
//绘制棋盘
for (int i=0; i<15; i++){
g.drawLine(50, 50 + i*35, 540, 50 + i*35);
g.drawLine(50 + i*35, 50, 50 + i*35, 540);
}
//绘制天元(中间的圆点)
g.fillOval(290,290,10,10);
}
}

可以将这个放入到棋盘当如到Swing界面上,编写代码创建GameFrame.java

GameFrame.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class GameFrame extends JFrame{
private JPanel boardPanel;
public GameFrame(){
this.setTitle("五子棋");
this.setSize(700, 600);
this.setResizable(false);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(null);
boardPanel = new BoardPanel();
boardPanel.setBounds(0, 0, 600,600);
this.add(boardPanel);
}
public static void main(String[] args) {
GameFrame tf = new GameFrame();
tf.setVisible(true);
}
}

这样执行代码,一个棋盘就出来了,接下来实现点击出现棋子,而棋子我们需要单独的类来生成,编写Board代码,并将之前的代码稍微修改

Board.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class Board {
private int [][] board = new int[15][15];
public void draw(Graphics g){
for (int i=0; i<board.length; i++){
for (int j=0; j<board[i].length; j++){
if(board[i][j] != 0){ //如果不是空格
if(board[i][j] == 1){ //如果是黑子
g.setColor(Color.BLACK);
}else{ //白子
g.setColor(Color.white);
}
g.fillOval(35*(j+1),35*(i+1),30,30);
//如果是白子,为了好看,给白子加上边框
if(board[i][j] == 2){
g.setColor(Color.BLACK);
g.drawOval(35*(j+1),35*(i+1),30,30);
}
}
}
}
}
/**
* 向棋盘中放置棋子
* @param row 行
* @param col 列
* @param isBlack 黑子还是白子
* @return 落子成功true,失败false(该位置已经有子)
*/
public boolean addPiece(int row, int col, boolean isBlack){
if(board[row][col] == 0){ //没有棋子的地方才能落子
board[row][col] = isBlack?1:2;
return true;
}
return false;
}
}

修改BoardPanel.java文件,加入棋子的绘制

BoardPanel.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.fivechess;
import javax.swing.*;
import java.awt.*;
public class BoardPanel extends JPanel{
private Board b = null;
public BoardPanel(Board b) {
this.b = b;
}
@Override
public void paint(Graphics g) {
g.setColor(new Color(165,185,75));
g.fillRect(35,35,525,525);
g.setColor(Color.BLACK);
//绘制棋盘
for (int i=0; i<15; i++){
g.drawLine(50, 50 + i*35, 540, 50 + i*35);
g.drawLine(50 + i*35, 50, 50 + i*35, 540);
}
//绘制天元(中间的圆点)
g.fillOval(290,290,10,10);
//绘制棋子
b.draw(g);
}
}

修改GameFrame.java代码,加入鼠标点击事件和相应的判断

GameFrame.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package com.fivechess;
import javax.swing.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class GameFrame extends JFrame{
private boolean isBlack = true; //是否黑子 true黑子 false白子
private JPanel boardPanel;
private Board b = new Board();
public GameFrame(){
this.setTitle("五子棋");
this.setSize(700, 600);
this.setResizable(false);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(null);
boardPanel = new BoardPanel(b);
boardPanel.setBounds(0, 0, 600,600);
//在boardPanel下棋需要执行点击事件
boardPanel.addMouseListener(new MouseHandle());
this.add(boardPanel);
}
private class MouseHandle extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
int x = e.getX();
int y = e.getY();
//点击事件必须在棋盘内
if( x >= 50 && x<= 540 && y>=50 && y<=540) {
//通过鼠标坐标计算出点击棋盘的行或者列
int row = Math.round((y - 50) / 35F);
int col = Math.round((x - 50) / 35F);
if (b.addPiece(row, col, isBlack)) {
//刷新页面
repaint();
//黑白子轮流下棋,每次进行替换
isBlack = !isBlack;
}
}
}
}
public static void main(String[] args) {
GameFrame tf = new GameFrame();
tf.setVisible(true);
}
}

这样,我们就可以再棋盘上落子了,只是还不能判断输赢而已

所以接下来,我们在棋子类中加入判断输赢的代码

Board.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
package com.fivechess;
import java.awt.*;
public class Board {
private int [][] board = new int[15][15];
/**
* 绘制棋盘
* @param g
*/
public void draw(Graphics g){
for (int i=0; i<board.length; i++){
for (int j=0; j<board[i].length; j++){
if(board[i][j] != 0){ //如果不是空格
if(board[i][j] == 1){ //如果是黑子
g.setColor(Color.BLACK);
}else{ //白子
g.setColor(Color.white);
}
g.fillOval(35*(j+1),35*(i+1),30,30);
//如果是白子,为了好看,给白子加上边框
if(board[i][j] == 2){
g.setColor(Color.BLACK);
g.drawOval(35*(j+1),35*(i+1),30,30);
}
}
}
}
}
/**
* 向棋盘中放置棋子
* @param row 行
* @param col 列
* @param isBlack 黑子还是白子
* @return 落子成功true,失败false(该位置已经有子)
*/
public boolean addPiece(int row, int col, boolean isBlack){
if(board[row][col] == 0){ //没有棋子的地方才能落子
board[row][col] = isBlack?1:2;
return true;
}
return false;
}
public boolean isWin(int row, int col, boolean isBlack){
return checkH(row,col,isBlack) || checkV(row, col, isBlack)
|| checkX1(row, col, isBlack) || checkX2(row, col, isBlack);
}
/**
* 从右斜线判断是否连成5颗
* @param row 行
* @param col 列
* @param isBlack 黑子还是白子
* @return 是否获胜
*/
public boolean checkX2(int row, int col, boolean isBlack){
int count = 1;
int currentRow = row;
int currentCol = col;
int v = isBlack ? 1 : 2;
//从左下到右上判断
while(currentRow > 0 && currentCol < 14
&& board[--currentRow][++currentCol] == v){
count ++;
}
currentRow = row;
currentCol = col;
//从右上到左下判断
while(currentRow < 14 && currentCol > 0
&& board[++currentRow][--currentCol] == v){
count ++;
}
return count >= 5;
}
/**
* 从左斜线判断是否连成5颗
* @param row 行
* @param col 列
* @param isBlack 黑子白子
* @return 是否获胜
*/
public boolean checkX1(int row, int col, boolean isBlack){
int count = 1;
int currentRow = row;
int currentCol = col;
int v = isBlack ? 1 : 2;
//从右下到左上判断
while(currentRow > 0 && currentCol > 0
&& board[--currentRow][--currentCol] == v){
count ++;
}
currentRow = row;
currentCol = col;
//从左上到右下判断
while(currentRow < 14 && currentCol < 14
&& board[++currentRow][++currentCol] == v){
count ++;
}
return count >= 5;
}
/**
* 竖线判断是否连成5颗
* @param row
* @param col
* @param isBlack
* @return
*/
public boolean checkV(int row, int col, boolean isBlack){
int count = 1;
int currentRow = row;
int currentCol = col;
int v = isBlack ? 1 : 2;
//从上到下判断
while(currentRow < 14
&& board[++currentRow][currentCol] == v){
count ++;
}
currentRow = row;
currentCol = col;
//从下到上判断
while(currentRow > 0
&& board[--currentRow][currentCol] == v){
count ++;
}
return count >= 5;
}
/**
* 横向判断是否连成5颗
* @param row
* @param col
* @param isBlack
* @return
*/
public boolean checkH(int row, int col, boolean isBlack){
int count = 1;
int currentRow = row;
int currentCol = col;
int v = isBlack ? 1 : 2;
//从左到右判断
while(currentCol < 14
&& board[currentRow][++currentCol] == v){
count ++;
}
currentRow = row;
currentCol = col;
//从右到左判断
while(currentCol > 0
&& board[currentRow][--currentCol] == v){
count ++;
}
return count >= 5;
}
public void clearBoard(){
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[i].length; j++) {
board[i][j] = 0;
}
}
}
}

这里修改Board.java代码其实主要就是加上了输赢判断,要判断输赢,就是判断横,输,左斜,右斜是否连续是一个颜色并且连成5个

最后在GameFrame.java中加入相应的代码和点击开始游戏的按钮

GameFrame.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package com.fivechess;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class GameFrame extends JFrame {
private boolean isBlack = true; //是否黑子
private Board b = new Board(); //棋盘对象
private boolean isWin = false; //是否胜利
private boolean isStart = false; //是否开始
private class MouseHandle extends MouseAdapter{
@Override
public void mousePressed(MouseEvent e) {
if(isStart && !isWin){
int x = e.getX();
int y = e.getY();
//点击事件必须在棋盘内
if( x >= 50 && x<= 540 && y>=50 && y<=540){
//通过鼠标坐标计算出点击棋盘的行或者列
int row = Math.round((y - 50) / 35F);
int col = Math.round((x - 50) / 35F);
if(b.addPiece(row,col,isBlack)){
repaint();
isWin = b.isWin(row,col,isBlack);
if(!isWin){
isBlack = !isBlack;
}else{
JOptionPane.showMessageDialog(null,
isBlack ? "黑子胜" : "白子胜");
btnStartGame.setEnabled(true);
}
}
}
}
}
}
private JPanel boardPanel;
private JButton btnStartGame;
private JLabel lblStatus;
public GameFrame() {
this.setTitle("五子棋");
this.setSize(700, 600);
this.setResizable(false);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(null);
//测试显示每次鼠标点击的坐标
lblStatus = new JLabel("~~~~");
lblStatus.setBounds(580, 200, 150,50);
boardPanel = new BoardPanel(b);
boardPanel.setBounds(0, 0, 600,600);
//在boardPanel下棋需要执行点击事件
boardPanel.addMouseListener(new MouseHandle());
/**测试坐标位置*/
boardPanel.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
lblStatus.setText("坐标 x:" + e.getX() + ",y:"+e.getY());
}
});
btnStartGame = new JButton("开始游戏");
btnStartGame.setBounds(580,100,100,35);
//点击开始游戏,初始化变量
btnStartGame.addActionListener(new AbstractAction() {
public void actionPerformed(ActionEvent e) {
isStart = true; //开始游戏
isWin = false; //开始游戏之后还没有输赢
btnStartGame.setEnabled(false); //点击之后按钮不可用
b.clearBoard(); //清空界面,实际就是将数组所有值设置为0
repaint(); //刷新页面
}
});
this.add(lblStatus);
this.add(boardPanel);
this.add(btnStartGame);
}
public static void main(String[] args) {
GameFrame gf = new GameFrame();
gf.setVisible(true);
}
}