【java GIUI】人机对弈五子棋

在学校的Java课程中,我们被分配了一项有趣的任务:开发一款能够实现人机对弈的五子棋游戏。为了更好地理解Java GUI的运用,并与大家分享学习心得,我将整个开发过程记录在这篇博客中。欢迎大家阅读并提供宝贵的意见和建议!”

python版五子棋(讲解的更详细)

)编辑

1.绘制棋盘

)编辑

1.定义myPanel类。

myPanel相当于画板。

myPanel要继承 JPanel类,并要覆盖父类的paint方法,在paint方法里面写负责绘画的代码

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
java复制代码
public class myPanel extends JPanel {
static final int start = 6;
@Override
public void paint(Graphics g)
{
//调用父类的paint初始化画笔
super.paint(g);
//绘制背景
DrawBackground(g);
//绘制外边框
DrawBorder(g);
//绘制棋盘
DrawChessBoard(g);

}
public void DrawBackground(Graphics g)
{ //绘制背景
g.setColor(new Color(211, 152, 91));
g.fillRect(0, 0, 620,620);

}
public void DrawBorder(Graphics g)
{
//绘制外边框
g.setColor(Color.BLACK);
g.fillRect(5,5,610,5);
g.fillRect(610,5,5,610);
g.fillRect(5,610,610,5);
g.fillRect(5,5,5,610);
}

public void DrawChessBoard(Graphics g)
{
g.setColor(Color.BLACK);
//画横线
for (int i = 0; i < 19; i++) {
g.drawLine(6+i*32,6,6+i*32,614);
}
//画竖线
for (int i = 0; i < 19; i++) {
g.drawLine(6,6+i*32,614,6+i*32);
}

}
//画棋子
public void DrawChess(Graphics g,int x,int y,int type){
switch (type){
case 1:
g.setColor(Color.BLACK);
break;
case 2:
g.setColor(Color.WHITE);
}
g.fillOval(x*32+start,y*32+start,30,30);

}


}

2.定义myFrame类。

myFrame相当于窗口,画板要放在窗口里。

myFram要继承 JFram类,在初始化函数设置窗口参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
java复制代码
public class MyFrame extends JFrame {
myPanel mp = null;
public MyFrame() {
mp = new myPanel();
this.setTitle("五子棋");
this.setSize(620, 620);
//添加画板
this.add(mp);
//点击窗口叉叉退出程序
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}

static public void main(String[] args) {
MyFrame mf = new MyFrame();
}
}

2.核心功能

1.实现下棋功能

1.定义相关变量

1
2
3
4
5
6
7
8
java复制代码    //偏移量
static final int IndexOffset = -10;
static final int ChessOffset = -10;
//黑子下棋标记
static boolean black = true;
boolean gameIsOver = false;

int chess[][]=new int[19][19];

2.添加事件监听

myPanel实现 MouseListener接口

重写mouseClicked方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
java复制代码    @Override
public void mouseClicked(MouseEvent e) {
//计算棋子坐标
//# 0表示空棋
//# 1表示黑棋
//# 2表示白棋

int x = (e.getX() - IndexOffset) / 32;
int y = (e.getY() - 32 - IndexOffset) / 32;
System.out.println(y);
chess[x][y] = 1;
this.repaint();

}

myFrame添加事件监听

1
2
3
4
5
6
7
8
9
10
11
java复制代码    public MyFrame() {
mp = new myPanel();
this.setTitle("五子棋");
this.setSize(620, 620);
//添加画板
this.add(mp);
//点击窗口叉叉退出程序
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.addMouseListener(mp);
this.setVisible(true);
}

2.实现自动下棋

1.按照优先级从高到低枚举出所有情况

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
java复制代码
//# 0表示空棋
//# 1表示黑棋
//# 2表示白棋
//# 3表示下棋的位置




private static final int[][] cdata = {

{3, 1, 1, 1, 1}, {1, 3, 1, 1, 1}, {1, 1, 3, 1, 1}, {1, 1, 1, 3, 1}, {1, 1, 1, 1, 3},

{2, 2, 3, 2, 2}, {2, 2, 2, 3, 2}, {2, 3, 2, 2, 2}, {3, 2, 2, 2, 2}, {2, 2, 2, 2, 3},

{3, 1, 1, 1, 0}, {1, 1, 1, 3, 0}, {1, 1, 3, 1, 0}, {1, 3, 1, 1, 0},

{3, 2, 2, 2, 0}, {2, 3, 2, 2, 0}, {2, 2, 3, 2, 0}, {2, 2, 2, 3, 0},

{1, 1, 3, 3, 0}, {3, 1, 1, 0, 0}, {0, 1, 3, 1, 0},

{3, 2, 2, 0, 0}, {2, 2, 3, 0, 0}, {1, 3, 1, 0, 0},

{3, 1, 0, 0, 0}, {1, 3, 0, 0, 0}

};

