diff --git a/src/main/java/org/usfirst/frc/team25/scouting/client/ui/MainController.java b/src/main/java/org/usfirst/frc/team25/scouting/client/ui/MainController.java index 452646c..6dc909b 100644 --- a/src/main/java/org/usfirst/frc/team25/scouting/client/ui/MainController.java +++ b/src/main/java/org/usfirst/frc/team25/scouting/client/ui/MainController.java @@ -291,8 +291,11 @@ private void processData() { } if (generatePredictions.isSelected()) { - eventReport.generateMatchPredictions(currentDataDirectory); - status += "\nFuture match predictions generated"; + if (eventReport.generateMatchPredictions(currentDataDirectory)) { + status += "\nFuture match predictions generated"; + } else { + status += "\nMatch prediction generation failed"; + } } diff --git a/src/main/java/org/usfirst/frc/team25/scouting/data/AllianceReport.java b/src/main/java/org/usfirst/frc/team25/scouting/data/AllianceReport.java index 36638e9..f8748b2 100644 --- a/src/main/java/org/usfirst/frc/team25/scouting/data/AllianceReport.java +++ b/src/main/java/org/usfirst/frc/team25/scouting/data/AllianceReport.java @@ -1,8 +1,7 @@ package org.usfirst.frc.team25.scouting.data; -import org.apache.commons.math3.exception.NotStrictlyPositiveException; - import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; /** @@ -24,7 +23,7 @@ public class AllianceReport { * The number of Monte Carlo simulation iterations to run to compute standard deviations of functions. * A larger number of iterations generally provides greater accuracy. */ - private final int MONTE_CARLO_ITERATIONS = 5000; + private final int MONTE_CARLO_ITERATIONS = 1000; private final String[] numStrNames = new String[]{"One", "Two", "Three", "total"}; /** * Denotes the best HAB levels to start from at the beginning of the match in order to maximize points earned. @@ -432,7 +431,6 @@ private double calculateStdDevTeleOpPoints(ArrayList>> generateMonteCarloSet() { } public double calculateClimbRpChance() { - double climbRpChance; - try { - climbRpChance = Stats.rightTailNormalProbability(15, predictedValues.get("endgamePoints"), - standardDeviations.get("endgamePoints")); - } catch (NotStrictlyPositiveException e) { - climbRpChance = predictedValues.get("endgamePoints") >= 15 ? 1.0 : 0.0; + double climbRpChance = 0.0; + + final int[] climbPointValues = new int[]{3, 6, 12}; + + for (int teamOneClimb = 0; teamOneClimb < 2; teamOneClimb++) { + for (int teamTwoClimb = 0; teamTwoClimb < 2; teamTwoClimb++) { + for (int teamThreeClimb = 0; teamThreeClimb < 2; teamThreeClimb++) { + int points = 0; + int[] climbStatus = new int[]{teamOneClimb, teamTwoClimb, teamThreeClimb}; + for (int i = 0; i < 3; i++) { + points += climbStatus[i] * climbPointValues[bestClimbLevels[i] - 1]; + } + if (points >= 15) { + double probabilityIteration = 1.0; + for (int i = 0; i < 3; i++) { + if (climbStatus[i] == 1) { + probabilityIteration *= teamReports[i].getAttemptSuccessRate("level" + numStrNames[bestClimbLevels[i] - 1] + "Climb"); + } else { + probabilityIteration *= 1 - teamReports[i].getAttemptSuccessRate("level" + numStrNames[bestClimbLevels[i] - 1] + "Climb"); + } + } + climbRpChance += probabilityIteration; + } + } + } } + predictedValues.put("climbRp", climbRpChance); return climbRpChance; @@ -499,6 +517,9 @@ public double calculateClimbRpChance() { */ public String getQuickAllianceReport() { + Object[] keys = predictedValues.keySet().toArray(); + Arrays.sort(keys); + String quickReport = ""; for (TeamReport report : teamReports) { quickReport += "Team " + report.getTeamNum(); @@ -509,7 +530,7 @@ public String getQuickAllianceReport() { quickReport += "\n"; } - for (String key : predictedValues.keySet()) { + for (Object key : keys) { quickReport += key + ": " + Stats.round(predictedValues.get(key), 2) + "\n"; } diff --git a/src/main/java/org/usfirst/frc/team25/scouting/data/EventReport.java b/src/main/java/org/usfirst/frc/team25/scouting/data/EventReport.java index 92a1fe4..9fccb36 100644 --- a/src/main/java/org/usfirst/frc/team25/scouting/data/EventReport.java +++ b/src/main/java/org/usfirst/frc/team25/scouting/data/EventReport.java @@ -13,7 +13,6 @@ import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Optional; /** @@ -523,7 +522,7 @@ public void generatePicklists(File outputDirectory) { pg.generatePickPointList(); } - public void generateMatchPredictions(File outputDirectory) { + public boolean generateMatchPredictions(File outputDirectory) { int greatestMatchNum = 0; for (ScoutEntry entry : scoutEntries) { @@ -531,57 +530,45 @@ public void generateMatchPredictions(File outputDirectory) { greatestMatchNum = entry.getPreMatch().getMatchNum(); } } - File matchList = FileManager.getMatchList(outputDirectory); - String[] blocksOfStringMatchesArray; - List futureMatchesBlockList = new ArrayList<>(); + try { - String matchesString = FileManager.getFileString(matchList); - blocksOfStringMatchesArray = matchesString.split("\n"); - for (String element : blocksOfStringMatchesArray) { - String[] tempArray = element.split(","); - for (String tempElement : tempArray) { - if (tempElement.equals("25") && Integer.parseInt(tempArray[0]) > greatestMatchNum) { - futureMatchesBlockList.add(element); + String predictions = ""; + + File matchList = FileManager.getMatchList(directory); + + String[] matches = FileManager.getFileString(matchList).split("\n"); + + for (int i = greatestMatchNum + 1; i < matches.length - 1; i++) { + AllianceReport[] allianceReports = getAlliancesInMatch(i); + predictions += "Match " + i + ": "; + for (int j = 0; j < allianceReports.length; j++) { + predictions += allianceReports[j].getTeamReports()[0].getTeamNum() + "-"; + predictions += allianceReports[j].getTeamReports()[1].getTeamNum() + "-"; + predictions += allianceReports[j].getTeamReports()[2].getTeamNum() + " ("; + predictions += Stats.round(allianceReports[j].calculatePredictedRp(allianceReports[Math.abs(j - 1)]), 1) + " RP, "; + predictions += Stats.round(allianceReports[j].getPredictedValue("totalPoints"), 1) + " pts)"; + if (j == 0) { + predictions += " vs. "; } } - } - for (String element : futureMatchesBlockList) { - String[] tempSplitElement = element.split(","); - for (int i = 1; i < 4; i++) { - if (tempSplitElement[i].equals("25")) { - AllianceReport futureMatchPredictions1 = - new AllianceReport(new TeamReport[]{ - teamReports.get(Integer.parseInt(tempSplitElement[1])), - teamReports.get(Integer.parseInt(tempSplitElement[2])), - teamReports.get(Integer.parseInt(tempSplitElement[3]))}); - futureMatchPredictions1.getQuickAllianceReport(); - - AllianceReport futureMatchPredictions2 = - new AllianceReport(new TeamReport[]{ - teamReports.get(Integer.parseInt(tempSplitElement[4])), - teamReports.get(Integer.parseInt(tempSplitElement[5])), - teamReports.get(Integer.parseInt(tempSplitElement[6]))}); - futureMatchPredictions2.getQuickAllianceReport(); - } else { - AllianceReport futureMatchPredictions1 = - new AllianceReport(new TeamReport[]{ - teamReports.get(Integer.parseInt(tempSplitElement[4])), - teamReports.get(Integer.parseInt(tempSplitElement[5])), - teamReports.get(Integer.parseInt(tempSplitElement[6]))}); - futureMatchPredictions1.getQuickAllianceReport(); - - AllianceReport futureMatchPrediction2 = - new AllianceReport(new TeamReport[]{ - teamReports.get(Integer.parseInt(tempSplitElement[1])), - teamReports.get(Integer.parseInt(tempSplitElement[2])), - teamReports.get(Integer.parseInt(tempSplitElement[3]))}); - futureMatchPrediction2.getQuickAllianceReport(); - } + double redWinChance = allianceReports[0].calculateWinChance(allianceReports[1]); + if (redWinChance > 0.5) { + predictions += " - Red win, " + Stats.round(redWinChance * 100, 2) + "%\n"; + } else { + predictions += " - Blue win, " + Stats.round((1 - redWinChance) * 100, 2) + "%\n"; } + + } + + if (!predictions.isEmpty()) { + FileManager.outputFile(outputDirectory.getAbsolutePath() + "/MatchPredictions", "txt", predictions); + return true; } } catch (Exception e) { } + + return false; } public AllianceReport[] getAlliancesInMatch(int matchNum) throws FileNotFoundException { diff --git a/src/main/java/org/usfirst/frc/team25/scouting/data/models/ScoutEntry.java b/src/main/java/org/usfirst/frc/team25/scouting/data/models/ScoutEntry.java index 27ff680..46ac218 100644 --- a/src/main/java/org/usfirst/frc/team25/scouting/data/models/ScoutEntry.java +++ b/src/main/java/org/usfirst/frc/team25/scouting/data/models/ScoutEntry.java @@ -40,14 +40,13 @@ public void calculateDerivedStats() { //Tele-Op - teleOpHatches = teleOpRocketHatches + teleOp.getCargoShipHatches(); - teleOpRocketHatches = teleOp.getRocketLevelOneHatches() + teleOp.getRocketLevelTwoHatches() + teleOp.getRocketLevelThreeHatches(); teleOpRocketCargo = teleOp.getRocketLevelOneCargo() + teleOp.getRocketLevelTwoCargo() + teleOp.getRocketLevelThreeCargo(); + teleOpHatches = teleOpRocketHatches + teleOp.getCargoShipHatches(); teleOpCargo = teleOpRocketCargo + teleOp.getCargoShipCargo(); @@ -69,16 +68,15 @@ public void calculateDerivedStats() { calculatedSandstormPoints += preMatch.getStartingLevel() * 3; } - calculatedTeleOpPoints = teleOpHatches * 2 - + teleOpCargo * 3; + calculatedTeleOpPoints = teleOpHatches * 2 + teleOpCargo * 3; calculatedClimbPoints = 0; if ((teleOp.isSuccessHabClimb()) || teleOp.getNumPartnerClimbAssists() > 0) { calculatedClimbPoints += Math.pow(2, (teleOp.getSuccessHabClimbLevel() - 1)) * 3; - calculatedClimbPoints += 3 * teleOp.getNumPartnerClimbAssists() - * (Math.pow(2, teleOp.getPartnerClimbAssistEndLevel() - 1) - - Math.pow(2, teleOp.getPartnerClimbAssistStartLevel() - 1)); + calculatedClimbPoints += 3 * teleOp.getNumPartnerClimbAssists() * (Math.pow(2, + teleOp.getPartnerClimbAssistEndLevel() - 1) - Math.pow(2, + teleOp.getPartnerClimbAssistStartLevel() - 1)); } calculatedPointContribution = calculatedSandstormPoints + calculatedClimbPoints + calculatedTeleOpPoints;