Code jam at the UK coral
Probably the two most difficult aspects of any sort of league based system are the generation of the leagues and the calculation of the league tables. This editions article will deal with the drawing up of the league fixtures. It excludes cup matches as they can be slotted in as and when (remember, when you first start out, you have basically the league and the F.A. Cup to contend for). Given that most non division 1 and premier teams are usually out of the cup by round 3 (when the big guns come in), it is no real problem to slot those in when they're required.
Okay let's look at the league fixture list.
As it stands, it looks quite simple, you have a list of 24 teams (22 in the premier league). Each team plays each other twice (home and away). It's a simple case to generate team 1's list, copy over when they play the other teams, generate team 2, create a fixture, make sure that the team generated to play is not playing another team on that day and so on. In theory, you should not need to generate team 24's list as that has already been done.
Creating the list in practise though is far from simple.
Follow my steps young Jedi....
We can do the generation one of two ways. The first is very simple.
In theory, this should work (indeed if I only wanted to generate a fixture list for just my team, then it would be fine). However, if you look at the jan-03-03.csv file you'll notice a problem with the theory. The code in listing (1) does not bother to look for transfer collisions and as the generation process continues, you start to get more and more of these collisions and that really does mess up the fixture lists!
Can we modify the listing so that the program works properly?
As it stands, the listing only checks to see if a home (or away) match for the current team is being played. If it is changed from
if (league_fix[team_no][fixture_no][ha] == -1)
if ((league_fix[team_no][fixture_no][ha] == -1) && (league_fix[opponent][fixture_no][hc] == -1)
then that should check to ensure that there isn't a fixture clash. And it does, quite admirably in fact. The only problem is that the code has to loop around again to create another fixture. Now we can do that by use of if and else.
If we tag onto the league_fix test
cout << "team fixture clash. The opponent is already playing that day.\n";
cout << "opponent = " << opponent << " fixture = " << fixture_no << "\n";
then let nature take its course (i.e. follow the path of the code) then we get something which is almost right, but still not there. Compile listing 2 and you'll see what I mean. Remember, a -1 signifies there is no match. "teams-listing2" gives a sample output from listing 2.
Something strange is happening, for some reason, the program seems to think that four matches have been played. Actually, nothing strange is happening. If you look closely, team 0 plays team 16 on match 5 at home (or team 16 plays team 0 on match 5 away), but at least it demonstrates the overall code problem more clearly; a method of looping back to generate the random number has to be included.
break, continue or goto?
Listings 3 to 5 show the effect of these. Unfortunately, they all exhibit the same problems.
This problem can be solved one of two ways. Generate team 1, propagate through the other matches. Generate team 2, propagate except where there is a conflict and so on.
Solution 2 is a re-write of the generation code.
Out of these two options, the first one is the best way forward; we already have the basis of the code, it just needs tampering with.
Onto the paper..
As I said at the start, the more you write down, the simpler the coding will be. In the instance of a league fixture list, a paper copy is the best way forward.
I designed mine like this
I started off with the blue columns (team 1) and generated 22 random numbers for the home games. The corresponding away fixtures were generated.
Next stage is to transpose those over to the other teams, except they would have to be in reverse (if team 1 plays team 3 at home, then at the same time, team 3 plays team 1 away). When the transfers are complete, team 2's fixtures are worked out. However, there is an added complication from here, not all of the cells will be empty. How is that best tackled?
We can either initialise the block holding any teams fixture list to be zero (or any number either less than 1 or greater than 24) and go down then fill the line until we reach a non-zero number, continue down until we hit the zero and fill from there or we can make a copy which contains both the original fixture number and the non-zero number next to it, the list is then generated and the numbers filled in with the correct order, in other words, the array would look like this:
The array on the left would be ordered 1, 6, 12, 2, 3, 4, 5, 7, 8, 9, 10, 11, 13 ... 23
This is possibly the most efficient method and listing 6 shows how it is done.
One thing which I have yet to mention, but is really important is licencing. Back in the days of the original FM series, teams and players didn't give two hoots about their names being used. However, today things are much different. Teams and players make big money lending their names to software packages and they certainly don't want a GPL program ripping them off (or if the package is really dire, lending their name to a turkey).
To avoid any possible repercussions, teams are referred to as team 1, team 2 etc and team players also by a number. The code though will allow you to construct a file which contains both the team and player names, neither myself, RiscStation or RISCWorld can be held to account for the text files you may use which contain the entire premiership and lower league names and players.
That's enough for now. Next time, we'll continue on this with more code and move onto the data structure and the theory behind inheritance (no, I don't mean my will either!)