2.选出最佳下棋位置

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
java复制代码    public Point getBestPoint() {
//记录最低分(分值越低,优先级越高)
int score = 100;
//最佳位置
Point point = new Point(0, 0);
//每次都要遍历四个方向 左下 下 右下 右
int[] dx = {-1, 0, 1, 1};
int[] dy = {1, 1, 1, 0};
for (int i = 0; i < 19; i++) {

for (int j = 0; j < 19; j++) {
for (int k = 0; k < 4; k++) {
int cnt = 0;
for (int[] e : cdata) {
int m;
int x = i;
int y = j;
int bestX = 0;
int bestY = 0;
for (m = 0; m < 5; m++) {
if (e[m] == 3 && chess[x][y] == 0) {
bestX = x;
bestY = y;
} else {
if (chess[x][y] != e[m]) {
break;
}
}
x += dx[k];
y += dy[k];
if (x < 0 || x >= 19 || y < 0 || y >= 19) {
break;
}

}
if (m == 5) {
if (cnt < score) {
score = cnt;
point.x = bestX;
point.y = bestY;
}
break;
}
cnt++;
}
}

}
}
if (score < 100) {
return point;
} else {
int x = (int) (Math.random() * 19);
int y = (int) (Math.random() * 19);
while (chess[x][y] != 0) {
x = (int) (Math.random() * 19);
y = (int) (Math.random() * 19);
}
return new Point(x, y);
}

}

3.判断游戏是否结束

遍历棋盘

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
java复制代码   public boolean check() {
//每次都要遍历四个方向 左下 下 右下 右
int[] dx = {-1, 0, 1, 1};
int[] dy = {1, 1, 1, 0};
for (int i = 0; i < 19; i++) {
for (int j = 0; j < 19; j++) {
for (int k = 0; k < 4; k++) {
int x = i;
int y = j;
int m;
boolean flag = true;
for (m = 0; m < 4; m++) {
int tx = x + dx[k];
int ty = y + dy[k];
if (tx < 0 || tx > 19 || ty < 0 || ty > 19) {
flag = false;
break;
}
if (chess[x][y] != chess[x + dx[k]][y + dy[k]]) {
flag = false;
break;
} else if (chess[x][y] == 0) {
flag = false;
break;
}
x = tx;
y = ty;
}
if (flag) {
gameIsOver = true;
return true;
}

}
}
}
return false;
}

4.事件循环
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
java复制代码   @Override
public void paint(Graphics g) {
//调用父类的paint初始化画笔
super.paint(g);
//绘制背景
DrawBackground(g);
//绘制外边框
DrawBorder(g);
//绘制棋盘
DrawChessBoard(g);
DrawChess(g);
//开始游戏

if (!gameIsOver)
game();

//游戏结束
if (check()) {
gameOver(g);
}

}

完整代码

myPanel

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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
java复制代码import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

