人工智能五子棋java实现

一、算法思想

1、搜索树
甲乙两人下棋,甲有很多种落子方式,乙也有多种应对走法,如果把所有的走法列出来,自然就构成了一棵树,即为搜索树,也称博弈树。树的根结点为先手的第一步走法,下面的走法构成了树的子结点,直至棋局结束。显然,如果棋盘足够大,子结点数会以几何级数上升,而我们的任务是从这些子结点中寻找一个对己方最有利的结点,从而得到棋局的最佳走法。
估值函数
估值函数通常是为了评价棋型的状态,根据实现定义的一个棋局估值表,对双方的棋局形态进行计算,根据得到的估值来判断应该采用的走法。棋局估值表是根据当前的棋局形势,定义一个分值来反映其优势程度,来对整个棋局形势进行评价。
3、极大极小搜索
极大极小搜索算法就是在博弈树在寻找最优解的一个过程,这主要是一个对各个子结点进行比较取舍的过程,定义一个估值函数F(n)来分别计算各个终结点的分值,通过双方的分值来对棋局形势进行分析判断。还是以甲乙两人下棋为例,甲为max,乙为min。当甲走棋时,自然在博弈树中寻找最大点的走法,轮到乙时,则寻找最小点的走法,如此反复,这就是一个极大极小搜索过程,以此来寻找对机器的最佳走法。
4、剪枝算法
αβ剪枝算法简单来说,就是在搜索过程中减少一定的冗余现象,如已经找到极大值,执行该走法就可以获胜,则无须再往下进行搜索比较,此过程即为剪枝。对于极大的MAX结点,称为α剪枝;反之为β剪枝。具体规则可以简单描述如下:
α剪枝:对于极大值层结点的α值如果不小于它的任一祖先极小值层结点的β值,即α(后续层)≥β(祖先层),则可中止该极大值层中这个MAX节点以下的搜索过程,这个MAX节点最终的倒推值就确定为这个α值。
β剪枝:对于极小值结点层的β值如果不大于它任一祖先极大值层结点的α值,即α(祖先层)≥β(后续层),则可中止对该极小值层中这个MIN节点以下结点的搜索,这个MIN节点最终的倒推值就确定为这个β值。

二、详细设计

