五子棋大战

目录

1.简介

2.项目展示

 3.项目概览

内容介绍

源代码结构图

4.实现方式

1.AI算法:

随机落子:

 AI落子:

2.Data处理:

3.判断方式:

4.五子连珠的判断。

5.菜单实现

 6.菜单指令实现

7.监听器实现

5.结尾


1.简介

    我们的课程设计题目是《五子棋大战》,该项目基于java swing进行开发,实现了人与电脑的五子棋对战,其中五子棋的人机对战采用了AI算法,真实模拟了双人对战的场景,另外在人机对战以外,添加了双人对战模式,可以实时进行双人对战。

2.项目展示

 

 3.项目概览

内容介绍

    本项目体现面向对象程序设计,体现了多用组合,少用继承的程序设计原则。本项目分为以下几类:

1.main类:控制程序运行,实现游戏窗口的启动以及游戏的运行。

2.GamePanel类:此类为游戏运行的主体与核心,其中包含了棋盘的布局(棋盘背景,棋盘网格实现,移动红框的绘制),棋盘二维数组的实现,主菜单以及子菜单,鼠标监听方法(鼠标移动事件,鼠标点击时间),菜单中元素的指令处理,以及指令触发后对话框的实现。

3.GameFrame类:此类实现了游戏的窗体,并将GamePanel中的布局元素添加到窗体中。

4.Pointer类:指示器类,此类中传入了棋盘二维数组的下标,并实现了判断鼠标是否在指定区域内的方法,方便了鼠标移动事件的实现。

5.Qizi类与ImageValue类:这两个类是传入白色棋子图片,黑色棋子图片的类,在GamePanel类中通过创建Qizi对象,并调用方法来实现棋子图片的加载与显示。

6.AI类:此类实现了人机对战时,AI棋子的走向算法,实现方法是实时计算每个棋子的分数,获取最高分数点进行落子位置的选择。具体实现方法将在下面介绍。此外,改类中还实现了判断“五子连珠”的public方法,设置为public是为了在GamePanel类中进行调用。

7.Data类:此类服务于AI类。AI类中有计算棋子分数的方法,Data类实现了对分数以及棋子元素的封装,方便了分数在GamePanel类中的调用。

源代码结构图

以下图片为源代码结构演示

4.实现方式

通过以下图片来演示两种模式的实现过程

 

1.AI算法:

在选择了人机对战之后,通过指令“restart”重置棋盘,并进入到人机模式的鼠标监视器中,调用方法如下。

if("restart".equals(command)){
            if(!"end".equals(gameFlag)){
                JOptionPane.showMessageDialog(null,"正在游戏中,无法重新开始!","提示",JOptionPane.INFORMATION_MESSAGE);
            }else{
                restart();
            }
            restart();
        }

这里再调用restart()方法

void restart() {
        //重置数据
        //游戏状态
        //指示器
        //棋子
        gameFlag="start";
        System.out.println("++"+gameFlag);
        Pointer pointer;
        for(int i=0;i<ROWS;i++){
            for(int j=0;j<CLOS;j++){
                pointer = pointers[i][j];
                pointer.setType(0);
                pointer.setShow(false);
            }
        }

        qizis.clear();
       reset();

    }

通过reset();方法调用鼠标监听后,系统会先执行人工落子,落子之后立即判断胜负,如果胜利则停止运行,否则使用AI.next();让AI落子。

落子过程:AI一共有两种落子方式,第一种是随机落子,

随机落子:

 private static boolean louziRandom(GamePanel panel) {
        //随机获取指示器位置
        Pointer pointer = getRandomPointer(panel);
        //根据位置落子
        luozi(pointer,1,panel);
        return false;
    }
    private static void luozi(Pointer pointer, int type,GamePanel panel) {
        //创建棋子对象
        Qizi qizi = new Qizi(pointer.getX(),pointer.getY(),type);
        qizi.setLast(true);
        //将棋子添加到集合中
        panel.qizis.add(qizi);
        //设置类型
        pointer.setType(type);
        //重绘
        panel.repaint();

        if(has5(pointer,panel)){
            panel.gameOver();
        }

    }
    private static Pointer getRandomPointer(GamePanel panel) {
        Random random = new Random();
        int i = random.nextInt(panel.ROWS);//0-14
        int j = random.nextInt(panel.CLOS);//0-14
        //获取对应位置的指示器对象
        Pointer pointer= panel.pointers[i][j];
        if(pointer.getType() != 0){
            return getRandomPointer(panel);//递归
        }
        return pointer;
    }
}

