Java 五子棋Alpha-Beta剪枝的人工智障实现(一)

五子棋界面实现

完整代码已上传到github上 地址 https://github.com/chenxin12138/repository 有需要的可以自取。

界面简介

一、我们得实现一个15X15的界面
先使用顶级容器JFrame,然后经过重写重绘函数public void paint(Graphics g)实现,主要在GameMap类中实现
Java 五子棋Alpha-Beta剪枝的人工智障实现(一)_第1张图片

二、我们需要在棋盘上下黑白子,并进行记录那么就需要给整个棋盘添加响应函数并记录轮走方,并将电机为值通过计算始得棋子下到棋盘交叉处。在FrameListener函数中
实现五子棋界面需要的API类:

JFrame 顶级容器类

BorderLayout 框架布局类——把容器分为上北下南左西右东中间五个部分,每个部分只能添加一个组件。在这里我们需要把整个界面分为左右两部分。选择在框架布局的中间和右边两个部分。

这里我们还需要另一个容器类——JPanel 面板容器类。主要用来实现右边的部分,因为原本框架布局的右边部分只能添加一个组件,但是我们需要添加的组件不只一个,因此就先这个部分加上一个JPanel,然后再在JPanel上加我们需要的组件,包括按钮等等。

JFrame和JPanel的区别:JFrame是最底层的容器,JPanel放在它上面,同一个界面只有一个JFrame,但是一个JFrame上面可以有多个JPanel。相当于JFrame是一个大餐桌,JPanel是盘子,如果我们要对餐桌JFrame上的东西进行管理分类等,我们就需要使用这些JPanel盘子。

FlowLayout 流式布局类。因为我们右边的JPanel部分需要将按钮等组件由上到下进行排列。

JButton 按钮组件类

JComboBox 下拉列表框类——实现那个人人对战和人机对战的选择

Dimension 封装组件宽度和高度的类——组件类不能直接用setSize方法来设置

事件监听机制的类:

ActionListener 状态监听处理类

ActionEvent 状态监听事件,监听某个组件的状态是否有改变

MouseListener 鼠标监听处理类

MouseEvent 鼠标监听事件,里面包含鼠标被点击等事件的处理方法。当界面被点击时就放下一个棋子。

绘画所需要的类:

Graphics|Graphics2D 画笔类

Color 颜色类,需要设置画笔的颜色,实现黑白棋子

代码介绍

GameMap类

1、public void initUI()初始化函数,主要进行相框的绘制,采用BoardLayout 中间添加GameMap,GameMap的绘制主演实在paint重绘函数中,通过jf.add(this,BoardLayout.Center)添加到JFrame的中间位置。右侧添加JPanel实现按钮还有玩家信息。ButtonListener类实现三个按钮功能。setImage主要是设置图片大小

package Game;

import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;

public class GameMap extends JPanel implements Image {
    public int [][]board=new int[15][15];//存放棋盘落子
    private int turn=0 ;//记录轮走方 1为玩家一,2位玩家二
    public int []lastmove=new int[2];//记录最后一步位置
    public ArrayList<Chessmove> chessmoves=new ArrayList<Chessmove>();//记录每一步棋子位置