2.1总体设计
在算法设计中,比较重要的是评价函数的求法,因为评价函数是在中级或者高级难度的游戏模式中,计算机选择落棋位置的重要依据。
在五子棋游戏中,棋型很重要,其中有连五(表示已经有五子连线),活四(四子连线并且两边都没有被堵住),眠四(四子连线有一边被堵住),活三(三子连线两边都没有被堵上),眠三(三子连线,有一边被堵上),活二,眠二依次类推,其中还有一些其他的情况如:EUUOUU,OUUOUUO等,其中E表示有冲突(边界或者对方的棋子),U表示已经连线的棋子,O表示空白的位置,我们对这些很有可能连线的棋型,按照连成五子的概率大小不同定义不同的分值。因为我们求评价函数的作用是选择一个合适的地方落子,所以求评价值是针对空位置。假如我要求某位置黑子的评价值,就是试验性的将这个位置放上黑子,在横向,纵向,两个斜线方向分别以这个位置(x,y)为中心,向两边分别截取4位(因为第五位和此位置无关)一共截取9位,再看棋型,得到分数,再将这四个方向的分数相加。就为此位置的评价值。具体的截取方法,匹配方法与计算的方法我在详细设计部分会很清楚的表达。这部分用方法public int calculateScore(final int x,final int y,int color)实现,x,y为横坐标,纵坐标,color为棋子的颜色。返回求得的评价值。
中级难度的下法为,遍历棋盘,找到己方评价函数最高的位置A,再找到对方评价值最高的位置B,假如自己方的分数高于或者等于对方的分数,就将棋子落在A,反之落在位置B。
高级的下法为
整个程序设计的类,属性,方法如下:
1、类fivechess:
public class fivechess extends JFrame implements ActionListener
成员:
JButton back=new JButton(“悔棋”);
JButton start=new JButton(“开始”);
JButton game=new JButton(“中级难度”);
JButton game2=new JButton(“高级难度”);
GameBoard gb=new GameBoard();
JPanel pb=new JPanel();
JPanel pg=new JPanel();
方法:
public fivechess()//构造函数
public void actionPerformed(ActionEvent e)//实现按钮事件
2、类GameBoard:
public class GameBoard extends JPanel implements MouseListener
成员:
public int row=14;//棋盘行数
public int col=14;//棋盘列数
public int length=30;//每个格子的大小
public int edgedis=30;//边距
public int[][] ChessBoard=new int[row+1][col+1];//棋子代表的二维数组,
int chessNum=0;//已经下了的棋子数目
boolean IsBlack=true;//判断哪方下子(黑子先行)
int lastx=-1,lasty=-1; //最后下子的位置
int llastx=-1,llasty=-1; //倒数第二次下的位置,方便悔棋
boolean Win=false;//是否胜利的标志
static final int radius=15;
//棋盘的位置的分值(固定为15x15的棋盘)
方法:
public GameBoard()//构造函数
public void paintComponent(Graphics g)//画棋局
public void mousePressed(MouseEvent e)//鼠标事件
public void computerplayer()//中级下法
public void computerplayerhigher()//高级下法
public int maxMinWithAlphaBetaCut(int chessBoard[][], int whiteOrBlack, int depth, int x,int y, int alpha, int beta)//剪枝算法
public int calculateScore(final int x,final int y,int color)//算分值
public boolean isExit(int x,int y)//此位置有没有棋子
public boolean IsWin()//判断是否已经有五子连线的情况
public int ChessCount(int xChange,int yChange,int color)//计算棋子在xChange和yChange方向上连接的数量(1,0)横向,(0,1)纵向,(1,1)主对角线,(-1,-1)副对角线
2.2 算法设计
这部分只介绍重要的算法,在此程序中重要的算法有三个,评价值的计算,中级难度下法
1.评价值计算
在横向,纵向,两个斜线方向分别以这个位置(x,y)为中心,向两边分别截取4位(因为第五位和此位置无关)一共截取9位,再看棋型,得到分数,再将这四个方向的分数相加。就为此位置的评价值。
首先需要定义棋型,我将棋型用字符串来表示存储在string类型的数组type中,将相应的得分存储在int类型的数组score中。其中E表示有冲突(边界或者对方的棋子),U表示已经连线的棋子,O表示空白的位置。用下标对应
在这里插入图片描述
在这里插入图片描述
每种棋型的类型,以及棋型的评分合理与否很大程度上反应了智能程度,所以在设置上要多留心,也可以在后续的测试中留意分值的设置是否合理。首先我们需要在棋盘中截取棋型,以指定的坐标(x,y)为中心,在横向,竖向,正斜个,反斜上向两边扩展,定义一temp[4]数组其为string类型,分别用来存放在横向,竖向,正斜,反斜方向截取的棋型。在横向上的截取是保持y坐标不变,设扩展的位数为bite。在x轴左向扩展时坐标的变化为(x-bite,y)所以要确保x-bite>=0,由于棋盘是以0开始的,所以当x小于4时能扩展的位数为bite=4-Math.abs(x-4)。
在往右向扩展时坐标的变化为(x+bite,y)所以要确保x+bite<=14,当在bite小于等于4而x+bite>14时就停止扩展。当在扩展到的位置遇到自己方的棋子有temp[0]=temp[0]+”U”当在扩展位置遇到对方的棋子或者遇到边界则有temp[0]=temp[0]+”C”扩展到的位置的为空位置则有temp[0]=temp[0]+”O”。同理在其他方向也按照这个原则进行扩展生成自己的棋型temp[]。
各个方向扩展的坐标变化如下:
在这里插入图片描述
竖向向上(x,y-bite) 竖向向下(x,y+bite)
正斜向上(x-bite,y-bite) 正斜向下(x+bite,y+bite)
反斜向上(x+bite,y-bite) 反斜向下(x-bite,y+bite)
需要注意边界问题。代码实现如下:

