五子棋V1.0
功能:
- 人人对战,人机对战(初级)
- 记录双方分数;
主要知识点:
二维坐标系中,各方向坐标的关系及规律。
效果图:
- 主框架类:
package com.gxlee.wzq; /** *五子棋 Java版 V1.0 *@author http://www.cnblogs.com/HFLY *时间2005-8-20 *功能:人机对战 人人对战 */ import java.awt.Color; import java.awt.Container; import java.awt.Font; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.List; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JRadioButton; @SuppressWarnings("serial") public class MainFrame extends JFrame { private JButton btStart = new JButton("开始"); private JComboBox model = new JComboBox(new Object[] { "人机对战", "人人对战" }); private JRadioButton jr1 = new JRadioButton("电脑先下"); private JRadioButton jr2 = new JRadioButton("自己先下"); private JRadioButton level1 = new JRadioButton("难"); private JRadioButton level2 = new JRadioButton("中"); private JRadioButton level3 = new JRadioButton("易"); private boolean myOrder = true;// false 对方,true 自己 private boolean gameOver = true;// false 游戏结束 private boolean win = false; private int advCouner;// 对方赢的次数 private int myCouter;// 自己赢的次数 private List<Chess> myChess = new ArrayList<Chess>();// 自己的棋 private List<Chess> advChess = new ArrayList<Chess>();// 对方的棋 private List<Chess> allChess = new ArrayList<Chess>();// 所有的棋 private int gameModel = 0;// 0 人机模式,1人人模式 public MainFrame() { // 构造函数 this.setTitle("五子棋 v1.0"); this.setSize(Utils.WIDTH, Utils.HEIGHT); this.setDefaultCloseOperation(EXIT_ON_CLOSE); this.setLocationRelativeTo(null); this.setResizable(false); Mypanel zb = new Mypanel(); zb.setLayout(null); // 添加难易 人机模式时才可选 level1.setBackground(new Color(224, 192, 0)); level2.setBackground(new Color(224, 192, 0)); level3.setBackground(new Color(224, 192, 0)); level1.setBounds(Utils.IMAGE_WIDTH + (Utils.WIDTH - Utils.IMAGE_WIDTH) / 2 - 53, Utils.HEIGHT - 290, 100, 30); level2.setBounds(Utils.IMAGE_WIDTH + (Utils.WIDTH - Utils.IMAGE_WIDTH) / 2 - 53, Utils.HEIGHT - 260, 100, 30); level3.setBounds(Utils.IMAGE_WIDTH + (Utils.WIDTH - Utils.IMAGE_WIDTH) / 2 - 53, Utils.HEIGHT - 230, 100, 30); level3.setSelected(true); zb.add(level1); zb.add(level2); zb.add(level3); ButtonGroup group1 = new ButtonGroup(); group1.add(level1); group1.add(level2); group1.add(level3); // 添加模式 model.setBounds(Utils.IMAGE_WIDTH + (Utils.WIDTH - Utils.IMAGE_WIDTH) / 2 - 53, Utils.HEIGHT - 180, 100, 30); model.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // String(model.getSelectedItem()); switch (model.getSelectedIndex()) { case 0: gameModel = 0; jr1.setText("电脑先下"); break; case 1: gameModel = 1; jr1.setText("对方先下"); break; default: break; } } }); zb.add(model); // 添加谁先下: jr1.setBounds(Utils.IMAGE_WIDTH + (Utils.WIDTH - Utils.IMAGE_WIDTH) / 2 - 53, Utils.HEIGHT - 150, 80, 30); jr1.setBackground(new Color(224, 192, 0)); jr1.setForeground(Color.WHITE); jr1.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { myOrder = false;// 轮到对方出棋 } }); zb.add(jr1); jr2.setBounds(Utils.IMAGE_WIDTH + (Utils.WIDTH - Utils.IMAGE_WIDTH) / 2 - 53, Utils.HEIGHT - 120, 80, 30); jr2.setBackground(new Color(224, 192, 0)); jr2.setForeground(Color.WHITE); jr2.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { myOrder = true;// 自己先下; } }); jr2.setSelected(true);// 默认自己先下 zb.add(jr2); ButtonGroup group2 = new ButtonGroup(); group2.add(jr1); group2.add(jr2); // 添加开始按钮 btStart.setBounds(Utils.IMAGE_WIDTH + (Utils.WIDTH - Utils.IMAGE_WIDTH) / 2 - 53, Utils.HEIGHT - 90, 100, 30); btStart.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // 复位 gameOver = false; win = false; myChess.clear(); advChess.clear(); allChess.clear(); // 其他复位的地方 btStart.setText("再来一局"); // 谁出? myOrder = jr1.isSelected() ? false : true; if (!myOrder) { computerGetNextChess(); myOrder = true; } repaint(); } }); zb.add(btStart); zb.addMouseListener(new MouseClick()); Container c = this.getContentPane(); c.add(zb); this.setVisible(true); } private class MouseClick extends MouseAdapter { @Override public void mouseClicked(MouseEvent e) { // 如果是游戏结束状态 if (gameOver) { return; } // 若是人机模式,并且当前是对方出的时候 if (gameModel == 0 && !myOrder) { return; } if (e.getX() > 430) // 坐标越界 return; int x = e.getX(); int y = e.getY() > 420 ? 420 : e.getY(); int xIndex = (x - 18) / 25 + ((x - 18) % 25 > 25 / 2 ? 1 : 0); int yIndex = (y - 18) / 25 + ((y - 18) % 25 > 25 / 2 ? 1 : 0); boolean result = addChess(new Chess(xIndex, yIndex), myOrder); if (result) { // 先绘画 repaint(); // 检查是否有输赢 if (gameOver = checkResult(xIndex, yIndex)) { win = true; return; } else { // 交换顺序 myOrder = !myOrder; // 如果没有赢的时候,人机模式需要调用电脑出棋 if (gameModel == 0) { if (gameOver = computerGetNextChess()) { win = true; return; } myOrder = true; } } } } } /** * 电脑自动下棋的方法 * * @return */ public boolean computerGetNextChess() { // 电脑出 最大索引为 16; int xIndex = Utils.r.nextInt(17); int yIndex = Utils.r.nextInt(17); // 如果没有棋 并且是电脑模式自己先出 if (myChess.size() == 0 && advChess.size() == 0) {// 这是表示是电脑先出 addChess(new Chess(xIndex, yIndex), advChess); return false; } else if (myChess.size() == 1 && advChess.size() == 0) {// 玩家先出 // 这个完全是多余的 纯粹增加花样 // 可以在玩的周边出一个 // 得到个随机数,在他的的哪个方向即偏移地址 Chess myCh = myChess.get(0); int offset = 1;// Utils.r.nextInt(15)+1;//偏移距离 int rndX = Utils.r.nextInt(2); int rndY = Utils.r.nextInt(2); int rX = rndX == 0 ? -1 : 1; int rY = rndY == 0 ? -1 : 1; while (!addChess(new Chess(myCh.getxIndex() + rX * offset, myCh .getyIndex() + rY * offset), advChess)) { rndX = Utils.r.nextInt(2); rndY = Utils.r.nextInt(2); rX = rndX == 0 ? -1 : 1; rY = rndY == 0 ? -1 : 1; } return false; } // 这时,如果自己要赢了就开始赢 Chess c = getBestChess(advChess, true); if (checkResult(c.getxIndex(), c.getyIndex(), advChess)) { return addChess(c, advChess); } // 电脑防御模式,如果玩家有只要放入一个棋可以达到4分,就要进行防御 Chess advC = getBestChess(myChess, false); if (advC == null) { advC = c; } addChess(advC, advChess); return false;// checkResult(c.getxIndex(),c.getyIndex());//是否胜 } /** * 得到玩家可能要赢了的点 玩家4分的点也要控制 得到一个可以最大分数的点 最佳的点 * * @param playerChess * @param flag * 标示电脑的棋还是玩家的棋 玩家的话 如果分数小于4则不要 * @return */ public Chess getBestChess(List<Chess> playerChess, boolean flag) { int maxScore = -1; int score = -1; int maxScoreX = -1; int maxScoreY = -1; int xIndex = -1, yIndex = -1; geted: for (Chess c : playerChess) { xIndex = c.getxIndex(); yIndex = c.getyIndex(); // 左边 {-1,0},右边{1,0},左上角的{-1,-1}.... for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { // 不能同时为零0 if (i == j && i == 0) continue; score = Utils.getBestPointScore(xIndex + i, yIndex + j, allChess, playerChess); if (score >= maxScore) { maxScore = score; maxScoreX = xIndex + i; maxScoreY = yIndex + j; if (maxScore >= 5) break geted; } } } } // 如果此时再判断玩家的棋 if (!flag) { if (maxScore < 4) return null; } return new Chess(maxScoreX, maxScoreY, true); } public boolean checkResult(int x, int y, List<Chess> playerChess) { int scorePre = 0; // 这个点的左,左上,上 ,左下能得分 int socreNext = 0;// 这个点的 右,右下,下,右上 int score = 0; int maxScore = 0; int offsetX, offsetY; /** * 前半段 后半段 X Y X Y 横 向 -1 0 1 0 竖 向 0 -1 0 1 下上斜 -1 1 1 -1 上下斜 -1 -1 1 1 */ for (int i = -1; i <= 0; i++) { for (int j = -1; j <= 1; j++) { if (i == j && i == 0) continue; if (0 == 0 && y == 1) continue;// 不判断也可以 // 前半段 offsetX = i; offsetY = j; scorePre = Utils.getPointScore(x, y, offsetX, offsetY, playerChess); // 后半段 offsetX = -i; offsetY = -j; socreNext = Utils.getPointScore(x, y, offsetX, offsetY, playerChess); score = scorePre + socreNext + 1; maxScore = score >= maxScore ? score : maxScore; if (maxScore >= 5) return true; } } return false; } /** * 重载,检查是否赢了 * * @param x * @param y * @return */ public boolean checkResult(int x, int y) { List<Chess> playerChess = myOrder ? myChess : advChess; return checkResult(x, y, playerChess); } /** * 添加棋的方法 * * @param chess * @param playerChess * @return */ public boolean addChess(Chess chess, List<Chess> playerChess) { // 判断是否越界 if (chess.getxIndex() < 0) return false; if (chess.getxIndex() > 16) return false; if (chess.getyIndex() < 0) return false; if (chess.getyIndex() > 16) return false; // 重载 if (allChess.contains(chess)) { return false; } Chess c = new Chess(chess); // 没有被占用的话 allChess.add(c); return playerChess.add(c); } // /** * 重载 添加棋的方法 * * @param chess * @param myOrder * @return */ public boolean addChess(Chess chess, boolean myOrder) { List<Chess> playerChess = myOrder ? myChess : advChess; return addChess(chess, playerChess); } /** * 画图容器 * * @author * */ public class Mypanel extends JPanel { @Override protected void paintComponent(Graphics g) { // 画背景 g.drawImage(Utils.images.get("Board.gif"), 0, 0, this); g.setColor(new Color(224, 192, 0)); g.fillRect(Utils.IMAGE_WIDTH, 0, Utils.WIDTH - Utils.IMAGE_WIDTH, Utils.HEIGHT); g.setColor(Color.WHITE); g.setFont(new Font("隶书", Font.PLAIN, 20)); // 画图标 g.drawString("当前:", Utils.IMAGE_WIDTH + 10, 52);// 让电脑延时几秒再出其 BufferedImage img = Utils.images.get("white.gif"); if (!myOrder) { img = Utils.images.get("black.gif"); } g.drawImage(img, Utils.IMAGE_WIDTH + 70, 35, this); // 画框 g.drawRect(Utils.IMAGE_WIDTH, 20, Utils.WIDTH - Utils.IMAGE_WIDTH - 10, Utils.HEIGHT - 68); // 画自己的棋 img = Utils.images.get("white.gif"); for (Chess c : myChess) { g.drawImage(img, c.getX(), c.getY(), this); } // 画对方的棋 img = Utils.images.get("black.gif"); for (Chess c : advChess) { g.drawImage(img, c.getX(), c.getY(), this); } // 画赢了 if (gameOver && win) { // 谁赢了? String name = ""; if (myOrder) { myCouter++; name = (gameModel == 1) ? "白方" : "我"; } else { advCouner++; name = (gameModel == 0) ? "电脑" : "黑方";// 电脑模式 } g.setFont(new Font("隶书", Font.BOLD, 65)); g.setColor(Color.WHITE); g.drawString(name + "赢了!", 100, 200); g.setFont(new Font("隶书", Font.BOLD, 65)); g.setColor(Color.RED); g.drawString(name + "赢了!", 100, 202); } // 画战绩: g.setFont(new Font("楷体", Font.PLAIN, 15)); g.setColor(Color.WHITE); g.drawString(((gameModel == 1) ? "黑方(赢):" : "电脑(赢):") + advCouner, Utils.IMAGE_WIDTH + 10, 100); g.drawString(((gameModel == 1) ? "白方(赢):" : " 我(赢):") + myCouter, Utils.IMAGE_WIDTH + 10, 120); } } public static void main(String[] args) { new MainFrame(); } }
- 棋子类:
package com.gxlee.wzq; /** * 棋 * @author http://www.cnblogs.com/HFLY * */ public class Chess { private int x;// x坐标 private int y;// y 坐标 private int xIndex; private int yIndex; // 构造函数 public Chess(int xIndex, int yIndex) { super(); this.xIndex = xIndex; this.yIndex = yIndex; this.x = xIndex * 25 + 18 - 12;// 通过格子求出十字架的位置 12 是棋子的一半 this.y = yIndex * 25 + 20 - 12; } public Chess(Chess c) { this.xIndex = c.getxIndex(); this.yIndex = c.getyIndex(); this.x = xIndex * 25 + 18 - 12;// this.y = yIndex * 25 + 20 - 12; } public Chess(int xIndex, int yIndex, boolean checkFlag) { super(); this.xIndex = xIndex; this.yIndex = yIndex; } @Override public boolean equals(Object obj) { if (obj instanceof Chess) { Chess c = (Chess) obj; if (c.xIndex == this.xIndex && c.yIndex == this.yIndex) { return true; } } return false; } public int getxIndex() { return xIndex; } public void setxIndex(int xIndex) { this.xIndex = xIndex; } public int getyIndex() { return yIndex; } public void setyIndex(int yIndex) { this.yIndex = yIndex; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } }
- 工具类:
package com.gxlee.wzq; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; import javax.imageio.ImageIO; /** * 工具类 * @author http://www.cnblogs.com/HFLY * */ public class Utils { public static Random r = new Random(); public static Map<String,BufferedImage> images = new HashMap<String,BufferedImage>(); public static final int WIDTH = 560;//游戏界面的宽 public static final int IMAGE_WIDTH = 437; public static final int HEIGHT = 465;//游戏界面的高 static{ File dir = new File("src/img"); File[] files = dir.listFiles(); for (File file : files) { BufferedImage img; try { img = ImageIO.read(file); images.put(file.getName(), img); } catch (IOException e) { e.printStackTrace(); } } } /**电脑出棋时判断双方最佳点的方法 * @param x * @param y * @param allChess * @param playerChess 传入哪方就得出哪方最佳点 * @return */ public static int getBestPointScore(int x,int y,List<Chess> allChess,List<Chess> playerChess){ //坐标越界 if(x<0) return -1; if(x>16) return -1; if(y<0) return -1; if(y>16) return -1; //如果这个点被电脑占用了 则不能使用 if(allChess.contains(new Chess(x,y))) return -1; // 向前延伸得分加上向后加当前1分为总得分 int scorePre=0; //这个点的左,左上,上 ,左下能得分 int socreNext=0;//这个点的 右,右下,下,右上 int score = 0 ; int maxScore = 0; int offsetX,offsetY; /** * 前半段 后半段 X Y X Y 横 向 -1 0 1 0 竖 向 0 -1 0 1 下上斜 -1 1 1 -1 上下斜 -1 -1 1 1 */ geted:for (int i = -1; i <=0; i++) { for(int j = -1;j<=1;j++){ if(i==j && i==0) continue; //前半段 offsetX = i;offsetY = j; scorePre = getPointScore(x,y,offsetX,offsetY,playerChess); //后半段 offsetX = i*(-1);offsetY = j*(-1); socreNext = getPointScore(x,y,offsetX,offsetY,playerChess); score = scorePre+socreNext+1; maxScore = score>=maxScore?score:maxScore; if (maxScore>=5) break geted; } } return maxScore; } /**每一点的得分 * @param x * @param y * @param offsetX * @param offsetY * @param playerChess * @return */ public static int getPointScore(int x,int y,int offsetX,int offsetY,List<Chess> playerChess){ int score = 0; int xAdd = offsetX; int yAdd = offsetY; while (playerChess.contains(new Chess(x+offsetX,y+offsetY))) { score ++; offsetX += xAdd; offsetY += yAdd; } return score; } }
- 素材
- 棋盘
- 棋子