五子棋V1.0
功能:
- 人人对战,人机对战(初级)
- 记录双方分数;
主要知识点:
二维坐标系中,各方向坐标的关系及规律。
效果图:
- 主框架类:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 package com.gxlee.wzq; 2 3 /** 4 *五子棋 Java版 V1.0 5 *@author http://www.cnblogs.com/HFLY 6 *时间2005-8-20 7 *功能:人机对战 人人对战 8 */ 9 import java.awt.Color; 10 import java.awt.Container; 11 import java.awt.Font; 12 import java.awt.Graphics; 13 import java.awt.event.ActionEvent; 14 import java.awt.event.ActionListener; 15 import java.awt.event.MouseAdapter; 16 import java.awt.event.MouseEvent; 17 import java.awt.image.BufferedImage; 18 import java.util.ArrayList; 19 import java.util.List; 20 21 import javax.swing.ButtonGroup; 22 import javax.swing.JButton; 23 import javax.swing.JComboBox; 24 import javax.swing.JFrame; 25 import javax.swing.JPanel; 26 import javax.swing.JRadioButton; 27 28 @SuppressWarnings("serial") 29 public class MainFrame extends JFrame { 30 private JButton btStart = new JButton("开始"); 31 32 private JComboBox model = new JComboBox(new Object[] { "人机对战", "人人对战" }); 33 private JRadioButton jr1 = new JRadioButton("电脑先下"); 34 private JRadioButton jr2 = new JRadioButton("自己先下"); 35 private JRadioButton level1 = new JRadioButton("难"); 36 private JRadioButton level2 = new JRadioButton("中"); 37 private JRadioButton level3 = new JRadioButton("易"); 38 private boolean myOrder = true;// false 对方,true 自己 39 private boolean gameOver = true;// false 游戏结束 40 private boolean win = false; 41 private int advCouner;// 对方赢的次数 42 private int myCouter;// 自己赢的次数 43 private List<Chess> myChess = new ArrayList<Chess>();// 自己的棋 44 private List<Chess> advChess = new ArrayList<Chess>();// 对方的棋 45 private List<Chess> allChess = new ArrayList<Chess>();// 所有的棋 46 private int gameModel = 0;// 0 人机模式,1人人模式 47 48 public MainFrame() { 49 // 构造函数 50 this.setTitle("五子棋 v1.0"); 51 this.setSize(Utils.WIDTH, Utils.HEIGHT); 52 this.setDefaultCloseOperation(EXIT_ON_CLOSE); 53 this.setLocationRelativeTo(null); 54 this.setResizable(false); 55 Mypanel zb = new Mypanel(); 56 zb.setLayout(null); 57 58 // 添加难易 人机模式时才可选 59 level1.setBackground(new Color(224, 192, 0)); 60 level2.setBackground(new Color(224, 192, 0)); 61 level3.setBackground(new Color(224, 192, 0)); 62 level1.setBounds(Utils.IMAGE_WIDTH + (Utils.WIDTH - Utils.IMAGE_WIDTH) 63 / 2 - 53, Utils.HEIGHT - 290, 100, 30); 64 level2.setBounds(Utils.IMAGE_WIDTH + (Utils.WIDTH - Utils.IMAGE_WIDTH) 65 / 2 - 53, Utils.HEIGHT - 260, 100, 30); 66 level3.setBounds(Utils.IMAGE_WIDTH + (Utils.WIDTH - Utils.IMAGE_WIDTH) 67 / 2 - 53, Utils.HEIGHT - 230, 100, 30); 68 level3.setSelected(true); 69 zb.add(level1); 70 zb.add(level2); 71 zb.add(level3); 72 ButtonGroup group1 = new ButtonGroup(); 73 group1.add(level1); 74 group1.add(level2); 75 group1.add(level3); 76 77 // 添加模式 78 model.setBounds(Utils.IMAGE_WIDTH + (Utils.WIDTH - Utils.IMAGE_WIDTH) 79 / 2 - 53, Utils.HEIGHT - 180, 100, 30); 80 model.addActionListener(new ActionListener() { 81 82 @Override 83 public void actionPerformed(ActionEvent e) { 84 // String(model.getSelectedItem()); 85 86 switch (model.getSelectedIndex()) { 87 case 0: 88 gameModel = 0; 89 jr1.setText("电脑先下"); 90 break; 91 case 1: 92 gameModel = 1; 93 jr1.setText("对方先下"); 94 break; 95 default: 96 break; 97 } 98 } 99 100 }); 101 zb.add(model); 102 103 // 添加谁先下: 104 jr1.setBounds(Utils.IMAGE_WIDTH + (Utils.WIDTH - Utils.IMAGE_WIDTH) / 2 105 - 53, Utils.HEIGHT - 150, 80, 30); 106 jr1.setBackground(new Color(224, 192, 0)); 107 jr1.setForeground(Color.WHITE); 108 jr1.addActionListener(new ActionListener() { 109 110 @Override 111 public void actionPerformed(ActionEvent e) { 112 myOrder = false;// 轮到对方出棋 113 } 114 115 }); 116 zb.add(jr1); 117 jr2.setBounds(Utils.IMAGE_WIDTH + (Utils.WIDTH - Utils.IMAGE_WIDTH) / 2 118 - 53, Utils.HEIGHT - 120, 80, 30); 119 jr2.setBackground(new Color(224, 192, 0)); 120 jr2.setForeground(Color.WHITE); 121 jr2.addActionListener(new ActionListener() { 122 123 @Override 124 public void actionPerformed(ActionEvent e) { 125 myOrder = true;// 自己先下; 126 } 127 128 }); 129 jr2.setSelected(true);// 默认自己先下 130 zb.add(jr2); 131 ButtonGroup group2 = new ButtonGroup(); 132 group2.add(jr1); 133 group2.add(jr2); 134 // 添加开始按钮 135 btStart.setBounds(Utils.IMAGE_WIDTH + (Utils.WIDTH - Utils.IMAGE_WIDTH) 136 / 2 - 53, Utils.HEIGHT - 90, 100, 30); 137 btStart.addActionListener(new ActionListener() { 138 139 @Override 140 public void actionPerformed(ActionEvent e) { 141 // 复位 142 gameOver = false; 143 win = false; 144 myChess.clear(); 145 advChess.clear(); 146 allChess.clear(); 147 // 其他复位的地方 148 btStart.setText("再来一局"); 149 // 谁出? 150 myOrder = jr1.isSelected() ? false : true; 151 if (!myOrder) { 152 computerGetNextChess(); 153 myOrder = true; 154 } 155 repaint(); 156 } 157 }); 158 zb.add(btStart); 159 zb.addMouseListener(new MouseClick()); 160 Container c = this.getContentPane(); 161 c.add(zb); 162 163 this.setVisible(true); 164 } 165 166 private class MouseClick extends MouseAdapter { 167 168 @Override 169 public void mouseClicked(MouseEvent e) { 170 171 // 如果是游戏结束状态 172 if (gameOver) { 173 return; 174 } 175 // 若是人机模式,并且当前是对方出的时候 176 if (gameModel == 0 && !myOrder) { 177 return; 178 } 179 if (e.getX() > 430) // 坐标越界 180 return; 181 182 int x = e.getX(); 183 int y = e.getY() > 420 ? 420 : e.getY(); 184 int xIndex = (x - 18) / 25 + ((x - 18) % 25 > 25 / 2 ? 1 : 0); 185 int yIndex = (y - 18) / 25 + ((y - 18) % 25 > 25 / 2 ? 1 : 0); 186 187 boolean result = addChess(new Chess(xIndex, yIndex), myOrder); 188 if (result) { 189 // 先绘画 190 repaint(); 191 // 检查是否有输赢 192 if (gameOver = checkResult(xIndex, yIndex)) { 193 win = true; 194 return; 195 } else { 196 // 交换顺序 197 myOrder = !myOrder; 198 // 如果没有赢的时候,人机模式需要调用电脑出棋 199 if (gameModel == 0) { 200 if (gameOver = computerGetNextChess()) { 201 win = true; 202 return; 203 } 204 myOrder = true; 205 } 206 } 207 } 208 } 209 } 210 211 /** 212 * 电脑自动下棋的方法 213 * 214 * @return 215 */ 216 public boolean computerGetNextChess() { 217 // 电脑出 最大索引为 16; 218 int xIndex = Utils.r.nextInt(17); 219 int yIndex = Utils.r.nextInt(17); 220 // 如果没有棋 并且是电脑模式自己先出 221 if (myChess.size() == 0 && advChess.size() == 0) {// 这是表示是电脑先出 222 addChess(new Chess(xIndex, yIndex), advChess); 223 return false; 224 } else if (myChess.size() == 1 && advChess.size() == 0) {// 玩家先出 225 // 这个完全是多余的 纯粹增加花样 226 // 可以在玩的周边出一个 227 // 得到个随机数,在他的的哪个方向即偏移地址 228 Chess myCh = myChess.get(0); 229 int offset = 1;// Utils.r.nextInt(15)+1;//偏移距离 230 int rndX = Utils.r.nextInt(2); 231 int rndY = Utils.r.nextInt(2); 232 int rX = rndX == 0 ? -1 : 1; 233 int rY = rndY == 0 ? -1 : 1; 234 while (!addChess(new Chess(myCh.getxIndex() + rX * offset, myCh 235 .getyIndex() 236 + rY * offset), advChess)) { 237 rndX = Utils.r.nextInt(2); 238 rndY = Utils.r.nextInt(2); 239 rX = rndX == 0 ? -1 : 1; 240 rY = rndY == 0 ? -1 : 1; 241 } 242 return false; 243 } 244 245 // 这时,如果自己要赢了就开始赢 246 Chess c = getBestChess(advChess, true); 247 if (checkResult(c.getxIndex(), c.getyIndex(), advChess)) { 248 return addChess(c, advChess); 249 } 250 // 电脑防御模式,如果玩家有只要放入一个棋可以达到4分,就要进行防御 251 Chess advC = getBestChess(myChess, false); 252 if (advC == null) { 253 advC = c; 254 } 255 addChess(advC, advChess); 256 return false;// checkResult(c.getxIndex(),c.getyIndex());//是否胜 257 } 258 259 /** 260 * 得到玩家可能要赢了的点 玩家4分的点也要控制 得到一个可以最大分数的点 最佳的点 261 * 262 * @param playerChess 263 * @param flag 264 * 标示电脑的棋还是玩家的棋 玩家的话 如果分数小于4则不要 265 * @return 266 */ 267 public Chess getBestChess(List<Chess> playerChess, boolean flag) { 268 int maxScore = -1; 269 int score = -1; 270 int maxScoreX = -1; 271 int maxScoreY = -1; 272 int xIndex = -1, yIndex = -1; 273 geted: for (Chess c : playerChess) { 274 xIndex = c.getxIndex(); 275 yIndex = c.getyIndex(); 276 // 左边 {-1,0},右边{1,0},左上角的{-1,-1}.... 277 for (int i = -1; i <= 1; i++) { 278 for (int j = -1; j <= 1; j++) { 279 // 不能同时为零0 280 if (i == j && i == 0) 281 continue; 282 score = Utils.getBestPointScore(xIndex + i, yIndex + j, 283 allChess, playerChess); 284 if (score >= maxScore) { 285 maxScore = score; 286 maxScoreX = xIndex + i; 287 maxScoreY = yIndex + j; 288 if (maxScore >= 5) 289 break geted; 290 } 291 } 292 } 293 } 294 // 如果此时再判断玩家的棋 295 if (!flag) { 296 if (maxScore < 4) 297 return null; 298 } 299 return new Chess(maxScoreX, maxScoreY, true); 300 } 301 302 public boolean checkResult(int x, int y, List<Chess> playerChess) { 303 int scorePre = 0; // 这个点的左,左上,上 ,左下能得分 304 int socreNext = 0;// 这个点的 右,右下,下,右上 305 int score = 0; 306 int maxScore = 0; 307 int offsetX, offsetY; 308 /** 309 * 前半段 后半段 X Y X Y 横 向 -1 0 1 0 竖 向 0 -1 0 1 下上斜 -1 1 1 -1 上下斜 -1 -1 1 1 310 */ 311 for (int i = -1; i <= 0; i++) { 312 for (int j = -1; j <= 1; j++) { 313 if (i == j && i == 0) 314 continue; 315 if (0 == 0 && y == 1) 316 continue;// 不判断也可以 317 // 前半段 318 offsetX = i; 319 offsetY = j; 320 scorePre = Utils.getPointScore(x, y, offsetX, offsetY, 321 playerChess); 322 // 后半段 323 offsetX = -i; 324 offsetY = -j; 325 socreNext = Utils.getPointScore(x, y, offsetX, offsetY, 326 playerChess); 327 score = scorePre + socreNext + 1; 328 maxScore = score >= maxScore ? score : maxScore; 329 if (maxScore >= 5) 330 return true; 331 } 332 } 333 return false; 334 } 335 336 /** 337 * 重载,检查是否赢了 338 * 339 * @param x 340 * @param y 341 * @return 342 */ 343 public boolean checkResult(int x, int y) { 344 List<Chess> playerChess = myOrder ? myChess : advChess; 345 return checkResult(x, y, playerChess); 346 } 347 348 /** 349 * 添加棋的方法 350 * 351 * @param chess 352 * @param playerChess 353 * @return 354 */ 355 public boolean addChess(Chess chess, List<Chess> playerChess) { 356 // 判断是否越界 357 if (chess.getxIndex() < 0) 358 return false; 359 if (chess.getxIndex() > 16) 360 return false; 361 if (chess.getyIndex() < 0) 362 return false; 363 if (chess.getyIndex() > 16) 364 return false; 365 // 重载 366 if (allChess.contains(chess)) { 367 return false; 368 } 369 Chess c = new Chess(chess); 370 // 没有被占用的话 371 allChess.add(c); 372 return playerChess.add(c); 373 } 374 375 // 376 /** 377 * 重载 添加棋的方法 378 * 379 * @param chess 380 * @param myOrder 381 * @return 382 */ 383 public boolean addChess(Chess chess, boolean myOrder) { 384 List<Chess> playerChess = myOrder ? myChess : advChess; 385 return addChess(chess, playerChess); 386 } 387 388 /** 389 * 画图容器 390 * 391 * @author 392 * 393 */ 394 public class Mypanel extends JPanel { 395 396 @Override 397 protected void paintComponent(Graphics g) { 398 399 // 画背景 400 g.drawImage(Utils.images.get("Board.gif"), 0, 0, this); 401 g.setColor(new Color(224, 192, 0)); 402 g.fillRect(Utils.IMAGE_WIDTH, 0, Utils.WIDTH - Utils.IMAGE_WIDTH, 403 Utils.HEIGHT); 404 g.setColor(Color.WHITE); 405 g.setFont(new Font("隶书", Font.PLAIN, 20)); 406 // 画图标 407 g.drawString("当前:", Utils.IMAGE_WIDTH + 10, 52);// 让电脑延时几秒再出其 408 BufferedImage img = Utils.images.get("white.gif"); 409 if (!myOrder) { 410 img = Utils.images.get("black.gif"); 411 } 412 g.drawImage(img, Utils.IMAGE_WIDTH + 70, 35, this); 413 414 // 画框 415 g.drawRect(Utils.IMAGE_WIDTH, 20, Utils.WIDTH - Utils.IMAGE_WIDTH 416 - 10, Utils.HEIGHT - 68); 417 // 画自己的棋 418 img = Utils.images.get("white.gif"); 419 for (Chess c : myChess) { 420 g.drawImage(img, c.getX(), c.getY(), this); 421 } 422 // 画对方的棋 423 img = Utils.images.get("black.gif"); 424 for (Chess c : advChess) { 425 g.drawImage(img, c.getX(), c.getY(), this); 426 } 427 // 画赢了 428 if (gameOver && win) { 429 // 谁赢了? 430 String name = ""; 431 if (myOrder) { 432 myCouter++; 433 name = (gameModel == 1) ? "白方" : "我"; 434 } else { 435 advCouner++; 436 name = (gameModel == 0) ? "电脑" : "黑方";// 电脑模式 437 } 438 g.setFont(new Font("隶书", Font.BOLD, 65)); 439 g.setColor(Color.WHITE); 440 g.drawString(name + "赢了!", 100, 200); 441 g.setFont(new Font("隶书", Font.BOLD, 65)); 442 g.setColor(Color.RED); 443 g.drawString(name + "赢了!", 100, 202); 444 } 445 // 画战绩: 446 g.setFont(new Font("楷体", Font.PLAIN, 15)); 447 g.setColor(Color.WHITE); 448 g.drawString(((gameModel == 1) ? "黑方(赢):" : "电脑(赢):") + advCouner, 449 Utils.IMAGE_WIDTH + 10, 100); 450 g.drawString(((gameModel == 1) ? "白方(赢):" : " 我(赢):") + myCouter, 451 Utils.IMAGE_WIDTH + 10, 120); 452 453 } 454 } 455 456 public static void main(String[] args) { 457 new MainFrame(); 458 } 459 460 }
- 棋子类:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 package com.gxlee.wzq; 2 3 /** 4 * 棋 5 * @author http://www.cnblogs.com/HFLY 6 * 7 */ 8 public class Chess { 9 private int x;// x坐标 10 private int y;// y 坐标 11 private int xIndex; 12 private int yIndex; 13 14 // 构造函数 15 public Chess(int xIndex, int yIndex) { 16 super(); 17 this.xIndex = xIndex; 18 this.yIndex = yIndex; 19 this.x = xIndex * 25 + 18 - 12;// 通过格子求出十字架的位置 12 是棋子的一半 20 this.y = yIndex * 25 + 20 - 12; 21 } 22 23 public Chess(Chess c) { 24 this.xIndex = c.getxIndex(); 25 this.yIndex = c.getyIndex(); 26 this.x = xIndex * 25 + 18 - 12;// 27 this.y = yIndex * 25 + 20 - 12; 28 } 29 30 public Chess(int xIndex, int yIndex, boolean checkFlag) { 31 super(); 32 this.xIndex = xIndex; 33 this.yIndex = yIndex; 34 } 35 36 @Override 37 public boolean equals(Object obj) { 38 if (obj instanceof Chess) { 39 Chess c = (Chess) obj; 40 if (c.xIndex == this.xIndex && c.yIndex == this.yIndex) { 41 return true; 42 } 43 } 44 return false; 45 } 46 47 public int getxIndex() { 48 return xIndex; 49 } 50 51 public void setxIndex(int xIndex) { 52 this.xIndex = xIndex; 53 } 54 55 public int getyIndex() { 56 return yIndex; 57 } 58 59 public void setyIndex(int yIndex) { 60 this.yIndex = yIndex; 61 } 62 63 public int getX() { 64 return x; 65 } 66 67 public void setX(int x) { 68 this.x = x; 69 } 70 71 public int getY() { 72 return y; 73 } 74 75 public void setY(int y) { 76 this.y = y; 77 } 78 79 }
- 工具类:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 package com.gxlee.wzq; 2 3 import java.awt.image.BufferedImage; 4 import java.io.File; 5 import java.io.IOException; 6 import java.util.HashMap; 7 import java.util.List; 8 import java.util.Map; 9 import java.util.Random; 10 11 import javax.imageio.ImageIO; 12 13 /** 14 * 工具类 15 * @author http://www.cnblogs.com/HFLY 16 * 17 */ 18 public class Utils { 19 public static Random r = new Random(); 20 public static Map<String,BufferedImage> images = new HashMap<String,BufferedImage>(); 21 public static final int WIDTH = 560;//游戏界面的宽 22 public static final int IMAGE_WIDTH = 437; 23 public static final int HEIGHT = 465;//游戏界面的高 24 static{ 25 File dir = new File("src/img"); 26 File[] files = dir.listFiles(); 27 for (File file : files) { 28 BufferedImage img; 29 try { 30 img = ImageIO.read(file); 31 images.put(file.getName(), img); 32 } catch (IOException e) { 33 e.printStackTrace(); 34 } 35 } 36 37 } 38 39 40 /**电脑出棋时判断双方最佳点的方法 41 * @param x 42 * @param y 43 * @param allChess 44 * @param playerChess 传入哪方就得出哪方最佳点 45 * @return 46 47 */ 48 public static int getBestPointScore(int x,int y,List<Chess> allChess,List<Chess> playerChess){ 49 //坐标越界 50 if(x<0) return -1; 51 if(x>16) return -1; 52 if(y<0) return -1; 53 if(y>16) return -1; 54 //如果这个点被电脑占用了 则不能使用 55 if(allChess.contains(new Chess(x,y))) return -1; 56 // 向前延伸得分加上向后加当前1分为总得分 57 int scorePre=0; //这个点的左,左上,上 ,左下能得分 58 int socreNext=0;//这个点的 右,右下,下,右上 59 int score = 0 ; 60 int maxScore = 0; 61 int offsetX,offsetY; 62 /** 63 * 前半段 后半段 64 X Y X Y 65 横 向 -1 0 1 0 66 竖 向 0 -1 0 1 67 下上斜 -1 1 1 -1 68 上下斜 -1 -1 1 1 69 */ 70 geted:for (int i = -1; i <=0; i++) { 71 for(int j = -1;j<=1;j++){ 72 if(i==j && i==0) continue; 73 //前半段 74 offsetX = i;offsetY = j; 75 scorePre = getPointScore(x,y,offsetX,offsetY,playerChess); 76 //后半段 77 offsetX = i*(-1);offsetY = j*(-1); 78 socreNext = getPointScore(x,y,offsetX,offsetY,playerChess); 79 score = scorePre+socreNext+1; 80 maxScore = score>=maxScore?score:maxScore; 81 if (maxScore>=5) break geted; 82 } 83 } 84 return maxScore; 85 } 86 87 /**每一点的得分 88 * @param x 89 * @param y 90 * @param offsetX 91 * @param offsetY 92 * @param playerChess 93 * @return 94 */ 95 public static int getPointScore(int x,int y,int offsetX,int offsetY,List<Chess> playerChess){ 96 int score = 0; 97 int xAdd = offsetX; 98 int yAdd = offsetY; 99 while (playerChess.contains(new Chess(x+offsetX,y+offsetY))) { 100 score ++; 101 offsetX += xAdd; 102 offsetY += yAdd; 103 } 104 return score; 105 } 106 }
- 素材
- 棋盘
-
- 棋子