bug5877: started with refactorings and comments; started new scoring scheme

This commit is contained in:
Axel Uhl
2023-07-20 18:32:46 +02:00
parent 5f510cc969
commit 261d506935
7 changed files with 140 additions and 22 deletions
@@ -116,6 +116,15 @@ public interface ScoringScheme extends Serializable {
*/
int compareByNumberOfRacesScored(int competitor1NumberOfRacesScored, int competitor2NumberOfRacesScored);
/**
* Having scored in a later medal series than the other is considered better. -1 means no medal series score at all.
* With a lesser result encoding "better" the direction of default integer comparison between the two parameters is
* reversed.
*/
default int compareByMedalRaceParticipation(int zeroBasedIndexOfLastMedalSeriesInWhichO1Scored, int zeroBasedIndexOfLastMedalSeriesInWhichO2Scored) {
return -Integer.compare(zeroBasedIndexOfLastMedalSeriesInWhichO1Scored, zeroBasedIndexOfLastMedalSeriesInWhichO2Scored);
}
ScoringSchemeType getType();
/**
@@ -175,6 +175,26 @@ public abstract class AbstractScoringSchemeImpl implements ScoringScheme {
return 0;
}
/**
* Returns a filtered view on the {@link Leaderboard#getRaceColumns() leaderboard's race columns}, removing
* all {@link RaceColumn#isMedalRace() medal races} from the filtered view.
*/
protected Iterable<RaceColumn> getOpeningSeriesRaceColumns(Leaderboard leaderboard) {
return Util.filter(leaderboard.getRaceColumns(), rc->!rc.isMedalRace());
}
protected LeaderboardTotalRankComparator getOpeningSeriesRankComparator(boolean nullScoresAreBetter,
TimePoint timePoint, Leaderboard leaderboard,
BiFunction<Competitor, RaceColumn, Double> totalPointsSupplier,
WindLegTypeAndLegBearingAndORCPerformanceCurveCache cache) {
final Iterable<RaceColumn> openingSeriesRaceColumns = getOpeningSeriesRaceColumns(leaderboard);
// pass on the totalPointsSupplier coming from the caller, most likely a LeaderboardTotalRankComparator,
// to speed up / save the total points (re-)calculation
final LeaderboardTotalRankComparator openingSeriesRankComparator =
new LeaderboardTotalRankComparator(leaderboard, timePoint, this, nullScoresAreBetter, openingSeriesRaceColumns, totalPointsSupplier, cache);
return openingSeriesRankComparator;
}
/**
* Looks backwards starting at the last race until the first score difference is found, including the discarded
* scored. This implements Racing Rules of Sailing (RRS) section A8.2:
@@ -249,7 +249,8 @@ public class LeaderboardTotalRankComparator implements Comparator<Competitor> {
}
}
}
int result = compareByMedalRaceParticipation(zeroBasedIndexOfLastMedalSeriesInWhichO1Scored, zeroBasedIndexOfLastMedalSeriesInWhichO2Scored);
// TODO bug5877: pass leaderboard and competitors and a totalPointsSupplier (based on totalPointsCache, see call to compareByBetterScore below) to allow for identifying competitors promoted through to later medal race
int result = scoringScheme.compareByMedalRaceParticipation(zeroBasedIndexOfLastMedalSeriesInWhichO1Scored, zeroBasedIndexOfLastMedalSeriesInWhichO2Scored);
if (result == 0) {
result = defaultFleetBasedComparisonResult;
if (result == 0) {
@@ -466,15 +467,6 @@ public class LeaderboardTotalRankComparator implements Comparator<Competitor> {
return result;
}
/**
* Having scored in a later medal series than the other is considered better. -1 means no medal series score at all.
* With a lesser result encoding "better" the direction of default integer comparison between the two parameters is
* reversed.
*/
private int compareByMedalRaceParticipation(int zeroBasedIndexOfLastMedalSeriesInWhichO1Scored, int zeroBasedIndexOfLastMedalSeriesInWhichO2Scored) {
return -Integer.compare(zeroBasedIndexOfLastMedalSeriesInWhichO1Scored, zeroBasedIndexOfLastMedalSeriesInWhichO2Scored);
}
/**
* Returns a comparator for comparing individual scores. This implementation returns a comparator for the usual ISAF
* scheme where lesser scores compare "better" which again means "lesser." Therefore, the comparator retunred compares
@@ -392,11 +392,9 @@ public class LowPointFirstToWinThreeRaces extends LowPoint {
result = compareByA81TieBreak(o1, o1Scores, o2, o2Scores, nullScoresAreBetter, timePoint, leaderboard,
discardedRaceColumnsPerCompetitor, totalPointsSupplier, cache);
} else {
final Iterable<RaceColumn> openingSeriesRaceColumns = getOpeningSeriesRaceColumns(leaderboard);
// pass on the totalPointsSupplier coming from the caller, most likely a LeaderboardTotalRankComparator,
// to speed up / save the total points (re-)calculation
result = new LeaderboardTotalRankComparator(leaderboard, timePoint, this, nullScoresAreBetter, openingSeriesRaceColumns, totalPointsSupplier, cache)
.compare(o1, o2);
final LeaderboardTotalRankComparator openingSeriesRankComparator = getOpeningSeriesRankComparator(
nullScoresAreBetter, timePoint, leaderboard, totalPointsSupplier, cache);
result = openingSeriesRankComparator.compare(o1, o2);
}
return result;
}
@@ -418,13 +416,6 @@ public class LowPointFirstToWinThreeRaces extends LowPoint {
discardedRaceColumnsPerCompetitor, totalPointsSupplier, cache);
}
/**
* Merge non-medal series columns, preserving order across {@code raceColumnsO1} and {@code raceColumnsO2}.
*/
private Iterable<RaceColumn> getOpeningSeriesRaceColumns(Leaderboard leaderboard) {
return Util.filter(leaderboard.getRaceColumns(), rc->!rc.isMedalRace());
}
private boolean hasMedalScores(List<Pair<RaceColumn, Double>> o1Scores) {
return o1Scores.stream().anyMatch(p->p.getA().isMedalRace() && p.getB() != null);
}
@@ -0,0 +1,10 @@
package com.sap.sailing.domain.leaderboard.impl;
public class LowPointWithEliminatingMedalSeriesPromotingOneToFinalAndTwoToSemifinal
extends LowPointWithEliminatingMedalSeriesWithPromotions {
private static final long serialVersionUID = -6753499035563730886L;
public LowPointWithEliminatingMedalSeriesPromotingOneToFinalAndTwoToSemifinal() {
super(new int[] { 2, 1 });
}
}
@@ -0,0 +1,57 @@
package com.sap.sailing.domain.leaderboard.impl;
import java.util.List;
import java.util.ListIterator;
import com.sap.sailing.domain.base.RaceColumnInSeries;
import com.sap.sse.common.Util;
public abstract class LowPointWithEliminatingMedalSeriesWithPromotions extends LowPoint {
private static final long serialVersionUID = 7759999270911627798L;
/**
* The last index for this array refers to the last medal race; e.g., the "Grand Final" race
* in an iQFOil regatta with the medal series consisting of a "Quarter Final," a "Semi Final"
* and a "Grand Final". The last-but-one index in the example would then refer to the Semi Final,
* and so on. The array may be empty, meaning that no competitor is promoted into any medal
* race. The field always has to refer to a valid array.
*/
private final int[] numberOfPromotedCompetitorsIntoLastMedalRaces;
/**
*
* @param numberOfPromotedCompetitorsIntoLastMedalRaces
* The last index for this array refers to the last medal race; e.g., the "Grand Final" race in an iQFOil
* regatta with the medal series consisting of a "Quarter Final," a "Semi Final" and a "Grand Final". The
* last-but-one index in the example would then refer to the Semi Final, and so on. The array may be
* empty, meaning that no competitor is promoted into any medal race. The field always has to refer to a
* valid array.
*/
public LowPointWithEliminatingMedalSeriesWithPromotions(int[] numberOfPromotedCompetitorsIntoLastMedalRaces) {
super();
this.numberOfPromotedCompetitorsIntoLastMedalRaces = numberOfPromotedCompetitorsIntoLastMedalRaces;
}
public int getNumberOfCompetitorsBetterThanThoseSailingInRace(RaceColumnInSeries medalRace) {
final List<? extends RaceColumnInSeries> allMedalRacesInSeries = Util.asList(medalRace.getSeries().getRaceColumns());
int result = 0;
int indexInNumberOfPromotedCompetitorsIntoLastMedalRaces = numberOfPromotedCompetitorsIntoLastMedalRaces.length-1;
if (allMedalRacesInSeries.size() > 1) {
for (final ListIterator<? extends RaceColumnInSeries> i=allMedalRacesInSeries.listIterator(allMedalRacesInSeries.size()); i.hasPrevious() && i.previous() != medalRace; ) {
result += numberOfPromotedCompetitorsIntoLastMedalRaces[indexInNumberOfPromotedCompetitorsIntoLastMedalRaces--];
}
}
return result;
}
@Override
public int compareByMedalRaceParticipation(int zeroBasedIndexOfLastMedalSeriesInWhichO1Scored,
int zeroBasedIndexOfLastMedalSeriesInWhichO2Scored) {
// TODO We'd like to consider those as "having participated" in a medal race that may not have a score but have been promoted already to a later medal race based on their opening series result;
// For that we need to check all medal race columns and need to know the two competitors.
// If promoted to a later medal race but not sailed in the one currently considered, consider as "has participated."
// If both participated, move on to next medal race column, if any. If last medal race column, return 0.
// If one competitor is considered as "has participated" and the other one not, prefer the one that "has participated" over the one that has not.
return super.compareByMedalRaceParticipation(zeroBasedIndexOfLastMedalSeriesInWhichO1Scored, zeroBasedIndexOfLastMedalSeriesInWhichO2Scored);
}
}