/**
*
*
* @author yuwei
* @date 23:29 2024/4/23
*/
public class myPanel extends JPanel implements MouseListener {
//偏移量
static final int IndexOffset = -10;
static final int ChessOffset = -10;
//黑子下棋标记
static boolean black = true;
boolean gameIsOver = false;

//# 0表示空棋
//# 1表示黑棋
//# 2表示白棋
//# 3表示下棋的位置


private static final int[][] cdata = {

{3, 1, 1, 1, 1}, {1, 3, 1, 1, 1}, {1, 1, 3, 1, 1}, {1, 1, 1, 3, 1}, {1, 1, 1, 1, 3},

{2, 2, 3, 2, 2}, {2, 2, 2, 3, 2}, {2, 3, 2, 2, 2}, {3, 2, 2, 2, 2}, {2, 2, 2, 2, 3},

{3, 1, 1, 1, 0}, {1, 1, 1, 3, 0}, {1, 1, 3, 1, 0}, {1, 3, 1, 1, 0},

{3, 2, 2, 2, 0}, {2, 3, 2, 2, 0}, {2, 2, 3, 2, 0}, {2, 2, 2, 3, 0},

{1, 1, 3, 3, 0}, {3, 1, 1, 0, 0}, {0, 1, 3, 1, 0},

{3, 2, 2, 0, 0}, {2, 2, 3, 0, 0}, {1, 3, 1, 0, 0},

{3, 1, 0, 0, 0}, {1, 3, 0, 0, 0}

};
int chess[][] = new int[20][20];

@Override
public void paint(Graphics g) {
//调用父类的paint初始化画笔
super.paint(g);
//绘制背景
DrawBackground(g);
//绘制外边框
DrawBorder(g);
//绘制棋盘
DrawChessBoard(g);
DrawChess(g);
//开始游戏

if (!gameIsOver)
game();

//游戏结束
if (check()) {
gameOver(g);
}

}

public void gameOver(Graphics g) {
Font font = new Font("Arial", Font.BOLD, 24);
g.setColor(Color.red);
g.setFont(font);
g.drawString("游戏结束", 270, 270);
}

public void DrawBackground(Graphics g) { //绘制背景
g.setColor(new Color(211, 152, 91));
g.fillRect(0, 0, 620, 620);

}

public void DrawBorder(Graphics g) {
//绘制外边框
g.setColor(Color.BLACK);
g.fillRect(5, 5, 610, 5);
g.fillRect(610, 5, 5, 610);
g.fillRect(5, 610, 610, 5);
g.fillRect(5, 5, 5, 610);
}

public void DrawChessBoard(Graphics g) {
g.setColor(Color.BLACK);
//画横线
for (int i = 0; i < 19; i++) {
g.drawLine(6 + i * 32, 6, 6 + i * 32, 614);
}
//画竖线
for (int i = 0; i < 19; i++) {
g.drawLine(6, 6 + i * 32, 614, 6 + i * 32);
}

}

//画棋子
public void DrawChess(Graphics g) {
for (int i = 0; i < 19; i++) {
for (int j = 0; j < 19; j++) {
if (chess[i][j] == 1) {
g.setColor(Color.BLACK);
} else if (chess[i][j] == 2) {
g.setColor(Color.WHITE);
} else {
continue;
}
g.fillOval(i * 32 + ChessOffset, j * 32 + ChessOffset, 30, 30);
}
}


}

public Point getBestPoint() {
//记录最低分(分值越低,优先级越高)
int score = 100;
//最佳位置
Point point = new Point(0, 0);
//每次都要遍历四个方向 左下 下 右下 右
int[] dx = {-1, 0, 1, 1};
int[] dy = {1, 1, 1, 0};
for (int i = 0; i < 19; i++) {

for (int j = 0; j < 19; j++) {
for (int k = 0; k < 4; k++) {
int cnt = 0;
for (int[] e : cdata) {
int m;
int x = i;
int y = j;
int bestX = 0;
int bestY = 0;
for (m = 0; m < 5; m++) {
if (e[m] == 3 && chess[x][y] == 0) {
bestX = x;
bestY = y;
} else {
if (chess[x][y] != e[m]) {
break;
}
}
x += dx[k];
y += dy[k];
if (x < 0 || x >= 19 || y < 0 || y >= 19) {
break;
}

}
if (m == 5) {
if (cnt < score) {
score = cnt;
point.x = bestX;
point.y = bestY;
}
break;
}
cnt++;
}
}

}
}
if (score < 100) {
return point;
} else {
int x = (int) (Math.random() * 19);
int y = (int) (Math.random() * 19);
while (chess[x][y] != 0) {
x = (int) (Math.random() * 19);
y = (int) (Math.random() * 19);
}
return new Point(x, y);
}

}

public boolean check() {
//每次都要遍历四个方向 左下 下 右下 右
int[] dx = {-1, 0, 1, 1};
int[] dy = {1, 1, 1, 0};
for (int i = 0; i < 19; i++) {
for (int j = 0; j < 19; j++) {
for (int k = 0; k < 4; k++) {
int x = i;
int y = j;
int m;
boolean flag = true;
for (m = 0; m < 4; m++) {
int tx = x + dx[k];
int ty = y + dy[k];
if (tx < 0 || tx > 19 || ty < 0 || ty > 19) {
flag = false;
break;
}
if (chess[x][y] != chess[x + dx[k]][y + dy[k]]) {
flag = false;
break;
} else if (chess[x][y] == 0) {
flag = false;
break;
}
x = tx;
y = ty;
}
if (flag) {
gameIsOver = true;
return true;
}

}
}
}
return false;
}

public void game() {

if (check()) {
return;
}
if (black) {
Point point = getBestPoint();
chess[point.x][point.y] = 1;
black = false;
this.repaint();
}


}


@Override
public void mouseClicked(MouseEvent e) {
//计算棋子坐标
//# 0表示空棋
//# 1表示黑棋
//# 2表示白棋
if (!black&&!gameIsOver) {
int x = (e.getX() - IndexOffset) / 32;
int y = (e.getY() - 32 - IndexOffset) / 32;
chess[x][y] = 2;
black = true;
this.repaint();

}

}

@Override
public void mousePressed(MouseEvent e) {

}

@Override
public void mouseReleased(MouseEvent e) {

}

@Override
public void mouseEntered(MouseEvent e) {

}

@Override
public void mouseExited(MouseEvent e) {

}
}

myFrame

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
java复制代码import javax.swing.*;

/**
* 用户服务
*
* @author yuwei
* @date 23:42 2024/4/23
*/
public class MyFrame extends JFrame {
myPanel mp = null;
public MyFrame() {
mp = new myPanel();
this.setTitle("五子棋");
this.setSize(620, 620);
//添加画板
this.add(mp);
//点击窗口叉叉退出程序
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.addMouseListener(mp);
this.setVisible(true);
}

static public void main(String[] args) {
MyFrame mf = new MyFrame();
}
}

感谢阅读,希望本文对你有所帮助

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%