Background
I am in the early stages of writing a "tournament bracketing" application (C#, although any object-oriented language would be appropriate). This application would theoretically generate bracket sheets for multiple types of tournaments:
- Single-elimination
- Double-elimination
- Double-elimination with "true second"
- Round robin
- Swiss-system
- ...and probably more that I've never even heard of, before.
For each type of tournament, I'd like to implement the 'bracket algorithm' as an instance of a common interface. In this way, I can make the system extensible, and easily add support for additional brackets in the future.
Given a variable list of 'competitors' - the user could simply choose their desired bracket plugin and poof, there's the generated bracket!
Design Challenges
I am currently struggling to visualize a design for bracketing; the needed APIs of the interface, and - more importantly - I'm not sure how to generically and flexibly represent the bracket 'model,' as a data structure. Some sort of node map, I guess?
Ideally, I'd need the interface to:
- Accept a variable-sized list of competitors as input
- Generate a graph (or other) structure as output, representing the 'flow' of the bracket.
- The graph structure would need to support some sort of 'Win / Lose' API, to 'advance' the various competitors through the bracket, and fill it in as it goes.
The Question
I wish I had a better way to phrase this question;
- How I do 'dis?
- What are your thoughts?
- What interface structure makes the most sense?
- How do I model this generically, in code?
My Initial Flailings
It wouldn't be a StackOverflow question unless I put some code on paper. Here are my initial thoughts;
// A plugin interface; generates a tournament bracket, given a list of competitors
public interface IBracketSheetGenerator
{
public IBracketSheet CreateBracket(IEnumerable<Competitor> competitors);
}
// Parent data structure, used to model a tournament bracket
public interface IBracketSheet
{
public IEnumerable<Competitor> Competitors { get; }
public IEnumerable<IBracketNode> Matches { get; }
}
// Node representing a single competitor match
public interface IBracketNode
{
public Competitor Left { get; }
public Competitor Right { get; }
public IBracketNode Winner { get; }
public IBracketNode Loser { get; }
// Advance the winner to the next winner's match,
// and the loser to the loser's match.
public Advance(Competitor winner, Competitor loser);
}
Right off the bat, I can see some shortcomings with my first attempt;
- How do I represent the 'winner' of the entire bracket?
- How do I represent losers who have been 'eliminated' from the bracket?
- How do I signal that the bracket has been completed/resolved? What does a resolved bracket look like?
- Does this framework support 'strange' brackets which don't fall into the simple 'elimination' mold (like round robin, for instance)?