From 90ea2c5ee4dc48f63ba75d2f2f116ca806d25a2d Mon Sep 17 00:00:00 2001 From: bumfo Date: Mon, 4 Feb 2019 15:37:16 +0800 Subject: [PATCH 01/11] Build with gradle --- .gitignore | 4 + build.gradle | 84 +++++++++++++++++++++ gradle/wrapper/gradle-wrapper.properties | 5 ++ scripts/{ => competitions}/sample_1v1.rrc | 0 scripts/{ => competitions}/sample_melee.rrc | 0 scripts/{ => competitions}/sample_teams.rrc | 0 scripts/rmall.sh | 4 +- scripts/rmdata.sh | 1 + scripts/rr.sh | 2 - scripts/setup.sh | 3 +- settings.gradle | 1 + 11 files changed, 99 insertions(+), 5 deletions(-) create mode 100644 .gitignore create mode 100644 build.gradle create mode 100644 gradle/wrapper/gradle-wrapper.properties rename scripts/{ => competitions}/sample_1v1.rrc (100%) rename scripts/{ => competitions}/sample_melee.rrc (100%) rename scripts/{ => competitions}/sample_teams.rrc (100%) delete mode 100755 scripts/rr.sh create mode 100644 settings.gradle diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2b40c64 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.gradle +.idea/* +libs/robocode.jar +build/ diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..bb12a5a --- /dev/null +++ b/build.gradle @@ -0,0 +1,84 @@ +import java.util.stream.Collectors + +plugins { + id 'java' +} + +group 'roborunner' +version '2.0-SNAPSHOT' + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + +dependencies { + implementation files('libs/robocode.jar') + implementation group: 'com.google.guava', name: 'guava', version: '30.0-jre' +} + +sourceSets { + main { + java { + srcDir 'src' + } + } +} + +def distDir = "$buildDir/dist" + +task cleanDist(type: Delete) { + delete += "$distDir" +} + +task copyDependencies(dependsOn: cleanDist, type: Copy) { + from(configurations.runtimeClasspath) { + include '*guava*' + } + into "$distDir/lib" +} + +task runnerJar(type: Jar, dependsOn: [compileJava]) { + from(compileJava.outputs) + + archiveName jar.archiveName +} + +task copyLibs(dependsOn: [runnerJar, copyDependencies], type: Copy) { + from(runnerJar.outputs) + into "$distDir/lib" +} + +task generateScripts(dependsOn: [copyLibs]) { + String genOutputDir = file("$buildDir/generated-scripts") + + File outputFile = file("$genOutputDir/rr.sh") + outputs.file(outputFile) + + doLast { + def libs = copyLibs.outputs.getFiles().singleFile + def path = fileTree(dir: libs).files.stream().map({ x -> 'lib' + x.toString().substring(libs.toString().length()) }).collect(Collectors.joining(File.pathSeparator)) + + def robocodeJar = ['robocodes','r1','libs','robocode.jar'].join(File.separator) + + outputFile.text = "#!/bin/sh\n" + + "java -cp '${path}${File.pathSeparator}${robocodeJar}' robowiki.runner.RoboRunner \$*" + } +} + +task makeDist(dependsOn: copyLibs, type: Copy, group: 'deploy') { + from('scripts') { + include '*.sh' + fileMode = 0755 + } + from('scripts') { + exclude '*.sh' + } + from(generateScripts.getOutputs()) { + fileMode = 0755 + } + into "$distDir" +} + +classes.dependsOn(makeDist) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..aa991fc --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/scripts/sample_1v1.rrc b/scripts/competitions/sample_1v1.rrc similarity index 100% rename from scripts/sample_1v1.rrc rename to scripts/competitions/sample_1v1.rrc diff --git a/scripts/sample_melee.rrc b/scripts/competitions/sample_melee.rrc similarity index 100% rename from scripts/sample_melee.rrc rename to scripts/competitions/sample_melee.rrc diff --git a/scripts/sample_teams.rrc b/scripts/competitions/sample_teams.rrc similarity index 100% rename from scripts/sample_teams.rrc rename to scripts/competitions/sample_teams.rrc diff --git a/scripts/rmall.sh b/scripts/rmall.sh index 34ab746..06a280a 100755 --- a/scripts/rmall.sh +++ b/scripts/rmall.sh @@ -1,7 +1,9 @@ +#!/usr/bin/env bash echo "Clearing Robocode JARs, robot caches and databases... " cd robocodes rm -rf r*/robots/.data rm r*/robots/robot.database -rm r*/robots/*.jar +#rm r*/robots/*.jar +find r*/robots -name '*.jar' -delete echo " Done!" diff --git a/scripts/rmdata.sh b/scripts/rmdata.sh index 0ac7a3a..2b8845d 100755 --- a/scripts/rmdata.sh +++ b/scripts/rmdata.sh @@ -1,2 +1,3 @@ +#!/usr/bin/env bash rm -rf robocodes/r*/robots/.data diff --git a/scripts/rr.sh b/scripts/rr.sh deleted file mode 100755 index 35d0e79..0000000 --- a/scripts/rr.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -java -cp lib/roborunner-1.2.3.jar:lib/guava-12.0.1.jar:robocodes/r1/libs/robocode.jar robowiki.runner.RoboRunner $* diff --git a/scripts/setup.sh b/scripts/setup.sh index 7341af5..77cee45 100755 --- a/scripts/setup.sh +++ b/scripts/setup.sh @@ -47,7 +47,6 @@ else echo " Done!" fi echo "robocodePaths=$paths" > roborunner.properties - echo "jvmArgs=-Xmx512M" >> roborunner.properties + echo "jvmArgs=-Xmx1024M -Dapple.awt.UIElement=true" >> roborunner.properties echo "botsDirs=./bots" >> roborunner.properties fi - diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..5cb4655 --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'roborunner' From 985cb26866da86c18641be0a61a5f87824267926 Mon Sep 17 00:00:00 2001 From: bumfo Date: Sun, 21 Jul 2019 18:45:03 +0800 Subject: [PATCH 02/11] Fix some NPE --- src/robowiki/runner/RoboRunner.java | 14 +++++++++----- src/robowiki/runner/ScoreLog.java | 9 ++++++--- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/src/robowiki/runner/RoboRunner.java b/src/robowiki/runner/RoboRunner.java index 497038d..c54b3df 100644 --- a/src/robowiki/runner/RoboRunner.java +++ b/src/robowiki/runner/RoboRunner.java @@ -424,7 +424,9 @@ private ScoreError getScoreError(ScoreLog scoreLog, List scores = Lists.newArrayList(); for (BattleScore battleScore : battleScores) { RobotScore totalScore = battleScore.getRelativeTotalScore(challenger); - scores.add(scoringStyle.getScore(totalScore)); + if (totalScore != null) { + scores.add(scoringStyle.getScore(totalScore)); + } } return new ScoreError(scores, scoreLog.getAverageBattleScore(botList).getElapsedTime()); @@ -739,10 +741,12 @@ public void processResults( errorMap.put(botList, getScoreError(scoreLog, scoringStyle, challenger, botList)); - printBattleScore(challenger, botList, lastScore, avgScore, - scoringStyle, elapsedTime, errorMap); - if (robotScores.size() > 2) { - printMeleeScores(lastScore, avgScore, challenger, scoringStyle); + if (lastScore != null) { + printBattleScore(challenger, botList, lastScore, avgScore, + scoringStyle, elapsedTime, errorMap); + if (robotScores.size() > 2 && avgScore != null) { + printMeleeScores(lastScore, avgScore, challenger, scoringStyle); + } } printOverallScores( scoreLog, errorMap, challenger, challenge, printWikiFormat, false); diff --git a/src/robowiki/runner/ScoreLog.java b/src/robowiki/runner/ScoreLog.java index e06391c..636c1bb 100644 --- a/src/robowiki/runner/ScoreLog.java +++ b/src/robowiki/runner/ScoreLog.java @@ -425,9 +425,12 @@ public RobotScore getRobotScore(String botName) { public RobotScore getRelativeTotalScore(String botName) { RobotScore referenceScore = getRobotScore(botName); - List enemyScores = Lists.newArrayList(_robotScores); - enemyScores.remove(referenceScore); - return referenceScore.getScoreRelativeTo(enemyScores, _numRounds); + if (referenceScore != null) { + List enemyScores = Lists.newArrayList(_robotScores); + enemyScores.remove(referenceScore); + return referenceScore.getScoreRelativeTo(enemyScores, _numRounds); + } + return null; } } } From 7fab942ba228ef5799bb96217b0e4e945566be26 Mon Sep 17 00:00:00 2001 From: bumfo Date: Sun, 21 Jul 2019 18:53:42 +0800 Subject: [PATCH 03/11] Skip self battles (todo return 50% directly) --- src/robowiki/runner/RoboRunner.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/robowiki/runner/RoboRunner.java b/src/robowiki/runner/RoboRunner.java index c54b3df..bd07bb7 100644 --- a/src/robowiki/runner/RoboRunner.java +++ b/src/robowiki/runner/RoboRunner.java @@ -379,6 +379,11 @@ private List getBattleList(ScoreLog scoreLog, for (BotList botList : challenge.allReferenceBots) { List battleBots = Lists.newArrayList(challenger); List botNames = botList.getBotNames(); + + if (botNames.contains(challenger)) { + continue; + } + if (!skip(skipMap, scoreLog.getSortedBotList(botNames))) { battleBots.addAll(botNames); battleList.add(new BotList(battleBots)); From d7d2444d9f13dbbafd7cf97410fa7f8bd33302f4 Mon Sep 17 00:00:00 2001 From: bumfo Date: Sun, 21 Jul 2019 19:13:31 +0800 Subject: [PATCH 04/11] Fix some logic about NaN result --- src/robowiki/runner/RoboRunner.java | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/robowiki/runner/RoboRunner.java b/src/robowiki/runner/RoboRunner.java index bd07bb7..f13c70d 100644 --- a/src/robowiki/runner/RoboRunner.java +++ b/src/robowiki/runner/RoboRunner.java @@ -626,9 +626,14 @@ private ScoreSummary getScoreSummary(ScoreLog scoreLog, RobotScore totalRobotScore = scoreLog .getAverageBattleScore(botListString) .getRelativeTotalScore(scoreLog.challenger); - sumScores += scoringStyle.getScore(totalRobotScore); - scoredBotLists++; - numBattles += totalRobotScore.numBattles; + double score = scoringStyle.getScore(totalRobotScore); + if (!Double.isNaN(score)) { + sumScores += score; + scoredBotLists++; + numBattles += totalRobotScore.numBattles; + } else { + System.err.println("NaN: " + scoreLog.challenger + " " + botListString); + } } } return new ScoreSummary(sumScores, numBattles, scoredBotLists); @@ -657,11 +662,12 @@ private void printAllScores(ScoreLog scoreLog, ChallengeConfig challenge, .getAverageBattleScore(botListString) .getRelativeTotalScore(scoreLog.challenger); ScoreError scoreError = errorMap.get(botListString); + double score = challenge.scoringStyle.getScore(totalRobotScore); System.out.println(" " + botListString + ": " - + round(challenge.scoringStyle.getScore(totalRobotScore), 2) - + (scoreError.numBattles > 1 - ? " +- " + round(1.96 * scoreError.getStandardError(), 2) : "") - + " (" + scoreError.numBattles + " battles)"); + + (Double.isNaN(score) ? Double.NaN : round(score, 2)) + + (scoreError.numBattles > 1 + ? " +- " + round(1.96 * scoreError.getStandardError(), 2) : "") + + " (" + scoreError.numBattles + " battles)"); } } } @@ -850,7 +856,7 @@ public ScoreSummary( } public double getTotalScore() { - return round(sumScores / scoredBotLists, 2); + return Double.isNaN(sumScores) ? Double.NaN : round(sumScores / scoredBotLists, 2); } } } From 8a275499090edd79aba3251eb42b9ddf5dc0b03a Mon Sep 17 00:00:00 2001 From: bumfo Date: Sun, 22 Jan 2023 14:23:12 +0800 Subject: [PATCH 05/11] Fix: treat 0/0 as 50% --- src/robowiki/runner/RobotScore.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/robowiki/runner/RobotScore.java b/src/robowiki/runner/RobotScore.java index 748381d..32457f9 100644 --- a/src/robowiki/runner/RobotScore.java +++ b/src/robowiki/runner/RobotScore.java @@ -116,8 +116,12 @@ private double getAverageScore( double challengerScore = scorer.apply(this); int numScores = 0; for (RobotScore robotScore : enemyScores) { - totalScore += 100 * (challengerScore - / (challengerScore + scorer.apply(robotScore))); + double sum = challengerScore + scorer.apply(robotScore); + if (sum == 0.) { + totalScore += 50; + } else { + totalScore += 100 * (challengerScore / sum); + } numScores++; } return totalScore / numScores; From 3aff1fe249ad0ee0246be7ede0e76317ce4c49eb Mon Sep 17 00:00:00 2001 From: bumfo Date: Fri, 26 Jun 2020 17:37:41 +0800 Subject: [PATCH 06/11] Fix freeze when init fails --- src/robowiki/runner/BattleRunner.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/robowiki/runner/BattleRunner.java b/src/robowiki/runner/BattleRunner.java index 9f2e5b4..257de8f 100644 --- a/src/robowiki/runner/BattleRunner.java +++ b/src/robowiki/runner/BattleRunner.java @@ -63,7 +63,10 @@ private void initEngine(String enginePath, String jvmArgs) { String processOutput; do { processOutput = reader.readLine(); - } while (!processOutput.equals(BattleProcess.READY_SIGNAL)); + } while (processOutput != null && !processOutput.equals(BattleProcess.READY_SIGNAL)); + if (processOutput == null) { + throw new IOException("processOutput == null"); + } System.out.println("done!"); _processQueue.add(battleProcess); } catch (IOException e) { From 563608e3292a9c2a997792dfa7bcfeef64c78025 Mon Sep 17 00:00:00 2001 From: bumfo Date: Mon, 12 Sep 2022 19:08:23 +0800 Subject: [PATCH 07/11] Fix robocode JvmArgs --- scripts/setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/setup.sh b/scripts/setup.sh index 77cee45..403ed32 100755 --- a/scripts/setup.sh +++ b/scripts/setup.sh @@ -47,6 +47,6 @@ else echo " Done!" fi echo "robocodePaths=$paths" > roborunner.properties - echo "jvmArgs=-Xmx1024M -Dapple.awt.UIElement=true" >> roborunner.properties + echo "jvmArgs=-Xmx1024M -Dapple.awt.UIElement\=true -Djava.security.manager=allow -XX:+IgnoreUnrecognizedVMOptions --add-opens\=java.base/sun.net.www.protocol.jar\=ALL-UNNAMED --add-opens\=java.base/java.lang.reflect\=ALL-UNNAMED --add-opens\=java.desktop/javax.swing.text\=ALL-UNNAMED --add-opens\=java.desktop/sun.awt\=ALL-UNNAMED --add-opens\=java.desktop/java.awt\=ALL-UNNAMED --add-opens\=java.base/java.lang\=ALL-UNNAMED --add-opens\=java.desktop/sun.java2d.opengl\=ALL-UNNAMED" >> roborunner.properties echo "botsDirs=./bots" >> roborunner.properties fi From ff4ee80eec06d2592917818778be4d1b27a6c0fb Mon Sep 17 00:00:00 2001 From: bumfo Date: Sun, 22 Jan 2023 14:44:42 +0800 Subject: [PATCH 08/11] Fix copy of guava lib --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index bb12a5a..9eb504c 100644 --- a/build.gradle +++ b/build.gradle @@ -34,7 +34,7 @@ task cleanDist(type: Delete) { task copyDependencies(dependsOn: cleanDist, type: Copy) { from(configurations.runtimeClasspath) { - include '*guava*' + include 'guava*' } into "$distDir/lib" } From 1f9620b6cf9d97e5b57e8dcc5c98b5a9e699f6c4 Mon Sep 17 00:00:00 2001 From: bumfo Date: Sun, 22 Jan 2023 15:09:10 +0800 Subject: [PATCH 09/11] Fix JavaDoc --- src/robowiki/runner/RobotScore.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/robowiki/runner/RobotScore.java b/src/robowiki/runner/RobotScore.java index 32457f9..c0a65d9 100644 --- a/src/robowiki/runner/RobotScore.java +++ b/src/robowiki/runner/RobotScore.java @@ -95,7 +95,7 @@ public RobotScore getScoreRelativeTo( /** * Calculates this score relative to the given enemy scores. * - * @param enemyScore score data for the other robots in the battle + * @param enemyScores score data for the other robots in the battle * @param numRounds number of rounds in the battle * @return the {@code RobotScore} relative to the given enemy robot scores */ From 09abc66eaa59f42fd828effa9eee54762bfc25f4 Mon Sep 17 00:00:00 2001 From: bumfo Date: Thu, 22 Dec 2022 19:49:11 +0800 Subject: [PATCH 10/11] Fix XML corrupt: use getElementText to prevent truncated values at the end of internal buffers --- src/robowiki/runner/ScoreLog.java | 57 ++++++++++++++++++------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/src/robowiki/runner/ScoreLog.java b/src/robowiki/runner/ScoreLog.java index 636c1bb..c6151d2 100644 --- a/src/robowiki/runner/ScoreLog.java +++ b/src/robowiki/runner/ScoreLog.java @@ -191,18 +191,24 @@ public static ScoreLog loadScoreLog(String inputFilePath) XMLEvent event = eventReader.nextEvent(); if (event.isStartElement()) { String localPart = event.asStartElement().getName().getLocalPart(); - if (localPart.equals(SCORES)) { - scoreLog = new ScoreLog(getAttribute(event, CHALLENGER)); - } else if (localPart.equals(BATTLE)) { - robotScores = Lists.newArrayList(); - } else if (localPart.equals(ROBOT_SCORE)) { - robotScores.add(readRobotScore(eventReader)); - } else if (localPart.equals(NUM_ROUNDS)) { - event = eventReader.nextEvent(); - numRounds = Integer.parseInt(event.asCharacters().getData()); - } else if (localPart.equals(TIME)) { - event = eventReader.nextEvent(); - time = Long.parseLong(event.asCharacters().getData()); + switch (localPart) { + case SCORES: + scoreLog = new ScoreLog(getAttribute(event, CHALLENGER)); + break; + case BOT_LIST: + break; + case BATTLE: + robotScores = Lists.newArrayList(); + break; + case ROBOT_SCORE: + robotScores.add(readRobotScore(eventReader)); + break; + case NUM_ROUNDS: + numRounds = Integer.parseInt(eventReader.getElementText()); + break; + case TIME: + time = Long.parseLong(eventReader.getElementText()); + break; } } else if (event.isEndElement()) { String localPart = event.asEndElement().getName().getLocalPart(); @@ -242,17 +248,22 @@ private static RobotScore readRobotScore(XMLEventReader eventReader) } else { if (event.isStartElement()) { String localPart = event.asStartElement().getName().getLocalPart(); - event = eventReader.nextEvent(); - if (localPart.equals(NAME)) { - name = event.asCharacters().getData(); - } else if (localPart.equals(SCORE)) { - score = Double.parseDouble(event.asCharacters().getData()); - } else if (localPart.equals(SURVIVAL_ROUNDS)) { - rounds = Double.parseDouble(event.asCharacters().getData()); - } else if (localPart.equals(SURVIVAL_SCORE)) { - survival = Double.parseDouble(event.asCharacters().getData()); - } else if (localPart.equals(DAMAGE)) { - damage = Double.parseDouble(event.asCharacters().getData()); + switch (localPart) { + case NAME: + name = eventReader.getElementText(); + break; + case SCORE: + score = Double.parseDouble(eventReader.getElementText()); + break; + case SURVIVAL_ROUNDS: + rounds = Double.parseDouble(eventReader.getElementText()); + break; + case SURVIVAL_SCORE: + survival = Double.parseDouble(eventReader.getElementText()); + break; + case DAMAGE: + damage = Double.parseDouble(eventReader.getElementText()); + break; } } } From d944b2fe84ea906b8ffb652c912b147a9ccbdfe9 Mon Sep 17 00:00:00 2001 From: bumfo Date: Sun, 22 Jan 2023 15:08:51 +0800 Subject: [PATCH 11/11] Fix APS: compute avg of percent score, instead of percent of sum score --- src/robowiki/runner/RobotScore.java | 20 +++++++++++++++ src/robowiki/runner/ScoreLog.java | 39 +++++++++++++++++++++++++---- 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/src/robowiki/runner/RobotScore.java b/src/robowiki/runner/RobotScore.java index c0a65d9..9539396 100644 --- a/src/robowiki/runner/RobotScore.java +++ b/src/robowiki/runner/RobotScore.java @@ -110,6 +110,26 @@ public RobotScore getScoreRelativeTo( numBattles); } + RobotScore getAverageScoreRelativeTo1(List enemyScores) { + return new RobotScore(botName, + getAverageScore(NORMAL_SCORER, enemyScores), + survivalRounds, + survivalScore, + bulletDamage, + energyConserved, + numBattles); + } + + RobotScore getAverageScoreRelativeTo2(List enemyScores, int numRounds) { + return new RobotScore(botName, + score, + getAverageScore(SURVIVAL_FIRSTS_SCORER, enemyScores), + getAverageScore(SURVIVAL_SCORER, enemyScores), + bulletDamage / numRounds, + getAverageEnergyConserved(enemyScores, numRounds), + numBattles); + } + private double getAverageScore( Function scorer, Collection enemyScores) { double totalScore = 0; diff --git a/src/robowiki/runner/ScoreLog.java b/src/robowiki/runner/ScoreLog.java index c6151d2..e5194ce 100644 --- a/src/robowiki/runner/ScoreLog.java +++ b/src/robowiki/runner/ScoreLog.java @@ -138,6 +138,8 @@ public BattleScore getAverageBattleScore(String botList) { boolean initializeTotalScores = true; for (BattleScore battleScore : battleScores) { for (RobotScore robotScore : battleScore.getRobotScores()) { + robotScore = battleScore.getAverageRelativeTotalScore(robotScore.botName); + if (initializeTotalScores) { totalScores.put(robotScore.botName, robotScore); } else { @@ -152,8 +154,8 @@ public BattleScore getAverageBattleScore(String botList) { totalRounds += battleScore.getNumRounds(); totalTime += battleScore.getElapsedTime(); } - return new BattleScore(totalScores.values(), - totalRounds / battleScores.size(), totalTime / battleScores.size()); + return new AverageBattleScore(totalScores.values(), + totalRounds / battleScores.size(), totalTime / battleScores.size()); } public int getBattleCount(List allReferenceBots) { @@ -402,9 +404,9 @@ private void writeValue(XMLEventWriter eventWriter, String name, String value, * @author Voidious */ public static class BattleScore { - private final List _robotScores; - private final int _numRounds; - private final long _elapsedTime; + final List _robotScores; + final int _numRounds; + final long _elapsedTime; public BattleScore( Collection scores, int numRounds, long nanoTime) { @@ -443,5 +445,32 @@ public RobotScore getRelativeTotalScore(String botName) { } return null; } + + RobotScore getAverageRelativeTotalScore(String botName) { + RobotScore referenceScore = getRobotScore(botName); + if (referenceScore != null) { + List enemyScores = Lists.newArrayList(_robotScores); + enemyScores.remove(referenceScore); + return referenceScore.getAverageScoreRelativeTo1(enemyScores); + } + return null; + } + } + + public static final class AverageBattleScore extends BattleScore { + public AverageBattleScore(Collection scores, int numRounds, long nanoTime) { + super(scores, numRounds, nanoTime); + } + + @Override + public RobotScore getRelativeTotalScore(String botName) { + RobotScore referenceScore = getRobotScore(botName); + if (referenceScore != null) { + List enemyScores = Lists.newArrayList(_robotScores); + enemyScores.remove(referenceScore); + return referenceScore.getAverageScoreRelativeTo2(enemyScores, _numRounds); + } + return null; + } } }