| Title: | Tournament Generator |
|---|---|
| Description: | Create and manage tournament brackets for various competition formats including single elimination, double elimination, round robin, Swiss system, and group-stage-to-knockout tournaments. Provides tools for seeding, scheduling, recording results, and tracking standings. |
| Authors: | Theo Blauberg [aut, cre, cph] (ORCID: <https://orcid.org/0000-0003-1780-0365>) |
| Maintainer: | Theo Blauberg <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.1.0.9000 |
| Built: | 2026-05-27 08:54:12 UTC |
| Source: | https://github.com/bbtheo/bracketeer |
Add a stage to a tournament specification
add_stage(spec, stage_id, stage)add_stage(spec, stage_id, stage)
spec |
A |
stage_id |
Unique stage identifier. |
stage |
Stage definition object. |
Updated tournament_spec.
Add a transition between stages
add_transition( spec, from, to, rule = NULL, seeding = "by_source_rank", take = NULL, priority = 1L, consume = TRUE, allow_overlap = FALSE, transition_id = NULL )add_transition( spec, from, to, rule = NULL, seeding = "by_source_rank", take = NULL, priority = 1L, consume = TRUE, allow_overlap = FALSE, transition_id = NULL )
spec |
A |
from |
Source stage ID, or |
to |
Destination stage ID. |
rule |
Transition rule object (optional for MVP graph wiring). |
seeding |
Seeding policy label. |
take |
Selector object for transition participant selection. |
priority |
Transition resolution priority. |
consume |
Whether selected participants are consumed. |
allow_overlap |
Whether overlap is allowed across transitions. |
transition_id |
Transition ID. If |
Updated tournament_spec.
Check if current round is complete and update bracket state.
advance(x, stage = NULL, ...) ## S3 method for class 'bracket' advance(x, stage = NULL, ...) ## S3 method for class 'double_elim_bracket' advance(x, stage = NULL, ...) ## S3 method for class 'group_stage_knockout' advance(x, stage = NULL, ...) ## S3 method for class 'single_elim_bracket' advance(x, stage = NULL, ...) ## S3 method for class 'swiss_bracket' advance(x, stage = NULL, ...) ## S3 method for class 'tournament' advance(x, stage = NULL, ...)advance(x, stage = NULL, ...) ## S3 method for class 'bracket' advance(x, stage = NULL, ...) ## S3 method for class 'double_elim_bracket' advance(x, stage = NULL, ...) ## S3 method for class 'group_stage_knockout' advance(x, stage = NULL, ...) ## S3 method for class 'single_elim_bracket' advance(x, stage = NULL, ...) ## S3 method for class 'swiss_bracket' advance(x, stage = NULL, ...) ## S3 method for class 'tournament' advance(x, stage = NULL, ...)
x |
A bracket object. |
stage |
Optional stage identifier for tournament methods. |
... |
Additional method-specific arguments. |
Updated bracket object
Select bottom ranked participants from source standings
bottom_n(n)bottom_n(n)
n |
Positive integer count. |
A bracketeer_selector object.
Select bottom ranked participants per group
bottom_per_group(n)bottom_per_group(n)
n |
Positive integer count per group. |
A bracketeer_selector object.
Build a live tournament runtime from a specification
build(x, participants)build(x, participants)
x |
A |
participants |
Character vector of participant names, or a data.frame
with a |
A tournament runtime object.
my_spec <- spec() |> swiss("open", rounds = 3) |> single_elim("playoffs", take = top_n(4)) # Materialize with participants trn <- build(my_spec, paste("Team", LETTERS[1:8]))my_spec <- spec() |> swiss("open", rounds = 3) |> single_elim("playoffs", take = top_n(4)) # Materialize with participants trn <- build(my_spec, paste("Team", LETTERS[1:8]))
Build a tournament runtime from a tournament specification
build_tournament(spec, participants)build_tournament(spec, participants)
spec |
A |
participants |
Character vector of participant names, or a data.frame
with a |
A tournament runtime object.
Compute tournament rankings
compute_tournament_rankings(tournament)compute_tournament_rankings(tournament)
tournament |
A |
Data frame with rank and participant, or NULL when unavailable.
Double elimination tournament with winners and losers brackets.
double_elim(participants, ...)double_elim(participants, ...)
participants |
Character vector of participant names, or a data.frame with a 'name' column and optional 'seed' column. |
... |
Additional arguments passed to bracket constructors or tournament stage-verb dispatch methods. |
A double_elim_bracket object
# Double elimination bracket (two losses to be eliminated) trn <- tournament(paste("Team", LETTERS[1:8])) |> double_elim("bracket") # After Swiss rounds trn <- tournament(paste("Team", LETTERS[1:16])) |> swiss("open", rounds = 4) |> double_elim("playoffs", take = top_n(8))# Double elimination bracket (two losses to be eliminated) trn <- tournament(paste("Team", LETTERS[1:8])) |> double_elim("bracket") # After Swiss rounds trn <- tournament(paste("Team", LETTERS[1:16])) |> swiss("open", rounds = 4) |> double_elim("playoffs", take = top_n(8))
Export tournament matches across materialized stages
export_matches(tournament)export_matches(tournament)
tournament |
A |
Data frame with stage-tagged matches and compound match IDs.
Export tournament standings across materialized stages
export_standings(tournament)export_standings(tournament)
tournament |
A |
Data frame with stage-tagged standings.
Export tournament routing log entries
export_tournament_log(tournament)export_tournament_log(tournament)
tournament |
A |
Data frame with one row per routing log entry.
Select participants using a custom predicate function
filter_by(fn)filter_by(fn)
fn |
A transition predicate function. |
A bracketeer_selector object.
Resolve source stage from most recently defined stage order
from_previous()from_previous()
Sentinel object to be resolved by add_transition().
Get stage IDs currently ready to advance
get_ready_stages(tournament)get_ready_stages(tournament)
tournament |
A |
Character vector of stage IDs in deterministic order.
Get transition routing log entries
get_routing_log(tournament)get_routing_log(tournament)
tournament |
A |
List of routing log entries in append order.
Create a group stage followed by knockout bracket
group_stage_knockout(participants, ...)group_stage_knockout(participants, ...)
participants |
Character vector of participant names, or a data.frame with a 'name' column and optional 'seed' column. |
... |
Additional arguments passed to bracket constructors or tournament stage-verb dispatch methods. |
A group_stage_knockout object
Check whether a stage is complete
is_stage_complete(x, ...)is_stage_complete(x, ...)
x |
A stage bracket object or |
... |
Additional method-specific arguments. |
Logical scalar.
Select losers from a source stage by elimination round
losers(round = "all", stage = NULL, ordering = "elimination_round")losers(round = "all", stage = NULL, ordering = "elimination_round")
round |
One of |
stage |
Optional stage selector (reserved for future use). |
ordering |
Ordering mode: |
A bracketeer_selector object.
Inspect tournament matches
matches(x, stage = NULL, status = "pending") ## S3 method for class 'tournament' matches(x, stage = NULL, status = "pending")matches(x, stage = NULL, status = "pending") ## S3 method for class 'tournament' matches(x, stage = NULL, status = "pending")
x |
A |
stage |
Optional stage identifier. |
status |
One of |
Data frame of matches.
trn <- tournament(c("A", "B", "C", "D")) |> round_robin("groups") # Get pending matches matches(trn, "groups") # Get all matches across stages matches(trn, status = "all")trn <- tournament(c("A", "B", "C", "D")) |> round_robin("groups") # Get pending matches matches(trn, "groups") # Get all matches across stages matches(trn, status = "all")
take = routingConstruct a selector object for transition take = routing
new_selector(kind, params = list(), evaluator)new_selector(kind, params = list(), evaluator)
kind |
Selector kind label. |
params |
Selector parameters list. |
evaluator |
Function implementing selection logic. |
A bracketeer_selector object.
Alias for from_previous() used by the rewritten stage-verb API.
previous_stage()previous_stage()
Sentinel object to be resolved by transition wiring.
teams <- paste("Team", LETTERS[1:8]) # Implicit: defaults to previous_stage() trn <- tournament(teams) |> swiss("open", rounds = 3) |> single_elim("playoffs", take = top_n(4)) # Explicit: useful for branching trn <- tournament(teams) |> round_robin("groups") |> single_elim("finals", from = previous_stage(), take = top_n(2))teams <- paste("Team", LETTERS[1:8]) # Implicit: defaults to previous_stage() trn <- tournament(teams) |> swiss("open", rounds = 3) |> single_elim("playoffs", take = top_n(4)) # Explicit: useful for branching trn <- tournament(teams) |> round_robin("groups") |> single_elim("finals", from = previous_stage(), take = top_n(2))
Print bracketeer objects
## S3 method for class 'group_stage_knockout' print(x, ...) ## S3 method for class 'bracket_match' print(x, ...) ## S3 method for class 'bracket' print(x, ...) ## S3 method for class 'double_elim_bracket' print(x, ...) ## S3 method for class 'tournament' print(x, ...)## S3 method for class 'group_stage_knockout' print(x, ...) ## S3 method for class 'bracket_match' print(x, ...) ## S3 method for class 'bracket' print(x, ...) ## S3 method for class 'double_elim_bracket' print(x, ...) ## S3 method for class 'tournament' print(x, ...)
x |
A bracket or match object. |
... |
Additional arguments (unused). |
The object, invisibly.
Returns a transition rule function intended for use with add_transition().
qualify_losers(round = "all", stage = NULL, ordering = "elimination_round")qualify_losers(round = "all", stage = NULL, ordering = "elimination_round")
round |
One of |
stage |
Optional stage selector (reserved for future use). |
ordering |
Ordering mode: |
A transition rule function.
Returns a transition rule function intended for use with add_transition().
During advance(), this selects all participants still available from the
source stage after higher-priority consuming transitions have resolved.
qualify_remaining()qualify_remaining()
A transition rule function.
Get tournament rankings
rankings(tournament)rankings(tournament)
tournament |
A |
Data frame of rankings.
Select entrants remaining in the current transition source pool
remaining()remaining()
A bracketeer_selector object.
Convenience wrapper around set_result() for tournament workflows.
result(tournament, stage, match, score, overwrite = FALSE, auto_advance = NULL)result(tournament, stage, match, score, overwrite = FALSE, auto_advance = NULL)
tournament |
A |
stage |
Stage identifier containing the match. |
match |
Match identifier inside |
score |
Numeric vector score payload. For a single match, pass
|
overwrite |
Logical; forwards to |
auto_advance |
Optional logical override. If |
Updated tournament object.
teams <- c("A", "B", "C", "D") trn <- tournament(teams) |> round_robin("groups") # Enter a single result trn <- result(trn, "groups", match = 1, score = c(2, 1))teams <- c("A", "B", "C", "D") trn <- tournament(teams) |> round_robin("groups") # Enter a single result trn <- result(trn, "groups", match = 1, score = c(2, 1))
Convenience wrapper for entering multiple match results for one stage.
results(tournament, stage, df, overwrite = FALSE, auto_advance = NULL)results(tournament, stage, df, overwrite = FALSE, auto_advance = NULL)
tournament |
A |
stage |
Stage identifier containing the matches. |
df |
Data frame with required columns: |
overwrite |
Logical; forwards to |
auto_advance |
Optional logical override for the final row. If |
Updated tournament object.
teams <- c("A", "B", "C", "D") trn <- tournament(teams) |> round_robin("groups") m <- matches(trn, "groups") trn <- results(trn, "groups", data.frame( match = m$match_id, score1 = c(2, 1, 3), score2 = c(1, 2, 0) ))teams <- c("A", "B", "C", "D") trn <- tournament(teams) |> round_robin("groups") m <- matches(trn, "groups") trn <- results(trn, "groups", data.frame( match = m$match_id, score1 = c(2, 1, 3), score2 = c(1, 2, 0) ))
Round robin tournament where each participant plays every other participant.
round_robin(participants, ...)round_robin(participants, ...)
participants |
Character vector of participant names, or a data.frame with a 'name' column and optional 'seed' column. |
... |
Additional arguments passed to bracket constructors or tournament stage-verb dispatch methods. |
A round_robin_bracket object
# Simple round robin trn <- tournament(c("A", "B", "C", "D")) |> round_robin("groups") # Multiple groups (World Cup style) teams <- paste("Team", sprintf("%02d", 1:32)) trn <- tournament(teams) |> round_robin("groups", groups = 8)# Simple round robin trn <- tournament(c("A", "B", "C", "D")) |> round_robin("groups") # Multiple groups (World Cup style) teams <- paste("Team", sprintf("%02d", 1:32)) trn <- tournament(teams) |> round_robin("groups", groups = 8)
Get transition routing log
routing_log(tournament)routing_log(tournament)
tournament |
A |
Data frame audit trail.
Configure tournament outcome depth
set_outcome(spec, track_placements = 1L)set_outcome(spec, track_placements = 1L)
spec |
A |
track_placements |
Number of placements to track. |
Updated tournament_spec.
Single elimination (knockout) tournament where losing a match eliminates the participant from the tournament.
single_elim(participants, ...)single_elim(participants, ...)
participants |
Character vector of participant names, or a data.frame with a 'name' column and optional 'seed' column. |
... |
Additional arguments passed to bracket constructors or tournament stage-verb dispatch methods. |
A single_elim_bracket object
# Simple knockout bracket trn <- tournament(paste("Team", LETTERS[1:8])) |> single_elim("bracket") # Chain after group stage trn <- tournament(c("A", "B", "C", "D")) |> round_robin("groups") |> single_elim("finals", take = top_n(2))# Simple knockout bracket trn <- tournament(paste("Team", LETTERS[1:8])) |> single_elim("bracket") # Chain after group stage trn <- tournament(c("A", "B", "C", "D")) |> round_robin("groups") |> single_elim("finals", take = top_n(2))
Stage specifications describe how to materialize a stage bracket from a
participant set inside a tournament_spec graph.
single_elim_stage( seed = TRUE, third_place = FALSE, best_of = NULL, reseed = FALSE ) double_elim_stage( seed = TRUE, grand_final_reset = TRUE, best_of = NULL, reseed = FALSE ) round_robin_stage( home_away = FALSE, n_rounds = NULL, best_of = NULL, tiebreakers = NULL, groups = NULL ) swiss_stage( rounds = NULL, seed = TRUE, allow_ties = TRUE, bye_points = 1, best_of = NULL, tiebreakers = NULL ) group_stage_knockout_stage( groups = 2, advance_per_group = 2, seed = TRUE, group_home_away = FALSE, group_best_of = NULL, group_tiebreakers = NULL, knockout_type = "single_elim", knockout_seed = TRUE, third_place = FALSE, grand_final_reset = TRUE, knockout_best_of = NULL ) two_leg_stage( seed = TRUE, third_place = FALSE, away_goals = TRUE, reseed = FALSE )single_elim_stage( seed = TRUE, third_place = FALSE, best_of = NULL, reseed = FALSE ) double_elim_stage( seed = TRUE, grand_final_reset = TRUE, best_of = NULL, reseed = FALSE ) round_robin_stage( home_away = FALSE, n_rounds = NULL, best_of = NULL, tiebreakers = NULL, groups = NULL ) swiss_stage( rounds = NULL, seed = TRUE, allow_ties = TRUE, bye_points = 1, best_of = NULL, tiebreakers = NULL ) group_stage_knockout_stage( groups = 2, advance_per_group = 2, seed = TRUE, group_home_away = FALSE, group_best_of = NULL, group_tiebreakers = NULL, knockout_type = "single_elim", knockout_seed = TRUE, third_place = FALSE, grand_final_reset = TRUE, knockout_best_of = NULL ) two_leg_stage( seed = TRUE, third_place = FALSE, away_goals = TRUE, reseed = FALSE )
seed |
Logical or character seed method. |
third_place |
Logical; include third-place match. |
best_of |
Optional best-of value (must be odd). |
reseed |
Logical; reseed between rounds for supported formats. |
grand_final_reset |
Logical; allow grand-final reset. |
home_away |
Logical; whether repeated pairings alternate home/away. |
n_rounds |
Number of round-robin cycles. |
tiebreakers |
Ordered tiebreakers. |
groups |
Number of groups. |
rounds |
Number of Swiss rounds. |
allow_ties |
Logical; whether ties are allowed. |
bye_points |
Points awarded for a bye. |
advance_per_group |
Number of qualifiers per group. |
group_home_away |
Logical; home/away behavior in groups. |
group_best_of |
Optional best-of in groups. |
group_tiebreakers |
Ordered group-stage tiebreakers. |
knockout_type |
Knockout format: |
knockout_seed |
Logical or character seed method for knockout. |
knockout_best_of |
Optional knockout best-of value. |
away_goals |
Logical; enable away-goals tiebreaker. |
A stage_spec object.
Select an inclusive standings slice per group
slice_per_group(from, to)slice_per_group(from, to)
from |
Positive integer starting position. |
to |
Positive integer ending position (must be |
A bracketeer_selector object.
Select an inclusive standings slice
slice_range(from, to)slice_range(from, to)
from |
Positive integer starting position. |
to |
Positive integer ending position (must be |
A bracketeer_selector object.
Create a bracketeer tournament specification
spec()spec()
A bracketeer_spec object.
# Create a reusable tournament blueprint my_spec <- spec() |> round_robin("groups") |> single_elim("finals", take = top_n(2)) # Build with different participant lists trn1 <- build(my_spec, c("A", "B", "C", "D")) trn2 <- build(my_spec, c("W", "X", "Y", "Z"))# Create a reusable tournament blueprint my_spec <- spec() |> round_robin("groups") |> single_elim("finals", take = top_n(2)) # Build with different participant lists trn1 <- build(my_spec, c("A", "B", "C", "D")) trn2 <- build(my_spec, c("W", "X", "Y", "Z"))
Convenience sugar for branching stage fan-out. Compiles into deterministic
add_transition() calls.
split_stage( spec, from, into, priority_start = 1L, consume = TRUE, allow_overlap = FALSE, seeding = "by_source_rank" )split_stage( spec, from, into, priority_start = 1L, consume = TRUE, allow_overlap = FALSE, seeding = "by_source_rank" )
spec |
A |
from |
Source stage ID, or |
into |
Named list mapping destination stage IDs to transition rules, or
branch configs with a required |
priority_start |
Starting priority for branch transitions when a branch
does not explicitly provide |
consume |
Default |
allow_overlap |
Default |
seeding |
Default seeding policy for branches. |
Updated tournament_spec.
Inspect tournament stage status
stage_status(tournament)stage_status(tournament)
tournament |
A |
Data frame with one row per stage.
Inspect tournament standings
standings(x, stage = NULL) ## S3 method for class 'tournament' standings(x, stage = NULL)standings(x, stage = NULL) ## S3 method for class 'tournament' standings(x, stage = NULL)
x |
A |
stage |
Optional stage identifier. |
Data frame of standings.
trn <- tournament(c("A", "B", "C", "D")) |> round_robin("groups") # Enter some results m <- matches(trn, "groups") trn <- result(trn, "groups", m$match_id[1], score = c(2, 1)) # View current standings standings(trn, "groups")trn <- tournament(c("A", "B", "C", "D")) |> round_robin("groups") # Enter some results m <- matches(trn, "groups") trn <- result(trn, "groups", m$match_id[1], score = c(2, 1)) # View current standings standings(trn, "groups")
Summarize bracketeer objects
## S3 method for class 'bracket' summary(object, ...)## S3 method for class 'bracket' summary(object, ...)
object |
A bracket object. |
... |
Additional arguments (unused). |
The object, invisibly.
Swiss system pairs participants by similar records each round.
swiss(participants, ...)swiss(participants, ...)
participants |
Character vector of participant names, or a data.frame with a 'name' column and optional 'seed' column. |
... |
Additional arguments passed to bracket constructors or tournament stage-verb dispatch methods. |
A swiss_bracket object
# Swiss system followed by top-cut playoffs teams <- paste("Team", LETTERS[1:16]) trn <- tournament(teams) |> swiss("open", rounds = 5) |> single_elim("playoffs", take = top_n(8))# Swiss system followed by top-cut playoffs teams <- paste("Team", LETTERS[1:16]) trn <- tournament(teams) |> swiss("open", rounds = 5) |> single_elim("playoffs", take = top_n(8))
For tournament runtimes, this un-materializes a stage and its downstream dependents so upstream results can be corrected and replayed.
teardown(x, stage = NULL, ...) ## S3 method for class 'bracket' teardown(x, stage = NULL, ...) ## S3 method for class 'tournament' teardown(x, stage = NULL, ...)teardown(x, stage = NULL, ...) ## S3 method for class 'bracket' teardown(x, stage = NULL, ...) ## S3 method for class 'tournament' teardown(x, stage = NULL, ...)
x |
A bracket or tournament object. |
stage |
Stage identifier to teardown (tournament method). |
... |
Additional method-specific arguments. |
Updated object.
Select top ranked participants from source standings
top_n(n)top_n(n)
n |
Positive integer count. |
A bracketeer_selector object.
# Route top 4 to playoffs trn <- tournament(paste("Team", LETTERS[1:8])) |> swiss("open", rounds = 3) |> single_elim("playoffs", take = top_n(4))# Route top 4 to playoffs trn <- tournament(paste("Team", LETTERS[1:8])) |> swiss("open", rounds = 3) |> single_elim("playoffs", take = top_n(4))
Select top ranked participants per group
top_per_group(n)top_per_group(n)
n |
Positive integer count per group. |
A bracketeer_selector object.
# World Cup style: 8 groups, top 2 per group advance teams <- paste("Team", sprintf("%02d", 1:32)) trn <- tournament(teams) |> round_robin("groups", groups = 8) |> single_elim("knockout", take = top_per_group(2))# World Cup style: 8 groups, top 2 per group advance teams <- paste("Team", sprintf("%02d", 1:32)) trn <- tournament(teams) |> round_robin("groups", groups = 8) |> single_elim("knockout", take = top_per_group(2))
Create an empty live tournament pipeline
tournament(participants, auto_advance = TRUE)tournament(participants, auto_advance = TRUE)
participants |
Character vector of participant names, or a data.frame
with a |
auto_advance |
Logical scalar. Stored as the runtime default for future result-entry helpers. |
A tournament runtime object with no stages materialized yet.
# Simple tournament with auto-advance teams <- c("Lions", "Bears", "Eagles", "Wolves") trn <- tournament(teams) |> round_robin("groups") |> single_elim("finals", take = top_n(2)) # Manual advance mode trn_manual <- tournament(teams, auto_advance = FALSE) |> swiss("open", rounds = 3)# Simple tournament with auto-advance teams <- c("Lions", "Bears", "Eagles", "Wolves") trn <- tournament(teams) |> round_robin("groups") |> single_elim("finals", take = top_n(2)) # Manual advance mode trn_manual <- tournament(teams, auto_advance = FALSE) |> swiss("open", rounds = 3)
Construct a multi-stage tournament specification object.
tournament_spec()tournament_spec()
A tournament_spec object.
Alias for two_leg_knockout() used by the tournament stage-verb API.
two_leg(participants, ...)two_leg(participants, ...)
participants |
Participants, a spec object, or a tournament object. |
... |
Additional arguments forwarded to |
A bracket, spec, or tournament depending on participants.
# Two-leg knockout (Champions League style) teams <- paste("Club", sprintf("%02d", 1:16)) trn <- tournament(teams) |> round_robin("groups", groups = 4) |> two_leg("knockouts", take = top_per_group(2))# Two-leg knockout (Champions League style) teams <- paste("Club", sprintf("%02d", 1:16)) trn <- tournament(teams) |> round_robin("groups", groups = 4) |> two_leg("knockouts", take = top_per_group(2))
Validate a tournament spec preflight
validate(x, n)validate(x, n)
x |
A |
n |
Participant count for feasibility checks. |
A preflight validation summary.
my_spec <- spec() |> round_robin("groups", groups = 4) |> single_elim("knockout", take = top_per_group(2)) # Check if 16 participants can work validate(my_spec, n = 16)my_spec <- spec() |> round_robin("groups", groups = 4) |> single_elim("knockout", take = top_per_group(2)) # Check if 16 participants can work validate(my_spec, n = 16)
Validates a tournament_spec against a participant count without running a
live tournament. This preflight catches infeasible routing paths and stage
size mismatches early.
validate_tournament(spec, n_participants)validate_tournament(spec, n_participants)
spec |
A |
n_participants |
Positive integer participant count. |
A tournament_validation summary list.
Validate a tournament specification
validate_tournament_spec(spec)validate_tournament_spec(spec)
spec |
A |
The validated tournament_spec.
Get tournament winner
winner(tournament)winner(tournament)
tournament |
A |
Winner name or NA_character_.
teams <- c("A", "B", "C", "D") trn <- tournament(teams) |> round_robin("groups") |> single_elim("finals", take = top_n(2)) # ... enter all results ... # Get the champion winner(trn)teams <- c("A", "B", "C", "D") trn <- tournament(teams) |> round_robin("groups") |> single_elim("finals", take = top_n(2)) # ... enter all results ... # Get the champion winner(trn)