溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

使用Java怎么實現(xiàn)五子棋AI

發(fā)布時間:2021-05-31 17:24:29 來源:億速云 閱讀:145 作者:Leah 欄目:編程語言

使用Java怎么實現(xiàn)五子棋AI?相信很多沒有經(jīng)驗的人對此束手無策,為此本文總結(jié)了問題出現(xiàn)的原因和解決方法,通過這篇文章希望你能解決這個問題。

思路:

  • ①五子棋界面的實現(xiàn)

  • ②交互下棋的實現(xiàn)

  • ③重繪

  • ④AI,實現(xiàn)人機對戰(zhàn)

五子棋和簡單AI的實現(xiàn):

首先將五子棋的界面寫出來。

首先我們寫一個接口類,定義好棋盤的數(shù)據(jù)(目的是方便修改)。

public interface Config {
  public static final int X0=50;//左上角起點X值
  public static final int Y0=50;//左上角起點Y值
  public static final int ROWS=15;//橫向線數(shù)
  public static final int COLUMNS=15;//縱向線數(shù)
  public static final int CHESSSIZE=40;//棋子直徑
  public static final int SIZE=50;//單元格大小
}

再來寫五子棋的界面。寫界面的方法和畫圖板是一樣的。

public class FiveChessUI extends JFrame implements Config {
  static FiveChessUI fcUI = new FiveChessUI();
  public static void main(String[] args){
    fcUI.initUI();
  }
  private int [][] chesses = new int[ROWS][COLUMNS];//創(chuàng)建一個二維數(shù)組用來標記棋盤上的位置
  /**
   * 初始化五子棋窗體的方法
   */
  public void initUI(){
    ChessListener listener = new ChessListener(chesses,fcUI);
    this.setTitle("五子棋v1.0");
    this.setSize(900, 800);//設置界面尺寸
    this.setResizable(false);//界面不可改變大小
    this.setLocationRelativeTo(null);//設置界面居中
    this.setDefaultCloseOperation(3);//設置退出進程
    BorderLayout bl = new BorderLayout();//設置界面布局為窗體式布局
    this.setLayout(bl);
    JPanel jp = new JPanel();
    jp.setPreferredSize(new Dimension(100,0));
    this.add(jp,BorderLayout.EAST);
    String [] name ={"重新開始","黑棋先下","白棋先下","悔棋","人機對戰(zhàn)","人人對戰(zhàn)"};
    for(int i=0;i<name.length;i++){//依次給按鈕添加動作監(jiān)聽,這里用循環(huán)可減少代碼
      JButton jbu = new JButton(name[i]);
      jbu.setPreferredSize(new Dimension(95,30));
      jp.add(jbu);
      jbu.addActionListener(listener);
    }
    this.setVisible(true);//設置可見
    listener.gr = this.getGraphics();
    this.addMouseListener(listener);//給界面加上鼠標監(jiān)聽
  }
  /**
   * 重寫繪制窗體的方法
   */
  public void paint(Graphics g){
    super.paint(g);
    //在重繪的同時繪制棋盤
    drawChessTable(g);
    //在重繪的同時繪制棋子
    drawChess(g);
  }
  public void drawChess(Graphics g){
    ImageIcon bai = new ImageIcon("C:\\Users\\Administrator\\Pictures\\五子棋\\baizi.png");//添加白子圖片
    ImageIcon hei = new ImageIcon("C:\\Users\\Administrator\\Pictures\\五子棋\\heizi.png");//添加黑子圖片
    for(int i=0;i<chesses.length;i++){
      for(int j=0;j<chesses.length;j++){
        if(chesses[i][j]==1){
          g.drawImage(hei.getImage(), X0 + SIZE * i - Config.CHESSSIZE / 2, Y0 + SIZE * j - Config.CHESSSIZE / 2, Config.CHESSSIZE,
              Config.CHESSSIZE, null);
        }else if(chesses[i][j]==-1){
          g.drawImage(bai.getImage(), X0 + SIZE * i - Config.CHESSSIZE / 2, Y0 + SIZE * j - Config.CHESSSIZE / 2, Config.CHESSSIZE,
              Config.CHESSSIZE, null);
        }
      }
    }
  }
  public void drawChessTable(Graphics g){
    //添加背景圖片
    ImageIcon img= new ImageIcon("C:\\Users\\Administrator\\Pictures\\chesstable.jpg");
    g.drawImage(img.getImage(), 0, 0, 800, 800,null);
    //畫棋盤橫線
    for(int i=0;i<ROWS;i++){
      g.drawLine(X0, Y0+i*SIZE, X0+(COLUMNS-1)*SIZE, Y0+i*SIZE);
    }
    //畫棋盤豎線
    for(int j=0;j<Config.COLUMNS;j++){
      g.drawLine(X0+j*SIZE, Y0, X0+j*SIZE,Y0+(ROWS-1)*SIZE );
    }
  }
}

