Java开发赛车模拟器:不修改原数组如何实现车手成绩排名
问题描述
我目前正尝试开发一款赛车模拟器来学习Java编程,已为每位车手及其驾驶的赛车创建了对应的对象数组:
public static Driver drivers[] = new Driver[18];
每位车手关联多项属性值,这些属性会决定车手的比赛表现:
int overall; int rating; int corners; int straightaways; int rain; int skill; int experience; int pace; int awareness;
进入比赛流程模拟首场赛事时,我会获取车手的overall属性值(取值范围为50-100),在该值基础上叠加“赛事日幸运值”因素得到未排序的完赛成绩。当前实现的比赛模拟类代码如下:
package races; import racers.CreateDrivers; import racers.Driver; public class RaceSimulator { // 复制车手数组,暂不确定是否需要 public Driver currentRace[] = CreateDrivers.drivers.clone(); public static void SimulateNextRace() { System.out.println("\nFirst Race is Beginning!!\n"); int racedayLuck; int raceFinishUnsorted; for(int i = 0; i < CreateDrivers.drivers.length; i++) { racedayLuck = (int) (Math.random() * 20 + 1); raceFinishUnsorted = racedayLuck + CreateDrivers.drivers[i].getOverall(); CreateDrivers.drivers[i].setRacedayFinish(raceFinishUnsorted); System.out.println(CreateDrivers.drivers[i].getName() + ": " + CreateDrivers.drivers[i].getRacedayFinish()); } // TODO 完成车手排名逻辑,为对应车手设置积分 } public static void getRank() { // } }
控制台输出示例如下:
First Race is Beginning!! Joseph Morgan: 90 Malachi Nguyen: 90 Greg Hart: 76 Ian Banks: 78 Gabriel Mcdonald: 84 Spencer Meyer: 94 Jordan Soto: 95 Abraham Wells: 94 Charles Frederiks: 82 Trevor Fleming: 92 Nathaniel Nguyen: 67 Johnathan Herrera: 79 Derek Miller: 88 Grant Reynolds: 86 Kyle Bailey: 82 Conner Sullivan: 98 Paul Perry: 96 Antonio Larson: 87
目前遇到的问题:无法在不对原数组排序的前提下,对所有CreateDrivers.drivers[x]对象的完赛成绩进行排名比对。需要在不修改任何原有属性值的前提下完成车手排名,同时支持为对应车手累加“赛季积分”。之前尝试过为Driver类添加id属性,对id数组排序后再反向匹配对应车手,但认为应当存在更简便的方式来完成18个整型成绩的比对排名。
解决方案
不需要给Driver类额外加id做反向匹配,只需要复制一份原数组的引用做排序,完全不会改动原数组的顺序和原有属性值,实现逻辑非常简单:
- 首先克隆一份车手数组的副本,注意这里是浅克隆,数组里存的是Driver对象的引用,克隆不会新建Driver对象,也不会修改原数组里的引用顺序,只是生成了一个新的数组容器
- 对这个副本数组,按照车手的完赛成绩做降序排序(成绩越高排名越靠前)
- 遍历排序后的副本数组,按照排名给对应车手累加积分即可,整个过程原
drivers数组的顺序、车手除了积分之外的属性都不会被改动
直接补全代码里的排名和积分计算逻辑就行,参考实现:
import java.util.Arrays; public static void calculateRaceResult() { // 克隆原数组得到排序用副本,完全不影响原数组顺序 Driver[] sortedDrivers = CreateDrivers.drivers.clone(); // 对副本按完赛成绩降序排序,成绩高的排前面 Arrays.sort(sortedDrivers, (a, b) -> Integer.compare(b.getRacedayFinish(), a.getRacedayFinish())); // 积分规则可自行调整,示例采用F1标准积分,索引0对应第一名 int[] pointsTable = {25, 18, 15, 12, 10, 8, 6, 4, 2, 1}; for (int rank = 0; rank < sortedDrivers.length; rank++) { Driver driver = sortedDrivers[rank]; System.out.printf("第%d名:%s 成绩:%d%n", rank+1, driver.getName(), driver.getRacedayFinish()); // 前10名累计积分,剩余名次积0分 if (rank < pointsTable.length) { driver.setPoints(driver.getPoints() + pointsTable[rank]); } } }
如果出现成绩相同的情况,上面的写法会按照数组原有的先后顺序排定同名次先后,需要追加平局判定规则(比如过弯属性高的排前面),只需要在比较逻辑里追加判断即可,示例:
Arrays.sort(sortedDrivers, (a, b) -> { int scoreCompare = Integer.compare(b.getRacedayFinish(), a.getRacedayFinish()); if (scoreCompare != 0) { return scoreCompare; } // 成绩相同时比较过弯属性,属性值高的排前面 return Integer.compare(b.getCorners(), a.getCorners()); });
你之前定义的currentRace数组就是用来承载这个排序副本的,完全不需要额外加id字段做反向匹配,整个实现只需要十余行代码,排序操作仅作用在克隆出的新数组上,原数组的顺序从头到尾都不会发生改变。
内容的提问来源于stack exchange,提问作者Colin Koenig
相关产品推荐
相关产品推荐