///////////////////////////在x轴方向上取////////////////////////////////
            if(x-4<0){     
                int bite=4-Math.abs(x-4);
                temp[0]=temp[0]+"C";
                while(bite!=0){
                    if(ChessBoard[x-bite][y]==0){
                        temp[0]=temp[0]+"O";
                    }
                    else if(ChessBoard[x-bite][y]==color){
                        temp[0]=temp[0]+"U";
                    }
                    else {
                        temp[0]=temp[0]+"C";
                    }
                    bite--;
                }
            }
            else {
                for(int i=4;i>0;i--){
                    if(ChessBoard[x-i][y]==0){
                        temp[0]=temp[0]+"O";
                    }
                    else if(ChessBoard[x-i][y]==color){
                        temp[0]=temp[0]+"U";
                    }
                    else {
                        temp[0]=temp[0]+"C";
                    }
                }
            }
            for(int i=0;i<=4;i++){
                if(x+i>14) {
                    temp[0]=temp[0]+"C";
                    break;
                }
                if(ChessBoard[x+i][y]==0){
                    temp[0]=temp[0]+"O";
                }
                else if(ChessBoard[x+i][y]==color){
                    temp[0]=temp[0]+"U";
                }
                else {
                    temp[0]=temp[0]+"C";
                }
            }
       //////////////////在y方向截取////////////////////////////
            if(y-4<0){     
                int bite=4-Math.abs(y-4);
                temp[1]=temp[1]+"C";
                while(bite!=0){
                    if(ChessBoard[x][y-bite]==0){
                        temp[1]=temp[1]+"O";
                    }
                    else if(ChessBoard[x][y-bite]==color){
                        temp[1]=temp[1]+"U";
                    }
                    else {
                        temp[1]=temp[1]+"C";
                    }
                    bite--;
                }
            }
            else {
                for(int i=4;i>0;i--){
                    if(ChessBoard[x][y-i]==0){
                        temp[1]=temp[1]+"O";
                    }
                    else if(ChessBoard[x][y-i]==color){
                        temp[1]=temp[1]+"U";
                    }
                    else {
                        temp[1]=temp[1]+"C";
                    }
                }
            }
            for(int i=0;i<=4;i++){
                if(y+i>14) {
                    temp[1]=temp[1]+"C";
                    break;
                }
                if(ChessBoard[x][y+i]==0){
                    temp[1]=temp[1]+"O";
                }
                else if(ChessBoard[x][y+i]==color){
                    temp[1]=temp[1]+"U";
                }
                else {
                    temp[1]=temp[1]+"C";
                }
            }

        //////////////////////在左下,右上方向上//////////////////////////////
            if(x-4<0||14-(y+4)<0){
            int b=0;
            if(x-4<0&&14-(y+4)<0){     
                 b=Math.min(4-Math.abs(x-4),14-y);
                 }
            else if(x-4<0&&y<=10){
                b=4-Math.abs(x-4);
            }
            else if(14-(y+4)<0&&x-4>=0){
                b=14-y;
            }
                temp[2]=temp[2]+"C";
                while(b!=0){
                    if(ChessBoard[x-b][y+b]==0){
                        temp[2]=temp[2]+"O";
                    }
                    else if(ChessBoard[x-b][y+b]==color){
                        temp[2]=temp[2]+"U";
                    }
                    else {
                        temp[2]=temp[2]+"C";
                    }
                    b--;
                }
            }
            else{
                for(int i=4;i>0;i--){
                    if(ChessBoard[x-i][y+i]==0){
                        temp[2]=temp[2]+"O";
                    }
                    else if(ChessBoard[x-i][y+i]==color){
                        temp[2]=temp[2]+"U";
                    }
                    else {
                        temp[2]=temp[2]+"C";
                    }
                }
            }
            if(y-4<0||14-(x+4)<0){  
                int b=0;
                if(y-4<0&&14-(x+4)<0){     
                     b=Math.min(4-Math.abs(y-4),14-x);
                     }
                else if(y-4<0&&x<=10){
                    b=4-Math.abs(y-4);
                }
                else if(14-(x+4)<0&&y-4>=0){
                    b=14-x;
                }
                    while(b!=0){
                        if(ChessBoard[x+b][y-b]==0){
                            temp[2]=temp[2]+"O";
                        }
                        else if(ChessBoard[x+b][y-b]==color){
                            temp[2]=temp[2]+"U";
                        }
                        else {
                            temp[2]=temp[2]+"C";
                        }
                        b--;
                    }
                    temp[2]=temp[2]+"C";
                }
                else{
                    for(int i=0;i<=4;i++){
                        if(ChessBoard[x+i][y-i]==0){
                            temp[2]=temp[2]+"O";
                        }
                        else if(ChessBoard[x+i][y-i]==color){
                            temp[2]=temp[2]+"U";
                        }
                        else {
                            temp[2]=temp[2]+"C";
                        }
                    }

            }
    //////////////////////在左上,右下方向上////////////////////////////////
            if(x-4<0||y-4<0){
                int bite=0;
                if(x-4<0&&y-4<0){
             bite=Math.min(4-Math.abs(x-4),4-Math.abs(y-4));
                }
                else if(x-4<0&&y-4>=0){
                    bite=4-Math.abs(x-4);
                }
                if(y-4<0&&x-4>=0){
                    bite=4-Math.abs(y-4);
                }
                temp[3]=temp[3]+"C";
                while(bite!=0){
                    if(ChessBoard[x-bite][y-bite]==0){
                        temp[3]=temp[3]+"O";
                    }
                    else if(ChessBoard[x-bite][y-bite]==color){
                        temp[3]=temp[3]+"U";
                    }
                    else {
                        temp[3]=temp[3]+"C";
                    }
                    bite--;
                }
            }
            else {
                for(int i=4;i>0;i--){
                    if(ChessBoard[x-i][y-i]==0){
                        temp[3]=temp[3]+"O";
                    }
                    else if(ChessBoard[x-i][y-i]==color){
                        temp[3]=temp[3]+"U";
                    }
                    else {
                        temp[3]=temp[3]+"C";
                    }
                }
            }
            for(int i=0;i<=4;i++){
                if(y+i>14||x+i>14) {
                    temp[3]=temp[3]+"C";
                    break;
                }
                if(ChessBoard[x+i][y+i]==0){
                    temp[3]=temp[3]+"O";
                }
                else if(ChessBoard[x+i][y+i]==color){
                    temp[3]=temp[3]+"U";
                }
                else {
                    temp[3]=temp[3]+"C";
                }
            }

