五子棋
一、实践目标:
1.掌握JavaGUI界面设计
2.掌握鼠标事件的监听(MouseListener,MouseMotionListener)
二、实践内容:
设计一个简单的五子棋程序,能够实现五子棋下棋过程。如下图所示
五子棋运行界面
1 package cn.edu.ouc.fiveChess; 2 3 import java.awt.Color; 4 import java.awt.Cursor; 5 import java.awt.Dimension; 6 import java.awt.Graphics; 7 import java.awt.Graphics2D; 8 import java.awt.Image; 9 import java.awt.RadialGradientPaint; 10 import java.awt.RenderingHints; 11 import java.awt.Toolkit; 12 import java.awt.event.MouseEvent; 13 import java.awt.event.MouseListener; 14 import java.awt.event.MouseMotionListener; 15 import java.awt.geom.Ellipse2D; 16 17 import javax.swing.*; 18 /** 19 * 五子棋--棋盘类 20 */ 21 22 public class ChessBoard extends JPanel implements MouseListener { 23 public static final int MARGIN=30;//边距 24 public static final int GRID_SPAN=35;//网格间距 25 public static final int ROWS=15;//棋盘行数 26 public static final int COLS=15;//棋盘列数 27 28 Point[] chessList=new Point[(ROWS+1)*(COLS+1)];//初始每个数组元素为null 29 boolean isBlack=true;//默认开始是黑棋先 30 boolean gameOver=false;//游戏是否结束 31 int chessCount;//当前棋盘棋子的个数 32 int xIndex,yIndex;//当前刚下棋子的索引 33 34 Image img; 35 Image shadows; 36 Color colortemp; 37 public ChessBoard(){ 38 39 // setBackground(Color.blue);//设置背景色为橘黄色 40 img=Toolkit.getDefaultToolkit().getImage("board.jpg"); 41 shadows=Toolkit.getDefaultToolkit().getImage("shadows.jpg"); 42 addMouseListener(this); 43 addMouseMotionListener(new MouseMotionListener(){ 44 public void mouseDragged(MouseEvent e){ 45 46 } 47 48 public void mouseMoved(MouseEvent e){ 49 int x1=(e.getX()-MARGIN+GRID_SPAN/2)/GRID_SPAN; 50 //将鼠标点击的坐标位置转成网格索引 51 int y1=(e.getY()-MARGIN+GRID_SPAN/2)/GRID_SPAN; 52 //游戏已经结束不能下 53 //落在棋盘外不能下 54 //x,y位置已经有棋子存在,不能下 55 if(x1<0||x1>ROWS||y1<0||y1>COLS||gameOver||findChess(x1,y1)) 56 setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); 57 //设置成默认状态 58 else setCursor(new Cursor(Cursor.HAND_CURSOR)); 59 60 } 61 }); 62 } 63 64 65 66 //绘制 67 public void paintComponent(Graphics g){ 68 69 super.paintComponent(g);//画棋盘 70 71 int imgWidth= img.getWidth(this); 72 int imgHeight=img.getHeight(this);//获得图片的宽度与高度 73 int FWidth=getWidth(); 74 int FHeight=getHeight();//获得窗口的宽度与高度 75 int x=(FWidth-imgWidth)/2; 76 int y=(FHeight-imgHeight)/2; 77 g.drawImage(img, x, y, null); 78 79 80 for(int i=0;i<=ROWS;i++){//画横线 81 g.drawLine(MARGIN, MARGIN+i*GRID_SPAN, MARGIN+COLS*GRID_SPAN, MARGIN+i*GRID_SPAN); 82 } 83 for(int i=0;i<=COLS;i++){//画竖线 84 g.drawLine(MARGIN+i*GRID_SPAN, MARGIN, MARGIN+i*GRID_SPAN, MARGIN+ROWS*GRID_SPAN); 85 86 } 87 88 //画棋子 89 for(int i=0;i<chessCount;i++){ 90 //网格交叉点x,y坐标 91 int xPos=chessList[i].getX()*GRID_SPAN+MARGIN; 92 int yPos=chessList[i].getY()*GRID_SPAN+MARGIN; 93 g.setColor(chessList[i].getColor());//设置颜色 94 // g.fillOval(xPos-Point.DIAMETER/2, yPos-Point.DIAMETER/2, 95 //Point.DIAMETER, Point.DIAMETER); 96 //g.drawImage(shadows, xPos-Point.DIAMETER/2, yPos-Point.DIAMETER/2, Point.DIAMETER, Point.DIAMETER, null); 97 colortemp=chessList[i].getColor(); 98 if(colortemp==Color.black){ 99 RadialGradientPaint paint = new RadialGradientPaint(xPos-Point.DIAMETER/2+25, yPos-Point.DIAMETER/2+10, 20, new float[]{0f, 1f} 100 , new Color[]{Color.WHITE, Color.BLACK}); 101 ((Graphics2D) g).setPaint(paint); 102 ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 103 ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT); 104 105 } 106 else if(colortemp==Color.white){ 107 RadialGradientPaint paint = new RadialGradientPaint(xPos-Point.DIAMETER/2+25, yPos-Point.DIAMETER/2+10, 70, new float[]{0f, 1f} 108 , new Color[]{Color.WHITE, Color.BLACK}); 109 ((Graphics2D) g).setPaint(paint); 110 ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 111 ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT); 112 113 } 114 115 Ellipse2D e = new Ellipse2D.Float(xPos-Point.DIAMETER/2, yPos-Point.DIAMETER/2, 34, 35); 116 ((Graphics2D) g).fill(e); 117 //标记最后一个棋子的红矩形框 118 119 if(i==chessCount-1){//如果是最后一个棋子 120 g.setColor(Color.red); 121 g.drawRect(xPos-Point.DIAMETER/2, yPos-Point.DIAMETER/2, 122 34, 35); 123 } 124 } 125 } 126 127 public void mousePressed(MouseEvent e){//鼠标在组件上按下时调用 128 129 //游戏结束时,不再能下 130 if(gameOver) return; 131 132 String colorName=isBlack?"黑棋":"白棋"; 133 134 //将鼠标点击的坐标位置转换成网格索引 135 xIndex=(e.getX()-MARGIN+GRID_SPAN/2)/GRID_SPAN; 136 yIndex=(e.getY()-MARGIN+GRID_SPAN/2)/GRID_SPAN; 137 138 //落在棋盘外不能下 139 if(xIndex<0||xIndex>ROWS||yIndex<0||yIndex>COLS) 140 return; 141 142 //如果x,y位置已经有棋子存在,不能下 143 if(findChess(xIndex,yIndex))return; 144 145 //可以进行时的处理 146 Point ch=new Point(xIndex,yIndex,isBlack?Color.black:Color.white); 147 chessList[chessCount++]=ch; 148 repaint();//通知系统重新绘制 149 150 151 //如果胜出则给出提示信息,不能继续下棋 152 153 if(isWin()){ 154 String msg=String.format("恭喜,%s赢了!", colorName); 155 JOptionPane.showMessageDialog(this, msg); 156 gameOver=true; 157 } 158 isBlack=!isBlack; 159 } 160 //覆盖mouseListener的方法 161 public void mouseClicked(MouseEvent e){ 162 //鼠标按键在组件上单击时调用 163 } 164 165 public void mouseEntered(MouseEvent e){ 166 //鼠标进入到组件上时调用 167 } 168 public void mouseExited(MouseEvent e){ 169 //鼠标离开组件时调用 170 } 171 public void mouseReleased(MouseEvent e){ 172 //鼠标按钮在组件上释放时调用 173 } 174 //在棋子数组中查找是否有索引为x,y的棋子存在 175 private boolean findChess(int x,int y){ 176 for(Point c:chessList){ 177 if(c!=null&&c.getX()==x&&c.getY()==y) 178 return true; 179 } 180 return false; 181 } 182 183 184 private boolean isWin(){ 185 int continueCount=1;//连续棋子的个数 186 187 //横向向西寻找 188 for(int x=xIndex-1;x>=0;x--){ 189 Color c=isBlack?Color.black:Color.white; 190 if(getChess(x,yIndex,c)!=null){ 191 continueCount++; 192 }else 193 break; 194 } 195 //横向向东寻找 196 for(int x=xIndex+1;x<=COLS;x++){ 197 Color c=isBlack?Color.black:Color.white; 198 if(getChess(x,yIndex,c)!=null){ 199 continueCount++; 200 }else 201 break; 202 } 203 if(continueCount>=5){ 204 return true; 205 }else 206 continueCount=1; 207 208 //继续另一种搜索纵向 209 //向上搜索 210 for(int y=yIndex-1;y>=0;y--){ 211 Color c=isBlack?Color.black:Color.white; 212 if(getChess(xIndex,y,c)!=null){ 213 continueCount++; 214 }else 215 break; 216 } 217 //纵向向下寻找 218 for(int y=yIndex+1;y<=ROWS;y++){ 219 Color c=isBlack?Color.black:Color.white; 220 if(getChess(xIndex,y,c)!=null) 221 continueCount++; 222 else 223 break; 224 225 } 226 if(continueCount>=5) 227 return true; 228 else 229 continueCount=1; 230 231 232 //继续另一种情况的搜索:斜向 233 //东北寻找 234 for(int x=xIndex+1,y=yIndex-1;y>=0&&x<=COLS;x++,y--){ 235 Color c=isBlack?Color.black:Color.white; 236 if(getChess(x,y,c)!=null){ 237 continueCount++; 238 } 239 else break; 240 } 241 //西南寻找 242 for(int x=xIndex-1,y=yIndex+1;x>=0&&y<=ROWS;x--,y++){ 243 Color c=isBlack?Color.black:Color.white; 244 if(getChess(x,y,c)!=null){ 245 continueCount++; 246 } 247 else break; 248 } 249 if(continueCount>=5) 250 return true; 251 else continueCount=1; 252 253 254 //继续另一种情况的搜索:斜向 255 //西北寻找 256 for(int x=xIndex-1,y=yIndex-1;x>=0&&y>=0;x--,y--){ 257 Color c=isBlack?Color.black:Color.white; 258 if(getChess(x,y,c)!=null) 259 continueCount++; 260 else break; 261 } 262 //东南寻找 263 for(int x=xIndex+1,y=yIndex+1;x<=COLS&&y<=ROWS;x++,y++){ 264 Color c=isBlack?Color.black:Color.white; 265 if(getChess(x,y,c)!=null) 266 continueCount++; 267 else break; 268 } 269 if(continueCount>=5) 270 return true; 271 else continueCount=1; 272 273 return false; 274 } 275 276 277 private Point getChess(int xIndex,int yIndex,Color color){ 278 for(Point p:chessList){ 279 if(p!=null&&p.getX()==xIndex&&p.getY()==yIndex 280 &&p.getColor()==color) 281 return p; 282 } 283 return null; 284 } 285 286 287 public void restartGame(){ 288 //清除棋子 289 for(int i=0;i<chessList.length;i++){ 290 chessList[i]=null; 291 } 292 //恢复游戏相关的变量值 293 isBlack=true; 294 gameOver=false; //游戏是否结束 295 chessCount =0; //当前棋盘棋子个数 296 repaint(); 297 } 298 299 //悔棋 300 public void goback(){ 301 if(chessCount==0) 302 return ; 303 chessList[chessCount-1]=null; 304 chessCount--; 305 if(chessCount>0){ 306 xIndex=chessList[chessCount-1].getX(); 307 yIndex=chessList[chessCount-1].getY(); 308 } 309 isBlack=!isBlack; 310 repaint(); 311 } 312 313 //矩形Dimension 314 315 public Dimension getPreferredSize(){ 316 return new Dimension(MARGIN*2+GRID_SPAN*COLS,MARGIN*2 317 +GRID_SPAN*ROWS); 318 } 319 320 321 322 }
2.棋子类
1 package cn.edu.ouc.fiveChess; 2 3 import java.awt.Color; 4 /** 5 * 棋子类 6 */ 7 public class Point { 8 private int x;//棋盘中的x索引 9 private int y;//棋盘中的y索引 10 private Color color;//颜色 11 public static final int DIAMETER=30;//直径 12 13 public Point(int x,int y,Color color){ 14 this.x=x; 15 this.y=y; 16 this.color=color; 17 } 18 19 public int getX(){//拿到棋盘中x的索引 20 return x; 21 } 22 public int getY(){ 23 return y; 24 } 25 public Color getColor(){//获得棋子的颜色 26 return color; 27 } 28 }
3.五子棋主框架类
1 package cn.edu.ouc.fiveChess; 2 import java.awt.event.*; 3 import java.awt.*; 4 5 import javax.swing.*; 6 /* 7 五子棋主框架類,程序啟動類 8 */ 9 public class StartChessJFrame extends JFrame { 10 private ChessBoard chessBoard; 11 private JPanel toolbar; 12 private JButton startButton,backButton,exitButton; 13 14 private JMenuBar menuBar; 15 private JMenu sysMenu; 16 private JMenuItem startMenuItem,exitMenuItem,backMenuItem; 17 //重新开始,退出,和悔棋菜单项 18 public StartChessJFrame(){ 19 setTitle("单机版五子棋");//设置标题 20 chessBoard=new ChessBoard(); 21 22 23 Container contentPane=getContentPane(); 24 contentPane.add(chessBoard); 25 chessBoard.setOpaque(true); 26 27 28 //创建和添加菜单 29 menuBar =new JMenuBar();//初始化菜单栏 30 sysMenu=new JMenu("系统");//初始化菜单 31 //初始化菜单项 32 startMenuItem=new JMenuItem("重新开始"); 33 exitMenuItem =new JMenuItem("退出"); 34 backMenuItem =new JMenuItem("悔棋"); 35 //将三个菜单项添加到菜单上 36 sysMenu.add(startMenuItem); 37 sysMenu.add(exitMenuItem); 38 sysMenu.add(backMenuItem); 39 //初始化按钮事件监听器内部类 40 MyItemListener lis=new MyItemListener(); 41 //将三个菜单注册到事件监听器上 42 this.startMenuItem.addActionListener(lis); 43 backMenuItem.addActionListener(lis); 44 exitMenuItem.addActionListener(lis); 45 menuBar.add(sysMenu);//将系统菜单添加到菜单栏上 46 setJMenuBar(menuBar);//将menuBar设置为菜单栏 47 48 toolbar=new JPanel();//工具面板实例化 49 //三个按钮初始化 50 startButton=new JButton("重新开始"); 51 exitButton=new JButton("退出"); 52 backButton=new JButton("悔棋"); 53 //将工具面板按钮用FlowLayout布局 54 toolbar.setLayout(new FlowLayout(FlowLayout.LEFT)); 55 //将三个按钮添加到工具面板 56 toolbar.add(startButton); 57 toolbar.add(exitButton); 58 toolbar.add(backButton); 59 //将三个按钮注册监听事件 60 startButton.addActionListener(lis); 61 exitButton.addActionListener(lis); 62 backButton.addActionListener(lis); 63 //将工具面板布局到界面”南方“也就是下方 64 add(toolbar,BorderLayout.SOUTH); 65 add(chessBoard);//将面板对象添加到窗体上 66 //设置界面关闭事件 67 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 68 //setSize(800,800); 69 pack();//自适应大小 70 71 } 72 73 private class MyItemListener implements ActionListener{ 74 public void actionPerformed(ActionEvent e){ 75 Object obj=e.getSource();//获得事件源 76 if(obj==StartChessJFrame.this.startMenuItem||obj==startButton){ 77 //重新开始 78 //JFiveFrame.this内部类引用外部类 79 System.out.println("重新开始"); 80 chessBoard.restartGame(); 81 } 82 else if (obj==exitMenuItem||obj==exitButton) 83 System.exit(0); 84 else if (obj==backMenuItem||obj==backButton){ 85 System.out.println("悔棋..."); 86 chessBoard.goback(); 87 } 88 } 89 } 90 91 92 93 public static void main(String[] args){ 94 StartChessJFrame f=new StartChessJFrame();//创建主框架 95 f.setVisible(true);//显示主框架 96 97 } 98 }
作者: 伊甸一点
出处: http://www.cnblogs.com/zpfbuaa/
本文版权归作者伊甸一点所有,欢迎转载和商用(须保留此段声明),且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
原文链接 如有问题, 可邮件(zpflyfe@163.com)咨询.