views:

263

answers:

2

I'm trying to create models that represent a swiss tournament, with multiple rounds. Each round everyone will be paired up with another player, except in the case where there is an odd player out, when one player will get a bye.

I need to keep track of the outcome of each pairing; i.e., which player won. Also, I'd like to be able to efficiently search later for all players who have ever played against a given player.

The obvious stuff:

class Tournament(models.Model):
    name = models.CharField(max_length=80)

class Player(models.Model):
    name = models.CharField(max_length=80)

At first I was planning to have a "TournamentPairing" class that looked something like this:

class TournamentPairing(models.Model):
    tournament = models.ForeignKey(Tournament)
    round = models.IntegerKey()
    player1 = models.ForeignKey(Player)
    player2 = models.ForeignKey(Player, null = True) # In case of a bye, this is None.
    outcome = models.CharField(max_length=1) # player1 wins, loses, bye, or tie

But that feels kind of hacky, especially the part about player2 being None sometimes. Also, I don't think it facilitates searching very well (since the player we're looking for could be in the player1 or player2 slot).

Is there a better way? I suspect my django noob-ness is holding me back from finding the right solution here.

A: 

I think you should have just a single player list and not split it into player1 and player2, those can be constructed when a round is set up.

Your player class could include a list of players they have played, and the last player on that list would be the current player they are facing. When you pick the next player someone must play, add that player to the list.

class Player(Models.model):
  name = models.CharField(max_length=80)
  playersPlayed = []

During each round, for a single player, simply iterate through the global list of players and compare a particular player to each element in playersPlayed. If the element does not exist, that person can be played and that player should be then added to the list. If a player cannot be found for a particular round, then that player is given a bye.

I hope this is at least a starting point.

AlbertoPL
+2  A: 

You can refactor your TournamentPairing class to be more "round" centric to aid in making queries.

CHOICES = ( ('n', 'Normal'), ('b', 'Bye'), )

class Round(models.Model):        
    number = models.IntegerField()
    round_type = models.CharField(max_length=1, default="n", choices=CHOICES)
    tournament = models.ForeignKey(Tournament)
    players = models.ManyToManyField(Player, related_name="rounds")
    winner = models.ForeignKey(Player, null=True, related_name="round_winner")

In the case of a tie, have winner field point to player called "Tie".

Then, for your search criteria, to see a list of the players that a given player has played against:

# grab a player 
p = Player.objects.get(name='Tom')

# see what rounds this player played in
rounds_played = p.rounds.all()

# who did this player play against?
[r.players for r in rounds_played]

# to see all rounds this player won
p.round_winner.all()
Harold
This really seems like the right way to do it. Thanks!
csbrooks