服务器之家

服务器之家 > 正文

Java棋类游戏实践之单机版五子棋

时间:2020-03-31 11:40     来源/作者:涛涌四海

本文实例讲述了java实现的五子棋游戏代码,分享给大家供大家参考,具体代码如下

一、实践目标

    1.掌握JavaGUI界面设计
       2.掌握鼠标事件的监听(MouseListener,MouseMotionListener)

二、实践内容

      设计一个简单的五子棋程序,能够实现五子棋下棋过程。如下图所示

Java棋类游戏实践之单机版五子棋

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
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
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
package cn.edu.ouc.fiveChess;
 
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RadialGradientPaint;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Ellipse2D;
 
import javax.swing.*;
/**
 * 五子棋--棋盘类
 */
 
public class ChessBoard extends JPanel implements MouseListener {
 public static final int MARGIN=30;//边距
 public static final int GRID_SPAN=35;//网格间距
 public static final int ROWS=15;//棋盘行数
 public static final int COLS=15;//棋盘列数
 
 Point[] chessList=new Point[(ROWS+1)*(COLS+1)];//初始每个数组元素为null
 boolean isBlack=true;//默认开始是黑棋先
 boolean gameOver=false;//游戏是否结束
 int chessCount;//当前棋盘棋子的个数
 int xIndex,yIndex;//当前刚下棋子的索引
 
 Image img;
 Image shadows;
 Color colortemp;
 public ChessBoard(){
 
 // setBackground(Color.blue);//设置背景色为橘黄色
 img=Toolkit.getDefaultToolkit().getImage("board.jpg");
 shadows=Toolkit.getDefaultToolkit().getImage("shadows.jpg");
 addMouseListener(this);
 addMouseMotionListener(new MouseMotionListener(){
 public void mouseDragged(MouseEvent e){
  
 }
 
 public void mouseMoved(MouseEvent e){
 int x1=(e.getX()-MARGIN+GRID_SPAN/2)/GRID_SPAN;
 //将鼠标点击的坐标位置转成网格索引
 int y1=(e.getY()-MARGIN+GRID_SPAN/2)/GRID_SPAN;
 //游戏已经结束不能下
 //落在棋盘外不能下
 //x,y位置已经有棋子存在,不能下
 if(x1<0||x1>ROWS||y1<0||y1>COLS||gameOver||findChess(x1,y1))
  setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
 //设置成默认状态
 else setCursor(new Cursor(Cursor.HAND_CURSOR));
 
 }
 });
 }
 
 
 
//绘制
 public void paintComponent(Graphics g){
 
 super.paintComponent(g);//画棋盘
 
 int imgWidth= img.getWidth(this);
 int imgHeight=img.getHeight(this);//获得图片的宽度与高度
 int FWidth=getWidth();
 int FHeight=getHeight();//获得窗口的宽度与高度
 int x=(FWidth-imgWidth)/2;
 int y=(FHeight-imgHeight)/2;
 g.drawImage(img, x, y, null);
 
 
 for(int i=0;i<=ROWS;i++){//画横线
 g.drawLine(MARGIN, MARGIN+i*GRID_SPAN, MARGIN+COLS*GRID_SPAN, MARGIN+i*GRID_SPAN);
 }
 for(int i=0;i<=COLS;i++){//画竖线
 g.drawLine(MARGIN+i*GRID_SPAN, MARGIN, MARGIN+i*GRID_SPAN, MARGIN+ROWS*GRID_SPAN);
 
 }
 
 //画棋子
 for(int i=0;i<chessCount;i++){
 //网格交叉点x,y坐标
 int xPos=chessList[i].getX()*GRID_SPAN+MARGIN;
 int yPos=chessList[i].getY()*GRID_SPAN+MARGIN;
 g.setColor(chessList[i].getColor());//设置颜色
 // g.fillOval(xPos-Point.DIAMETER/2, yPos-Point.DIAMETER/2,
  //Point.DIAMETER, Point.DIAMETER);
 //g.drawImage(shadows, xPos-Point.DIAMETER/2, yPos-Point.DIAMETER/2, Point.DIAMETER, Point.DIAMETER, null);
 colortemp=chessList[i].getColor();
 if(colortemp==Color.black){
 RadialGradientPaint paint = new RadialGradientPaint(xPos-Point.DIAMETER/2+25, yPos-Point.DIAMETER/2+10, 20, new float[]{0f, 1f}
 , new Color[]{Color.WHITE, Color.BLACK});
 ((Graphics2D) g).setPaint(paint);
 ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
 ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT);
 
 }
 else if(colortemp==Color.white){
 RadialGradientPaint paint = new RadialGradientPaint(xPos-Point.DIAMETER/2+25, yPos-Point.DIAMETER/2+10, 70, new float[]{0f, 1f}
 , new Color[]{Color.WHITE, Color.BLACK});
 ((Graphics2D) g).setPaint(paint);
 ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
 ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT);
 
 }
 