截取完之后我们需要计算得分,因为截取到的长度是长于定义的棋型的,所以只要在截取到棋型构成的字符串里面,有已经定义的棋型的子串,那么就算匹配上,该位置的得分加上该棋型对应的分数。匹配引入包:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
调用方法来求得
Pattern p=Pattern.compile(type[j]);
Matcher m=p.matcher(temp[i]);
if(m.find())
因为棋型在type数组里面存储顺序是按分数递减存储的,所以最开始找到的棋型为最好的,在这四个方向上找到最好的就停止寻找,继续找下一个方向的。直到得到四个方向的分数并且相加,就为最终的结果。
代码实现为:

 int result=0;
            for(int i=0;i<4;i++){
                for(int j=0;j<38;j++){
                    Pattern p=Pattern.compile(type[j]);
                    Matcher m=p.matcher(temp[i]);
                    if(m.find()){
                        result+=score[j];
                        break;
                    }
                }
            }

3.3.2中级下法
中级难度的下法为,遍历棋盘,找到己方评价函数最高的位置A,再找到对方评价值最高的位置B,假如自己方的分数高于或者等于对方的分数,就将棋子落在A,反之落在位置B。
代码实现如下:

public void computerplayer(){
        /////////////默认黑棋先行///////////////////////////
            int MaxScoreBlack=0;
            int MaxScorewhite=0;
            int TempScore=0;
            int maxXB=0,maxYB=0,maxXW=0,maxYW=0;
            int color=2;
            llastx=lastx;
            llasty=lasty;
   ///////////////////////算白棋总分,当对方的棋局威胁不大时,自己方就进攻选择得分最高的棋局////////////////
            TempScore=0;
            for(int i=0;i<15;i++){
                for(int j=0;j<15;j++){
                    if(ChessBoard[i][j]==0){
                    TempScore=this.calculateScore(i, j,color);
                    if(TempScore>MaxScorewhite){
                        MaxScorewhite=TempScore;
                        maxXW=i;
                        maxYW=j;
                    }    
                }
             }
            }
    /////////////////////////算黑棋总分///////////////////////////////
            color=1;
            TempScore=0;
            for(int i=0;i<15;i++){
                for(int j=0;j<15;j++){
                    if(ChessBoard[i][j]==0){
                    TempScore=this.calculateScore(i, j,color);
                    if(TempScore>MaxScoreBlack){
                        MaxScoreBlack=TempScore;
                        maxXB=i;
                        maxYB=j;
                    }    
                }
             }
            }
         if(MaxScorewhite>=MaxScoreBlack){
               lastx=maxXW;
                lasty=maxYW;
         }
         else {
               lastx=maxXB;
                lasty=maxYB;
         }
         System.out.println(MaxScorewhite);
         System.out.println(MaxScoreBlack);
            ChessBoard[lastx][lasty]=2;
                        IsBlack=!IsBlack;  //换白棋
            chessNum++;
            return;
        }

3、代码源码

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RadialGradientPaint;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

public class fivechess extends JFrame implements ActionListener{
    JButton back=new JButton("悔棋");
    JButton start=new JButton("开始");
    JButton game=new JButton("中级难度");
    JButton game2=new JButton("高级难度");
    GameBoard gb=new GameBoard();
    JPanel pb=new JPanel();
    JPanel pg=new JPanel();
    public fivechess(){

        pb.add(start);
        pb.add(back);
        pb.add(game);
        pb.add(game2);
        setLayout(new BorderLayout());
        add(pb,BorderLayout.NORTH);

        add(pg);
        gb.setOpaque(true);
        add(gb);
        back.addActionListener(this);
        start.addActionListener(this);
        game.addActionListener(this);
        game2.addActionListener(this);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(526,549);
        setLocation(400,100);
    }


    public static void main(String[] args) {
        // TODO Auto-generated method stub
        fivechess f=new fivechess();
        f.setTitle("五子棋");
        f.setVisible(true);
    }
    public class GameBoard extends JPanel implements MouseListener{
        public BufferedImage bgImage=null;//背景图片
        public int row=14;//棋盘行数
        public int col=14;//棋盘列数
        public int length=30;//每个格子的大小
        public int edgedis=30;//边距
        public int[][] ChessBoard=new int[row+1][col+1];//棋子代表的二维数组,其中0代表没有落子1代表黑子2代表白子
        //棋局判断,其中为有可能出现五子连线的类型,并判分,分数d额合理不合理影响了智能程度,*代表了有想相同颜色的棋子,O为空#代表被堵住了
        //一共32种棋型
        public String[] type={"UUUUU",//胜利
                   "OUUUUO","UOUUUU",//活四
                   "OUUUUC","CUUUUO","CUOUUU","CUUUOU","CUUOUU","UUOUUC","UUOUUC","UUUOUC",//眠四
                   "OOUUUOO","OUUUO",
                   "COUUUOO","COOUUUO","COUUUOO","OUUUOOC","OOUUUOC","OUUUOOC",//活三和上一个评分差别不大
                   "OUOUUO","OUUOUO",//活三
                   "CUUUOO","OOUUUC",
                   "OUOUUC","CUUOUO","OUUOUC",//眠三
                   "OOOUUOOO","OOUUOO","OUUO","OOUOUOO","OUOOUO",//活二
                   "OOOUUC","CUUOOO","OOUOUC","CUOUOO",//眠二
                   "OOOOUOOOO","OOUOO","OUO"//都为空白
                   };


