a failing test case for bug3794, trying to push scores through the race log into the leaderboard's score corrections

Change-Id: I35bc58c25f032e254932b157790557c6f07d3621
This commit is contained in:
Axel Uhl committed 2016-07-20 11:07:25 +02:00
1 parent 912892eeff
commit 352c007a49
4 files changed
+349 -191

No files matched your search

@@ -55,7 +55,6 @@ import com.sap.sailing.domain.common.dto.LeaderboardDTO;
import com.sap.sailing.domain.leaderboard.FlexibleLeaderboard;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.LeaderboardGroup;
import com.sap.sailing.domain.leaderboard.ScoringScheme;
import com.sap.sailing.domain.leaderboard.impl.FlexibleLeaderboardImpl;
import com.sap.sailing.domain.leaderboard.impl.HighPoint;
import com.sap.sailing.domain.leaderboard.impl.HighPointExtremeSailingSeriesOverall;
@@ -70,7 +69,6 @@ import com.sap.sailing.domain.racelog.impl.EmptyRaceLogStore;
import com.sap.sailing.domain.ranking.OneDesignRankingMetric;
import com.sap.sailing.domain.regattalog.impl.EmptyRegattaLogStore;
import com.sap.sailing.domain.test.mock.MockedTrackedRaceWithStartTimeAndRanks;
import com.sap.sailing.domain.test.mock.MockedTrackedRaceWithStartTimeAndZeroRanks;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.TrackedRegattaRegistry;
@@ -82,10 +80,10 @@ import com.sap.sse.common.Util;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.util.impl.ArrayListNavigableSet;
public class LeaderboardScoringAndRankingTest extends AbstractLeaderboardTest {
private ArrayList<Series> series;
public class LeaderboardScoringAndRankingTest extends LeaderboardScoringAndRankingTestBase {
protected ArrayList<Series> series;
private Leaderboard createLeaderboard(Regatta regatta, int[] discardingThresholds) {
protected Leaderboard createLeaderboard(Regatta regatta, int[] discardingThresholds) {
ThresholdBasedResultDiscardingRuleImpl discardingRules = new ThresholdBasedResultDiscardingRuleImpl(discardingThresholds);
return new RegattaLeaderboardImpl(regatta, discardingRules);
}
@@ -1250,19 +1248,6 @@ public class LeaderboardScoringAndRankingTest extends AbstractLeaderboardTest {
checkScoresAfterSomeRaces(leaderboard, raceColumnsToConsider, scoresAfter6Races, later, c);
}
private void checkScoresAfterSomeRaces(Leaderboard leaderboard, List<RaceColumn> raceColumnsToConsider,
double[][] scoresAfterNRaces, TimePoint timePoint, Competitor[] competitors) throws NoWindException {
for (int competitorIndex=0; competitorIndex<scoresAfterNRaces.length; competitorIndex++) {
final Set<RaceColumn> discardedRaceColumns = leaderboard.getResultDiscardingRule()
.getDiscardedRaceColumns(competitors[competitorIndex], leaderboard, raceColumnsToConsider, timePoint);
for (int raceColumnIndex=0; raceColumnIndex<raceColumnsToConsider.size(); raceColumnIndex++) {
assertEquals(scoresAfterNRaces[competitorIndex][raceColumnIndex],
leaderboard.getNetPoints(competitors[competitorIndex], raceColumnsToConsider.get(raceColumnIndex),
timePoint, discardedRaceColumns), 0.00000001);
}
}
}
@Test
public void testTieBreakByMedalRaceScoreOnlyIfEqualNetScore() throws NoWindException {
Competitor[] c = createCompetitors(2).toArray(new Competitor[0]);
@@ -1863,177 +1848,6 @@ public class LeaderboardScoringAndRankingTest extends AbstractLeaderboardTest {
assertEquals(0., leaderboard1.getNetPoints(c[3], beforeStartOfR1), 0.00000001); // not even the R1 scores apply before the start time of R1
}
private TimePoint createAndAttachTrackedRaces(Series theSeries, String fleetName, boolean withScores, Competitor[]... competitorLists) {
TimePoint now = MillisecondsTimePoint.now();
TimePoint later = new MillisecondsTimePoint(now.asMillis()+1000);
Iterator<? extends RaceColumn> columnIter = theSeries.getRaceColumns().iterator();
for (Competitor[] competitorList : competitorLists) {
RaceColumn raceColumn = columnIter.next();
final TrackedRace trackedRace;
if (withScores) {
trackedRace = new MockedTrackedRaceWithStartTimeAndRanks(now, Arrays.asList(competitorList));
} else {
trackedRace = new MockedTrackedRaceWithStartTimeAndZeroRanks(now, Arrays.asList(competitorList));
}
raceColumn.setTrackedRace(raceColumn.getFleetByName(fleetName), trackedRace);
}
return later;
}
private void createAndAttachTrackedRacesWithStartTimeAndLastMarkPassingTimes(
Series theSeries, String fleetName, Competitor[][] competitorLists, TimePoint[] startTimes,
Map<Competitor, TimePoint>[] lastMarkPassingTimesForCompetitors) {
Iterator<? extends RaceColumn> columnIter = theSeries.getRaceColumns().iterator();
int i=0;
for (Competitor[] competitorList : competitorLists) {
RaceColumn raceColumn = columnIter.next();
final Map<Competitor, TimePoint> lastMarkPassingTimes = lastMarkPassingTimesForCompetitors[i];
final Waypoint start = new WaypointImpl(new ControlPointWithTwoMarksImpl(new MarkImpl("Left StartBuoy"), new MarkImpl("Right StartBuoy"), "Start"));
final Waypoint finish = new WaypointImpl(new MarkImpl("FinishBuoy"));
TrackedRace trackedRace = new MockedTrackedRaceWithStartTimeAndRanks(startTimes[i], Arrays.asList(competitorList)) {
private static final long serialVersionUID = 1L;
@Override
public NavigableSet<MarkPassing> getMarkPassings(Competitor competitor) {
ArrayListNavigableSet<MarkPassing> result = new ArrayListNavigableSet<>(new TimedComparator());
result.add(new MarkPassingImpl(lastMarkPassingTimes.get(competitor), finish, competitor));
return result;
}
};
trackedRace.getRace().getCourse().addWaypoint(0, start);
trackedRace.getRace().getCourse().addWaypoint(1, finish);
raceColumn.setTrackedRace(raceColumn.getFleetByName(fleetName), trackedRace);
i++;
}
}
private List<Competitor> createCompetitors(int numberOfCompetitorsToCreate) {
List<Competitor> result = new ArrayList<Competitor>();
for (int i=1; i<=numberOfCompetitorsToCreate; i++) {
result.add(createCompetitor("C"+i));
}
return result;
}
private Regatta createSimpleRegatta(final int numberOfRaces, final String regattaName, BoatClass boatClass, ScoringScheme scoringScheme) {
series = new ArrayList<Series>();
List<Fleet> fleets = new ArrayList<Fleet>();
fleets.add(new FleetImpl("Default"));
List<String> raceColumnNames = new ArrayList<String>();
for (int i = 1; i <= numberOfRaces; i++) {
raceColumnNames.add("R" + i);
}
Series defaultSeries = new SeriesImpl("Default", /* isMedal */false, /* isFleetsCanRunInParallel */true,
fleets, raceColumnNames, /* trackedRegattaRegistry */null);
series.add(defaultSeries);
Regatta regatta = new RegattaImpl(RegattaImpl.getDefaultName(regattaName, boatClass.getName()), boatClass,
/* startDate */null, /* endDate */null, series, /* persistent */false, scoringScheme, "123", null,
OneDesignRankingMetric::new);
return regatta;
}
private Regatta createRegatta(final int numberOfQualifyingRaces, String[] qualifyingFleetNames, final int numberOfFinalRaces,
String[] finalFleetNames, boolean medalRaceAndSeries, final int numberOfMedalRaces, final String regattaBaseName, BoatClass boatClass, ScoringScheme scoringScheme) {
series = new ArrayList<Series>();
// -------- qualifying series ------------
if (qualifyingFleetNames != null && qualifyingFleetNames.length > 0) {
List<Fleet> qualifyingFleets = new ArrayList<Fleet>();
for (String qualifyingFleetName : qualifyingFleetNames) {
qualifyingFleets.add(new FleetImpl(qualifyingFleetName));
}
List<String> qualifyingRaceColumnNames = new ArrayList<String>();
for (int i = 1; i <= numberOfQualifyingRaces; i++) {
qualifyingRaceColumnNames.add("Q" + i);
}
Series qualifyingSeries = new SeriesImpl("Qualifying", /* isMedal */false, /* isFleetsCanRunInParallel */ true, qualifyingFleets,
qualifyingRaceColumnNames, /* trackedRegattaRegistry */null);
series.add(qualifyingSeries);
}
// -------- final series ------------
if (finalFleetNames != null && finalFleetNames.length > 0) {
List<Fleet> finalFleets = new ArrayList<Fleet>();
int fleetOrdering = 1;
for (String finalFleetName : finalFleetNames) {
finalFleets.add(new FleetImpl(finalFleetName, fleetOrdering++));
}
List<String> finalRaceColumnNames = new ArrayList<String>();
for (int i = 1; i <= numberOfFinalRaces; i++) {
finalRaceColumnNames.add("F" + i);
}
Series finalSeries = new SeriesImpl("Final", /* isMedal */false, /* isFleetsCanRunInParallel */ true, finalFleets, finalRaceColumnNames, /* trackedRegattaRegistry */ null);
series.add(finalSeries);
}
if (medalRaceAndSeries) {
// ------------ medal --------------
List<Fleet> medalFleets = new ArrayList<Fleet>();
medalFleets.add(new FleetImpl("Medal"));
List<String> medalRaceColumnNames = new ArrayList<String>();
if(numberOfMedalRaces == 1) {
medalRaceColumnNames.add("M");
} else if(numberOfMedalRaces > 1) {
for (int i = 1; i <= numberOfMedalRaces; i++) {
medalRaceColumnNames.add("M" + i);
}
}
Series medalSeries = new SeriesImpl("Medal", /* isMedal */true, /* isFleetsCanRunInParallel */ true, medalFleets, medalRaceColumnNames, /* trackedRegattaRegistry */ null);
series.add(medalSeries);
}
Regatta regatta = new RegattaImpl(RegattaImpl.getDefaultName(regattaBaseName, boatClass.getName()), boatClass,
/*startDate*/ null, /*endDate*/ null, series, /* persistent */ false, scoringScheme, "123", null, OneDesignRankingMetric::new);
return regatta;
}
private Regatta createRegattaWithEliminations(final int numberOfEliminations, final int[] numbersOfHeatsPerRound,
final String regattaBaseName, BoatClass boatClass, ScoringScheme scoringScheme) {
series = new ArrayList<Series>();
// example for numbersOfHeatsPerRound: [8, 4, 2, 2]
for (int elimination=1; elimination<=numberOfEliminations; elimination++) {
int heatNumber = 1;
// create one elimination consisting of a number of rounds, each consisting of a number of heats
int roundNumber = 1;
for (int numberOfHeatsPerRound : numbersOfHeatsPerRound) {
final boolean isFinalRound = roundNumber == numbersOfHeatsPerRound.length;
// create one round as a series that has one fleet per heat
List<Fleet> fleetsInRound = new ArrayList<Fleet>();
for (int heatInRound=1; heatInRound<=numberOfHeatsPerRound; heatInRound++) {
final int ordering = numbersOfHeatsPerRound.length-roundNumber+1+
// in final round distinguish Final and Losers Final
(isFinalRound ? heatInRound-1 : 1);
fleetsInRound.add(new FleetImpl("Heat "+(heatNumber++), ordering));
}
List<String> raceColumnNameForRound = new ArrayList<String>();
raceColumnNameForRound.add("E"+elimination+"R"+roundNumber);
final String roundName;
if (numbersOfHeatsPerRound.length-roundNumber == 2) {
roundName = "Quarter-Final";
} else if (numbersOfHeatsPerRound.length-roundNumber == 1) {
roundName = "Semi-Final";
} else if (numbersOfHeatsPerRound.length-roundNumber == 0) {
roundName = "Final";
} else {
roundName = "Round "+roundNumber;
}
Series seriesForRound = new SeriesImpl("E"+elimination+" "+roundName, /* isMedal */ false, /* isFleetsCanRunInParallel */ true, fleetsInRound,
raceColumnNameForRound, /* trackedRegattaRegistry */null);
if (isFinalRound) {
// last "Final" round; here, the fleets are contiguously scored
seriesForRound.setSplitFleetContiguousScoring(true);
}
series.add(seriesForRound);
roundNumber++;
}
}
Regatta regatta = new RegattaImpl(RegattaImpl.getDefaultName(regattaBaseName, boatClass.getName()), boatClass,
/*startDate*/ null, /*endDate*/ null, series, /* persistent */ false, scoringScheme,
/* ID */ "123", /* course area */ null, OneDesignRankingMetric::new);
return regatta;
}
/**
* See bug 1260. There must be a possibility to have ordered fleets that are scored such that the winner of the race of the best fleet
* gets the best score in that column; and the winner of the second-best fleet gets the n-th best score in the column with n being the
@@ -0,0 +1,233 @@
package com.sap.sailing.domain.test;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NavigableSet;
import java.util.Set;
import com.sap.sailing.domain.base.BoatClass;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.Fleet;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.Series;
import com.sap.sailing.domain.base.Waypoint;
import com.sap.sailing.domain.base.impl.ControlPointWithTwoMarksImpl;
import com.sap.sailing.domain.base.impl.FleetImpl;
import com.sap.sailing.domain.base.impl.MarkImpl;
import com.sap.sailing.domain.base.impl.RegattaImpl;
import com.sap.sailing.domain.base.impl.SeriesImpl;
import com.sap.sailing.domain.base.impl.WaypointImpl;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.leaderboard.ScoringScheme;
import com.sap.sailing.domain.leaderboard.impl.RegattaLeaderboardImpl;
import com.sap.sailing.domain.leaderboard.impl.ThresholdBasedResultDiscardingRuleImpl;
import com.sap.sailing.domain.ranking.OneDesignRankingMetric;
import com.sap.sailing.domain.test.mock.MockedTrackedRaceWithStartTimeAndRanks;
import com.sap.sailing.domain.test.mock.MockedTrackedRaceWithStartTimeAndZeroRanks;
import com.sap.sailing.domain.tracking.MarkPassing;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.domain.tracking.impl.MarkPassingImpl;
import com.sap.sailing.domain.tracking.impl.TimedComparator;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.util.impl.ArrayListNavigableSet;
public class LeaderboardScoringAndRankingTestBase extends AbstractLeaderboardTest {
protected ArrayList<Series> series;
protected Leaderboard createLeaderboard(Regatta regatta, int[] discardingThresholds) {
ThresholdBasedResultDiscardingRuleImpl discardingRules = new ThresholdBasedResultDiscardingRuleImpl(discardingThresholds);
return new RegattaLeaderboardImpl(regatta, discardingRules);
}
protected void checkScoresAfterSomeRaces(Leaderboard leaderboard, List<RaceColumn> raceColumnsToConsider,
double[][] scoresAfterNRaces, TimePoint timePoint, Competitor[] competitors) throws NoWindException {
for (int competitorIndex=0; competitorIndex<scoresAfterNRaces.length; competitorIndex++) {
final Set<RaceColumn> discardedRaceColumns = leaderboard.getResultDiscardingRule()
.getDiscardedRaceColumns(competitors[competitorIndex], leaderboard, raceColumnsToConsider, timePoint);
for (int raceColumnIndex=0; raceColumnIndex<raceColumnsToConsider.size(); raceColumnIndex++) {
assertEquals(scoresAfterNRaces[competitorIndex][raceColumnIndex],
leaderboard.getNetPoints(competitors[competitorIndex], raceColumnsToConsider.get(raceColumnIndex),
timePoint, discardedRaceColumns), 0.00000001);
}
}
}
protected TimePoint createAndAttachTrackedRaces(Series theSeries, String fleetName, boolean withScores, Competitor[]... competitorLists) {
TimePoint now = MillisecondsTimePoint.now();
TimePoint later = new MillisecondsTimePoint(now.asMillis()+1000);
Iterator<? extends RaceColumn> columnIter = theSeries.getRaceColumns().iterator();
for (Competitor[] competitorList : competitorLists) {
RaceColumn raceColumn = columnIter.next();
final TrackedRace trackedRace;
if (withScores) {
trackedRace = new MockedTrackedRaceWithStartTimeAndRanks(now, Arrays.asList(competitorList));
} else {
trackedRace = new MockedTrackedRaceWithStartTimeAndZeroRanks(now, Arrays.asList(competitorList));
}
raceColumn.setTrackedRace(raceColumn.getFleetByName(fleetName), trackedRace);
}
return later;
}
protected void createAndAttachTrackedRacesWithStartTimeAndLastMarkPassingTimes(
Series theSeries, String fleetName, Competitor[][] competitorLists, TimePoint[] startTimes,
Map<Competitor, TimePoint>[] lastMarkPassingTimesForCompetitors) {
Iterator<? extends RaceColumn> columnIter = theSeries.getRaceColumns().iterator();
int i=0;
for (Competitor[] competitorList : competitorLists) {
RaceColumn raceColumn = columnIter.next();
final Map<Competitor, TimePoint> lastMarkPassingTimes = lastMarkPassingTimesForCompetitors[i];
final Waypoint start = new WaypointImpl(new ControlPointWithTwoMarksImpl(new MarkImpl("Left StartBuoy"), new MarkImpl("Right StartBuoy"), "Start"));
final Waypoint finish = new WaypointImpl(new MarkImpl("FinishBuoy"));
TrackedRace trackedRace = new MockedTrackedRaceWithStartTimeAndRanks(startTimes[i], Arrays.asList(competitorList)) {
private static final long serialVersionUID = 1L;
@Override
public NavigableSet<MarkPassing> getMarkPassings(Competitor competitor) {
ArrayListNavigableSet<MarkPassing> result = new ArrayListNavigableSet<>(new TimedComparator());
result.add(new MarkPassingImpl(lastMarkPassingTimes.get(competitor), finish, competitor));
return result;
}
};
trackedRace.getRace().getCourse().addWaypoint(0, start);
trackedRace.getRace().getCourse().addWaypoint(1, finish);
raceColumn.setTrackedRace(raceColumn.getFleetByName(fleetName), trackedRace);
i++;
}
}
public static List<Competitor> createCompetitors(int numberOfCompetitorsToCreate) {
List<Competitor> result = new ArrayList<Competitor>();
for (int i=1; i<=numberOfCompetitorsToCreate; i++) {
result.add(createCompetitor("C"+i));
}
return result;
}
protected Regatta createSimpleRegatta(final int numberOfRaces, final String regattaName, BoatClass boatClass, ScoringScheme scoringScheme) {
series = new ArrayList<Series>();
List<Fleet> fleets = new ArrayList<Fleet>();
fleets.add(new FleetImpl("Default"));
List<String> raceColumnNames = new ArrayList<String>();
for (int i = 1; i <= numberOfRaces; i++) {
raceColumnNames.add("R" + i);
}
Series defaultSeries = new SeriesImpl("Default", /* isMedal */false, /* isFleetsCanRunInParallel */true,
fleets, raceColumnNames, /* trackedRegattaRegistry */null);
series.add(defaultSeries);
Regatta regatta = new RegattaImpl(RegattaImpl.getDefaultName(regattaName, boatClass.getName()), boatClass,
/* startDate */null, /* endDate */null, series, /* persistent */false, scoringScheme, "123", null,
OneDesignRankingMetric::new);
return regatta;
}
protected Regatta createRegatta(final int numberOfQualifyingRaces, String[] qualifyingFleetNames, final int numberOfFinalRaces,
String[] finalFleetNames, boolean medalRaceAndSeries, final int numberOfMedalRaces, final String regattaBaseName, BoatClass boatClass, ScoringScheme scoringScheme) {
series = new ArrayList<Series>();
// -------- qualifying series ------------
if (qualifyingFleetNames != null && qualifyingFleetNames.length > 0) {
List<Fleet> qualifyingFleets = new ArrayList<Fleet>();
for (String qualifyingFleetName : qualifyingFleetNames) {
qualifyingFleets.add(new FleetImpl(qualifyingFleetName));
}
List<String> qualifyingRaceColumnNames = new ArrayList<String>();
for (int i = 1; i <= numberOfQualifyingRaces; i++) {
qualifyingRaceColumnNames.add("Q" + i);
}
Series qualifyingSeries = new SeriesImpl("Qualifying", /* isMedal */false, /* isFleetsCanRunInParallel */ true, qualifyingFleets,
qualifyingRaceColumnNames, /* trackedRegattaRegistry */null);
series.add(qualifyingSeries);
}
// -------- final series ------------
if (finalFleetNames != null && finalFleetNames.length > 0) {
List<Fleet> finalFleets = new ArrayList<Fleet>();
int fleetOrdering = 1;
for (String finalFleetName : finalFleetNames) {
finalFleets.add(new FleetImpl(finalFleetName, fleetOrdering++));
}
List<String> finalRaceColumnNames = new ArrayList<String>();
for (int i = 1; i <= numberOfFinalRaces; i++) {
finalRaceColumnNames.add("F" + i);
}
Series finalSeries = new SeriesImpl("Final", /* isMedal */false, /* isFleetsCanRunInParallel */ true, finalFleets, finalRaceColumnNames, /* trackedRegattaRegistry */ null);
series.add(finalSeries);
}
if (medalRaceAndSeries) {
// ------------ medal --------------
List<Fleet> medalFleets = new ArrayList<Fleet>();
medalFleets.add(new FleetImpl("Medal"));
List<String> medalRaceColumnNames = new ArrayList<String>();
if(numberOfMedalRaces == 1) {
medalRaceColumnNames.add("M");
} else if(numberOfMedalRaces > 1) {
for (int i = 1; i <= numberOfMedalRaces; i++) {
medalRaceColumnNames.add("M" + i);
}
}
Series medalSeries = new SeriesImpl("Medal", /* isMedal */true, /* isFleetsCanRunInParallel */ true, medalFleets, medalRaceColumnNames, /* trackedRegattaRegistry */ null);
series.add(medalSeries);
}
Regatta regatta = new RegattaImpl(RegattaImpl.getDefaultName(regattaBaseName, boatClass.getName()), boatClass,
/*startDate*/ null, /*endDate*/ null, series, /* persistent */ false, scoringScheme, "123", null, OneDesignRankingMetric::new);
return regatta;
}
protected Regatta createRegattaWithEliminations(final int numberOfEliminations, final int[] numbersOfHeatsPerRound,
final String regattaBaseName, BoatClass boatClass, ScoringScheme scoringScheme) {
series = new ArrayList<Series>();
// example for numbersOfHeatsPerRound: [8, 4, 2, 2]
for (int elimination=1; elimination<=numberOfEliminations; elimination++) {
int heatNumber = 1;
// create one elimination consisting of a number of rounds, each consisting of a number of heats
int roundNumber = 1;
for (int numberOfHeatsPerRound : numbersOfHeatsPerRound) {
final boolean isFinalRound = roundNumber == numbersOfHeatsPerRound.length;
// create one round as a series that has one fleet per heat
List<Fleet> fleetsInRound = new ArrayList<Fleet>();
for (int heatInRound=1; heatInRound<=numberOfHeatsPerRound; heatInRound++) {
final int ordering = numbersOfHeatsPerRound.length-roundNumber+1+
// in final round distinguish Final and Losers Final
(isFinalRound ? heatInRound-1 : 1);
fleetsInRound.add(new FleetImpl("Heat "+(heatNumber++), ordering));
}
List<String> raceColumnNameForRound = new ArrayList<String>();
raceColumnNameForRound.add("E"+elimination+"R"+roundNumber);
final String roundName;
if (numbersOfHeatsPerRound.length-roundNumber == 2) {
roundName = "Quarter-Final";
} else if (numbersOfHeatsPerRound.length-roundNumber == 1) {
roundName = "Semi-Final";
} else if (numbersOfHeatsPerRound.length-roundNumber == 0) {
roundName = "Final";
} else {
roundName = "Round "+roundNumber;
}
Series seriesForRound = new SeriesImpl("E"+elimination+" "+roundName, /* isMedal */ false, /* isFleetsCanRunInParallel */ true, fleetsInRound,
raceColumnNameForRound, /* trackedRegattaRegistry */null);
if (isFinalRound) {
// last "Final" round; here, the fleets are contiguously scored
seriesForRound.setSplitFleetContiguousScoring(true);
}
series.add(seriesForRound);
roundNumber++;
}
}
Regatta regatta = new RegattaImpl(RegattaImpl.getDefaultName(regattaBaseName, boatClass.getName()), boatClass,
/*startDate*/ null, /*endDate*/ null, series, /* persistent */ false, scoringScheme,
/* ID */ "123", /* course area */ null, OneDesignRankingMetric::new);
return regatta;
}
}
@@ -0,0 +1,111 @@
package com.sap.sailing.server.test;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.junit.Test;
import com.sap.sailing.domain.abstractlog.impl.LogEventAuthorImpl;
import com.sap.sailing.domain.abstractlog.race.CompetitorResults;
import com.sap.sailing.domain.abstractlog.race.RaceLog;
import com.sap.sailing.domain.abstractlog.race.impl.CompetitorResultImpl;
import com.sap.sailing.domain.abstractlog.race.impl.CompetitorResultsImpl;
import com.sap.sailing.domain.abstractlog.race.state.RaceState;
import com.sap.sailing.domain.abstractlog.race.state.impl.RaceStateImpl;
import com.sap.sailing.domain.abstractlog.race.state.racingprocedure.impl.RacingProcedureFactoryImpl;
import com.sap.sailing.domain.base.Competitor;
import com.sap.sailing.domain.base.DomainFactory;
import com.sap.sailing.domain.base.RaceColumn;
import com.sap.sailing.domain.base.Regatta;
import com.sap.sailing.domain.base.configuration.impl.EmptyRegattaConfiguration;
import com.sap.sailing.domain.base.impl.BoatClassImpl;
import com.sap.sailing.domain.base.impl.BoatImpl;
import com.sap.sailing.domain.base.impl.NationalityImpl;
import com.sap.sailing.domain.base.impl.PersonImpl;
import com.sap.sailing.domain.base.impl.TeamImpl;
import com.sap.sailing.domain.common.MaxPointsReason;
import com.sap.sailing.domain.common.NoWindException;
import com.sap.sailing.domain.common.ScoringSchemeType;
import com.sap.sailing.domain.leaderboard.Leaderboard;
import com.sap.sailing.domain.test.LeaderboardScoringAndRankingTestBase;
import com.sap.sailing.domain.test.mock.MockedTrackedRaceWithStartTimeAndRanks;
import com.sap.sailing.domain.tracking.TrackedRace;
import com.sap.sailing.server.RacingEventService;
import com.sap.sailing.server.impl.RacingEventServiceImpl;
import com.sap.sse.common.Color;
import com.sap.sse.common.TimePoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
public class ApplyScoresFromRaceLogTest extends LeaderboardScoringAndRankingTestBase {
/**
* See also bug 3794: make sure that different variants of scores and max points reasons / penalties are applied to the
* leaderboard.
*/
@Test
public void testApplicationOfScoresFromRaceLog() throws NoWindException {
final RacingEventService service = new RacingEventServiceImpl();
final List<Competitor> competitors = new ArrayList<>();
for (int i=0; i<20; i++) {
final String competitorName = "C"+i;
competitors.add(service.getBaseDomainFactory().getCompetitorStore().getOrCreateCompetitor(UUID.randomUUID(),
competitorName, /* displayColor */ Color.RED, /* email */ null, /* flagImageURI */ null,
new TeamImpl("STG", Collections.singleton(
new PersonImpl(competitorName, new NationalityImpl("GER"),
/* dateOfBirth */ null, "This is famous "+competitorName)),
new PersonImpl("Rigo van Maas", new NationalityImpl("NED"),
/* dateOfBirth */null, "This is Rigo, the coach")), new BoatImpl(competitorName + "'s boat",
new BoatClassImpl("505", /* typicallyStartsUpwind */ true), /* sailID */ null),
/* timeOnTimeFactor */ null, /* timeOnDistanceAllowancePerNauticalMile */ null, null));
}
final Regatta regatta = createRegatta(/* qualifying */0, new String[] { "Default" }, /* final */1,
new String[] { "Default" },
/* medal */false, /* medal */ 0, "testOneStartedRaceWithDifferentScores",
DomainFactory.INSTANCE.getOrCreateBoatClass("49er", /* typicallyStartsUpwind */true), DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT));
TimePoint now = MillisecondsTimePoint.now();
TimePoint later = new MillisecondsTimePoint(now.asMillis()+1000);
TrackedRace f1 = new MockedTrackedRaceWithStartTimeAndRanks(now, competitors);
RaceColumn f1Column = series.get(1).getRaceColumnByName("F1");
f1Column.setTrackedRace(f1Column.getFleets().iterator().next(), f1);
final Leaderboard leaderboard = createLeaderboard(regatta, /* discarding thresholds */ new int[0]);
service.addLeaderboard(leaderboard); // should add a RaceLogScoringReplicator as listener to the leaderboard
service.addRegattaWithoutReplication(regatta);
final Map<Competitor, Double> scores = new HashMap<>();
final Map<Competitor, MaxPointsReason> mprs = new HashMap<>();
int oneBasedRank = 1;
final CompetitorResults results = new CompetitorResultsImpl();
for (final Competitor c : competitors) {
final MaxPointsReason mpr = new MaxPointsReason[] { null, MaxPointsReason.NONE, MaxPointsReason.DNF, MaxPointsReason.OCS }[oneBasedRank%4];
final Double score = oneBasedRank%5 == 0 ? null : 20*Math.random();
scores.put(c, score);
mprs.put(c, mpr);
results.add(new CompetitorResultImpl(c.getId(), c.getName(),
oneBasedRank++, mpr, score, /* finishingTime */ null, /* comment */ null));
}
final RaceLog f1RaceLog = f1Column.getRaceLog(f1Column.getFleets().iterator().next());
final LogEventAuthorImpl author = new LogEventAuthorImpl("Axel", 0);
final RaceState f1RaceState = new RaceStateImpl(service, f1RaceLog, author,
new RacingProcedureFactoryImpl(author, new EmptyRegattaConfiguration()));
f1RaceState.setFinishPositioningListChanged(now, results);
final List<Competitor> rankedCompetitorsBeforeApplying = leaderboard.getCompetitorsFromBestToWorst(later);
assertEquals(competitors, rankedCompetitorsBeforeApplying); // no effects of preliminary results list yet
f1RaceState.setFinishPositioningConfirmed(now);
for (final Competitor c : competitors) {
assertEquals(scores.get(c)==null?competitors.indexOf(c)+1:scores.get(c), leaderboard.getTotalPoints(c, f1Column, now), 0.00000001);
}
final List<Competitor> expectedNewOrder = new ArrayList<>(competitors);
expectedNewOrder.sort((c1, c2)->
new Double(scores.get(c1)==null?competitors.indexOf(c1)+1:scores.get(c1)).compareTo(
new Double(scores.get(c2)==null?competitors.indexOf(c2)+1:scores.get(c2))));
final List<Competitor> rankedCompetitorsAfterApplying = leaderboard.getCompetitorsFromBestToWorst(later);
assertEquals(expectedNewOrder, rankedCompetitorsAfterApplying);
}
}
@@ -148,7 +148,7 @@ public class RaceLogScoringReplicator implements RaceColumnListener {
if (positioningList != null) {
for (CompetitorResult positionedCompetitor : positioningList) {
Competitor competitor = service.getBaseDomainFactory().getExistingCompetitorById(positionedCompetitor.getCompetitorId());
if (positionedCompetitor.getMaxPointsReason().equals(MaxPointsReason.NONE)) {
if (Util.equalsWithNull(positionedCompetitor.getMaxPointsReason(), MaxPointsReason.NONE)) {
try {
resetMaxPointsReasonIfNecessary(leaderboard, raceColumn, timePoint, competitor);
int rankByRaceCommittee = getRankInPositioningListByRaceCommittee(positionedCompetitor);
@@ -172,7 +172,7 @@ public class RaceLogScoringReplicator implements RaceColumnListener {
boolean scoreHasBeenCorrected = false;
MaxPointsReason trackedMaxPointsReason = leaderboard.getMaxPointsReason(competitor, raceColumn, timePoint);
MaxPointsReason maxPointsReasonByRaceCommittee = positionedCompetitor.getMaxPointsReason();
if (!maxPointsReasonByRaceCommittee.equals(trackedMaxPointsReason)) {
if (!Util.equalsWithNull(maxPointsReasonByRaceCommittee, trackedMaxPointsReason)) {
applyMaxPointsReasonOperation(leaderboard, raceColumn, competitor, maxPointsReasonByRaceCommittee, timePoint);
scoreHasBeenCorrected = true;
}