面向对象程序设计(Java)课程设计——三少五子棋Part2


目录

一、团队成员及任务

二、项目简介

三、.功能架构图

四、运行结果截图

五、项目git地址

六、个人部分实现过程


一、团队成员及任务

队长:

高晔川 计科(智能)22-1 202203200035

负责模块:Java Swing界面搭建,Graphic 2D图形绘制,Panel面板搭建,五子棋过程的实现构思

面向对象程序设计(Java) 课程设计——三少五子棋 Part1_Aimless.的博客-CSDN博客

队员:

戚彦良 计科(智能)22-1 202203200029

负责模块: 排行榜功能的实现 负责函数算法的编写,使用函数方法体判断哪方获胜

用score()方法来评估当前棋局的分数的,以便计算计算机下一步的最佳落子点。

队员:

吴沅峰 计科(智能)22-1 202203200020

负责模块:鼠标监听器,动作监听器,自动下棋算法

面对程序设计(Java)课程设计————三少五子棋_a1067793829的博客-CSDN博客

团队博客:

面向对象程序设计(Java) 课程设计——三少五子棋(Final)_Aimless.的博客-CSDN博客

参考博客:

五元组评价算法实现简易五子棋【人工智能】_五子棋五元组算法_YouthUpward的博客-CSDN博客

二、项目简介

功能描述:由三人合作运用Java编写五子棋小游戏,具有双人对战,人机对战,悔棋,Replay,GameOver,投降,排行榜功能。可从排行榜中刷新,查看战绩,并且在About us 中加入了我们制作人的信息。

三、.功能架构图

四、运行结果截图

五、项目git地址

五子棋_final: 此仓库专用于课程设计任务

六、个人部分实现过程

LeaderboardFrame.java

这是一个Java Swing程序,用于实现五子棋游戏的排行榜功能。通过JFrame和一些Swing组件创建了一个简单的排行榜窗口。该窗口中包括一个JTextArea和一个JButtonJTextArea用于显示排行榜内容,JButton用于刷新排行榜内容。

当用户点击“刷新”按钮时,程序将读取之前保存在文件中的五子棋游戏数据,并将其显示在JTextArea中。具体来说,程序通过FileReader读取文件中的数据,并使用JTextAreaappend()方法将这些数据添加到JTextArea中显示出来。

package MyFrame;

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
/*Java Swing的窗口类,包含一个文本区域和一个按钮。
当用户点击按钮时,窗口会读取文件中的数据并在文本区域中显示,以此来刷新排行榜。具
体来说,文本区域被添加在窗口左上角的位置,按钮被添加在窗口中间下方的位置。
在构造函数中,设置了窗口的标题、大小、位置等属性,并将文本区域和按钮添加到窗口中。
在按钮的监听器中,当用户点击按钮时,先判断按钮的文本是否为“刷新”,
如果是则清空文本区域并尝试读取文件。如果文件不存在,则创建一个新文件,然
后将文件中的内容读取到字符数组中,并将数组转换为字符串后添加到文本区域中。
如果读取文件过程中发生任何异常,则在控制台中打印出异常的堆栈跟踪信息。
 */

public class LeaderboardFrame extends JFrame {
    //JTextArea 是 Swing 类库中的一个组件,用于显示多行文本。
    //JButton 也是 Swing 类库中的一个组件,用于显示按钮。
    JTextArea textArea = new JTextArea();//创建了一个文本区域 textArea
    JButton button = new JButton("刷新");//创建了一个按钮 button,并将按钮的文本设置为 “刷新”