    public void initUI(){
        //初始化一个界面,并设置标题大小等属性
        Reset();//将board,turn置为初始值,进行新一句的棋局
        JFrame jf=new JFrame();
        jf.setTitle("五子棋");
        jf.setSize(UIWIDTH,UIHIGHTH);
        jf.setLocationRelativeTo(null);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.setLayout(new BorderLayout());//设置顶级容器JFrame为框架布局
        //实现左边的界面,把GoBangframe的对象添加到框架布局的中间部分
        //已经有一个GameMap对象了,表示当前类的对象是this
        this.setBackground(Color.WHITE);//设置下棋界面的颜色
        //这里的话直接把左边的画板添加上去,指明是在框架布局的中间版块
        jf.add(this,BorderLayout.CENTER);//添加到框架布局的中间部分
        JPanel jp=new JPanel();
        jp.setPreferredSize(dim1);//因采用了布局管理,不适用setsize,设置大小
        jf.add(jp,BorderLayout.EAST);//添加到框架布局的东边部分
        jp.setLayout(new FlowLayout());//设置JPanel为流式布局

        //用户信息
        String[] userMessage={"pic","昵称:尘心","性别:男","等级:新手"};
        JLabel[] user =new JLabel[4];
        //设置用户头像的大小
        USERPICTURE.setImage(USERPICTURE.getImage().getScaledInstance(dim3.width, dim3.height, java.awt.Image.SCALE_DEFAULT ));
        user[0]=new JLabel(USERPICTURE);
        //设置Lable的大小
        Dimension dim5=new Dimension(dim3.width,dim3.height+20);
        user[0].setPreferredSize(dim5);
        jp.add(user[0]);

        for(int i=1;i<4;i++){
            user[i]=new JLabel(userMessage[i]);
            user[i].setPreferredSize(dim2);
            /*
             *利用setFont来设置TextField文本框输入信息的字体大小
             *textx1.setFont(new Font(Font.DIALOG,Font.PLAIN,30));
             */
            user[i].setFont(new Font(Font.MONOSPACED,Font.ITALIC,20));
            jp.add(user[i]);
        }
        String []button_name={"开始新游戏","悔棋","认输"};
        JButton []buttons=new JButton[3];
        ImageIcon []BackGroundPictures={STARTBUTTON,BACKBUTTON,LOSEBUTTON};
        for (int i = 0; i < 3; i++) {
            BackGroundPictures[i].setImage(BackGroundPictures[i].getImage().getScaledInstance(dim4.width+20, dim4.height, java.awt.Image.SCALE_DEFAULT));
            buttons[i]=new JButton(button_name[i],BackGroundPictures[i]);
            buttons[i].setPreferredSize(dim4);
            jp.add(buttons[i]);
        }
        ButtonLisener bu=new ButtonLisener(this);
        for (int i = 0; i < 3; i++) {
            buttons[i].addActionListener(bu);
        }
        FrameListener fl=new FrameListener(this);
        this.addMouseListener(fl);
        jf.setVisible(true);

    }

    //重写重绘方法
    public void paint(Graphics g){
        super.paint(g);
        System.out.println(111111);
        //引用图片
        g.drawImage(CHESSBOARD, 0, 0,this.getWidth(), this.getHeight(), this);
       //绘制棋盘
        g.setColor(Color.BLACK);
        for (int i = 0; i < 15; i++) {
            g.drawLine(X,Y+SIZE*i,X+SIZE*14,Y+SIZE*i);
        }
        for (int i = 0; i < 15; i++) {
            g.drawLine(X+SIZE*i,Y,X+SIZE*i,Y+SIZE*14);
        }
        for (int i = 0; i < 15; i++) {
            for (int j = 0; j < 15; j++) {
                if(board[i][j]==1){
                    int count_ai_x=i*SIZE+X;
                    int count_ai_y=j*SIZE+Y;
                    g.setColor(Color.BLACK);
                    g.fillOval(count_ai_x-15,count_ai_y-15,30,30);
                }
                else if(board[i][j]==2){
                    int count_ai_x=i*SIZE+X;
                    int count_ai_y=j*SIZE+Y;
                    g.setColor(Color.WHITE);
                    g.fillOval(count_ai_x-15,count_ai_y-15,30,30);
                    if(i==lastmove[0]&&j==lastmove[1]){
                        g.setColor(Color.RED);
                        g.drawRect(count_ai_x-15,count_ai_y-15,30,30);
                    }
                }
            }
        }

    }

    public int getTurn(){
        return turn;
    }

    public void ChangeTurn(){
        if (turn==1)
            turn=2;
        else
            turn=1;
    }


    public void Reset(){
        for (int i = 0; i < 15; i++) {
            for (int j = 0; j < 15; j++) {
                board[i][j]=0;
            }
        }
        turn=0;
    }

//对话框
    public void PopUp(String top,String result) {
        JOptionPane jo=new JOptionPane();
        jo.showMessageDialog(null, result, top, JOptionPane.PLAIN_MESSAGE);
    }
}

