多线程—飞机大战排行榜功能(2.0版本)

(一)实现功能:

1.基础的成绩排序
2.相同成绩随机排名
3.用户名注册重复

(二)效果视频:

(三)代码实现:

3.1 && 3.2 在FileRead类中新增方法如下:

具体的代码实现:

java 复制代码
package DemoProject.fjm0601.FileWandRSystem;

import DemoProject.fjm0601.GameWD;

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

public class FileRead {
    public static File file = new File("src/DemoProject/fjm0601/ScoreFile.txt");
    static FileReader fr;
    static BufferedReader bfr;

    //获取初始的绘制高度:
    static int y = 10;

    //最终画板采取的绘制方法:
    public static void RankOutCurrentBest(File file,Graphics graphics) throws IOException {
        try {
            fr= new FileReader(file);
            bfr  = new BufferedReader(fr);

        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }

        //获取字符串形式的成绩名单
        ArrayList<String> scoreList = getScoreList(bfr);
        System.out.println("此时的成绩名单为:"+scoreList);
        //获取先前查询过的最大值数组
        ArrayList<Integer> BScoreList = new ArrayList<>();

        int BScore;
        String [] NameArr;
        int CurrentNum = 0;

        while (true){

            //获取此时的最大成绩(除去先前已检查过的成绩)
            BScore = getBestScore(BScoreList,scoreList);
            System.out.println("此时最好成绩为:"+BScore);

            //获取成绩最大且相同的用户名数组
            NameArr = viaScoreToNameArr(BScore,scoreList);
            System.out.println("成绩相同的有"+NameArr.length+"个人");
            System.out.println("成绩最好的人为:"+NameArr[0]);

            //将BScore放入查询过的最大数组中:
            BScoreList.add(BScore);

            //将此时成绩最大的用户们成绩写出到面板中
            readFileOnRow(BScore,NameArr,graphics);
            System.out.println("此人的成绩已被写入");

            //将被录入成绩的人计入
            CurrentNum += getTheScoreNum(BScore,scoreList);
            System.out.println("此时被写入成绩的人有:"+CurrentNum);
            //当被录入成绩的人等于scoreList的大小,意味着所有人的成绩皆被录入
            if(CurrentNum == scoreList.size()){
                System.out.println("成绩已写入完毕");
                break;
            }
            y += 20;
        }


    }

    //将文件里面的成绩存储进入动态数组
    public static ArrayList<String> getScoreList(BufferedReader bfr) throws IOException {
        ArrayList<String> scoreList = new ArrayList<>();
        String strLine;
        while (true){
            if((strLine = bfr.readLine()) != null){
                scoreList.add(strLine);

            }else{
                break;
            }
        }
        return scoreList;
    }

    //获取此时最大的成绩
    public static int getBestScore(ArrayList<Integer> BScoreList,ArrayList<String> scoreList){
        int BScore = 0 ;
        System.out.println("scoreList的长度为:"+scoreList.size());

        LabelName:
        for(String perScore : scoreList){

            int score = Integer.valueOf(perScore.split(":")[1]);
            System.out.println("此时找到的成绩为:"+score);
            //将"这一个"用户的成绩与先前的成绩做对比,一旦发现相同则跳出内循环,进而检查下一个同学的成绩。
            for(int previousScore : BScoreList){
                if(score == previousScore){
                    //一旦发现相同,则跳出内部循环并开启下一次循环
                    System.out.println("找到的该成绩与先前一致,因此退出并进入下一次循环");
                    continue LabelName;
                }
            }

            if(BScore < score){
                BScore = score;
            }
        }
        System.out.println("最终获取的最好成绩为:"+BScore);
        return BScore;
    }

    //获取具有该成绩的人数
    public static int getTheScoreNum(int Score, ArrayList<String> scoreList){
        int EachScore;
        int i = 0;
        for(String Each : scoreList){
            String [] EachArr = Each.split(":");
            EachScore = Integer.valueOf(EachArr[1]);
            if(EachScore == Score){
                i++;
            }
        }
        return i;
    }