    LeaderboardFrame(){
        setTitle("排行榜");//设置标题为“排行榜”
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置点击窗口关闭按钮时退出程序
        setSize(300, 400);//设置窗口大小为宽度 300 像素,高度 400 像素
        setLocationRelativeTo(null); // 设置窗口居中显示
        setVisible(true);//JFrame 类的方法,用于将窗口设置为可见状态,即在屏幕上显示窗口。
        setLayout(null);//设置布局为空布局(null layout)
        //使用了 setBounds() 方法,该方法将组件的位置和大小设置为给定的 x 坐标、y 坐标、宽度和高度。
        textArea.setBounds(20,20,260,260);//文本区域的左上角坐标为 (20,20),宽度为 260 像素,高度为 260 像素;
        button.setBounds(90,300,100,30);//按钮的左上角坐标为 (90,300),宽度为 100 像素,高度为 30 像素。
        //注册按钮的 ActionListener,以便在按钮被点击时执行对应的操作,这里是执行 actionListener 中定义的逻辑。
        button.addActionListener(actionListener);
        //将文本区域设置为不可编辑,这意味着用户不能修改文本区域的内容,仅能查看。
        textArea.setEditable(false);
        //将文本区域和按钮添加到窗口中
        add(textArea);
        add(button);
    }
    //当用户点击了名为 “刷新” 的按钮时,它将读取文件 “a.txt” 中的内容,并将其显示在窗口中的文本区域中。这样,用户就可以查看最新的排行榜信息了

    ActionListener actionListener = new ActionListener() {//定义了一个 ActionListener 对象 actionListener,用于监听按钮的 ActionEvent 事件。
        @Override
        public void actionPerformed(ActionEvent e) {//当按钮被点击时,actionPerformed() 方法会被调用,执行对应的逻辑
            JButton button1 = (JButton) e.getSource();//通过 e.getSource() 方法获取触发事件的源组件(即被点击的按钮),并将其转换成 JButton 类型的对象 button1。
            String text = button1.getText();//通过 button1.getText() 方法获取按钮的显示文本,即按钮上显示的文字内容,并将其赋值给字符串 text。
            if ("刷新".equals(text)){//如果 text 的值是 “刷新”,则执行后面的代码。
                textArea.setText("");//先使用 textArea.setText("") 将文本区域的内容清空。
                try{
                    File file = new File("a.txt");//使用 File 类打开名为 “a.txt” 的文件。
                    if (!file.exists()){//如果文件不存在,则创建一个新文件。
                        file.createNewFile();
                    }
                    FileReader fr = new FileReader(file);//使用 FileReader 类创建一个新的文件读取器 fr,将其与打开的文件关联。
                    int line,len = 0;
                    char[] ch = new char[10000];//创建一个字符数组 ch,用于保存文件中的内容。
                    while ((line = fr.read()) != -1){//fr.read() 方法每次读取一个字符,并将其赋值给 line 变量,同时将 line 的值与 -1 进行比较。如果读取到了文件的末尾,则 line 的值为 -1,循环终止;
                        ch[len] = (char)line;//通过 fr.read() 方法一次从文件中读取一个字符,如果读取成功,将读取到的字符转换成字符类型,并将其添加到字符数组 ch 的尾部。并且让数组的长度 len 加 1。
                        len ++ ;
                    }//在循环结束后,变量 len 的值就等于读取的字符总数,变量 ch 中的前 len 个字符就是从文件中读取到的内容。
                    String result = new String(ch);//将字符数组转换成字符串 result,便于将其添加到窗口中的文本区域中。
                    textArea.append(result);//通过 textArea.append(result) 方法将其添加到文本区域中。
                    fr.close();//关闭文件流。
                }catch (IOException f){//定义了一个捕获文件读取过程中可能出现的 IOException 异常的 catch 语句块。
                    f.printStackTrace();//如果读取文件时出现错误,就将错误信息打印到控制台或日志文件中(调用方法 printStackTrace()),以便查找和解决问题。
                }//IOException 表示捕获的异常类型,f 是该异常对象的引用,f.printStackTrace() 用于将异常信息输出到标准错误流(即控制台或日志文件),以便程序员进行调试和错误排查
            }
        }
    };

}
函数算法的编写,使用函数方法体判断哪方获胜