    public int[] score={10000000,   //胜利
                 900000,850000,//活四
                 8000,8000,8000,8000,8000,8000,8000,8000,//眠四
                 7500, 7500, //活三
                 7200,7200,7200,7200,7200,7200,//活三
                 5000,5000,
                 3000,3000,//眠三
                 2500,2500,2500,//眠三
                 1000,1000,1000,800,800,
                 500,500,500,500,
                 80,50,20,
                 };

         int chessNum=0;//已经下了的棋子数目
         boolean IsBlack=true;//判断哪方下子(黑子先行)
         int lastx=-1,lasty=-1;   //最后下子的位置
         int llastx=-1,llasty=-1; //倒数第二次下的位置,方便悔棋
         boolean Win=false;//是否胜利的标志
         Vector allx=new Vector();
         Vector ally=new Vector();
        // int[][][]Player=new int[row+1][col+1][2];//最后【】【】【0】表示有没有棋子,【】【】【1】表示评分
         //int[][][]Computer=new int[row+1][col+1][2];
        //设置棋子半径
         static final int radius=15;
        //棋盘的位置的分值(固定为15x15的棋盘)

        //构造函数
        public GameBoard() {
            try {
                bgImage=ImageIO.read(new File("src/wuziqi.jpg"));
            } catch (IOException e) {
                e.printStackTrace();
            }
            this.addMouseListener(this);
            //初始化棋盘
            for(int i=0;i<row+1;i++){
                for(int j=0;j<col+1;j++){
                    ChessBoard[i][j]=0;
                }
            }

        }
        /*public void copyChess(){
            for(int i=0;i<15;i++){
                for(int j=0;j<15;j++){
                    if(ChessBoard[i][j]==1){
                        Player[i][j][0]=1;
                    }
                    else if(ChessBoard[i][j]==2){
                        Computer[i][j][0]=1;
                    }
                }
            }
        }
        */
        //绘制棋盘
        public void paintComponent(Graphics g){
            super.paintComponent(g);
            //g.drawImage(bgImage, 0, 0, row*length+2*edgedis, col*length+2*edgedis, null);
            g.drawImage(bgImage, 0, 0, 526, 549, null);
            //绘制线条
            for(int i=0;i<=row;i++){//横线
                g.drawLine(edgedis, edgedis+i*length, col*length+edgedis, edgedis+i*length);
            }
            for(int j=0;j<=col;j++){//竖线
                g.drawLine(edgedis+j*length, edgedis, edgedis+j*length, row*length+edgedis);
            }
            //绘制棋子
            for(int i=0;i<row+1;i++){
                for(int j=0;j<col+1;j++){
                    if(ChessBoard[i][j]!=0){//存在落子
                        //获取网格交叉点的坐标(在屏幕上的)
                        int x=i*length+edgedis;
                        int y=j*length+edgedis;
                        if(ChessBoard[i][j]==1){//如果落黑子
                            g.setColor(Color.BLACK);
                            RadialGradientPaint paint=new RadialGradientPaint(x-radius+25,y-radius+10,20,new float[]{0f,1f},new Color[]{Color.WHITE,Color.BLACK});
                            ((Graphics2D) g).setPaint(paint);  
                            ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);  
                            ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT); 
                        }
                        else if(ChessBoard[i][j]==2){//如果落白子
                            g.setColor(Color.WHITE);
                            RadialGradientPaint paint=new RadialGradientPaint(x-radius+25,y-radius+10,70,new float[]{0f,1f},new Color[]{Color.WHITE,Color.BLACK});
                            ((Graphics2D) g).setPaint(paint);  
                            ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);  
                            ((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT); 
                        }
                        Ellipse2D e = new Ellipse2D.Float(x-radius, y-radius, 30, 30);  
                        ((Graphics2D) g).fill(e);
                        if(i==lastx&&j==lasty){
                            g.setColor(Color.RED);
                            g.drawRect(x-radius, y-radius, 30, 30);
                        }
                    }
                }
            }
        }
        @Override
        public void mousePressed(MouseEvent e) {
            // TODO Auto-generated method stub 
            String info="";
            String ChessColor=IsBlack?"黑子":"白子";
            if(Win){
                info=String.format("游戏结束!%s已经取得游戏胜利,请重新开始游戏!", ChessColor);
                JOptionPane.showMessageDialog(this, info);
                return;
            }
            if(chessNum==(row+1)*(col+1)){
                info="棋盘已满!";
                JOptionPane.showMessageDialog(this, info);
                return;//不执行任何操作
            }
            //获得鼠标落点在二维数组的索引
            lastx=(e.getX()-edgedis+length/2)/length;
            lasty=(e.getY()-edgedis+length/2)/length;
            //落点不在棋盘内不能落子
            if(lastx<0||lastx>row||lasty<0||lasty>col){
                info="落子处超出棋盘范围!";
                JOptionPane.showMessageDialog(this, info);
                return;
            }
            //落点已经存在棋子不能落子
            if(isExit(lastx,lasty)){
                info="该处已有落子!";
                JOptionPane.showMessageDialog(this, info);
                return;
            }
            //绘制落子
            if(IsBlack)
                ChessBoard[lastx][lasty]=1;
            else ChessBoard[lastx][lasty]=2;
            allx.add(lastx);
            ally.add(lasty);
            chessNum++;
            repaint();
            if(IsWin()){
                Win=true;
                info=String.format("恭喜,%s赢了!", ChessColor);
                JOptionPane.showMessageDialog(this, info);
                return;
            }
            computerplayer();
            repaint();
            //判断胜负
            ChessColor=IsBlack?"黑子":"白子";
            if(IsWin()){
                Win=true;
                info=String.format("恭喜,%s赢了!", ChessColor);
                JOptionPane.showMessageDialog(this, info);
                return;
            }
            IsBlack=!IsBlack;//换黑棋
        }
        public void computerplayer(){
        /////////////默认黑棋先行///////////////////////////
            int MaxScoreBlack=0;
            int MaxScorewhite=0;
            int TempScore=0;
            int maxXB=0,maxYB=0,maxXW=0,maxYW=0;
            int color=2;
            llastx=lastx;
            llasty=lasty;
     ///////////////////////算白棋总分,当对方的棋局威胁不大时,自己方就进攻选择得分最高的棋局////////////////
            TempScore=0;
            for(int i=0;i<15;i++){
                for(int j=0;j<15;j++){
                    if(ChessBoard[i][j]==0){
                    TempScore=this.calculateScore(i, j,color);
                    if(TempScore>MaxScorewhite){
                        MaxScorewhite=TempScore;
                        maxXW=i;
                        maxYW=j;
                    }    
                }
             }
            }
    /////////////////////////算黑棋总分///////////////////////////////
            color=1;
            TempScore=0;
            for(int i=0;i<15;i++){
                for(int j=0;j<15;j++){
                    if(ChessBoard[i][j]==0){
                    TempScore=this.calculateScore(i, j,color);
                    if(TempScore>MaxScoreBlack){
                        MaxScoreBlack=TempScore;
                        maxXB=i;
                        maxYB=j;
                    }    
                }
             }
            }
         if(MaxScorewhite>=MaxScoreBlack){
               lastx=maxXW;
                lasty=maxYW;
         }
         else {
               lastx=maxXB;
                lasty=maxYB;
         }
         System.out.println(MaxScorewhite);
         System.out.println(MaxScoreBlack);
            ChessBoard[lastx][lasty]=2;
            allx.add(lastx);
            ally.add(lasty);
            //System.out.println(ChessBoard[maxX][maxY]);
            IsBlack=!IsBlack;  //换白棋
            chessNum++;
            return;
        }
        public int calculateScore(final int x,final int y,int color){//输入坐标,若有活4,连5直接返回-1,下此位置,否则返回评分
            String[] temp=new String [4];
            for(int i=0;i<4;i++){
                temp[i]="";
            }
            ChessBoard[x][y]=color;
            ///////////////////////////在x轴方向上取////////////////////////////////
            if(x-4<0){     
                int bite=4-Math.abs(x-4);
                temp[0]=temp[0]+"C";
                while(bite!=0){
                    if(ChessBoard[x-bite][y]==0){
                        temp[0]=temp[0]+"O";
                    }
                    else if(ChessBoard[x-bite][y]==color){
                        temp[0]=temp[0]+"U";
                    }
                    else {
                        temp[0]=temp[0]+"C";
                    }
                    bite--;
                }
            }
            else {
                for(int i=4;i>0;i--){
                    if(ChessBoard[x-i][y]==0){
                        temp[0]=temp[0]+"O";
                    }
                    else if(ChessBoard[x-i][y]==color){
                        temp[0]=temp[0]+"U";
                    }
                    else {
                        temp[0]=temp[0]+"C";
                    }
                }
            }
            for(int i=0;i<=4;i++){
                if(x+i>14) {
                    temp[0]=temp[0]+"C";
                    break;
                }
                if(ChessBoard[x+i][y]==0){
                    temp[0]=temp[0]+"O";
                }
                else if(ChessBoard[x+i][y]==color){
                    temp[0]=temp[0]+"U";
                }
                else {
                    temp[0]=temp[0]+"C";
                }
            }
       //////////////////在y方向截取////////////////////////////
            if(y-4<0){     
                int bite=4-Math.abs(y-4);
                temp[1]=temp[1]+"C";
                while(bite!=0){
                    if(ChessBoard[x][y-bite]==0){
                        temp[1]=temp[1]+"O";
                    }
                    else if(ChessBoard[x][y-bite]==color){
                        temp[1]=temp[1]+"U";
                    }
                    else {
                        temp[1]=temp[1]+"C";
                    }
                    bite--;
                }
            }
            else {
                for(int i=4;i>0;i--){
                    if(ChessBoard[x][y-i]==0){
                        temp[1]=temp[1]+"O";
                    }
                    else if(ChessBoard[x][y-i]==color){
                        temp[1]=temp[1]+"U";
                    }
                    else {
                        temp[1]=temp[1]+"C";
                    }
                }
            }
            for(int i=0;i<=4;i++){
                if(y+i>14) {
                    temp[1]=temp[1]+"C";
                    break;
                }
                if(ChessBoard[x][y+i]==0){
                    temp[1]=temp[1]+"O";
                }
                else if(ChessBoard[x][y+i]==color){
                    temp[1]=temp[1]+"U";
                }
                else {
                    temp[1]=temp[1]+"C";
                }
            }

            //////////////////////在左下,右上方向上//////////////////////////////
            if(x-4<0||14-(y+4)<0){
            int b=0;
            if(x-4<0&&14-(y+4)<0){   //两者都小取小的 
                 b=Math.min(4-Math.abs(x-4),14-y);
                 }
            else if(x-4<0&&y<=10){
                b=Math.abs(x);
            }
            else if(y>10&&x-4>=0){
                b=14-y;
            }
                temp[2]=temp[2]+"C";
                while(b!=0){
                    if(ChessBoard[x-b][y+b]==0){
                        temp[2]=temp[2]+"O";
                    }
                    else if(ChessBoard[x-b][y+b]==color){
                        temp[2]=temp[2]+"U";
                    }
                    else {
                        temp[2]=temp[2]+"C";
                    }
                    b--;
                }
            }
            else{
                for(int i=4;i>0;i--){
                    if(ChessBoard[x-i][y+i]==0){
                        temp[2]=temp[2]+"O";
                    }
                    else if(ChessBoard[x-i][y+i]==color){
                        temp[2]=temp[2]+"U";
                    }
                    else {
                        temp[2]=temp[2]+"C";
                    }
                }
            }
            if(y-4<0||x>10){  
                int b=0;
                if(y-4<0&&x>10){     
                     b=Math.min(4-Math.abs(y-4),14-x);
                     }
                else if(y-4<0&&x<=10){
                    b=4-Math.abs(y-4);
                }
                else if(14-(x+4)<0&&y-4>=0){
                    b=14-x;
                }
                    /*while(b!=0){
                        if(ChessBoard[x+b][y-b]==0){
                            temp[2]=temp[2]+"O";
                        }
                        else if(ChessBoard[x+b][y-b]==color){
                            temp[2]=temp[2]+"U";
                        }
                        else {
                            temp[2]=temp[2]+"C";
                        }
                        b--;
                    }*/
                    for(int i=0;i<=b;i++){
                        if(ChessBoard[x+i][y-i]==0){
                            temp[2]=temp[2]+"O";
                        }
                        else if(ChessBoard[x+i][y-i]==color){
                            temp[2]=temp[2]+"U";
                        }
                        else {
                            temp[2]=temp[2]+"C";
                        }
                    }
                    temp[2]=temp[2]+"C";
                }
                else{
                    for(int i=0;i<=4;i++){
                        if(ChessBoard[x+i][y-i]==0){
                            temp[2]=temp[2]+"O";
                        }
                        else if(ChessBoard[x+i][y-i]==color){
                            temp[2]=temp[2]+"U";
                        }
                        else {
                            temp[2]=temp[2]+"C";
                        }
                    }

            }
            //////////////////////在左上,右下方向上////////////////////////////////
            if(x-4<0||y-4<0){
                int bite=0;
                if(x-4<0&&y-4<0){
             bite=Math.min(4-Math.abs(x-4),4-Math.abs(y-4));
                }
                else if(x-4<0&&y-4>=0){
                    bite=4-Math.abs(x-4);
                }
                if(y-4<0&&x-4>=0){
                    bite=4-Math.abs(y-4);
                }
                temp[3]=temp[3]+"C";
                //System.out.println(bite);
                //System.out.println(x);
                //System.out.println(y);
                while(bite!=0){
                    if(ChessBoard[x-bite][y-bite]==0){
                        temp[3]=temp[3]+"O";
                    }
                    else if(ChessBoard[x-bite][y-bite]==color){
                        temp[3]=temp[3]+"U";
                    }
                    else {
                        temp[3]=temp[3]+"C";
                    }
                    bite--;
                }
            }
            else {
                for(int i=4;i>0;i--){
                    if(ChessBoard[x-i][y-i]==0){
                        temp[3]=temp[3]+"O";
                    }
                    else if(ChessBoard[x-i][y-i]==color){
                        temp[3]=temp[3]+"U";
                    }
                    else {
                        temp[3]=temp[3]+"C";
                    }
                }
            }
            for(int i=0;i<=4;i++){
                if(y+i>14||x+i>14) {
                    temp[3]=temp[3]+"C";
                    break;
                }
                if(ChessBoard[x+i][y+i]==0){
                    temp[3]=temp[3]+"O";
                }
                else if(ChessBoard[x+i][y+i]==color){
                    temp[3]=temp[3]+"U";
                }
                else {
                    temp[3]=temp[3]+"C";
                }
            }
           //////////////////////////////求出棋型之后计算分数////////////////////////////
            int result=0;
            for(int i=0;i<4;i++){
                for(int j=0;j<38;j++){
                    Pattern p=Pattern.compile(type[j]);
                    Matcher m=p.matcher(temp[i]);
                    if(m.find()){
                        result+=score[j];
                        //因为棋型在type数组里面存储顺序是按分数递减存储的,所以最开始找到的棋型为最好的
                        //在这四个方向上找到最好的就停止寻找,继续找下一个方向的。直到得到四个方向的分数
                        break;
                    }
                }
            }

            ChessBoard[x][y]=0;//只是实验下在此处会有什么情况,算出分值之后就回复原样
        return result;
    }
   public void regret(){//悔棋操所
            ChessBoard[(int)allx.lastElement()][(int)ally.lastElement()]=0;
            allx.removeElementAt(allx.size()-1);
            ally.removeElementAt(ally.size()-1);
            ChessBoard[(int)allx.lastElement()][(int)ally.lastElement()]=0;
            allx.removeElementAt(allx.size()-1);
            ally.removeElementAt(ally.size()-1);
            repaint();
        }
    public void startagain(){
        Win=false;
        IsBlack=true;
        for(int i=0;i<15;i++){
            for(int j=0;j<15;j++){
                ChessBoard[i][j]=0;
            }
        }
        repaint();
    }
        @Override
        public void mouseClicked(MouseEvent e) {
            // TODO Auto-generated method stub
        }
        @Override
        public void mouseEntered(MouseEvent e) {
            // TODO Auto-generated method stub
        }
        @Override
        public void mouseExited(MouseEvent e) {
            // TODO Auto-generated method stub
        }
        @Override
        public void mouseReleased(MouseEvent e) {
            // TODO Auto-generated method stub
        }  
        public boolean isExit(int x,int y){
            if(ChessBoard[x][y]!=0)
                return true;
            return false;
        }

        public boolean IsWin(){
            int count=1;
            int color=ChessBoard[lastx][lasty];
            //判断横向上的相同颜色的棋子数量
            count=this.ChessCount(1, 0, color);
            if(count>=5)
                return true;
            //判断纵向上的相同颜色棋子的数量
            count=this.ChessCount(0, 1, color);
            if(count>=5)
                return true;
            //判断主对角线上/的相同颜色棋子的数量
            count=this.ChessCount(1, 1, color);
            if(count>=5)
                return true;
            //判断副对角线上\的相同颜色棋子的数量
            count=this.ChessCount(1, -1, color);
            if(count>=5)
                return true;
            return false;
        }
        //计算棋子在xChange和yChange方向上连接的数量
        public int ChessCount(int xChange,int yChange,int color){
            int count=1;//棋子计数器
            int tempx=xChange;
            int tempy=yChange;
            //xChange取值范围(1,0,1,1)和yChange取值范围(0,1,1,-1)分别代表(横向,纵向,/,\)
            //先计算正方向上的数量
            while (lastx + xChange >= 0 && lastx + xChange <= row && lasty + yChange >= 0 && lasty + yChange <= col && color == ChessBoard[lastx + xChange][lasty + yChange]) {
                count++;
                if (xChange != 0) {
                    xChange++;
                }
                if (yChange != 0) {
                    if (yChange > 0) 
                        yChange++;
                    else 
                        yChange--;
                }
            }
            //回到最开始的方向
            xChange = tempx;
            yChange = tempy;
            //接着计算反方向上的数量
            while (lastx - xChange >= 0 && lastx - xChange <= row && lasty - yChange >= 0 && lasty - yChange <= col && color == ChessBoard[lastx - xChange][lasty - yChange]) {
                count++;
                if (xChange != 0) {
                    xChange++;
                }
                if (yChange != 0) {
                    if (yChange > 0) 
                        yChange++;
                    else 
                        yChange--;
                }
            }
            return count;
        }
    }
    @Override
    public void actionPerformed(ActionEvent e) {
        // TODO 自动生成的方法存根
            if(e.getSource()==back){
                gb.regret();
            }
            if(e.getSource()==start){
                gb.startagain();
            }
            if(e.getSource()==game){
                gb.startagain();
            }
            if(e.getSource()==game2){
                gb.startagain();
            }
        }
    }

四、源码下载

五子棋的java实现


   转载规则


《人工智能五子棋java实现》 ivory 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
保研历程经验与大学建议 保研历程经验与大学建议
基本情况:本人是某211大学的计算机科学与技术专业的学生。本学校的计算机的学科评价为B,自认为本校的计算机专业对学生的锻炼还是足的,由于本人是中途转专业的,所以基本上大二就在忙补课了,参加的比赛不多。科研是大三才有意识去做的。情况总结:成绩
2019-07-08
下一篇 
Linux操作系统下配置opencv-3.2+openpose+caffe Linux操作系统下配置opencv-3.2+openpose+caffe
Linux操作系统下配置opencv-3.2+openpose+caffe首先需要安装cuda8.0可以先配置一下这个,源码用cmake编译可以用cmake-gui是一个非常好用的工具安装代码如下: sudo apt-get install
2019-07-08
  目录