Ranking Engine

The ranking engine is a subset of classes designed to rank skaters by a wide-variety of user-configurable metrics.

Concepts

A skater rank is a skater’s ordinal in an ordered list of skaters. Most of the complex logic within the application requires that skaters be sorted by very specific critera.

For example, a skater’s Place within a race is the skater’s Rank by Finish Time, fastest-to-slowest. In the event that two skaters have the exact same time, we might consider them tied. The concept of a tie does not exist in set theory, however: in a one-dimensional list, two entities cannot inhabit the same ordinal.

Rank

Place

Skater

Time

1

1

Bob

56.722

2

1

Jim

56.722

3

3

Harry

58.328

4

4

Joe

59.100

While we can use logic to change the Place of the skater, their Rank, or ordinal within the list, is arbitrary or undefined. Jim could come before or after Bob. In the case of skater placement, a tie may be acceptable because we can assign both skaters the same place, but in many other cases we must define a way to break the tie. This is the case with Lane Position, where two skaters cannot physically inhabit the same position on the starting line. If we leave the logic for tie-breaking undefined, that means some unknown, but predictable, process may break the tie for us. This could be the order of the list of skaters in the competition, or ordered by last name, for example. This could reasonably be considered unfair by the skaters if certain people gained a slight advantage because the software just happens to prioritize skaters by last name. Instead, we’d want to define the process by which ties are resolved. Presumably this would be by random draw, but tie-breaking can (and often does) involve other metrics available to the application.

In more complex scenarios, such as Distance Classification, skater ranking is determined by a well-defined series of metrics. Skaters are ranked first by points awarded. In the case of a tie, by best time in the distance. Lastly ties would be broken by seed time. Here we see a pattern emerge where skaters are often ranked by a given metric with ties resolved by similarly specific metrics, with multiple levels of tie-breaking.

The way in which skaters are placed, seeded, or otherwise ranked can change between competitions and should be configurable (i.e. changes to the rules should not require software changes). Rules can change for regional, national, or international competitions. Rules change over time. The ranking engine provides a common interface for defining ranking behavior of skaters using configurable files.

Usage

Ranking Metric - The measure to capture (e.g. Time, Place, Points) Ranking Level - The level of the measure (e.g. National, Distance, Round, Race) Ranking Factor - The combination of Measure and Level (e.g. “National 1000 Time”, “Race Place”) Skater Rank Metrics - A collection of actual metrics collected

In the following example, skaters would be ranked by place, then by time, and lastly by random draw.

Configuration

"Ranking": [
  //Factor #1: Rank by place
  {  
    "Level": "Race",
    "Metric": "Place"
  },
  //Factor #2: Tie-break by best time in round
  {  
    "Level": "Round",
    "Metric": "Time"
  },
  //Factor #3: Ties resolved by random draw.
  {  
    "Randomize": true
  }
]

Code

//Assume factors were deserialized from the JSON above into the factors argument
IEnumerable<Skater> DoRanking(IEnumerable<Skater> skaters, IEnumerable<RankingFactor> factors, Race race)
{
  //SkaterRankMetrics constructor will collect and store the metrics defined in factors using the
  //supplied race and skater as context
  var metrics = skaters.Select(skater => new SkaterRankMetrics(skater, factors, race)); 

  //Hash represents all factors in a single integer value that can be used for sorting.
  return metrics.OrderBy(rank => rank.Hash);
}

Implementation

For “no-elimination” formats, ranking is defined in the Rules. The Rules for any given race can be chosen by the user. Multiple sets of rules are defined in the default settings for the application, allowing users to easily switch between rules (and ranking methods). For example, two different sets of rules may be named National Competitions and the other Regional Competitions, where perhaps in the latter lane position is always random. Ranking is configured specifically in the RoundSettings class, with different settings for the first round of the distance and of the first round of the competition. This would allow the first round of the competition to be seeded by a skater’s best time (seed time), with the subsequent distances seeded by Distance Classification.

(See also: ProgressionRules, RoundSettings)