[Tutor] Please review my code - a simple iterator thingy to make round-robin pairings

Mon Dec 12 16:49:16 CET 2005

```I hope my code and comments are clear enough for you to work out what
I want to do. Please review my code, my commenting and give some
advice on how to use the testing module. This is a fairly trivial
example, but I'd like to learn how to make & run tests properly, so as
to use them with Real Code. I'm looking forward to your replies.

Pekka (first posting, I hope the code doesn't break in transit)

# rrobin.py - Round-robin pairing algorithm

# Implementation of the standard Round-robin pairing algorithm. See:
# http://en.wikipedia.org/wiki/Round-robin_tournament
#
# The algorithm works as follows. Assume an even number of
# participants, since with odd numbers a dummy player can be added.
# (Drawing the dummy as opponent means having a free round.) Let there be
# n players, with n even.
#
# Initially the players are in a list ordered by their number from 1 to
# n. Pair each players number k from 0 to n/2-1 with number n-k-1 in the
# first round. Then modify the list as follows for all successive
# rounds. There are total of n-1 rounds. (NB: k starts from 0 as in
# Python list indices.)
#
# To modify the list for further rounds, first fix player 1. Then place
# the last player in the list after player 1, which causes the other
# players' positions to move higher by one step each. After this the
# pairing proceeds as in the first round, using the player's current
# position in the list.
#
# Additionally, colors are often important, e.g. in chess. However, it is
# not possible to assign colors perfectly fairly.
#
# The fairest possible color assignment follows from fixing the colors
# by playing position in all tables except where player 1 plays. Have
# player 1 draw alternating colors on alternating rounds. In this
# program the colors are indicated by the pairing order, so
#
# ("player1", "player2") implies player 1 has white and
# ("player2", "player1") implies player 1 has black (v.v. for pl. 2)
#
# This program creates an iterator that returns a list of tuples
# indicating the pairings for each round in order. Its input is a list
# of players. Passing a list of players' names as strings works well.
#
# Written by Pekka Karjalainen December 2005
# This code is in the public domain.

class RoundRobinPairs (object):
"""Iterator for Round-robin pairing. The constructor takes a list of
players (strings recommended) and an optional argument indicating the
possible empty player needed to round up to even players. By default
this is the string 'empty', and it is placed in the beginning of the
list.
"""

# the constructor
def __init__ (self,players,empty="empty"):
if len(players)%2: players.insert(0,empty)
self.players = players[:] # copy, so can modify
self.times = 0

# the iterator protocol
def __iter__ (self):
return self

# next()
def next(self):
"Returns the next pairing."
self.times += 1
n = len(self.players)
if self.times == n:
# max number of rounds is len -1
raise StopIteration
# only modify list on later passes
if self.times > 1:
mover=self.players.pop()
self.players.insert(1,mover)
# build pairings
pairings = []
for k in range(n/2):
playwhite = self.players[k]
playblack = self.players[n-k-1]
# switch colors on every odd table and on first table
# every other round for balanced colors
if (self.times%2 and k==0) or (k%2):
playblack,playwhite = playwhite,playblack
pairings.append( (playwhite,playblack) ) # parens make tuple
return pairings

# End of class defn

def main():
# default small odd pairing
mylist = ["player1","player2","player3","player4","player5"]
pairs = RoundRobinPairs (mylist)
for pairing in pairs:
print pairing

if __name__=="__main__":
main()
```