    //将成绩按行写入面板中
    public static void readFileOnRow(int BScore, String [] NameArr,Graphics graphics){


            String condition1;
            int x = 10;
            int i = 0;
            graphics.setColor(Color.BLACK);

            while (true){
                System.out.println("进入此循环中");
                if(i < NameArr.length){
                    condition1 = NameArr[i] + ": " +BScore;
                    graphics.drawString(condition1,x,y);
                    if(NameArr.length > 1 && i != NameArr.length-1){
                        y += 20;
                    }
                    i++;
                }else{
                    break;
                }
            }


    }

    //整合获取相同成绩的用户名数组
    public static String[] viaScoreToNameArr(int BScore, ArrayList<String> scoreList){
        int EachScore;
        int len = getLen(BScore,scoreList);
        String [] NameArr = new String[len];
        int i = 0;
        for(String Each : scoreList){
            String [] EachArr = Each.split(":");
            EachScore = Integer.valueOf(EachArr[1]);
            if(EachScore == BScore){
                NameArr[i] = EachArr[0];
                i++;
            }
        }
        return NameArr;


    }

    //获取用户名数组的长度
    public static int getLen(int BScore, ArrayList<String> scoreList){
        int EachScore;
        int len = 0;
        for(String Each : scoreList){
            EachScore = Integer.valueOf(Each.split(":")[1]);
            if(EachScore == BScore){
                len++;
            }
        }
        return len;
    }


    public static void main(String[] args) {
        JFrame jFrame = new JFrame();
        jFrame.setSize(400,400);
        jFrame.setLocationRelativeTo(null);
        JPanel jPanel = new JPanel();
        jFrame.add(jPanel);
        jFrame.setVisible(true);

        Graphics graphics = jPanel.getGraphics();
      //  readFileOnRow(file,graphics);
    }




}
复制代码
由于需要考虑相同成绩的排名,因此不能简单获取成绩再排序,整体的实现思路如下
1.先获得此时的成绩单
2.创建一个死循环,在单次循环中:
	获取此时的最好成绩->
	依据最好成绩获取具有相同成绩的用户->
	按照用户 + 成绩的格式写到面板上。
	
	下次排序时,避开此次及先前排好的成绩
	记录并追加已排好的用户成绩,当排好所有用户后退出循环
3.3 在GameWD中的paint2()方法中修改按钮监听方法
复制代码
实现提示框的添加
java 复制代码
confirmBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                String name = jtf.getText();
                try {
                    if(name == null){
                        JOptionPane.showMessageDialog(null,"用户名不可为空");
                        return;
                    }
                    if(scoreMap.containsKey(name)){
                        JOptionPane.showMessageDialog(null,"该用户名已注册");
                        return;
                    }
                    writeFile(name,Score);
                    JOptionPane.showMessageDialog(null,"写入成功,祝您下次取得更好成绩");
                } catch (IOException ex) {
                    throw new RuntimeException(ex);
                }

            }
        });
3.4 在RankPanel中替换成RankOutCurrentBest()方法
java 复制代码
public class RankJPanel extends JPanel {

