JAVA小项目之五子棋

时间:2023-03-08 23:22:57
JAVA小项目之五子棋

  五子棋V1.0

  功能:

  1. 人人对战,人机对战(初级)
  2. 记录双方分数;

主要知识点:

   二维坐标系中,各方向坐标的关系及规律。

效果图:

  JAVA小项目之五子棋

  • 主框架类:
 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;
 }
 }
  • 素材
    •   棋盘

        JAVA小项目之五子棋

    •   棋子

        JAVA小项目之五子棋JAVA小项目之五子棋