判断某种棋子是否已经在当前局面中胜利。它通过遍历八个方向来判断该种棋子的连子情况,如果存在一个方向中有四个或以上的同色棋子,则将win标记置为true,表示该种棋子获胜。

具体来说,该段代码中的directions数组存储了八个方向的偏移量,其中{ -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 }分别表示横向、纵向、左斜和右斜四个方向,{ -1, -1 }, { 1, 1 }, { -1, 1 }, { 1, -1 }分别表示左上到右下、右下到左上、左下到右上和右上到左下四个方向。然后对于每个方向,程序将棋子逐个向一个方向延伸,直到遇到一个空位置或者边界,如果在此过程中遇到了相同颜色的棋子,则将 sum 计数器加1,表示已经扩展了一个棋子,直到 sum 累计数值等于或者大于4,则表示该种棋子已经获胜。

当某种棋子获胜时,将win标记置为true,同时记录下获胜时的棋局情况,包括步数和胜利方。这段代码将数据写入到一个文件中,文件路径为a.txt。如果文件不存在,则会创建一个空文件。

    //判断谁赢,扫描整个棋盘,来判断是否练成五个
    private void judgement(int type, int x, int y) {
        // 传入参数 type 用于判断黑(2)或白(1)方,x 和 y 用于定位当前下的棋子在棋盘中的位置。

        int[][] directions = { {-1, 0}, {1, 0}, {0, -1}, {0, 1}, {-1, -1}, {1, 1}, {-1, 1}, {1, -1} };
        //定义了一个二维数组 directions,其中记录了八个方向的偏移量,方便之后的遍历。

        for (int[] direction : directions) {//通过一个以 direction 这个变量名来遍历这八个方向
            int sum = 0;//定义变量 sum 记录相邻颜色相同的棋子数
            int dx = direction[0];//变量 dx 和 dy 记录当前方向的横纵坐标偏移值
            int dy = direction[1];
            int i = x + dx;//初始化变量 i 和 j,定位到当前正在被判断的棋子的上下左右或斜方向上的一个棋子。
            int j = y + dy;

            while (i >= 0 && i < num && j >= 0 && j < num && table[i][j] == type) {//循环的条件为 i 和 j 均在棋盘范围内,且 table[i][j] 的值与要检查的棋子的颜色相同
                sum++;//在循环体中,先将 sum 的值加一
                i += dx;//然后将 i 和 j 分别增加一个偏移值 dx 和 dy
                j += dy;//就可以在当前方向上继续检查相邻的棋子,直到遇到颜色不同的棋子或到达棋盘边界。
            }//循环结束时,sum 记录的就是当前方向上相邻颜色相同的棋子个数。

            i = x - dx;
            j = y - dy;
//反方向检查当前方向上相邻颜色相同的棋子个数。循环首先是由前往后检查棋子的个数,然后在由后往前验证是否达到了胜负条件。
            while (i >= 0 && i < num && j >= 0 && j < num && table[i][j] == type) {
                sum++;
                i -= dx;
                j -= dy;
            }//循环体中判断棋子是否相邻,并累计相邻棋子的个数,最终得到当前方向和相反方向上相邻颜色相同的棋子的个数。

//在 judgment 函数检查棋盘上的每个棋子后,如果此时某一玩家连成四个相邻的棋子,将游戏状态 win 设为 true,并将棋局信息记录到文件中。
            if (sum >= 4) {//使用 if 判断变量 sum 是否大于等于 4,如果成立,表示当前玩家连成了四个相邻的棋子。
                win = true;//将游戏状态 win 设为 true,表示当前玩家已经取得了胜利
                if (win){//强调在赢得游戏之后记录棋局信息。
                    try{//在 try 块中通过创建 File 和 FileWriter 对象,将信息记录到文件中
                        java.io.File file = new java.io.File("a.txt");//定义一个 java.io.File 对象,其指向名为 “a.txt” 的文件。
                        if (!file.exists()){//如果该文件不存在,使用 file.createNewFile() 创建一个新文件
                            file.createNewFile();
                        }
                        if (oval_type == 1){//通过 if 判断变量 oval_type,如果其等于 1,则当前玩家为黑色方,否则表示其为白色方。
                            String result = "步数:" + step + "黑方赢" + '\n';//设置 String result 为对应颜色方赢得比赛的信息,即记录形式为 “步数:X 黑方/白方赢”。
                            java.io.FileWriter fileWriter = new java.io.FileWriter(file,true);//创建一个 java.io.FileWriter 对象
                            fileWriter.write(result);//向文件中写入文本信息 result
                            fileWriter.close();//关闭文件流,回收资源。
                        } else {
                            String result = "步数:" + step + "白方赢通过 printStackTrace() 打印出异常的堆栈跟踪信息。" + '\n';
                            java.io.FileWriter fileWriter = new java.io.FileWriter(file,true);
                            fileWriter.write(result);FileWriter 的第二个参数为 true,表示以追加的方式向文件中写入数据。这样,以后每次记录游戏胜负信息时,会在该文件中追加记录。
                            fileWriter.close();
                        }
                    }catch (java.io.IOException e){//如果在文件写入操作过程中发生了 I/O 异常(如文件不存在或其他错误),则会由 catch 块中的代码块捕获异常
                        e.printStackTrace();//通过 printStackTrace() 打印出异常的堆栈跟踪信息。
                    }
                }
                return;//继续执行后续程序,并通过 return 退出函数,避免重复记录胜负信息。
            }
        }
    }

