mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-11-14 06:18:12 +00:00
fixed application of score corrections for valid MaxPointsReason and no rank; adjusted test case to accomodate for changed behavior of bug4167
Change-Id: Ic36eaafcde53a0dd2f0816366561b48b73831794
This commit is contained in:
1 parent
1ee5e21092
commit
bfb4e41642
2 files changed
+55
-29
No files matched your search
+23
-12
@@ -112,7 +112,9 @@ public class ApplyScoresFromRaceLogTest extends LeaderboardScoringAndRankingTest
|
||||
final List<Competitor> rankedCompetitorsBeforeApplying = leaderboard.getCompetitorsFromBestToWorst(later);
|
||||
assertEquals(competitors, rankedCompetitorsBeforeApplying); // no effects of preliminary results list yet
|
||||
f1RaceState.setFinishPositioningConfirmed(now);
|
||||
final Function<Competitor, Double> expectedPoints = (c)->scores.get(c)==null?(mprs.get(c) == null || mprs.get(c) == MaxPointsReason.NONE ? competitors.indexOf(c)+1 : competitors.size()+1):scores.get(c);
|
||||
final Function<Competitor, Double> expectedPoints =
|
||||
(c)->scores.get(c)==null?(mprs.get(c) == null || mprs.get(c) == MaxPointsReason.NONE ?
|
||||
competitors.indexOf(c)+1 : competitors.size()+1):scores.get(c);
|
||||
for (final Competitor c : competitors) {
|
||||
assertEquals(expectedPoints.apply(c), leaderboard.getTotalPoints(c, f1Column, now), 0.00000001);
|
||||
}
|
||||
@@ -169,16 +171,22 @@ public class ApplyScoresFromRaceLogTest extends LeaderboardScoringAndRankingTest
|
||||
}
|
||||
|
||||
/**
|
||||
* See bug 4025: When a scoring race log event is received it may contain a partial competitor set. It shall depend on
|
||||
* the previous state resulting from the race log, without the last event, what needs to be done with the leaderboard
|
||||
* score corrections. If a competitor which which an earlier message did have a correction now no longer is part of
|
||||
* the latest scoring race log event, and if the score corrections in the leaderboard match up with what the previous
|
||||
* event had caused, remove that score correction again.
|
||||
* See bugs 4025 and 4167: When a scoring race log event is received it may contain a partial competitor set. Before bug4167
|
||||
* there was an implementation that reset score corrections if previous messages had a result for a competitor, and later
|
||||
* messages did not. With bug 4167 we found that it should be possible to send in partial results, owed to the insight that
|
||||
* multiple devices may be used for the same race, not all in sync at all times, therefore producing partial results that
|
||||
* should not clear or overwrite valid results input by other devices.<p>
|
||||
*
|
||||
* Therefore, now, with bug4167, this test has been modified such that first it ensures that a partial result
|
||||
* does <em>not</em> clear a previous score correction. Furthermore it tests that when sending a result that
|
||||
* has 0 as the rank and {@link MaxPointsReason#NONE} as the {@link MaxPointsReason} with no explicit score set,
|
||||
* the score correction for the competitor will be reset in the leaderboard.
|
||||
*/
|
||||
@Test
|
||||
public void testApplyingOCSThenClearingOCS() {
|
||||
TimePoint now = MillisecondsTimePoint.now();
|
||||
TimePoint later = new MillisecondsTimePoint(now.asMillis()+1000);
|
||||
TimePoint later = now.plus(1000);
|
||||
TimePoint yetLater = later.plus(1000);
|
||||
final int numberOfCompetitors = 2;
|
||||
setUp(numberOfCompetitors, now, ScoringSchemeType.LOW_POINT);
|
||||
final CompetitorResults results = new CompetitorResultsImpl();
|
||||
@@ -202,9 +210,15 @@ public class ApplyScoresFromRaceLogTest extends LeaderboardScoringAndRankingTest
|
||||
setResultForCompetitor(competitors.get(1), /* one-based rank */ 0, resultsWithOCSCleared, MaxPointsReason.OCS, /* explicit score */ null);
|
||||
f1RaceState.setFinishPositioningListChanged(later, resultsWithOCSCleared);
|
||||
f1RaceState.setFinishPositioningConfirmed(later);
|
||||
// validate that it got cleared in leaderboard
|
||||
// validate that it did not get cleared in leaderboard (changed by bug 4167):
|
||||
assertScoreCorrections(leaderboard, f1Column, competitors.get(1), MaxPointsReason.OCS, numberOfCompetitors+1, /* score is corrected */ false, later);
|
||||
assertScoreCorrections(leaderboard, f1Column, competitors.get(0), MaxPointsReason.NONE, 1, /* score is corrected */ false, later); // ranking first, one point in low-point scheme
|
||||
assertScoreCorrections(leaderboard, f1Column, competitors.get(0), MaxPointsReason.OCS, numberOfCompetitors+1, /* score is corrected */ false, later); // ranking first, one point in low-point scheme
|
||||
// now explicitly overwrite with a 0/null/null result, validating that this will clear the corrections for competitor 0:
|
||||
setResultForCompetitor(competitors.get(0), /* one-based rank */ 0, resultsWithOCSCleared, /* maxPointsReason */ null, /* explicit score */ null);
|
||||
f1RaceState.setFinishPositioningListChanged(yetLater, resultsWithOCSCleared);
|
||||
f1RaceState.setFinishPositioningConfirmed(yetLater);
|
||||
assertScoreCorrections(leaderboard, f1Column, competitors.get(1), MaxPointsReason.OCS, numberOfCompetitors+1, /* score is corrected */ false, yetLater);
|
||||
assertScoreCorrections(leaderboard, f1Column, competitors.get(0), MaxPointsReason.NONE, 1, /* score is corrected */ false, yetLater); // ranking first, one point in low-point scheme
|
||||
}
|
||||
|
||||
private void assertScoreCorrections(Leaderboard leaderboard, RaceColumn raceColumn, Competitor competitor,
|
||||
@@ -219,7 +233,4 @@ public class ApplyScoresFromRaceLogTest extends LeaderboardScoringAndRankingTest
|
||||
final CompetitorResults results, MaxPointsReason maxPointsReason, Double explicitScore) {
|
||||
results.add(new CompetitorResultImpl(competitor.getId(), competitor.getName(), oneBasedRank, maxPointsReason, explicitScore, /* finishingTime */ null, /* comment */ null));
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
+32
-17
@@ -71,15 +71,19 @@ public class RaceLogScoringReplicator implements RaceColumnListenerWithDefaultAc
|
||||
* <li>When no {@link CompetitorResult} object is received for a competitor, no change is applied to that
|
||||
* competitor's score corrections.</li>
|
||||
* <li>When a {@link CompetitorResult} object is received for a competitor, if it contains {@code null} for the
|
||||
* score and 0 for the rank, any existing score correction (points) is removed for that competitor, otherwise, the
|
||||
* score and 0 for the rank or {@code null} for the score and a valid non-{@link MaxPointsReason#NONE NONE}
|
||||
* {@link MaxPointsReason}, any existing score correction (points) is removed for that competitor, otherwise, the
|
||||
* score correction (points) from the CompetitorResult object is applied if provided (in this case a rank provided
|
||||
* in the {@link CompetitorResult} object is ignored); if only a rank but no score is provided in the
|
||||
* {@link CompetitorResult}, the scoring scheme will compute the score from the rank, and that score will be applied
|
||||
* as a score correction.</li>
|
||||
* in the {@link CompetitorResult} object is ignored); if no {@link MaxPointsReason} is provided and only a rank but
|
||||
* no score is provided in the {@link CompetitorResult}, the scoring scheme will compute the score from the rank,
|
||||
* considering any {@link MaxPointsReason} provided in the result, and that score will be applied as a score
|
||||
* correction. If a {@link MaxPointsReason} but no explicit score is provided, the rank is ignored because
|
||||
* the scoring scheme is expected to compute the score from the {@link MaxPointsReason}; therefore, the score
|
||||
* correction (points) is cleared in this case so that the scoring scheme will be used for score calculation.</li>
|
||||
* <li>When a {@link CompetitorResult} object is received for a competitor, if it contains {@code null} for the
|
||||
* {@link MaxPointsReason}, any existing {@link MaxPointsReason} is removed for that competitor; otherwise, the
|
||||
* {@link MaxPointsReason} from the {@link CompetitorResult} object is applied. This is handled entirely
|
||||
* independently of the score (points).</li>
|
||||
* {@link MaxPointsReason} from the {@link CompetitorResult} object is applied, and if no explicit score is provided
|
||||
* in the result, the score is computed by the scoring scheme, ignoring any rank provided in the result.</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
*
|
||||
@@ -116,7 +120,7 @@ public class RaceLogScoringReplicator implements RaceColumnListenerWithDefaultAc
|
||||
final Competitor competitor = service.getBaseDomainFactory().getExistingCompetitorById(positionedCompetitor.getCompetitorId());
|
||||
int rankByRaceCommittee = getRankInPositioningListByRaceCommittee(positionedCompetitor);
|
||||
correctScoreInLeaderboardIfNecessary(leaderboard, raceColumn, timePoint, numberOfCompetitorsInRace, competitor,
|
||||
rankByRaceCommittee, positionedCompetitor.getScore());
|
||||
rankByRaceCommittee, positionedCompetitor.getScore(), positionedCompetitor.getMaxPointsReason());
|
||||
setMaxPointsReasonInLeaderboardIfNecessary(leaderboard, raceColumn, timePoint, positionedCompetitor.getMaxPointsReason(), competitor);
|
||||
}
|
||||
// Since the metadata update is used by the Sailing suite to determine the final state of a race, it has to
|
||||
@@ -137,11 +141,13 @@ public class RaceLogScoringReplicator implements RaceColumnListenerWithDefaultAc
|
||||
}
|
||||
}
|
||||
|
||||
private void correctScoreInLeaderboardIfNecessary(Leaderboard leaderboard, RaceColumn raceColumn, TimePoint timePoint,
|
||||
final int numberOfCompetitorsInRace,
|
||||
Competitor competitor, int rankByRaceCommittee, Double optionalExplicitScore) {
|
||||
final Double scoreByRaceCommittee = getScoreFromRaceCommittee(leaderboard, raceColumn, timePoint,
|
||||
numberOfCompetitorsInRace, competitor, rankByRaceCommittee, optionalExplicitScore);
|
||||
private void correctScoreInLeaderboardIfNecessary(Leaderboard leaderboard, RaceColumn raceColumn,
|
||||
TimePoint timePoint, final int numberOfCompetitorsInRace, Competitor competitor, int rankByRaceCommittee,
|
||||
Double optionalExplicitScore, MaxPointsReason maxPointsReason) {
|
||||
final Double scoreByRaceCommittee = optionalExplicitScore==null && maxPointsReason != null &&
|
||||
maxPointsReason != MaxPointsReason.NONE ? null :
|
||||
getScoreFromRaceCommittee(leaderboard, raceColumn, timePoint,
|
||||
numberOfCompetitorsInRace, competitor, rankByRaceCommittee, optionalExplicitScore, maxPointsReason);
|
||||
// Apply the score correction if it will cause a change in the explicit score set for the competitor
|
||||
if (!Util.equalsWithNull(leaderboard.getScoreCorrection().getExplicitScoreCorrection(competitor, raceColumn), scoreByRaceCommittee)) {
|
||||
applyScoreCorrectionOperation(leaderboard, raceColumn, competitor, scoreByRaceCommittee, timePoint);
|
||||
@@ -149,19 +155,28 @@ public class RaceLogScoringReplicator implements RaceColumnListenerWithDefaultAc
|
||||
}
|
||||
|
||||
/**
|
||||
* If a non-{@code null} {@code optionalExplicitScore} is provided, it it returned. Otherwise, a score is determined
|
||||
* from the {@code oneBasedRankByRaceCommittee} using the leaderboard scoring scheme's
|
||||
* If a non-{@code null} {@code optionalExplicitScore} is provided, it it returned. Otherwise, if a valid
|
||||
* {@link MaxPointsReason} is provided, {@code null} is returned as the explicit score because the scoring scheme
|
||||
* shall be used dynamically to determine the penalty score (see
|
||||
* {@link ScoringScheme#getPenaltyScore(RaceColumn, Competitor, MaxPointsReason, Integer, com.sap.sailing.domain.leaderboard.NumberOfCompetitorsInLeaderboardFetcher, TimePoint)}).
|
||||
* If no explicit score is provided and no {@link MaxPointsReason} is specified, a score is determined from the
|
||||
* {@code oneBasedRankByRaceCommittee} using the leaderboard scoring scheme's
|
||||
* {@link ScoringScheme#getScoreForRank(Leaderboard, RaceColumn, Competitor, int, java.util.concurrent.Callable, com.sap.sailing.domain.leaderboard.NumberOfCompetitorsInLeaderboardFetcher, TimePoint)
|
||||
* getScoreForRank(...)} method. Usually, scoring schemes will return {@code null} as score for {@code 0} as
|
||||
* (one-based) rank.
|
||||
*/
|
||||
private Double getScoreFromRaceCommittee(Leaderboard leaderboard, RaceColumn raceColumn, TimePoint timePoint,
|
||||
final int numberOfCompetitorsInRace, Competitor competitor, int oneBasedRankByRaceCommittee,
|
||||
Double optionalExplicitScore) {
|
||||
Double optionalExplicitScore, MaxPointsReason maxPointsReason) {
|
||||
final Double scoreByRaceCommittee;
|
||||
if (optionalExplicitScore == null) {
|
||||
scoreByRaceCommittee = leaderboard.getScoringScheme().getScoreForRank(leaderboard, raceColumn, competitor,
|
||||
oneBasedRankByRaceCommittee, ()->numberOfCompetitorsInRace, leaderboard.getNumberOfCompetitorsInLeaderboardFetcher(), timePoint);
|
||||
if (maxPointsReason != null && maxPointsReason != MaxPointsReason.NONE) {
|
||||
// let scoring scheme calculate the penalty score dynamically
|
||||
scoreByRaceCommittee = null;
|
||||
} else {
|
||||
scoreByRaceCommittee = leaderboard.getScoringScheme().getScoreForRank(leaderboard, raceColumn, competitor,
|
||||
oneBasedRankByRaceCommittee, ()->numberOfCompetitorsInRace, leaderboard.getNumberOfCompetitorsInLeaderboardFetcher(), timePoint);
|
||||
}
|
||||
} else {
|
||||
scoreByRaceCommittee = optionalExplicitScore;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user