FrameListener类

FrameListener为棋盘添加点击响应函数实现下棋。并计算出棋盘的交叉点,将其绘制在交叉点上。

package Game;

import javafx.css.Size;

import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

public class FrameListener implements MouseListener,Image {

    private GameMap gm;
    private ChessAI ai;
    private static int step=0;

    public FrameListener(GameMap gm){
        this.gm=gm;//引用GameMap中的变量
        this.ai=new ChessAI();
    }

    //下棋
    @Override
    public void mouseClicked(MouseEvent e) {
        int x=e.getX();
        int y=e.getY();
        int count_x;
        int count_y;
        //计算交叉点
        if((x-X)%SIZE>(int)(SIZE/2)){
            count_x=X+SIZE*(int)((x-X)/SIZE+1);
        }
        else {
            count_x=X+SIZE*(int)((x-X)/SIZE);
        }
        if((y-Y)%SIZE>(int)(SIZE/2)){
            count_y=Y+SIZE*(int)((y-Y)/SIZE+1);
        }
        else {
            count_y=Y+SIZE*(int)((y-Y)/SIZE);
        }
        Graphics g=gm.getGraphics();
        int index_i=(count_x-X)/SIZE;
        int index_j=(count_y-Y)/SIZE;
        if((index_i<0)||(index_j<0)||(index_i>14)||(index_j>14))
            return ;
        //先手下棋为1,后手为2
        if (gm.getTurn()==1){
            if(gm.board[index_i][index_j]!=0){
                gm.PopUp("错误提示","此处已经有棋子了,请下在其它地方");
            }
            else {
                //gm.repaint();
                g.fillOval(count_x-15,count_y-15,30,30);
                Chessmove chessmove=new Chessmove(index_i,index_j);
                gm.chessmoves.add(chessmove);
                gm.board[index_i][index_j]=gm.getTurn();
                step++;
                g.setColor(Color.RED);
                g.drawRect(count_x-15,count_y-15,30,30);
                if(ai.CheckWin(gm.board,gm.getTurn())) {
                    gm.PopUp("胜者", "胜者黑方");
                    gm.repaint();
                }
                else
                    gm.ChangeTurn();
            }
        }
        //智障通过FindBestmove(gm.board,gm.getTurn()函数通过博弈树算法得出最佳位置
        if(gm.getTurn()==2)
        {
            gm.repaint();
            int []bestmove=ai.FindBestmove(gm.board,gm.getTurn());
            System.out.println("AIx+AIy"+bestmove[0]+" "+bestmove[1]);
            g.setColor(Color.WHITE);
            int count_ai_x=bestmove[0]*SIZE+X;
            int count_ai_y=bestmove[1]*SIZE+Y;
            g.fillOval(count_ai_x-15,count_ai_y-15,30,30);
            Chessmove chessmove=new Chessmove(bestmove[0],bestmove[1]);
            gm.chessmoves.add(chessmove);
            System.out.println(11111);
            gm.board[bestmove[0]][bestmove[1]]=gm.getTurn();
            gm.lastmove=bestmove;
            step++;
            if(ai.CheckWin(gm.board,gm.getTurn())) {
                gm.PopUp("胜者", "胜者白方");
                gm.repaint();
                gm.Reset();
            }
            else
                gm.ChangeTurn();
        }
    }

    @Override
    public void mousePressed(MouseEvent e) {

    }

    @Override
    public void mouseReleased(MouseEvent e) {

    }

    @Override
    public void mouseEntered(MouseEvent e) {

    }

    @Override
    public void mouseExited(MouseEvent e) {

    }
}

编译环境

idea jdk10.0.2

人工智障将在下一节细讲。

参考链接:https://blog.csdn.net/Alexwym/article/details/80847170

你可能感兴趣的:(Java 五子棋Alpha-Beta剪枝的人工智障实现(一))