在Django中建模瑞士制比赛
我正在尝试创建一些模型,用来表示一种叫做瑞士赛的比赛,这种比赛会有多个回合。在每一回合中,所有的选手都会和其他选手配对,除非有一个选手是单独的,这种情况下他会被称为“轮空”。
我需要记录每对选手的比赛结果,也就是哪个选手赢了。此外,我还想能够方便地查找所有曾经和某个选手对战过的选手。
一些明显的事情:
class Tournament(models.Model):
name = models.CharField(max_length=80)
class Player(models.Model):
name = models.CharField(max_length=80)
一开始我打算创建一个叫“TournamentPairing”的类,大概是这样的:
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
但是这样感觉有点不太靠谱,尤其是有时候player2会是None(空值)这一点。而且,我觉得这样不太方便查找(因为我们要找的选手可能在player1或player2的位置上)。
有没有更好的办法?我觉得我在django方面的经验不足,让我找不到合适的解决方案。
2 个回答
1
我觉得你只需要一个玩家列表,不用把它分成玩家1和玩家2,这些可以在每轮开始时再设置。
你的玩家类可以包含一个他们曾经对战过的玩家列表,列表中的最后一个玩家就是他们当前面对的对手。当你选择下一个要对战的玩家时,就把这个玩家加到列表里。
class Player(Models.model):
name = models.CharField(max_length=80)
playersPlayed = []
在每一轮中,对于一个玩家,只需遍历所有玩家的全局列表,看看这个玩家是否在他们已经对战过的列表中。如果没有找到,那这个人就可以参赛,然后把他加到列表里。如果在某一轮找不到合适的玩家,那么这个玩家就会被安排休息。
我希望这至少能给你一个起点。
5
你可以对你的TournamentPairing类进行一些调整,让它更关注“轮次”,这样在查询时会更方便。
可选项有:
CHOICES = (
('n', '正常'),
('b', '轮空'),
)
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")
如果出现平局,可以把赢家字段指向一个叫“平局”的玩家。
然后,关于你的搜索条件,如果你想查看某个玩家对战过的所有玩家,可以使用:
# 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()