score()方法

用来评估当前棋局的分数的,以便计算计算机下一步的最佳落子点。该方法的输入参数wb分别表示白色和黑色棋子在当前局面中连续的棋子个数,其中wb至少有一个为0。如果两个参数都为0,则返回7,表示此处可以下子。如果wb都大于0,则返回0,表示此处不能下子。如果只有其中一种连续的棋子,则根据对应的分数返回结果。分数越高,表明这个位置越有利。

具体来说,当白子连续1颗时返回15分,连续2颗时返回400分,连续3颗时返回1800分,连续4颗时返回100000分;当黑子连续1颗时返回35分,连续2颗时返回800分,连续3颗时返回15000分,连续4颗时返回800000分。

 //用于根据给定形式的棋盘数据计算出当前评分。这个评分可以用于评估当前棋局的优劣,方便 AI 程序作出下一步棋的决策。
    private int score(int w, int b) {//方法的输入参数是两个整形数 w 和 b,分别表示黑方和白方在棋盘上的棋子数量。
        if (w > 0 && b > 0) {//使用 if 语句,判断棋盘中是否同时出现了两个玩家的棋子。如果出现了,游戏处于平局状态,返回 0 分。
            return 0;
        }
        if (w == 0 && b == 0) {//判断棋盘上是否有一方的棋子都没有,这种情况也是平局,此时返回 7 分。
            return 7;
        }
        //接下来根据白方或黑方棋子的数量来计算得分。
        if (w == 1) {//如果黑方有 1 枚棋子,返回 35 分
            return 35;
        }
        if (w == 2) {//有两枚返回 800 分
            return 800;
        }
        if (w == 3) {//有三枚返回 15000 分,
            return 15000;
        }
        if (w == 4) {//有四枚返回 800000 分。
            return 800000;
        }
        if (b == 1) {//如果白方有一枚棋子,返回 15 分,
            return 15;
        }
        if (b == 2) {//有两枚返回 400 分
            return 400;
        }
        if (b == 3) {//有三枚返回 1800 分
            return 1800;
        }
        if (b == 4) {//有四枚返回 100000 分
            return 100000;
        }

        return -1;//如果输入参数 w 和 b 不符合以上任何条件,返回 -1 分。
    }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值