​

   louziRandom(GamePanel panel): 这个方法用于在游戏板上随机落子。它首先调用getRandomPointer(panel)方法获取一个随机的指示器位置,然后调用luozi(Pointer pointer, int type, GamePanel panel)方法来落子,并将落子的类型设为1。最后,它返回了一个false值。

      luozi(Pointer pointer, int type, GamePanel panel): 这个方法用于在指定的位置落子。它首先创建一个棋子对象Qizi,并设置其坐标和类型。然后将该棋子对象添加到游戏板的棋子集合中,设置对应位置的指示器类型为落子的类型,并重新绘制游戏板。如果这次落子导致获胜,就调用panel.gameOver()方法来结束游戏。

      getRandomPointer(GamePanel panel): 这个方法用于随机获取一个可用的指示器位置。它使用Random类生成随机数来选择一个随机的行和列。然后检查所选位置的指示器类型,如果不为0(表示已经有棋子落在该位置),就通过递归调用自身来重新选择一个位置。最后返回一个可用的指示器位置。

 AI落子:

AI落子使用分数计算法来确定落点的位置。

首先通过pointer指示器获取二维数组中改点是否被占用,再进行分数计算

 type == 1由人工落子,落子为黑子,再棋盘中计算黑子的分数即可。

if(type == 1){
                for(int k = j+1;k<panel.CLOS;k++){
                    temPointer = pointers[i][k];//拿到循环元素(指示器)
                    if(temPointer.getType() == pointer.getType())

设置分数方式:

如果当前找到一个黑子,有以下情况:

连续32
31
间断30

计算分数要求棋子数大于2

以上棋子基础分30分

以该棋子为中心,如果左边可以放置棋子,放在左边加为32分,如果可以放在右边,放在右边分数为31分,如果为间断的情况放在中间为30分。

也就是说,如果是连续的情况,左边放棋子的权重更高,优先往左边放置棋子。其次是右边,最后是中间。

以此类推,如果3个棋子连续,基础分为40分,4个棋子连续基础分50分。这样再后期筛选分数时,通过最高分来判定优先往哪里放置棋子。显然,如果基础为40分或者更高,则放置棋子的优先级就更高,以此方法来优先堵住玩家即将完成“五子连珠”的棋子。

上述表格仅为对棋子的横向判断,完成“五子连珠”共有四种方向,分别是横向,竖向,左撇,右撇。所以定义四种方向的变量dir。而且以每一个棋子为中心,向左计算分数以及向右计算分数也是不一样的,所以每一种方向分别计算两次分数,并添加到分数的数组中进行排序。

 if(dir == 1){
            //从左到右
            if(type == 1){
                for(int k = j+1;k<panel.CLOS;k++){
                    temPointer = pointers[i][k];//拿到循环元素(指示器)
                    if(temPointer.getType() == pointer.getType()){ //连续
                        num++;
                        num2++;
                        if(k == panel.CLOS-1){
                            rClose = true;
                        }
                    }else if(temPointer.getType() == 0){//如果是空
                        if(breakFlag){
                            //判断前一个子是否空白
                            if(pointers[i][k-1].getType() == 0){//如果空白
                                breakFlag = false;
                            }
                            break;
                        }
                        num++;
                        breakFlag = true;
                        resData.setI(i);
                        resData.setJ(k);
                    }else{//对立,不同颜色
                        rClose = true;
                        break;
                    }

                    //处理左边关闭
                    if(j == 0){
                        lClose = true;
                    }else{
                        if(pointers[i][j-1].getType() != 0){
                            lClose = true;
                        }
                    }

                }
            }else{//从右往左

                for(int k = j-1;k>=0;k--){
                    temPointer = pointers[i][k];//拿到循环元素(指示器)
                    if(temPointer.getType() == pointer.getType()){ //连续
                        num++;
                        num2++;
                        if(k == 0){
                            lClose = true;
                        }
                    }else if(temPointer.getType() == 0){//如果是空
                        if(breakFlag){
                            //判断前一个子是否空白
                            if(pointers[i][k+1].getType() == 0){//如果空白
                                breakFlag = false;
                            }
                            break;
                        }
                        num++;
                        breakFlag = true;
                        resData.setI(i);
                        resData.setJ(k);
                    }else{//对立,不同颜色
                        lClose = true;
                        break;
                    }

                    //处理右边关闭
                    if(j == panel.CLOS-1){
                        rClose = true;
                    }else{
                        if(pointers[i][j-1].getType() != 0){
                            rClose = true;
                        }
                    }

                }

            }
        }else if(dir == 2){
            if(type == 1){
                for(int k = i+1;k<panel.ROWS;k++){
                    temPointer = pointers[k][j];
                    if(temPointer.getType() == pointer.getType()){//连续
                        num++;
                        num2++;
                        if(k == panel.ROWS-1){//左后一个连续,右边关闭
                            rClose = true;
                        }
                    }else if(temPointer.getType() == 0) {//null
                        if (breakFlag) {//有一个不通过
                            if (pointers[k - 1][j].getType() == 0) {
                                breakFlag = false;
                            }
                            break;
                        }
                        num++;
                        if (k == 0 || k == panel.ROWS - 1) {
                            break;
                        }
                        breakFlag = true;
                        //食终端那种,设定落子位置
                        resData.setI(k);
                        resData.setJ(j);

                    }else{//对立右边关闭
                        rClose = true;
                        break;
                    }
                }
                //判读左边关闭
                if(i == 0){//当前为最左边子
                    lClose = true;
                }else{
                    temPointer= pointers[i-1][j];
                    if(temPointer.getType() != 0){//如果左边有子,关闭
                        lClose = true;
                }
            }

        }else{
                for(int k = i-1;k>=0;k--){
                    temPointer = pointers[k][j];
                    if(temPointer.getType() == pointer.getType()){
                        num++;
                        num2++;
                        if(k == 0){
                            lClose = true;
                        }
                    }else if(temPointer.getType() == 0){
                        if(breakFlag){
                            if(pointers[k+1][j].getType() == 0){
                                breakFlag = false;
                            }
                            break;
                        }
                        breakFlag = true;
                        resData.setI(k);
                        resData.setJ(j);
                    }else{
                        lClose = true;
                        break;
                    }
                }
                //判断有关闭
                if(i==panel.ROWS-1){
                    rClose = true;
                }else{
                    temPointer = pointers[i+1][j];
                    if(temPointer.getType() != 0){
                        rClose = true;
                    }
                }
            }
        }else if(dir == 3){
            int tempi = i;
            if(type == 1){
                for(int k=j+1;k<panel.CLOS;k++){
                    tempi++;
                    if(tempi>panel.CLOS-1){//超粗边界
                        rClose = true;
                        break;
                    }
                    temPointer = pointers[tempi][k];
                    if(temPointer.getType() == pointer.getType()){//连续
                        num++;
                        num2++;
                        if(k == panel.CLOS-1){
                            rClose = true;
                        }
                    }else if(temPointer.getType() == 0){
                        if(breakFlag){//有一个不能通过
                            if(pointers[tempi-1][k-1].getType() == 0){//如果钱一个食空子,设置不中断
                                breakFlag = false;
                            }
                            break;
                        }
                        breakFlag = true;
                        resData.setI(tempi);
                        resData.setJ(k);
                    }else{//对立
                        rClose = true;
                        break;
                    }
                }
                //对立食做关闭
                if(j == 0||i == 0){
                    lClose = true;
                }else{
                    temPointer = pointers[i-1][j-1];
                    if((temPointer.getType() != 0)){
                        lClose = true;
                    }
                }
            }else{//从右往左
                for(int k=j-1;k>=0;k--){
                    tempi--;
                    if(tempi<0){
                        lClose = true;
                        break;
                    }
                    temPointer = pointers[tempi][k];
                    if(temPointer.getType() == pointer.getType()){//连续
                        num++;
                        num2++;
                        if(k == 0){
                            lClose = true;
                        }
                    }else if(temPointer.getType() == 0){
                        if(breakFlag){
                            if(pointers[tempi+1][k+1].getType() == 0){
                                breakFlag = false;
                            }
                            break;
                        }
                        breakFlag = true;
                        resData.setI(tempi);
                        resData.setJ(k);
                    }else{
                        lClose = true;
                        break;
                    }
                }
                //判断左关闭
                if(j==panel.CLOS-1||i == panel.ROWS-1){
                    rClose = true;
                }else{
                    temPointer = pointers[i+1][j+1];
                    if(temPointer.getType() != 0){
                        rClose = true;
                    }
                }
            }
        }else if(dir == 4){
            int tempi = i;
            if(type == 1){
                for(int k = j+1;k<panel.ROWS;k++){
                    tempi--;
                    if(tempi<0){
                        rClose = true;
                        break;
                    }
                    temPointer = pointers[tempi][k];
                    if(temPointer.getType()==pointer.getType()){
                        num++;
                        num2++;
                        if(k == panel.CLOS-1){
                            rClose = true;
                        }
                    }else if(temPointer.getType() == 0){//空白子
                        if(breakFlag){
                         if(pointers[tempi+1][k-1].getType() == 0){
                             breakFlag = false;
                         }
                         break;
                        }
                        num++;
                        if(tempi==0||tempi==panel.ROWS-1||k==0||k==panel.CLOS-1){
                            break;
                        }
                        breakFlag = true;
                        resData.setI(tempi);
                        resData.setJ(k);
                    }else{
                        rClose = true;
                        break;
                    }
                }
                //判断右边关闭
                if(j == 0||i == 0){
                    lClose = true;
                }else{
                    if(i == panel.ROWS-1){
                        lClose = true;
                    }else{
                        temPointer = pointers[i+1][j-1];
                        if(temPointer.getType() != 0){
                            lClose = true;
                        }
                    }
                }
            }else{//有望左
                for(int k=j-1;k>=0;k--){
                    tempi++;
                    if(tempi>panel.ROWS-1){
                        lClose = true;
                        break;
                    }
                    temPointer = pointers[tempi][k];
                    if(temPointer.getType() == pointer.getType()){
                        num++;
                        num2++;
                        if(k == 0){
                            lClose = true;
                        }
                    }else if(temPointer.getType() == 0){
                        if(breakFlag){
                            if(pointers[tempi-1][k+1].getType() == 0){
                                breakFlag = false;
                            }
                            break;
                        }
                        num++;
                        if(tempi==0||tempi==panel.ROWS-1||k==0||k==panel.CLOS-1){
                            break;
                        }
                        breakFlag = true;
                        resData.setI(tempi);
                        resData.setJ(k);
                    }else{//对立
                        lClose = true;
                        break;
                    }
                }
                //判断有关闭
                if(j == panel.CLOS-1||i == panel.ROWS-1){
                    rClose = true;
                }else{
                    if(i == 0){
                        rClose = true;
                    }else{
                        temPointer = pointers[i-1][j+1];
                        if(temPointer.getType() != 0){
                            rClose = true;
                        }
                    }
                }
            }
        }

如上代码,dir==1-4表示共有四种方向,每种方向通过从右向左,从左向右计算两次,使用num来纪录连续情况子的数目,num2纪录当前棋子的总个数,将num num2的值传入setCount();方法中,进行分数计算。

接下来是setcount();方法。

 private static void setCount(Data resData, int i,int j ,int dir ,int type,int num, int num2, boolean breakFlag, boolean lClose, boolean rClose, GamePanel panel) {
        //计的算分数
        int count = 0;
        if(num <= 2){
            return;
        }
        //分数初步设定
        if(num == 3){
            count = 30;
        }else if(num == 4){
            count = 40;
        } else if (num == 5) {
            count = 50;
        }
        //如果5子,设定分数100
        if(num2 >= 5 && !breakFlag){
            count=100;
            resData.setCount(100);
            return;
        }
        if(breakFlag){//如果中断
            if(lClose&&rClose){
                count = -1;
            }

        }else{
            //连续
            if(lClose && rClose){
                count = -1;
            }else if(!lClose){
                count += 2;
                //横向
                if(dir == 1){
                    //从左往右
                    if(type == 1){
                        resData.setI(i);
                        resData.setJ(j-1);
                    }else{
                        resData.setI(i);
                        resData.setJ(j-num+1);
                    }
                }else if(dir == 2){
                    if(type == 1){
                        resData.setI(i-1);
                        resData.setJ(j);
                    }else{
                        resData.setI(i-num+1);
                        resData.setJ(j);
                    }
                }else if(dir == 3){
                    if(type == 1){
                        resData.setI(i-1);
                        resData.setJ(j-1);
                    }else{
                        resData.setI(i-num+1);
                        resData.setJ(j-num+1);
                    }
                }else if(dir == 4){
                    if(type == 1){
                        resData.setI(i+1);
                        resData.setJ(j-1);
                    }else{
                        resData.setI(i+num-1);
                        resData.setJ(j-num+1);
                    }
                }

            }else if(!rClose){
                count += 1;
                //横向
                if(dir == 1){
                    //从左往右
                    if(type == 1){
                        resData.setI(i);
                        resData.setJ(j+num-1);
                    }else{
                        resData.setI(i);
                        resData.setJ(j+1);
                    }
                }else if(dir == 2){
                    if(type == 1){
                        resData.setI(i+num-1);
                        resData.setJ(j);
                    }else{
                        resData.setI(i+1);
                        resData.setJ(j);
                    }
                }else if(dir == 3){
                    if(type == 1){
                        resData.setI(i+num-1);
                        resData.setJ(j+num-1);
                    }else{
                        resData.setI(i+1);
                        resData.setJ(j+1);
                    }
                }else if(dir == 4){
                    if(type == 1){
                        resData.setI(i-num+1);
                        resData.setJ(j+num-1);
                    }else{
                        resData.setI(i-1);
                        resData.setJ(j+1);
                    }
                }
            }
        }
        resData.setCount(count);
    }

该方法对左右是否能放子的情况进行判断,并且给出分数,以及需要方子的坐标。同样判断了四种dir方向。

此方法的末尾resData.setCount();方法对得到的分数进行封装,在二里进行介绍。

2.Data处理:

我们在上面得到棋子分数值以及应当放置的坐标,如上图。此时我们使用Data类中的setI,setJ。方法,传递坐标,对坐标进行封装,使用SetCount();传分数值,并在Data类中写入get set方法对分数进行封装。这就是Data类实现的功能。

3.判断方式:

在AI类中建立DataCount类,对分数判断大小t

class DataCount implements Comparator<Data>{

    @Override
    public int compare(Data o1, Data o2) {
        if(o1.getCount() > o2.getCount()){
            return -1;
        }
        return 1;
    }

}

接着调用collection.sort();方法对所得分数进行排序

 Collections.sort(datas,new DataCount());

排序完成后执行go();方法进行AI落子。

private static boolean go(GamePanel panel) {
        List<Data> datas = new ArrayList<Data>();
        Pointer[][] pointers = panel.pointers;
        //循环指示器
        Pointer pointer;
        Data data;
        for(int i=0;i<panel.ROWS;i++)
        {
            for(int j=0;j<panel.CLOS;j++)
            {
                pointer = pointers[i][j];
                if(pointer==null || pointer.getType() == 0){
                    continue;
                }
                    int dir = 0;
                    for(int k = 1;k<=4;k++) {
                        dir = k;
                        //获取权重1
                        data = getData(dir ,1,panel,pointer);
                        System.out.println(data.getCount());
                        if(data.getCount() !=0 && data.getCount() != -1){

                            datas.add(data);
                        }
                        //获取权重分2
                        data = getData(dir,2,panel,pointer);
                        if(data.getCount() != 0 && data.getCount() != -1){
                            //添加到集合中
                            datas.add(data);
                        }


                }
            }
        }
        Collections.sort(datas,new DataCount());//排序
        for(int i=0;i<datas.size();i++)
        {
            System.out.println("权重分"+datas.get(i).getCount());
        }

        if(datas.size()>0){
            Data data2 = datas.get(0);
            Pointer pointer1 = pointers[data2.getI()][data2.getJ()];
            luozi(pointer1,1,panel);

            return true;
        }
        return false;
    }

方法中取排序后的datas.get(0);即分数最大的落子点进行落子操作。如果操作成功为true,否则为false。返回false时将会通过boolean flag = go(panel) || louziRandom(panel); 判断来执行随机落子。同时实现了随机落子与AI落子的组和。

4.五子连珠的判断。

以下为判断方法

static boolean has5(Pointer pointer1,GamePanel panel){
        List<Data> datas = new ArrayList<Data>();
        Pointer pointer;
        for(int i=0;i<panel.ROWS;i++){
            for(int j=0;j<panel.CLOS;j++){
                pointer = panel.pointers[i][j];
                if(pointer==null)continue;;
                if(pointer.getType() == 0){
                    continue;
                }
                if(pointer.getType() != pointer1.getType())continue;
                //循环四个方向
                int dir = 1;
                for(int k=1;k<=4;k++){
                    dir = k;
                    Data data = getData(dir,1,panel,pointer);
                    if(data.getCount()!=-1&&data.getCount()!=0){
                        datas.add(data);
                    }
                    data = getData(dir,1,panel,pointer);
                    if(data.getCount()!=-1&&data.getCount()!=0){
                        datas.add(data);
                    }
                }
            }
        }
        Collections.sort(datas,new DataCount());
        if(datas.size()>0){
            Data data = datas.get(0);
            if(data.getCount() == 100){
                return true;
            }
        }
        return false;
    }

判断五子连珠是通过”count == 100“来判断。之前在计算分数时,当num2 == 5,即连续5给珠子时,会设定count=100;因此在该方法中,只需对数组排序,如果data.get(0)中的count值==100,就可以判断有5个珠子连续,即为获胜。获胜返回bool值true,并在gamepanel的鼠标监听器方法中进行调用。

5.菜单实现

 private void creatMnue() {
        //创建jmb
        jmb = new JMenuBar();

        Font tfont = createFont();//字体取得
        //jme1,2为游戏选项。
        JMenu jMenu1 = new JMenu("游戏");
        jMenu1.setFont(createFont());
        JMenu jMenu2 = new JMenu("帮助");
        jMenu2.setFont(createFont());

        JMenuItem jmi1 = new JMenuItem("人机对战");
        JMenuItem jmi5 = new JMenuItem("双人对战");

        jmi1.setFont(tfont);
        JMenuItem jmi2 = new JMenuItem("退出");//创建子菜单
        jmi2.setFont(tfont);//字体
        jmi5.setFont(tfont);

        JMenuItem jmi3 = new JMenuItem("操作帮助");
        jmi3.setFont(tfont);
        JMenuItem jmi4 = new JMenuItem("胜利条件");
        jmi4.setFont(tfont);//字体

        jMenu1.add(jmi1);
        jMenu1.add(jmi5);
        jMenu1.add(jmi2);//添加子菜单1,2

        jMenu2.add(jmi3);
        jMenu2.add(jmi4);//添加子菜单3,4


        jmb.add(jMenu1);
        jmb.add(jMenu2);//添加菜单1,2

        mainFrame.setJMenuBar(jmb);

        //添加监听
        jmi1.addActionListener( this);
        jmi2.addActionListener( this);
        jmi3.addActionListener( this);
        jmi4.addActionListener( this);
        jmi5.addActionListener( this);
        //设置指令
        jmi1.setActionCommand("restart");
        jmi2.setActionCommand("exit");
        jmi3.setActionCommand("help");
        jmi4.setActionCommand("win");
        jmi5.setActionCommand("restart_man");


    }

 6.菜单指令实现

public void actionPerformed(ActionEvent e) {
       // System.out.println("菜单子项被点击");
        String command = e.getActionCommand();
        System.out.println(command);
        UIManager.put("OptionPane.buttonFont",new FontUIResource(new Font("微软雅黑",Font.ITALIC,18)));
        UIManager.put("OptionPane.messageFont",new FontUIResource(new Font("微软雅黑",Font.ITALIC,18)));
        if("exit".equals(command)){
            Object [] options = {
                    "确定","取消"
            };
            int response = JOptionPane.showConfirmDialog(this,"你真的要退出吗?呜呜");
            if(response == 0){
                System.exit(0);

            }
        }else if("restart".equals(command)){
//            if(!"end".equals(gameFlag)){
//                JOptionPane.showMessageDialog(null,"正在游戏中,无法重新开始!","提示",JOptionPane.INFORMATION_MESSAGE);
//            }else{
//                restart();
//            }
            restart();
        }else if("restart_man".equals(command)){
//            if(!"end".equals(gameFlag)){
//                JOptionPane.showMessageDialog(null,"正在游戏中,无法重新开始!","提示",JOptionPane.INFORMATION_MESSAGE);
//            }else{
//                restart_man();
//            }
            restart_man();

        }else if("help".equals(command)){
            JOptionPane.showMessageDialog(null,"鼠标在红色区域内落子!","提示",JOptionPane.INFORMATION_MESSAGE);

        }else if("win".equals(command)){
            JOptionPane.showMessageDialog(null,"五个棋子连一起就win了","提示",JOptionPane.INFORMATION_MESSAGE);
        }
    }

如果指令是restart或restart_man,

会调用restart();,restart_man();方法。

 void restart_man() {

            //重置数据
            //游戏状态
            //指示器
            //棋子
            gameFlag="start_man";
             //System.out.println("++"+gameFlag);
            Pointer pointer;
            for(int i=0;i<ROWS;i++){
                for(int j=0;j<CLOS;j++){
                    pointer = pointers[i][j];
                    pointer.setType(0);
                    pointer.setShow(false);
                }
            }

            qizis.clear();
            System.out.println("over" );
            reset();


    }

    void restart() {
        //重置数据
        //游戏状态
        //指示器
        //棋子
        gameFlag="start";
        System.out.println("++"+gameFlag);
        Pointer pointer;
        for(int i=0;i<ROWS;i++){
            for(int j=0;j<CLOS;j++){
                pointer = pointers[i][j];
                pointer.setType(0);
                pointer.setShow(false);
            }
        }

        qizis.clear();
       reset();

    }

这里将改变gameFlag的值,并通过reset();实现。

  void reset(){
        if("start_man".equals(gameFlag)){
            createMouseListener1();
            //System.out.println("zhixonh");
            // System.out.println("jj");
        }else{
            // System.out.println("jjjjjj");
            //System.out.println("..."+gameFlag);
            createMouseListener();
        }
    }

7.监听器实现

通过gameFlag的值来选择鼠标监听器,从而实现对“人机对战”和“双人对战”的选择。

如果选择“人机对战”调用以下监听器

private void createMouseListener() {
        MouseAdapter mouseAdapter = new MouseAdapter() {

            @Override//click事件
            public void mouseClicked(MouseEvent e) {
                if(!"start".equals(gameFlag)) return;//flag判断是否发生
                Pointer pointer;
                //获取鼠标坐标
                int x = e.getX();
                int y = e.getY();
                //循环指示器的二维数组
                for(int i=0;i<ROWS;i++)
                {
                    for(int j=0;j<ROWS;j++)
                    {
                        //得到每一个指示器对象
                        pointer =pointers [i][j] ;
                        if(pointer.isPoint(x,y) && pointer.getType() == 0){
                           Qizi qizi = new Qizi(pointer.getX(),pointer.getY(),2);
                           qizis.add(qizi);
                           pointer.setType(2);//被黑棋占用
                           //重绘
                            repaint();
                            clearAILast();
                            //AI走棋子

                            if(AI.has5(pointer,panel)){//你已经连成功了
                                gameWin();
                            }else{
                                AI.next(panel);
                            }
                            return;
                        }

                    }
                }

            }
            
            @Override//move事件
            public void mouseMoved(MouseEvent e) {
                if(!"start".equals(gameFlag)) return;//flag判断是否发生
                Pointer pointer;
                //获取鼠标坐标
                int x = e.getX();
                int y = e.getY();
                //循环指示器的二维数组
                for(int i=0;i<14;i++)
                {
                    for(int j=0;j<14;j++)
                    {
                        //得到每一个指示器对象
                        pointer =pointers [i][j] ;
                        if(pointer.isPoint(x,y) && pointer.getType() == 0){
                            pointer.setShow(true);
                        }
                        else{
                            pointer.setShow(false);
                        }
                    }
                }
                //System.out.println("mouse_move");
                //重绘
                repaint();
            }
        };

        addMouseMotionListener(mouseAdapter);
        addMouseListener(mouseAdapter);

    }

如果选择“双人对战”调用以下监听器

private void createMouseListener1() {
        MouseAdapter mouseAdapter = new MouseAdapter() {

            @Override//click事件

            public void mouseClicked(MouseEvent e) {
                //System.out.println("jj");
                if(!"start_man".equals(gameFlag)) return;//flag判断是否发生
                Pointer pointer;
                //获取鼠标坐标
                int x = e.getX();
                int y = e.getY();
                //循环指示器的二维数组int fl = 1;
                for(int i=0;i<ROWS;i++)
                {
                    for(int j=0;j<ROWS;j++)
                    {
                        //得到每一个指示器对象
                        pointer =pointers [i][j] ;
                        if(pointer.isPoint(x,y) && pointer.getType() == 0){
                            {
                                if(te  == 1){
                                    Qizi qizi = new Qizi(pointer.getX(),pointer.getY(),1);
                                    qizis.add(qizi);
                                    pointer.setType(1);//被黑棋占用
                                    //System.out.println("hh1");
                                    if(AI.has5_w(pointer,panel)){//你已经连成功了
                                        gameWin_w();
                                    }
                                    te = -te;
                                }else if(te == -1){
                                    Qizi qizi = new Qizi(pointer.getX(),pointer.getY(),2);
                                    qizis.add(qizi);
                                    pointer.setType(2);//被黑棋占用
                                    //System.out.println("hh1");
                                    te = -te;
                                    if(AI.has5_w(pointer,panel)){//你已经连成功了
                                        gameWin_w();
                                    }
                                    else if(AI.has5_b(pointer,panel)){//你已经连成功了
                                        gameWin_b();
                                    }
                                }


                               // System.out.println("heiqi");

                            }
                            repaint();

                            //重绘

                           // clearAILast();
                            //AI不走棋子
                            return;
                        }
                    }
                }
            }
            
            @Override//move事件
            public void mouseMoved(MouseEvent e) {
                if(!"start_man".equals(gameFlag)) return;//flag判断是否发生
                Pointer pointer;
                //获取鼠标坐标
                int x = e.getX();
                int y = e.getY();
                //循环指示器的二维数组
                for(int i=0;i<14;i++)
                {
                    for(int j=0;j<14;j++)
                    {
                        //得到每一个指示器对象
                        pointer =pointers [i][j] ;
                        if(pointer.isPoint(x,y) && pointer.getType() == 0){
                            pointer.setShow(true);
                        }
                        else{
                            pointer.setShow(false);
                        }
                    }
                }
                //System.out.println("mouse_move");
                //重绘
                repaint();
            }
        };
        addMouseMotionListener(mouseAdapter);
        addMouseListener(mouseAdapter);

    }

5.结尾

    在本项目的完成过程中,遇到了很多困难,比如AI算法,我们上网查询了相关资料,借鉴他人代码思路并分析后,完成了算法过程,这次课程设计收获很大。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值