監(jiān)聽器類代碼如下:

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.util.HashMap;
import javax.swing.ImageIcon;
import javax.swing.JOptionPane;
public class ChessListener extends MouseAdapter implements Config, ActionListener {
  public Graphics gr;
  private int count = 0;// 計數(shù)器
  private int[][] chesses;// 創(chuàng)建一個二維數(shù)組用來存放棋子的坐標
  private String name;
  private int t, r;
  private int cl = 0, AI=2;
  private int i, j, x, y, z = 0, w = 0,zz=0,ww=0;
  private FiveChessUI fc;// 聲明FiveChessUI類的一個對象
  private int setX[] = new int[ROWS * COLUMNS];// 創(chuàng)建一維數(shù)組setX[]
  private int setY[] = new int[ROWS * COLUMNS];// 創(chuàng)建一維數(shù)組setY[]
  private int[][] chessValue = new int[ROWS][COLUMNS];
  private int index = 0;// 創(chuàng)建數(shù)組的下標
  HashMap<String, Integer> hm = new HashMap<String, Integer>();//創(chuàng)建權(quán)值表
  public ChessListener(int[][] chesses, FiveChessUI fc) {
    this.fc = fc;
    this.chesses = chesses;
    //權(quán)值設置,這個需要自己慢慢調(diào),小編寫的一般,AI有時會出問題
    hm.put("1", 20);
    hm.put("11", 60);
    hm.put("111", 200);
    hm.put("1111", 1000);
    hm.put("-1", 20);
    hm.put("-1-1", 60);
    hm.put("-1-1-1", 200);
    hm.put("-1-1-1-1", 1000);
    hm.put("1-1", 20);
    hm.put("11-1", 30);
    hm.put("111-1", 80);
    hm.put("1111-1", 1000);
    hm.put("-11", 20);
    hm.put("-111", 30);
    hm.put("-1111", 80);
    hm.put("-11111", 1000);
    hm.put("1-1", 20);
    hm.put("-1-11", 30);
    hm.put("-1-1-11", 80);
    hm.put("-1-1-1-11", 1000);
    hm.put("1-1", 20);
    hm.put("1-1-1", 30);
    hm.put("1-1-1-1", 80);
    hm.put("1-1-1-1-1", 1000);
  }
  public void mouseReleased(MouseEvent e) {
    // 得到鼠標事件發(fā)生的時候光標的位置
    int x1 = e.getX();
    int y1 = e.getY();
    // 按行遍歷棋盤,坐標(i,j)
    for (j = 0; j < ROWS; j++) {
      for (i = 0; i < ROWS; i++) {// 得到交叉點的坐標
        x = X0 + SIZE * i;// 橫坐標
        y = Y0 + SIZE * j;// 縱坐標
        // 與圓心的誤差為size/3
        if (x1 > x - SIZE * 5 / 12 && x1 < x + SIZE * 5 / 12 && y1 > y - SIZE * 5 / 12
            && y1 < y + SIZE * 5 / 12) {
          ImageIcon bai = new ImageIcon("C:\\Users\\Administrator\\Pictures\\baizi5.png");
          ImageIcon hei = new ImageIcon("C:\\Users\\Administrator\\Pictures\\heizi4.png");
          if (AI == 0) { // 人人對戰(zhàn)
            if (chesses[i][j] == 0) {// 如果選的位置沒有棋子
              if (count == 0) {
                chesses[i][j] = 1;// 如果是黑子,就為1
                count++;
                gr.drawImage(hei.getImage(), X0 + SIZE * i - CHESSSIZE / 2,
                    Y0 + SIZE * j - CHESSSIZE / 2, CHESSSIZE, CHESSSIZE, null);
                cl = 0;
              } else {
                chesses[i][j] = -1;// 如果是白子就為-1
                count--;
                gr.drawImage(bai.getImage(), X0 + SIZE * i - CHESSSIZE / 2,
                    Y0 + SIZE * j - CHESSSIZE / 2, CHESSSIZE, CHESSSIZE, null);
                cl = 1;
              }
              setX[index] = i;// 將下的棋子的橫坐標存入setX[]
              setY[index] = j;// 將下的棋子的縱坐標存入setY[]
              index++;// 存入一個坐標,一維數(shù)組角標加1
              // 以交叉點畫圓
              checkRow(i, j);
              z = 1;
              w = 1;
              return;
            }
          }
          if (AI == 1) { // 人機對戰(zhàn)
            if (chesses[i][j] == 0) {// 如果選的位置沒有棋子
              if (count == 0) {
                // 玩家下棋
                chesses[i][j] = 1;// 如果是黑子,就為1
                // count++;
                gr.drawImage(hei.getImage(), X0 + SIZE * i - CHESSSIZE / 2,
                    Y0 + SIZE * j - CHESSSIZE / 2, CHESSSIZE, CHESSSIZE, null);
                cl = 0;
                count++;
                checkRow(i, j);//判斷是否勝利
                setX[index] = i;// 將下的棋子的橫坐標存入setX[]
                setY[index] = j;// 將下的棋子的縱坐標存入setY[]
                index++;// 存入一個坐標,一維數(shù)組角標加1
              }
              this.AI();
              if (count == 1) {
                // 輸出所有點的權(quán)值
                for (int j = 0; j < chessValue.length; j++) {
                  for (int i = 0; i < chessValue.length; i++) {
                    System.out.print(chessValue[i][j] + " ");
                  }
                  System.out.println();
                }
                // 電腦下棋
                // 篩選出chessValue最大值的交點坐標, 該坐標電腦下棋
                for (int j = 0; j < chessValue.length; j++) {
                  for (int i = 0; i < chessValue.length; i++) {
                    if (chessValue[0][0] < chessValue[i][j]) {
                      chessValue[0][0] = chessValue[i][j];
                      t = i;
                      r = j;
                    }
                  }
                }
                count--;
                chesses[t][r] = -1;
                gr.drawImage(bai.getImage(), X0 + SIZE * t - CHESSSIZE / 2,
                    Y0 + SIZE * r - CHESSSIZE / 2, CHESSSIZE, CHESSSIZE, null);
                cl = 1;
                setX[index] = r;// 將下的棋子的橫坐標存入setX[]
                setY[index] = t;// 將下的棋子的縱坐標存入setY[]
                index++;// 存入一個坐標,一維數(shù)組角標加1
                checkRow(t, r);//判斷是否勝利
                zz = 1;//
                ww = 1;
                // 清空value
                for (int i = 0; i < chessValue.length; i++) {
                  for (int j = 0; j < chessValue.length; j++) {
                    chessValue[i][j] = 0;
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  // 判斷勝利的條件
  public int checkRow(int x, int y) {
    int count1 = 0, count2 = 0, count3 = 0, count4 = 0;// 定義4個棋子計數(shù)器,分別計數(shù)水平,豎直、斜向右下、斜向左下
    for (int i = x + 1; i < chesses.length; i++) {
      if (chesses[i][y] == chesses[x][y]) {
        count1++;
      } else
        break;
    }
    for (int i = x; i >= 0; i--) {
      if (chesses[i][y] == chesses[x][y]) {
        count1++;
      } else
        break;
    }
    for (int j = y + 1; j < chesses.length; j++) {
      if (chesses[x][j] == chesses[x][y]) {
        count2++;
      } else
        break;
    }
    for (int j = y; j >= 0; j--) {
      if (chesses[x][y] == chesses[x][j]) {
        count2++;
      } else
        break;
    }
    for (int i = x + 1, j = y + 1; i < chesses.length && j < chesses.length; i++, j++) {
      if (chesses[i][j] == chesses[x][y]) {
        count3++;
      } else
        break;
    }
    for (int i = x, j = y; i >= 0 && j >= 0; i--, j--) {
      if (chesses[i][j] == chesses[x][y]) {
        count3++;
      } else
        break;
    }
    for (int i = x, j = y; i < chesses.length && j >= 0; i++, j--) {
      if (chesses[i][j] == chesses[x][y]) {
        count4++;
      } else
        break;
    }
    for (int i = x - 1, j = y + 1; i >= 0 && j < chesses.length; i--, j++) {
      if (chesses[i][j] == chesses[x][y]) {
        count4++;
      } else
        break;
    }
    if (count1 >= 5 || count2 >= 5 || count3 >= 5 || count4 >= 5) {
      count = 0;
      if (cl == 0) {
        JOptionPane.showMessageDialog(null, "黑棋贏!");
        for (int i = 0; i < chesses.length; i++) {
          for (int j = 0; j < chesses.length; j++) {
            chesses[i][j] = 0;
          }
        }
        fc.repaint();
      }
      if (cl == 1) {
        JOptionPane.showMessageDialog(null, "白棋贏!");
        for (int i = 0; i < chesses.length; i++) {
          for (int j = 0; j < chesses.length; j++) {
            chesses[i][j] = 0;
          }
        }
        fc.repaint();
      }
    }
    return count;
  }
  public void actionPerformed(ActionEvent e) {
    name = e.getActionCommand();
    if ("重新開始".equals(name)) {
      count = 0;
      z = 0;
      w = 0;
      for (int i = 0; i < chesses.length; i++) {
        for (int j = 0; j < chesses.length; j++) {
          chesses[i][j] = 0;
        }
      }
      fc.repaint();
    }
    if ("白棋先下".equals(name)) {
      if (z == 0) {
        count = 1;
        z = 1;
      }
    }
    if ("黑棋先下".equals(name)) {
      if (w == 0) {
        count = 0;
        w = 1;
      }
    }
    if ("悔棋".equals(name)) {
      this.huiqi();
    }
    if ("人機對戰(zhàn)".equals(name)) {
      if(w==0){
      AI = 1;
      ww=1;
      }
    }
    if ("人人對戰(zhàn)".equals(name)) {
      if(z==0){
      AI = 0;
      }
    }
  }
  public void huiqi() {
    if (index >= 0) {
      index--;
      if (index < 0) {
        index = 0;
      }
      x = setX[index];
      y = setY[index];
      if (chesses[x][y] == 1) {
        chesses[x][y] = 0;
        count = 0;
      }
      if (chesses[x][y] == -1) {
        chesses[x][y] = 0;
        count = 1;
      }
      if(chesses[t][r]==-1){
        chesses[t][r]=0;
        count=1;
      }
      fc.repaint();
    }
  }
  public void AI() {
    for (int i = 0; i < chesses.length; i++) {
      for (int j = 0; j < chesses.length; j++) {
        if (chesses[i][j] == 0) {// 判斷當前位置是否有棋子
          // 定義兩個變量分別保存棋局,顏色
          String code = "";
          int color = 0;
          // 向右
          for (int k = i + 1; k < chesses.length; k++) {
            if (chesses[k][j] == 0) {
              break;
            } else {
              if (color == 0) {// 右邊第一顆棋子
                color = chesses[k][j];// 保存顏色
                code += chesses[k][j];// 保存棋局
              } else if (chesses[k][j] == color) {// 右邊第二,第三同顏色棋子
                code += chesses[k][j];// 保存棋局
              } else { // 右邊不同顏色
                code += chesses[k][j];
                break;
              }
            }
          }
          // 根據(jù)code取出hm對應的權(quán)值
          Integer value = hm.get(code);
          if (value != null) {
            chessValue[i][j] += value;
          }
          // 向左方向
          code = "";
          color = 0;
          for (int k = i - 1; k >= 0; k--) {
            if (chesses[k][j] == 0) {
              break;
            } else {
              if (color == 0) {// 右邊第一顆棋子
                color = chesses[k][j];// 保存顏色
                code += chesses[k][j];// 保存棋局
              } else if (chesses[k][j] == color) {// 右邊第二,第三同顏色棋子
                code += chesses[k][j];// 保存棋局
              } else { // 右邊不同顏色
                code += chesses[k][j];
                break;
              }
            }
          }
          // 根據(jù)code取出hm對應的權(quán)值
          Integer value2 = hm.get(code);
          if (value2 != null) {
            chessValue[i][j] += value2;
          }
          // 向上方向
          code = "";
          color = 0;
          for (int k = j - 1; k >= 0; k--) {
            if (chesses[i][k] == 0) {
              break;
            } else {
              if (color == 0) {// 右邊第一顆棋子
                color = chesses[i][k];// 保存顏色
                code += chesses[i][k];// 保存棋局
              } else if (chesses[i][k] == color) {// 右邊第二,第三同顏色棋子
                code += chesses[i][k];// 保存棋局
              } else { // 右邊不同顏色
                code += chesses[i][k];
                break;
              }
            }
          }
          // 根據(jù)code取出hm對應的權(quán)值
          Integer value3 = hm.get(code);
          if (value3 != null) {
            chessValue[i][j] += value3;
          }
          // 向下方向
          code = "";
          color = 0;
          for (int k = j + 1; k < chesses.length; k++) {
            if (chesses[i][k] == 0) {
              break;
            } else {
              if (color == 0) {// 右邊第一顆棋子
                color = chesses[i][k];// 保存顏色
                code += chesses[i][k];// 保存棋局
              } else if (chesses[i][k] == color) {// 右邊第二,第三同顏色棋子
                code += chesses[i][k];// 保存棋局
              } else { // 右邊不同顏色
                code += chesses[i][k];
                break;
              }
            }
          }
          // 根據(jù)code取出hm對應的權(quán)值
          Integer value4 = hm.get(code);
          if (value4 != null) {
            chessValue[i][j] += value4;
          }
          // 右上方向
          code = "";
          color = 0;
          for (int k = j + 1, l = i - 1; l >= 0 && k < chesses.length; l--, k++) {
            if (chesses[l][k] == 0) {
              break;
            } else {
              if (color == 0) {// 右邊第一顆棋子
                color = chesses[l][k];// 保存顏色
                code += chesses[l][k];// 保存棋局
              } else if (chesses[l][k] == color) {// 右邊第二,第三同顏色棋子
                code += chesses[l][k];// 保存棋局
              } else { // 右邊不同顏色
                code += chesses[l][k];
                break;
              }
            }
          }
          // 根據(jù)code取出hm對應的權(quán)值
          Integer value6 = hm.get(code);
          if (value6 != null) {
            chessValue[i][j] += value6;
          }
          // 左下方向
          code = "";
          color = 0;
          for (int k = i + 1, l = j - 1; l >= 0 && k < chesses.length; k++, l--) {
            if (chesses[k][l] == 0) {
              break;
            } else {
              if (color == 0) {// 右邊第一顆棋子
                color = chesses[k][l];// 保存顏色
                code += chesses[k][l];// 保存棋局
              } else if (chesses[k][l] == color) {// 右邊第二,第三同顏色棋子
                code += chesses[k][l];// 保存棋局
              } else { // 右邊不同顏色
                code += chesses[k][l];
                break;
              }
            }
          }
          // 根據(jù)code取出hm對應的權(quán)值
          Integer value7 = hm.get(code);
          if (value7 != null) {
            chessValue[i][j] += value7;
          }
          // 右下方向
          code = "";
          color = 0;
          for (int k = i - 1, l = j - 1; l >= 0 && k >= 0; l--, k--) {
            if (chesses[k][l] == 0) {
              break;
            } else {
              if (color == 0) {// 右邊第一顆棋子
                color = chesses[k][l];// 保存顏色
                code += chesses[k][l];// 保存棋局
              } else if (chesses[k][l] == color) {// 右邊第二,第三同顏色棋子
                code += chesses[k][l];// 保存棋局
              } else { // 右邊不同顏色
                code += chesses[k][l];
                break;
              }
            }
          }
          // 根據(jù)code取出hm對應的權(quán)值
          Integer value8 = hm.get(code);
          if (value8 != null) {
            chessValue[i][j] += value8;
          }
          // 左上方向
          code = "";
          color = 0;
          for (int k = i + 1, l = j + 1; k < chesses.length && l < chesses.length; l++, k++) {
            if (chesses[k][l] == 0) {
              break;
            } else {
              if (color == 0) {// 右邊第一顆棋子
                color = chesses[k][l];// 保存顏色
                code += chesses[k][l];// 保存棋局
              } else if (chesses[k][l] == color) {// 右邊第二,第三同顏色棋子
                code += chesses[k][l];// 保存棋局
              } else { // 右邊不同顏色
                code += chesses[k][l];
                break;
              }
            }
          }
          // 根據(jù)code取出hm對應的權(quán)值
          Integer value5 = hm.get(code);
          if (value5 != null) {
            chessValue[i][j] += value5;
          }
        }
      }
    }
  }
}

看完上述內(nèi)容,你們掌握使用Java怎么實現(xiàn)五子棋AI的方法了嗎?如果還想學到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI