当前位置: 首页 > news >正文

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

(一)实现功能:

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

(二)效果视频:

(三)代码实现:

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

在这里插入图片描述

具体的代码实现:

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()方法中修改按钮监听方法
实现提示框的添加

在这里插入图片描述

confirmBtn.addActionListener(new ActionListener() {@Overridepublic 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()方法
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的方法的死循环中修改为下:
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的按钮监听方法里面加入:
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()方法获取[用户,成绩]格式的一维数组,最后比对成绩。间接达到二维数组的效果,实现用户与成绩的关系绑定

http://www.lryc.cn/news/626039.html

相关文章:

  • 科技云报到:AI推理破局,金融服务如何“逆天改命”
  • 颠覆性进化:OpenAI正式发布GPT-5,AI大模型进入“超级智能”时代
  • bit-Agent正式接入GPT-5,九科信息智能体能力再升级!
  • 电子电气架构 ---SDV技术基础与传统E/E架构有何不同?
  • 免费OCR工具支持哪些文档格式转换
  • 中兴B862AV3.2M/B862AV3.1-M2 晨星mso9385_安卓9_原厂备份救砖包
  • 基于C语言基础对C++的进一步学习_知识补充、组合类、类中的静态成员与静态函数、类中的常对象和常成员函数、类中的this指针、类中的友元
  • 网络编程day3
  • 机器翻译60天修炼专栏介绍和目录
  • 大模型问题:幻觉分类+原因+各个训练阶段产生幻觉+幻觉的检测和评估基准
  • 【技术揭秘】AI Agent操作系统架构演进:从单体到分布式智能的跃迁
  • Incredibuild 新增 Unity 支持:击破构建时间过长的痛点
  • Pygame第11课——实现经典打方块小游戏
  • 数据结构:二叉树oj练习
  • Linux------《零基础到联网:CentOS 7 在 VMware Workstation 中的全流程安装与 NAT 网络配置实战》
  • Apache ShenYu网关与Nacos的关联及如何配合使用
  • AJAX (一)
  • C# DevExpress控件安装使用教程
  • 【学习】Linux 内核中的 cgroup freezer 子系统
  • 【自动化运维神器Ansible】Playbook调用Role详解:从入门到精通
  • 常用css
  • 【C++】C++ 的护身符:解锁 try-catch 异常处理
  • 用java语言完成手写mybatis框架(第2章)
  • 借助AI将infoNES移植到HarmonyOS平台的详细方案介绍
  • Linux操作系统编程——进程间的通信
  • 极海APM32F107V6 gpio模拟串口
  • 决策树算法学习总结
  • 【Vivado TCL 教程】从零开始掌握 Xilinx Vivado TCL 脚本编程(三)
  • UML常见图例
  • 一文精通 Swagger 在 .NET 中的全方位配置与应用