 Ellipse2D e = new Ellipse2D.Float(xPos-Point.DIAMETER/2, yPos-Point.DIAMETER/2, 34, 35);
 ((Graphics2D) g).fill(e);
 //标记最后一个棋子的红矩形框
 
 if(i==chessCount-1){//如果是最后一个棋子
 g.setColor(Color.red);
 g.drawRect(xPos-Point.DIAMETER/2, yPos-Point.DIAMETER/2,
  34, 35);
 }
 }
 }
 
 public void mousePressed(MouseEvent e){//鼠标在组件上按下时调用
 
 //游戏结束时,不再能下
 if(gameOver) return;
 
 String colorName=isBlack?"黑棋":"白棋";
 
 //将鼠标点击的坐标位置转换成网格索引
 xIndex=(e.getX()-MARGIN+GRID_SPAN/2)/GRID_SPAN;
 yIndex=(e.getY()-MARGIN+GRID_SPAN/2)/GRID_SPAN;
 
 //落在棋盘外不能下
 if(xIndex<0||xIndex>ROWS||yIndex<0||yIndex>COLS)
 return;
 
 //如果x,y位置已经有棋子存在,不能下
 if(findChess(xIndex,yIndex))return;
 
 //可以进行时的处理
 Point ch=new Point(xIndex,yIndex,isBlack?Color.black:Color.white);
 chessList[chessCount++]=ch;
 repaint();//通知系统重新绘制
 
 
 //如果胜出则给出提示信息,不能继续下棋
 
 if(isWin()){
 String msg=String.format("恭喜,%s赢了!", colorName);
 JOptionPane.showMessageDialog(this, msg);
 gameOver=true;
 }
 isBlack=!isBlack;
 }
 //覆盖mouseListener的方法
 public void mouseClicked(MouseEvent e){
 //鼠标按键在组件上单击时调用
 }
 
 public void mouseEntered(MouseEvent e){
 //鼠标进入到组件上时调用
 }
 public void mouseExited(MouseEvent e){
 //鼠标离开组件时调用
 }
 public void mouseReleased(MouseEvent e){
 //鼠标按钮在组件上释放时调用
 }
 //在棋子数组中查找是否有索引为x,y的棋子存在
 private boolean findChess(int x,int y){
 for(Point c:chessList){
 if(c!=null&&c.getX()==x&&c.getY()==y)
 return true;
 }
 return false;
 }
 
 
 private boolean isWin(){
 int continueCount=1;//连续棋子的个数
 
 //横向向西寻找
 for(int x=xIndex-1;x>=0;x--){
 Color c=isBlack?Color.black:Color.white;
 if(getChess(x,yIndex,c)!=null){
 continueCount++;
 }else
 break;
 }
 //横向向东寻找
 for(int x=xIndex+1;x<=COLS;x++){
 Color c=isBlack?Color.black:Color.white;
 if(getChess(x,yIndex,c)!=null){
 continueCount++;
 }else
 break;
 }
 if(continueCount>=5){
 return true;
 }else
 continueCount=1;
 
 //继续另一种搜索纵向
 //向上搜索
 for(int y=yIndex-1;y>=0;y--){
 Color c=isBlack?Color.black:Color.white;
 if(getChess(xIndex,y,c)!=null){
 continueCount++;
 }else
 break;
 }
 //纵向向下寻找
 for(int y=yIndex+1;y<=ROWS;y++){
 Color c=isBlack?Color.black:Color.white;
 if(getChess(xIndex,y,c)!=null)
 continueCount++;
 else
 break;
 
 }
 if(continueCount>=5)
 return true;
 else
 continueCount=1;
 
 
 //继续另一种情况的搜索:斜向
 //东北寻找
 for(int x=xIndex+1,y=yIndex-1;y>=0&&x<=COLS;x++,y--){
 Color c=isBlack?Color.black:Color.white;
 if(getChess(x,y,c)!=null){
 continueCount++;
 }
 else break;
 }
 //西南寻找
 for(int x=xIndex-1,y=yIndex+1;x>=0&&y<=ROWS;x--,y++){
 Color c=isBlack?Color.black:Color.white;
 if(getChess(x,y,c)!=null){
 continueCount++;
 }
 else break;
 }
 if(continueCount>=5)
 return true;
 else continueCount=1;
 
 
 //继续另一种情况的搜索:斜向
 //西北寻找
 for(int x=xIndex-1,y=yIndex-1;x>=0&&y>=0;x--,y--){
 Color c=isBlack?Color.black:Color.white;
 if(getChess(x,y,c)!=null)
 continueCount++;
 else break;
 }
 //东南寻找
 for(int x=xIndex+1,y=yIndex+1;x<=COLS&&y<=ROWS;x++,y++){
 Color c=isBlack?Color.black:Color.white;
 if(getChess(x,y,c)!=null)
 continueCount++;
 else break;
 }
 if(continueCount>=5)
 return true;
 else continueCount=1;
 
 return false;
 }
 
 
 private Point getChess(int xIndex,int yIndex,Color color){
 for(Point p:chessList){
 if(p!=null&&p.getX()==xIndex&&p.getY()==yIndex
  &&p.getColor()==color)
 return p;
 }
 return null;
 }
 
 
 public void restartGame(){
 //清除棋子
 for(int i=0;i<chessList.length;i++){
 chessList[i]=null;
 }
 //恢复游戏相关的变量值
 isBlack=true;
 gameOver=false; //游戏是否结束
 chessCount =0; //当前棋盘棋子个数
 repaint();
 }
 
 //悔棋
 public void goback(){
 if(chessCount==0)
 return ;
 chessList[chessCount-1]=null;
 chessCount--;
 if(chessCount>0){
 xIndex=chessList[chessCount-1].getX();
 yIndex=chessList[chessCount-1].getY();
 }
 isBlack=!isBlack;
 repaint();
 }
 
 //矩形Dimension
 
 public Dimension getPreferredSize(){
 return new Dimension(MARGIN*2+GRID_SPAN*COLS,MARGIN*2
  +GRID_SPAN*ROWS);
 }
 
 
 
}

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
package cn.edu.ouc.fiveChess;
 
