# LoL Worlds: Swiss Stage to Top-Cut Bracket

    library(bracketeer)

This vignette models a League of Legends Worlds style event:

- A Swiss stage where all 16 teams compete over several rounds,
- The top 8 advance to a single-elimination top-cut bracket.

This is the canonical linear chain pattern — two stages in sequence with no branching. It demonstrates:

- `swiss("open", rounds = 5)` for a Swiss-system stage,
- `single_elim("top_cut", take = top_n(8))` reading from the prior stage automatically (no `from =` needed),
- `top_n(8)` as the simplest flat routing selector,
- the auto-advance default, and
- full inspection with `stage_status()`, `standings()`, and `winner()`.

## 1) Define the entrants

    teams <- c(
      "Gen.G",        "T1",          "Hanwha Life", "Dplus KIA",
      "BLG",          "TES",         "LNG",         "JDG",
      "G2",           "Fnatic",      "MAD Lions",   "BDS",
      "Cloud9",       "Team Liquid",  "FlyQuest",    "100 Thieves"
    )

    length(teams)

## 2) Define the tournament

Because the pipeline is a straight line, `from` is never written. The `single_elim` stage implicitly reads from `swiss` via `previous_stage()`.

    trn <- tournament(teams) |>
      swiss("open", rounds = 5) |>
      single_elim("top_cut", take = top_n(8))

This is the entire routing definition: 16 teams play a 5-round Swiss; the top 8 by Swiss standings advance to a single-elimination bracket.

## 3) Preflight check (spec path)

When reusing a format across multiple events, define a spec first and validate before building.

    worlds_spec <- spec() |>
      swiss("open", rounds = 5) |>
      single_elim("top_cut", take = top_n(8))

    validate(worlds_spec, n = 16)   # passes

    # Build for this year's entrants
    trn <- worlds_spec |> build(teams)

## 4) Inspect the Swiss schedule

    stage_status(trn)

    open_ms <- matches(trn, "open")
    nrow(open_ms)   # 5 rounds × 8 matches = 40 matches
    head(open_ms)

## 5) Enter Swiss results

Round-by-round entry. Swiss schedules are generated round-by-round as results come in, so you’ll see new pending matches after each round.

    for (i in seq_len(nrow(open_ms))) {
      trn <- trn |> result("open", match = open_ms$id[i], score = c(1, 0))

      # Refresh pending matches — Swiss generates each round dynamically.
      open_ms <- matches(trn, "open")
    }

After the final Swiss result, the top-cut stage materializes automatically.

## 6) Confirm advancement

    stage_status(trn)
    #   stage     status     complete  total  materialized
    #   open      complete         40     40          TRUE
    #   top_cut   active            0      7          TRUE

    standings(trn, "open")   # full Swiss standings, 1st through 16th
    matches(trn, "top_cut")  # 8-team bracket

## 7) Run the top-cut bracket

    cut_ms <- matches(trn, "top_cut")

    for (i in seq_len(nrow(cut_ms))) {
      trn <- trn |> result("top_cut", match = cut_ms$id[i], score = c(1, 0))
    }

## 8) Outcomes

    winner(trn)
    rankings(trn)
    routing_log(trn)

## 9) Manual advance mode

For tournament operations where stages advance on an explicit signal (e.g., after a broadcast break), use `auto_advance = FALSE`:

    trn <- tournament(teams, auto_advance = FALSE) |>
      swiss("open", rounds = 5) |>
      single_elim("top_cut", take = top_n(8))

    # ... enter all Swiss results ...

    # Stage does not advance until you say so:
    trn <- trn |> advance("open")

## 10) Batch result entry

`results()` accepts a data frame for entering multiple results at once.

    round1 <- data.frame(
      match  = matches(trn, "open")$id,
      score1 = rep(1L, 8),
      score2 = rep(0L, 8)
    )

    trn <- trn |> results("open", round1)