mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-30 09:26:44 +00:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
+8
-5
@@ -250,16 +250,19 @@ public class LeaderboardOfflineTest extends AbstractLeaderboardTest {
|
||||
}
|
||||
List<Integer> ranksOfNonMedalStartedRaces = new ArrayList<Integer>();
|
||||
TimePoint now = MillisecondsTimePoint.now();
|
||||
int numberOfRacesToCompareToDiscardThresholds = 0;
|
||||
for (RaceColumn column : raceColumnsInLeaderboard.values()) {
|
||||
if (!column.isMedalRace() && column.getTrackedRace(defaultFleet) != null && column.getTrackedRace(defaultFleet).hasStarted(now)) {
|
||||
ranksOfNonMedalStartedRaces.add(column.getTrackedRace(defaultFleet).getRank(competitor, now));
|
||||
if (column.getTrackedRace(defaultFleet) != null && column.getTrackedRace(defaultFleet).hasStarted(now)) {
|
||||
numberOfRacesToCompareToDiscardThresholds++;
|
||||
if (!column.isMedalRace()) {
|
||||
ranksOfNonMedalStartedRaces.add(column.getTrackedRace(defaultFleet).getRank(competitor, now));
|
||||
}
|
||||
}
|
||||
}
|
||||
Collections.sort(ranksOfNonMedalStartedRaces);
|
||||
int carryInt = (carry == null ? 0 : carry);
|
||||
int totalPoints = carryInt;
|
||||
int medalRacePoints = getMedalRacePoints(competitor, now, defaultFleet);
|
||||
int numberOfRacesFromWhichToDiscard = ranksOfNonMedalStartedRaces.size();
|
||||
for (TrackedRace race : testRaces) {
|
||||
RaceColumn raceColumn = raceColumnsInLeaderboard.get(race);
|
||||
Pair<Competitor, RaceColumn> key = new Pair<Competitor, RaceColumn>(competitor, raceColumn);
|
||||
@@ -274,8 +277,8 @@ public class LeaderboardOfflineTest extends AbstractLeaderboardTest {
|
||||
// One race is discarded because four races were started, and for [3-6) one race can be discarded.
|
||||
// The discarded race is the worst of those started, so the one with rank 4.
|
||||
int expectedNumberOfDiscardedRaces =
|
||||
numberOfRacesFromWhichToDiscard < firstDiscardingThreshold ? 0 :
|
||||
numberOfRacesFromWhichToDiscard < secondDiscardingThreshold ? 1 : 2;
|
||||
numberOfRacesToCompareToDiscardThresholds < firstDiscardingThreshold ? 0 :
|
||||
numberOfRacesToCompareToDiscardThresholds < secondDiscardingThreshold ? 1 : 2;
|
||||
boolean discarded = ranksOfNonMedalStartedRaces.indexOf(rank) >= ranksOfNonMedalStartedRaces.size()-expectedNumberOfDiscardedRaces;
|
||||
int expected = discarded ? 0 : rank==medalRacePoints?2*rank:rank;
|
||||
assertEquals(expected, leaderboard.getTotalPoints(competitor, raceColumn, now), 0.000000001);
|
||||
|
||||
+86
-2
@@ -228,6 +228,90 @@ public class LeaderboardScoringAndRankingTest extends AbstractLeaderboardTest {
|
||||
assertEquals(47.0, leaderboard.getTotalPoints(competitors.get(9), later), 0.00000001);
|
||||
}
|
||||
|
||||
/**
|
||||
* Regarding bug 961, test scoring in a leaderboard that has a qualification series with two unordered groups where for one
|
||||
* column only one group has raced (expressed by a mocked TrackedRace attached to the column). Ensure that the column doesn't
|
||||
* count for computing the number of discards.
|
||||
*/
|
||||
@Test
|
||||
public void testDiscardsForUnorderedGroupsWithOneGroupNotHavingRacedInAColumn() throws NoWindException {
|
||||
List<Competitor> competitors = createCompetitors(10);
|
||||
Regatta regatta = createRegatta(/* qualifying */ 2, new String[] { "Yellow", "Blue" }, /* final */0,
|
||||
new String[] { "Default" },
|
||||
/* medal */false, "testDiscardsForUnorderedGroupsWithOneGroupNotHavingRacedInAColumn",
|
||||
DomainFactory.INSTANCE.getOrCreateBoatClass("49er", /* typicallyStartsUpwind */true),
|
||||
DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT));
|
||||
Leaderboard leaderboard = createLeaderboard(regatta, /* discarding thresholds */ new int[]{2}); // one discard for two or more races
|
||||
Series qualificationSeries;
|
||||
Iterator<? extends Series> seriesIter = regatta.getSeries().iterator();
|
||||
qualificationSeries = seriesIter.next();
|
||||
TimePoint now = MillisecondsTimePoint.now();
|
||||
TimePoint later = new MillisecondsTimePoint(now.asMillis()+1000);
|
||||
TrackedRace q1Yellow = new MockedTrackedRaceWithStartTimeAndRanks(now, competitors.subList(0, 5));
|
||||
TrackedRace q1Blue = new MockedTrackedRaceWithStartTimeAndRanks(now, competitors.subList(5, 10));
|
||||
RaceColumn q1Column = qualificationSeries.getRaceColumnByName("Q1");
|
||||
q1Column.setTrackedRace(q1Column.getFleetByName("Yellow"), q1Yellow);
|
||||
q1Column.setTrackedRace(q1Column.getFleetByName("Blue"), q1Blue);
|
||||
// now add one race for yellow fleet and test that there are no discards still because blue fleet is still missing its race for Q2
|
||||
TrackedRace q2Yellow = new MockedTrackedRaceWithStartTimeAndRanks(now, competitors.subList(3, 8));
|
||||
RaceColumn q2Column = qualificationSeries.getRaceColumnByName("Q2");
|
||||
q2Column.setTrackedRace(q2Column.getFleetByName("Yellow"), q2Yellow);
|
||||
for (Competitor competitor : competitors) {
|
||||
assertFalse("Competitor "+competitor+" has a discard in Q1 but shouldn't", leaderboard.isDiscarded(competitor, q1Column, later));
|
||||
assertFalse("Competitor "+competitor+" has a discard in Q2 but shouldn't", leaderboard.isDiscarded(competitor, q2Column, later));
|
||||
}
|
||||
// now add a tracked race for the blue fleet for Q2 and assert that all competitors have one discard
|
||||
TrackedRace q2Blue = new MockedTrackedRaceWithStartTimeAndRanks(now,
|
||||
Arrays.asList(new Competitor[] { competitors.get(0), competitors.get(1), competitors.get(2),
|
||||
competitors.get(8), competitors.get(9) }));
|
||||
q2Column.setTrackedRace(q2Column.getFleetByName("Blue"), q2Blue);
|
||||
for (Competitor competitor : competitors) {
|
||||
assertTrue("Competitor "+competitor+" has no discard but should",
|
||||
leaderboard.isDiscarded(competitor, q1Column, later) || leaderboard.isDiscarded(competitor, q2Column, later));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Regarding bug 961, test scoring in a leaderboard that has a qualification series with two ordered groups where for one
|
||||
* column only one group has raced (expressed by a mocked TrackedRace attached to the column). Ensure that the competitors in
|
||||
* that column get their discard.
|
||||
*/
|
||||
@Test
|
||||
public void testDiscardsForOrderedGroupsWithOneGroupNotHavingRacedInAColumn() throws NoWindException {
|
||||
List<Competitor> competitors = createCompetitors(10);
|
||||
Regatta regatta = createRegatta(/* qualifying */ 0, new String[] { "Default" }, /* final */2,
|
||||
new String[] { "Gold", "Silver" },
|
||||
/* medal */false, "testDiscardsForOrderedGroupsWithOneGroupNotHavingRacedInAColumn",
|
||||
DomainFactory.INSTANCE.getOrCreateBoatClass("49er", /* typicallyStartsUpwind */true),
|
||||
DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT));
|
||||
Leaderboard leaderboard = createLeaderboard(regatta, /* discarding thresholds */ new int[]{2}); // one discard for two or more races
|
||||
Series finalSeries;
|
||||
Iterator<? extends Series> seriesIter = regatta.getSeries().iterator();
|
||||
seriesIter.next();
|
||||
finalSeries = seriesIter.next();
|
||||
TimePoint now = MillisecondsTimePoint.now();
|
||||
TimePoint later = new MillisecondsTimePoint(now.asMillis()+1000);
|
||||
TrackedRace f1Gold = new MockedTrackedRaceWithStartTimeAndRanks(now, competitors.subList(0, 5));
|
||||
TrackedRace f1Silver = new MockedTrackedRaceWithStartTimeAndRanks(now, competitors.subList(5, 10));
|
||||
RaceColumn f1Column = finalSeries.getRaceColumnByName("F1");
|
||||
f1Column.setTrackedRace(f1Column.getFleetByName("Gold"), f1Gold);
|
||||
f1Column.setTrackedRace(f1Column.getFleetByName("Silver"), f1Silver);
|
||||
// now add one race for yellow fleet and test that there are no discards still because blue fleet is still missing its race for Q2
|
||||
TrackedRace f2Gold = new MockedTrackedRaceWithStartTimeAndRanks(now, competitors.subList(0, 5));
|
||||
RaceColumn f2Column = finalSeries.getRaceColumnByName("F2");
|
||||
f2Column.setTrackedRace(f2Column.getFleetByName("Gold"), f2Gold);
|
||||
for (int i=0; i<5; i++) {
|
||||
assertTrue("Competitor "+competitors.get(i)+" has no discard in F1 or F2 but should",
|
||||
leaderboard.isDiscarded(competitors.get(i), f1Column, later) ||
|
||||
leaderboard.isDiscarded(competitors.get(i), f2Column, later));
|
||||
}
|
||||
for (int i=5; i<10; i++) {
|
||||
assertFalse("Competitor "+competitors.get(i)+" has a discard in F1 or F2 but shouldn't",
|
||||
leaderboard.isDiscarded(competitors.get(i), f1Column, later) ||
|
||||
leaderboard.isDiscarded(competitors.get(i), f2Column, later));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the competitors ranking worse than the disqualified competitor advance by one in the
|
||||
* {@link Leaderboard#getCompetitorsFromBestToWorst(TimePoint)} ordering. Note that this does not test
|
||||
@@ -238,7 +322,7 @@ public class LeaderboardScoringAndRankingTest extends AbstractLeaderboardTest {
|
||||
List<Competitor> competitors = createCompetitors(10);
|
||||
Regatta regatta = createRegatta(/* qualifying */0, new String[] { "Default" }, /* final */1,
|
||||
new String[] { "Default" },
|
||||
/* medal */false, "testOneStartedRaceWithDifferentScores",
|
||||
/* medal */false, "testOneStartedRaceWithDifferentScoresAndDisqualification",
|
||||
DomainFactory.INSTANCE.getOrCreateBoatClass("49er", /* typicallyStartsUpwind */true), DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT));
|
||||
Leaderboard leaderboard = createLeaderboard(regatta, /* discarding thresholds */ new int[0]);
|
||||
Series finalSeries;
|
||||
@@ -277,7 +361,7 @@ public class LeaderboardScoringAndRankingTest extends AbstractLeaderboardTest {
|
||||
}
|
||||
Regatta regatta = createRegatta(/* qualifying */1, new String[] { "Yellow", "Blue" }, /* final */0,
|
||||
new String[] { "Default" },
|
||||
/* medal */false, "testAllTrackedAndStartedWithDifferentScores",
|
||||
/* medal */false, "testDistributionAcrossQualifyingFleetsWithDifferentScores",
|
||||
DomainFactory.INSTANCE.getOrCreateBoatClass("49er", /* typicallyStartsUpwind */true), DomainFactory.INSTANCE.createScoringScheme(ScoringSchemeType.LOW_POINT));
|
||||
Leaderboard leaderboard = createLeaderboard(regatta, /* discarding thresholds */ new int[0]);
|
||||
TimePoint now = MillisecondsTimePoint.now();
|
||||
|
||||
@@ -261,11 +261,13 @@ public interface Leaderboard extends Named {
|
||||
* Tells if the column represented by <code>raceColumn</code> shall be considered when counting the number of "races
|
||||
* so far" for discarding. Although medal races are never discarded themselves, they still count in determining the
|
||||
* number of "races so far" which is then the basis for deciding how many races may be discarded. If a leaderboard
|
||||
* has corrections for a column then that column shall be considered for discarding and counts for determining the
|
||||
* number of races so far. Also, if a tracked race is connected to the column and has started already, the column is
|
||||
* to be considered for discarding.
|
||||
* has corrections for a column for the <code>competitor</code> then that column shall be considered for discarding
|
||||
* and counts for determining the number of races so far. Also, if a tracked race is connected to the column and has
|
||||
* started already, the column is to be considered for discarding unless the column has several unordered fleets and
|
||||
* not all fleets have started their race yet (see
|
||||
* {@link ScoringScheme#isValidInTotalScore(Leaderboard, RaceColumn, TimePoint)}).
|
||||
*/
|
||||
boolean considerForDiscarding(RaceColumn raceColumn, TimePoint timePoint);
|
||||
boolean countRaceForComparisonWithDiscardingThresholds(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint);
|
||||
|
||||
public void setResultDiscardingRule(ThresholdBasedResultDiscardingRule discardingRule);
|
||||
|
||||
|
||||
+1
-1
@@ -94,7 +94,7 @@ public abstract class AbstractScoringSchemeImpl implements ScoringScheme {
|
||||
Fleet fleet = raceColumn.getFleetOfCompetitor(competitor);
|
||||
if (fleetsForWhichNoScoreWasFound.contains(fleet)) {
|
||||
try {
|
||||
if (leaderboard.getTotalPoints(competitor, raceColumn, at) != null) {
|
||||
if (leaderboard.getNetPoints(competitor, raceColumn, at) != null) {
|
||||
fleetsForWhichNoScoreWasFound.remove(fleet);
|
||||
}
|
||||
} catch (NoWindException nwe) {
|
||||
|
||||
+6
-12
@@ -336,18 +336,12 @@ public abstract class AbstractSimpleLeaderboardImpl implements Leaderboard, Race
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean considerForDiscarding(RaceColumn raceColumn, TimePoint timePoint) {
|
||||
boolean result = getScoreCorrection().hasCorrectionFor(raceColumn);
|
||||
if (!result && !raceColumn.isMedalRace()) {
|
||||
for (Fleet fleet : raceColumn.getFleets()) {
|
||||
TrackedRace trackedRace = raceColumn.getTrackedRace(fleet);
|
||||
if (trackedRace != null && trackedRace.hasStarted(timePoint)) {
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
public boolean countRaceForComparisonWithDiscardingThresholds(Competitor competitor, RaceColumn raceColumn, TimePoint timePoint) {
|
||||
TrackedRace trackedRaceForCompetitorInColumn;
|
||||
return getScoreCorrection().isScoreCorrected(competitor, raceColumn) ||
|
||||
(getScoringScheme().isValidInTotalScore(this, raceColumn, timePoint) &&
|
||||
(trackedRaceForCompetitorInColumn=raceColumn.getTrackedRace(competitor)) != null &&
|
||||
trackedRaceForCompetitorInColumn.hasStarted(timePoint));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-3
@@ -51,7 +51,7 @@ public class ResultDiscardingRuleImpl implements ThresholdBasedResultDiscardingR
|
||||
|
||||
@Override
|
||||
public Set<RaceColumn> getDiscardedRaceColumns(final Competitor competitor, final Leaderboard leaderboard, final TimePoint timePoint) {
|
||||
int resultsToDiscard = getNumberOfResultsToDiscard(leaderboard.getRaceColumns(), leaderboard, timePoint);
|
||||
int resultsToDiscard = getNumberOfResultsToDiscard(competitor, leaderboard.getRaceColumns(), leaderboard, timePoint);
|
||||
Set<RaceColumn> result;
|
||||
if (resultsToDiscard > 0) {
|
||||
result = new HashSet<RaceColumn>();
|
||||
@@ -94,11 +94,11 @@ public class ResultDiscardingRuleImpl implements ThresholdBasedResultDiscardingR
|
||||
return result;
|
||||
}
|
||||
|
||||
private int getNumberOfResultsToDiscard(Iterable<RaceColumn> raceColumns, Leaderboard leaderboard, TimePoint timePoint) {
|
||||
private int getNumberOfResultsToDiscard(Competitor competitor, Iterable<RaceColumn> raceColumns, Leaderboard leaderboard, TimePoint timePoint) {
|
||||
int numberOfResultsToDiscard;
|
||||
int numberOfStartedRaces = 0;
|
||||
for (RaceColumn raceInLeaderboard : raceColumns) {
|
||||
if (leaderboard.considerForDiscarding(raceInLeaderboard, timePoint)) {
|
||||
if (leaderboard.countRaceForComparisonWithDiscardingThresholds(competitor, raceInLeaderboard, timePoint)) {
|
||||
numberOfStartedRaces++;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user