import java.awt.Color;
/**
 * 棋子类
 */
public class Point {
 private int x;//棋盘中的x索引
 private int y;//棋盘中的y索引
 private Color color;//颜色
 public static final int DIAMETER=30;//直径
 
 public Point(int x,int y,Color color){
 this.x=x;
 this.y=y;
 this.color=color;
 }
 
 public int getX(){//拿到棋盘中x的索引
 return x;
 }
 public int getY(){
 return y;
 }
 public Color getColor(){//获得棋子的颜色
 return color;
 }
}

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
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
package cn.edu.ouc.fiveChess;
import java.awt.event.*;
import java.awt.*;
 
import javax.swing.*;
/*
 五子棋主框架類,程序啟動類
 */
public class StartChessJFrame extends JFrame {
 private ChessBoard chessBoard;
 private JPanel toolbar;
 private JButton startButton,backButton,exitButton;
 
 private JMenuBar menuBar;
 private JMenu sysMenu;
 private JMenuItem startMenuItem,exitMenuItem,backMenuItem;
 //重新开始,退出,和悔棋菜单项
 public StartChessJFrame(){
 setTitle("单机版五子棋");//设置标题
 chessBoard=new ChessBoard();
 
 
 Container contentPane=getContentPane();
 contentPane.add(chessBoard);
 chessBoard.setOpaque(true);
 
 
 //创建和添加菜单
 menuBar =new JMenuBar();//初始化菜单栏
 sysMenu=new JMenu("系统");//初始化菜单
 //初始化菜单项
 startMenuItem=new JMenuItem("重新开始");
 exitMenuItem =new JMenuItem("退出");
 backMenuItem =new JMenuItem("悔棋");
 //将三个菜单项添加到菜单上
 sysMenu.add(startMenuItem);
 sysMenu.add(exitMenuItem);
 sysMenu.add(backMenuItem);
 //初始化按钮事件监听器内部类
 MyItemListener lis=new MyItemListener();
 //将三个菜单注册到事件监听器上
 this.startMenuItem.addActionListener(lis);
 backMenuItem.addActionListener(lis);
 exitMenuItem.addActionListener(lis);
 menuBar.add(sysMenu);//将系统菜单添加到菜单栏上
 setJMenuBar(menuBar);//将menuBar设置为菜单栏
 
 toolbar=new JPanel();//工具面板实例化
 //三个按钮初始化
 startButton=new JButton("重新开始");
 exitButton=new JButton("退出");
 backButton=new JButton("悔棋");
 //将工具面板按钮用FlowLayout布局
 toolbar.setLayout(new FlowLayout(FlowLayout.LEFT));
 //将三个按钮添加到工具面板
 toolbar.add(startButton);
 toolbar.add(exitButton);
 toolbar.add(backButton);
 //将三个按钮注册监听事件
 startButton.addActionListener(lis);
 exitButton.addActionListener(lis);
 backButton.addActionListener(lis);
 //将工具面板布局到界面”南方“也就是下方
 add(toolbar,BorderLayout.SOUTH);
 add(chessBoard);//将面板对象添加到窗体上
 //设置界面关闭事件
 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 //setSize(800,800);
 pack();//自适应大小
 
 }
 
