defmodule Bracketology do @moduledoc """ Bracketology is the art/science of seeding and playing out competitions. Imagine Alice and Bob play a single round of “rock-paper-scissors”. It is a single `Bracketology.Match` with 2 participants . If Alice plays scissors and Bob plays paper, then Alice wins. To store this data, we say Alice’s `rank` is `0` and Bob’s `rank` is `1`. If the `Participants` play “best-of-3” then we say this is 1 `Match` and the participants have a `score`, e.g. 2-1. To make this kind of competition accommodate more than 2 `Participants` we need to figure out “how can we decide a winner from n participants when we can only pair/play/compare 2 at a time?”. A `Stage` is the word used to describe the higher-level structure that: 1. contains all the matches 2. has a method for ranking n > 2 participants using multiple matches 3. has its own Participants, with their own rank. The simplest ranking method for multiple matches is a “single elimination” stage. This is the familiar binary-tree structure with knockout matches and a single final winner. In a single elimination stage, It is clear which `Stage Participant` will have rank 0. Other stage participants may share the same rank. For example, 2 participants knocked out in the first round will have the same rank. A lot of large-scale tournaments have multiple stages. For example, the world cup : - stage 0, round robin, 4 per group, players all meet once, 2 advance per group - stage 1, single elimination Since we alway want to have an overall winner, we need to have a yet higher-level structure to house all the stages, to have its own participants with their own ranks. This is what we call a `Tournament`. It should be seen that tournament → stages → matches model can be nested further still because all levels share the concept of “ranked participants”. For example, we could introduce a more deeply-nested structure within matches, but the details of this are game-dependant. Similarly, we could introduce a yet higher-level structure to house groups of tournaments, e.g. a “series”. In the best-of-3 rock-paper-scissors with just Alice and Bob presented above, we chose to create a single match instead of 2 or 3 matches (would only need 2 if, e.g. Alice won twice in a row). This is because the “best-of-3” is a detail of the particular rules decided by the tournament organiser. If they had instead been playing, say CS:G, the best-of-3 would be 3 different maps, each possibly consisting of many rounds, each consisting of many individual stats. To make it clear - a Match is far too simple a structure to represent the details of what actually went down. For example, Even if we know the score is 2-1, we don’t know who won first. This is acceptable because it shares a conceptual boundary with Stage, which is complicated. Grilla currently supports these 5 types of stages: - `Bracketology.StageTypes.SingleElimination` - double_elimination - round_robin - swiss - battle_royale Many tournaments are single-stage. Most of the rest are 2-stage, e.g. The International. Our multi-stage conceptual model (and much of the foundation code) is well-abstracted, but we explicitly support a small restricted set of 2-stage combinations. Supporting any n-stage combination is achievable, but would require more work (primarily writing tests and UI). Stages, like matches, have “rounds”. The first stage has `round=0`, the next has `round=1`. When the last match in a stage is finished and the match participants’ ranks are set, we calculate the stage participant ranks. The details of this depend on the stage type. The stage participants rank algorithm for each stage type is described later (TODO). If any 2 “relevant” stage participants have the same rank, the tournament organiser must break the tie by manually setting the stage participant ranks. By “relevant” stage participants, we mean those whose initial inferred rank meant that they would be eligible to be “prized” (if it is the final stage) or to advance to be seeded in the next stage. """ end