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)?
Just brainstorming here, but I guess I would model the concept of a Round too. For the elimination systems rounds already make sense, but you should be able to simulate rounds for the other systems as well. I think the total number of rounds can be predetermined for all of them.
Each round has matches and each match has winners and losers, the implementation of the bracket system would be able to generate the next matches after a round is completed and you supply the outcome of each match.
If a competitor is not placed on a match in the subsequent round, they're "out". Perhaps the bracket system could return an ordered list of competitors representing the current standing, or even a custom CompetitorAndScore class that contains statistics?
Related
I'm writing an RPG in C#, I have the character classes initialising nicely but I'm struggling with the attack classes.
Each attack will have its unique damage calculation formulas based off of multiple stats and eventually decorators.
Is there a way to dynamically create/append these damage formulas and decorators, or should I create a unique class for each attack that extends a generic attack class?
Here is some Pseudocode for what I'm after:
public class Attack
{
public string Name {get; set;}
List<Decorators> DamageCalc;
public Attack(string[] data, List<Decorators> decorators)
{
Name = data[DataList.Name]; //I'm using constants to keep my indexes readable
DamageCalc = data[DataList.Damage]; //i.e. strength * 10 + agility
Decorators = decorators
ApplyDecorators(Decorators)
}
public double DamageCalculation(Character attacker)
{
return DamageCalc; //attacker.Strength * 10 + attacker.Agility
}
...
}
Flexibility to add new features and behaviours is of particular interest to me.
Many thanks for your input!
Edit 1
Where I to use JSON, would there be any simple way to relate JSON fields to my Character class's stat variables or do I need write custom code to interoperate it?
Off hand I can't think of a tidy way to use a JSON field, or any field for that matter, that can dynamically collect information from my Character class.
Edit 2
Ideally this would allow me to dynamically create all my attacks as instances of a single attack class by taking data from a JSON file, string, XML file or database table.
I changed the code sample on the DamageCalculation method.
Closed
I the selected answer does provide a solution for my particular problem. It seems that I really would have to write code to parse formulas and generate the dynamic tool that I'm envisioning. As such I will see if I can get around this particular problem from a design perspective.
You need to write a base class that contain the signature of your calculations and on the derived classes implement them based on their specialty.
It is a solid, and you can find more about it under the title of "Strategy Design Pattern"
To give some background on what I am doing:
I have a program that allows a user to modify and create a general calibration. Inside this calibration includes groups. Groups differ by the type of analysis they perform. These groups also included spectral sets with each set containing data for only one molecule. Inside these sets also includes spectral data at varying concentrations. Each spectra data is a discrete set of data which is specified by its resolution (x-axis space between each point) and its spectral range (x axis range).
One of the main aspects of building these calibration files is to keep the resolution and spectral range consistent in all spectral data in each set. This means that spectral data cannot be added unless it matches the spectral data of the rest. Also, if the user deletes all spectral data the resolution and range is reset allowing Spectra data of any range or resolution to be added to the calibration.
The question is: How can I provided an effective way to prevent adding spectral data to the calibration that doesn't match the current resolution and spectral range???
Below is a general description of a calibration class. This is a very general description and contains the only info needed to explain what I am trying to do.
class calibration
{
List<Group> groups;
}
class Group
{
List<SpectralSet> sets;
}
class SpectralSet
{
List<SpectraData> spectras;
}
class SpectraData
{
double firstXPoint;
double lastXPoint;
double resolution;
double[] Ypoints;
}
I'm sure you could apply all sorts of fancy design patterns to enforce the rules you mention.
However, for the sake of simplicity, I would just encapsulate the logic in the calibration class with an AddGroup method which validates the added group conforms to the calibration's requirements. Similarly, I would create an AddSpectralSet method to the group class as a gate keeper into the sets collection.
At that point, depending on how often these things change, I would think about exposing the groups collection and sets collection as ReadOnlyCollection to ensure code doesn't try to add items without using the prescribed methods.
Hope this helps.
Your approach will probably vary a bit, but here's an outline of how you could achieve this. You need to do the following:
Only expose immutable public collection properties, along with an Add method, so that you can do your own validation.
For example, you don't want to do:
class Group
{
public List<SpectralSet> sets;
}
Because then anyone can just do myGroup.sets.Add(mySet), without you getting a chance to do any validation on the set. One common pattern to achieve this is as follows:
class Group
{
private List<SpectralSet> _sets;
public IEnumerable<SpectralSet> Sets { get { return _sets; } }
public void Add(SpectralSet set)
{
//Do validation here, throw an exception or whatever you want to do if the set isn't valid
_sets.Add(set);
}
//Have a similar Remove method
}
Store the criteria that the data must match
I'm not quite sure what a spectral range is, so I'll just use the resolution as an example. You can extend this to whatever the range criteria is simply. There's at least three possible ways you could do this:
When you construct a class, pass it the resolution that it's allowed in the constructor, and make this immutable.
When adding and removing, update the allowed resolution as necessary.
Don't store the resolution explicitly, calculate it every time you add or remove.
Out of those, option 1 is by far the simplest. Life is always much easier when you can keep things as immutable as possible. So you'd do something like:
class Group
{
private List<SpectralSet> _sets;
public IEnumerable<SpectralSet> Sets { get { return _sets; } }
public readonly double Resolution;
public Group(double resolution)
{
Resolution = resolution;
}
public void Add(SpectralSet set)
{
if(set.Resolution != resolution)
//Throw an Exception here, or however you want to handle invalid data
_sets.Add(set);
}
//Have a similar Remove method
}
Following this example, each of the classes you included would need a Resolution parameter with the same kind of logic, just checking the Resolution of any direct child you tried to add. Likewise with whatever you use for spectral range.
You also want to be able to change the resolution allowed if all data is cleared. The simplest way to do this is just create new objects whenever the data is cleared, rather than just clearing out the collections in existing objects.
Make SpectraData immutable
All this is useless if you can get a SpectraData out of one of the carefully gated collections and change it arbitrarily. Make anything that needs to be validated immutable, only allowing it to be set on construction. If you have a requirement not to do that, you need to think very carefully about how you will allow it to be changed.
I'm playing around with writing an item crafting system that I might want to put into a game someday. There are Recipes which specify the ingredients they require and what they produce.
I wanted the recipes to be flexible, such that they only required a broad category of ingredients, not an exact one. For example, a recipe for a weapon blade might just say it requires a metal, not specifically steel. The recipes have to verify that the ingredients given are within the acceptable category. Some materials might belong to multiple categories.
Then I had a possibly brilliant, possibly insane idea. The .net type system already implements that! So for each material, I add a property of type Type, and use IsAssignableFrom to verify the ingredients' compatibility.
I have a file that looks like this:
public interface ItemType { }
public interface Material : ItemType { }
public interface Metal : Material { }
public interface Gold : Metal { }
public interface Silver : Metal { }
public interface Iron : Metal { }
public interface Steel : Metal { }
public interface Wood : Material { }
public interface Coal : Material { }
And so on. None of those are ever implemented. I'm just borrowing the built in type checking for my own purposes.
Is there anything necessarily wrong with this?
edit: actual question
If I've been clear enough to explain what I'm trying to accomplish here, then what would you suggest is a good way to go about it, ignoring this whole type system abuse thing? Would you have also used this solution, or something else?
Second question, are there any pitfalls to watch out for in what I've done here?
Is there anything necessarily wrong with this?
Yes, everything.
Classes and interfaces are meant to express behavior. There is no behavior in your code. Your code is not miscomunicating the intentions. Usually, when you see interface, you expect it to have some method and that method is called. That is not the case here.
It will become impossible to define the materials and recipes in some kind of configuration/resource file, like most normal games do. So you have to recompile every time you want to change the materials or recipe a little.
It will become problematic to create items/materials that are somehow related. For example, lets say there are multiple tools and each tool can be from different materials. In your case, you have to write down every combination. In ideal case, you can just run few nested for loops which create each combination.
You cannot parametrize the materials in any way without creating classes of them. For example, you might want different colors of wool. How would you do it? Create interface for each color? Or use some kind of enum as parameter. But you have to create class for that.
Better way would be simple Item class that has collection of tags. Even simple strings should be enough.
For my homework, I'm implementing a course registration system for a university and I implemented a simple class for Curriculum with list of semesters and other properties like name of the department, total credits etc.
But I'm wondering if I can inherit this class from a Graph Data Structure with Edges and vertices.
Anybody done similar things before?
My current design is something like this:
public class Curriculum
{
public string NameOfDepartment { get; set; }
public List<Semester> Semesters { get; set; }
public bool IsProgramDesigned { get; set; }
public Curriculum()
{
IsProgramDesigned = false;
}
//
public string AddSemester(Semester semester)
{
As an enterprise architect I would absolutely not use a graph structure for this data. This data is a list and nothing more.
For a problem similar to this, the only reason I would ever consider using a graph structure would be to potentially create the relationship of course requirements and prerequisites.
This way you could then use the graph algorithm to determine if it is valid for a student to register for a class by making sure it is a valid addition to the tree. Same for removing classes, it could be validated to make sure you aren't dropping a class and staying enrolled in the lab for the class example.
Now if I was going to actually implement this. I would still have an overall list of classes that have a Key to the vertex in the graph representation. One thing to keep in mind is that graph algorithms are about the biggest heavy hitter you can throw at a database so minimize the amount of work done to pull the graph out is always key. Depending on the size and scope, I would also evaluate if I could store entire graphs in a serialized form or to use a document database for the same reason.
Which in this example would be the most likely route I would take. I would store the entire object of prerequisites co-requisites and so on right inline with my course object. Since the graph is a set it and done event there's no need to do an actual graph traversal and you're better off storing the pre-calculated graph.
Yes you can inherit this class from a Graph data structure. You can make it a subclass of anything you want (except for a sealed class). The question of whether or not it is a wise design is entirely dependant on what you want to do. I assume you know how, so comment if you need an example of how to implement inheritance.
IF you are wanting to write your own graphing algorithms, why not just model it yourself? It would probably be a fun exercise.
I have an order edit and quote edit screen that are very similar. I want to try to avoid code like this:
if (order is Order)
SetupScreenForOrder();
if (order is Quote)
SetupScreenForQuote();
But maintaining two screens is not good either. If I create some common interface between a Quote and Order then how do you deal with fields like OrderNumber or QuoteDate?
What's the best way to handle this?
Foo foo = GetFoo();
if (foo is Order)
...
if (foo is Quote)
...
If you don't want to write these conditionals, avoid referring to Order instances and Quote instances by their common parent type (if any).
Order order = GetOrder()
SetupScreen(order); // resolves to void SetupScreen(Order order)
Quote quote = GetQuote()
SetupScreen(quote); //resolves to void SetupScreen(Quote quote)
Often if the display screens for two classes are similar, it's because they have fields that are similar in function, even if they don't have the same name.
For example, it might be that each instance (of an order or a quote) will have a date displayed with it. So you might have an interface:
interface displayableInOrderAndQuoteList {
Date getDisplayDate();
}
public class Order {
private Date orderDate;
public Date getOrderDate() { //used only when treating object as an order
return orderDate;
}
public Date getDisplayDate() {//used when displaying object via interface
return orderDate;
}
}
public class Quote {
private Date quoteDate;
public Date getQuoteDate() { //used only when treating object as a quote
return quoteDate;
}
public Date getDisplayDate() {//used when displaying object via interface
return quoteDate;
}
}
In other words, the interface represents questions you want to ask the object in order to build the screen. Each object decides how to answer those questions.
If the display is different enough that you need to ask the objects totally different questions, then you probably should have two screens.
I think a common interface between the two objects would be a good idea.
Perhaps define the uncommon fields as nullable and have the screen check for null and determine how to display those fields.
int? OrderNumber {get;set;}
DateTime? QuoteDate {get;set;}
EDIT: in response to JC's comment
Perhaps consider trying to take it a step further and, at least logically, consider an Order and a Quote to be the same kind of object but at different stages in the "Order lifecycle". I.e. a "Quote" is an order at the beginning of the lifecycle, whereas an "Order" is an order at the middle or end of the lifecycle.
You could have an OrderState property defined on your interface, and then your UI could use the OrderState property to decide how the quote/order should be displayed, rather than checking each piece of data individually.
If you feel that the problem is more that you have too many if statements in your UI, then perhaps consider creating small user controls to handle displaying chunks of the UI for either a quote or for an order. You could then either dynamically add the appropriate control (a quote control or an order controL) to your UI, or have both controls already added and just show/hide them as appropriate. I would caution, though, that this sounds like it could be a messy approach, so just be careful that the solution doesn't end up being more complicated than the problem that you're trying to solve.