 private class MyItemListener implements ActionListener{
 public void actionPerformed(ActionEvent e){
 Object obj=e.getSource();//获得事件源
 if(obj==StartChessJFrame.this.startMenuItem||obj==startButton){
 //重新开始
 //JFiveFrame.this内部类引用外部类
 System.out.println("重新开始");
 chessBoard.restartGame();
 }
 else if (obj==exitMenuItem||obj==exitButton)
 System.exit(0);
 else if (obj==backMenuItem||obj==backButton){
 System.out.println("悔棋...");
 chessBoard.goback();
 }
 }
 }
 
 
 
 public static void main(String[] args){
 StartChessJFrame f=new StartChessJFrame();//创建主框架
 f.setVisible(true);//显示主框架
 
 }
}

三、总结

1.菜单的设计与实现?
2.鼠标点击棋盘后,如何绘制棋子?如何为刚下的棋子绘制一个红色框?
3.棋谱是如何一个数据结构?

以上就是本文的全部内容,希望对大家学习java程序设计有所帮助。

标签:

相关文章

热门资讯

沙雕群名称大全2019精选 今年最火的微信群名沙雕有创意
沙雕群名称大全2019精选 今年最火的微信群名沙雕有创意 2019-07-07
玄元剑仙肉身有什么用 玄元剑仙肉身境界等级划分
玄元剑仙肉身有什么用 玄元剑仙肉身境界等级划分 2019-06-21
男生常说24816是什么意思?女生说13579是什么意思?
男生常说24816是什么意思?女生说13579是什么意思? 2019-09-17
超A是什么意思 你好a表达的是什么
超A是什么意思 你好a表达的是什么 2019-06-06
华为nova5pro和p30pro哪个好 华为nova5pro和华为p30pro对比详情
华为nova5pro和p30pro哪个好 华为nova5pro和华为p30pro对比详情 2019-06-22
返回顶部