    public void paint(Graphics graphics){
        super.paint(graphics);
        File file = FileRead.file;
        try {
            FileRead.RankOutCurrentBest(file,graphics);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

补充:

1.为排行榜加入柱状图

2.加入用户名规范

实现代码如下:

1.在readFileOnRow的方法的死循环中修改为下:
java 复制代码
while (true){
                System.out.println("进入此循环中");
                if(i < NameArr.length){
                    condition1 = NameArr[i] + ": ";
                    double pillarLen = 0;
                    graphics.drawString(condition1,x,y);
                    if(BScore > 1000){
                        pillarLen = BScore / 10.0;
                    }else if( BScore < 100){
                        pillarLen = BScore ;
                    }

                    graphics.fillRect(x + 90,y -7 , (int) pillarLen,5);
                    graphics.drawString(BScore + "",x +(int)pillarLen  + 100,y);

                    if(NameArr.length > 1 && i != NameArr.length-1){
                        y += 20;
                    }
                    i++;
                }else{
                    break;
                }
            }
复制代码
注意:为避免成绩过长画出边界,对超高成绩的柱状图作压缩处理
2.在GameWD的按钮监听方法里面加入:
java 复制代码
if(!name.matches("^[\u4e00-\u9fa5]{5}\\d{4}$")){
                        JOptionPane.showMessageDialog(null,"用户名不规范,注册格式为:五个中文字符+四个数字");
                        return;
                    }
复制代码
括号内的字符就是五个中文字符+四个数字的格式
3.小漏洞修复:反复点击排行榜,整体的成绩图会不断下滑。

原因 :单次程序(整个飞机大战)运行后,每次点击排行榜,y值始终在增加
解决方法 :在按钮监听器中新增 FileRead.y = 20; :

确保每次点击排行榜的y的初始值都为20

异常/遗漏修复:

复制代码
(一)数组越界异常:
异常:每次拼接内容:
原因:用户 + 成绩的时候,数组调用在条件判断之前,
解决方法:将数组调用放在条件判断内
(二)排行榜上重复添加相同成绩用户且该用户成绩为0:
原因:使用新方法LabelName的时候,误用break LabelName,导致没有进入下一次的大循环反而直接掠过了整个循环。使得后续的成绩皆为此次成绩0
解决方法:将break LabelName改为continue LabelName
(三) 排行榜显示完后无法结束程序
原因:一开始简单认为退出死循环的条件为:
遍历到成绩为0的时候(实际上最低成绩可能不为0)
解决方法:修改退出循环条件为:排好序的人数达到成绩数组的长度(也就是所有人都排好序)即退出。
(四)排行榜上相同成绩的信息重叠在一块。
原因:相同成绩的人在写入时,没有改变y值
解决方法:当NameArr(也就是相同成绩的玩家)的长度大于1,且没有遍历到最后一人(防止其他成绩的用户在绘制时出现 "空行" 的问题),y += 20.
(五) 绘制的时候所有成绩全部画在一块
原因:绘制的y位置仅在方法调用时创建,每一次调用方法后都会创建新的y,致使y没有实时增加
解决方法:添加静态修饰符static,并将其提到全局变量的位置。

感悟:

在进行排序功能时,曾想过:先用哈希表存储各值,比较完值之后,反推回到键(也就是用户名),再进行拼接,失败。

原因 : 哈希表没有通过值返回键 的方法,也难以通过手动遍历哈希表 获取键。
解决方法 :通过使用String[]数组 预先存储各人的 "用户:成绩" 信息。再通过split()方法获取 [用户,成绩]格式的一维数组,最后比对成绩。间接达到二维数组 的效果,实现用户与成绩的关系绑定

相关推荐
老虎06271 分钟前
JavaWeb前端02(JavaScript)
开发语言·前端·javascript
一语长情13 分钟前
Netty流量整形:保障微服务通信稳定性的关键策略
java·后端·架构
风往哪边走18 分钟前
自定义仿日历组件弹框
android
Python私教21 分钟前
YggJS RLogin暗黑霓虹主题登录注册页面 版本:v0.1.1
开发语言·javascript·ecmascript
没有了遇见22 分钟前
Android 外接 U 盘开发实战:从权限到文件复制
android
盖世英雄酱581361 小时前
第一个RAG项目遇到的问题
java·spring boot
carver w1 小时前
MFC,C++,海康SDK,回调,轮询
开发语言·c++·mfc
最初的↘那颗心1 小时前
Flink Stream API - 源码开发需求描述
java·大数据·hadoop·flink·实时计算
王廷胡_白嫖帝1 小时前
Qt猜数字游戏项目开发教程 - 从零开始构建趣味小游戏
开发语言·qt·游戏
XH华1 小时前
C语言第九章字符函数和字符串函数
c语言·开发语言