# Scoring

EU/EFTA teams and guest teams will have seperate scoreboards, but will use the same platforms.

## Jeopardy​

Jeopardy challenges will using dynamic scoring.

### Parameters​

solved_by_teams is the number of teams that have solved a challenge.

total_teams is the total number of teams.

max_score is the maximum score for the challenge. In ECSC 2023 this is set 1000 points.

min_score is the minimum score for the challenge. In ECSC 2023 this is set 400 points.

If only one teams solves a challenge, the challenge will be worth the maximum score.

If 75% or more teams solves a challenge, it will be worth the minimum score.

If there are between 1 and 75% of teams that have solved a challenge, the points for that challenge is calculated by a simple linear interpolation between these two endpoints.

### Reference implementation​

# ECSC 2023 jeopardy dynamic scoring algorithmdef dynamic_score(solved_by_teams: int, total_teams: int, max_score: int, min_score: int):    # Calculate the ratio of solved teams to total teams    ratio = solved_by_teams / total_teams    # Ensure that if only one team solves the challenge, they'll get the max_score    fraction_high_score = 1 / total_teams    # If more than 3/4 of teams solves a challenge it drops to min_score    # "+ fraction_high_score" is there make sure this also works correctly when total_teams    # is an integer multiple of 4    fraction_low_score = 3/4 + fraction_high_score    match ratio:        # Set to the maximum score if less than the fraction for highest score have solved challenge        case ratio if ratio <= fraction_high_score:            score = max_score        # Set to the minimum score if more than the fraction for lowest score have solved challenge        case ratio if ratio >= fraction_low_score:            score = min_score        # All other score must be between max_score and min_score        # Here we use a simple linear interpolation between min_score and max_score when the fraction        # of teams that have solved a challenge is between fraction_hig_score and fraction_low_score        case _:            score = max_score - (max_score - min_score) * (ratio - fraction_high_score) / (fraction_low_score - fraction_high_score)    return round(score)# Simple tests showing score for a challenge based on number of solvesif __name__ == '__main__':    MAX_SCORE = 1000    MIN_SCORE = 400    TOTAL_TEAMS = 28    print(f"\nECSC EU/EFTA with {TOTAL_TEAMS} teams\n"          f"Solves\tPoints\tPercent drop in score\n{'-' * 80}")    number_of_teams = TOTAL_TEAMS    for i in range(number_of_teams + 1):        score = dynamic_score(i, number_of_teams, MAX_SCORE, MIN_SCORE)        print(f"{i:2}\t\t{score:4}\t{1-(score/MAX_SCORE):>6.2%}")    TOTAL_TEAMS = 7    print(f"\nECSC Guests with {TOTAL_TEAMS} teams\n"          f"Solves\tPoints\tPercent drop in score\n{'-' * 80}")    number_of_teams = TOTAL_TEAMS    for i in range(number_of_teams + 1):        score = dynamic_score(i, number_of_teams, MAX_SCORE, MIN_SCORE)        print(f"{i:2}\t\t{score:4}\t{1-(score/MAX_SCORE):>6.2%}")

## Attack/Defense​

### Tick score per service​

$T_{s} = \left( D_{s} + S_{s} \right) + \sum_{a=1}^{t} A_{s_{a}}$

where:

$s$ is the service id.

$T_{s}$ is the teams' total score in a tick for a service.

$D_{s}$ is the defense score in a tick for a service.

$S_{s}$ is the SLA score in a tick for a service.

$a$ is the attack teams' id.

$t$ is the total number of teams.

$A_{s_{a}}$ is the score for a successful attack on team $a$'s service in a tick.

### Attack​

$A = 1 + \frac{1}{f} + 1 \cdot \left\{ \begin{array}{cl} 1 & if\ r_{a} \leq r_{v} \\ 1 - R & if\ r_{a} > r_{v} \\ \end{array} \right. and\ f > 0$

where:

$R$ is the score reduction for attacking down, and $R$ is calculated with:

$R = \frac{4}{5} \cdot \left ( \frac{r_{v}-r_{a}}{t} \right )^{2}$

and:

$A$ is a the attack score for a successful attack on a vitcim in a tick.

$f$ is the number of teams that have captured a flag from the victimin a tick.

$r_{a}$ is the rank of attacker in tick flag was lost captured from victim.

$r_{v}$ is the rank of the victim in tick flag was lost to attacker.

$t$ is the total number of teams.

Attack score is only calculated if a flag was captured.

### SLA​

$S = \left\{ \begin{array}{cl} 3 & if\ service\ is\ up \\ \frac{3}{2} & if\ service\ is\ recovering\\ 0 & if\ service\ is\ down \\ \end{array} \right.$

where:

$S$ is a the SLA score for a keeping the service up in a tick.

A service is considered up if the service checker returns the state UP.

A service is considered recovering if the service checker returns the state RECOVERING.

A service is considered down if service cheke returns any other state.

### Defense​

$D = \left\{ \begin{array}{cl} 2 + \frac{1}{d} & if\ S > 0\ and\ d > 0 \\ 0 & if\ S = 0 \\ \end{array} \right.$

where:

$D$ is a the defense score for successfully defending a service in a tick from all attackers.

$d$ is the number of teams that did not loose flags for service in tick.

### Full scoring equations​

The full form of scoring equations for A/D are documented in this document.

## Overall ranking​

The overall rank will be based on normalized scores from each day.

Jeopardy will count 50% of the overall score and Attack/Defense will count 50% of the overall score.

Day 1Day 2Day 3
CTF styleJeopardyA/DJeopardy
Weigth percentage25%50%25%
Weigthed normalized max points5000100005000

### Calcultation of normalized day score​

Calcultation of normalized score per team per day:

$D_{t_{d}} = \frac{S_{t_{d}}}{H_{d}} \cdot N_{d}$

where:

$t$ is the team number.

$d$ is the day number.

$D_{t_{d}}$ is a teams normalized score for day $d$.

$S_{t_{d}}$ is the teams total score of the day $d$.

$H_{d}$ is the highest total score of the day $d$.

$N_{d}$ is the weighted normalized max score of the day $d$.

### Final ranking score​

Final ranking score for a team is:

$F_{t} = D_{t_{1}} + D_{t_{2}} + D_{t_{3}}$

where:

$F_{t}$ is the teams' final ranking score.

$D_{t_{1}}$ is the teams' normalized score from day 1.

$D_{t_{2}}$ is the teams' normalized score from day 2.

$D_{t_{3}}$ is the teams' normalized score from day 3.

### Tiebreaker​

If two teams, $x$ and $y$, end up with the same final ranking score, that is $F_{x} = F_{y}$, then the results from Attack/Defense on day 2 will be used as a tiebreaker.

The team with the highest score in Attack/Defense will be ranked highest of the teams with equal final ranking score.