MTG: Small AngularJS project    Posted:


Every now and then me, my brother and some friends get together to play Magic the Gathering. We usually play a small tournament where everyone plays against each other once (aka Round-Robin) and the winner gets a small prize.

So I decided to make a small webapp to help with matchmaking and scorekeeping. It's completely in HTML/JS and will work without a webserver. It can run directly by just opening the index.htm file. The only dependency is the cdn for the font-awesome icons.

Here is the site. You can also find the code on Github.

Design

For design I used the Kube CSS framework, which I've been using as an alternative to Pure. I still think Pure is good, but it's nice to have alternatives. Otherwise everything starts to look too samey. I also used the font-awesome icons. Well, one of them. The layout seems to be responive, which is a cool bonus since I never intended it to be. I guess Kube did that for me.

Matchmaking

For the Round-Robin matchmaking I made up my own algorithm. Preferably as many players as possible should be playing at the same time at the same time as having a random order. First I generate all the matches (O(n log n)?), then I randomly shuffle them (O(n)?). Finally, I pick out the matches one at a time so that matches with the same players aren't picked close to each other.

This is what that snippet looks like from the app. A match is "picked" when an index is assigned to it.

$scope.matches = ... All the round robin matches. (n-1) + (n-2) + ... + 1.
matches_without_index = random_shuffle($scope.matches)

picked_players = [];
for(var i = 0; i < $scope.matches.length;) {
        var m = 0;
        for(; m < $scope.matches.length; m++) {
                var match = $scope.matches[matches_without_index[m]]; // accessing the random order.

                if(match.index > -1)
                        continue; // already visited.

                if(picked_players.indexOf(match.players[0]) > -1 || picked_players.indexOf(match.players[1]) > -1)
                        continue; // at least one of the players already has a matchup this round.

                match.index = i++;
                picked_players.push(match.players[0]);
                picked_players.push(match.players[1]);
                break; // This break can probably be removed
        }

        if(m == $scope.matches.length) {
                picked_players = []; // new round.
        }
}

So probably not the most optimal solution. I think the problem can be reduced to finding a series of Hamilton Paths in a complete graph so that each edge is visited at least once in the series.

After some research I found that wikipedia suggests this algorithm instead. http://en.wikipedia.org/wiki/Round-robin_tournament#Scheduling_algorithm

It would be interesting to try out these algorithms in a better language to see the difference in times.

Todo?

Some improvements I'd like to do:

  • Add filtering on the matches based on player name.
  • Add other types of tournaments, Swiss for example. Round-Robin takes too long to play if there are more than 5 players.
  • Refactoring (always)
  • Perhaps improve the matchmaking algorithm to be more correct.