Velocity Reviews > Code works fine except...

# Code works fine except...

Ross
Guest
Posts: n/a

 05-04-2009
For the past couple weeks, I've been working on an algorithm to
schedule tennis leagues given court constraints and league
considerations (i.e. whether it's a singles or a doubles league). Here
were my requirements when I was designing this algorithm:

-Each player plays against a unique opponent each week.
-Similarly, in a doubles league, each player plays with a unique
partner each week.
-Each player gets a fair number of bye weeks (i.e. the player with the
most bye weeks will have no more than one bye week than the player
with the least number of bye weeks)

I'm very close to arriving at my desired solution, but I have one
glaring flaw. When I have an even number of players sign up for my
league and there are court constraints, my current algorithm gives the
first player in my league a bye week every single week. I'll post my
code below and see how you guys think I should add to/ amend my code.

def round_robin(players, rounds):
if len(players)%2:
players.insert(0, None)
mid = len(players)//2
for i in range(rounds):
yield zip(players[:mid], players[mid:])
players = players[0:1] + players[mid:mid+1] + players[1:mid-1] +
players[mid+1:] + players[mid-1:mid]

def test_round_robin(players, rounds, courts, doubles = False):
players = range(players)
for week in round_robin(players,rounds,courts):
if doubles == True:
doubles_week = len(week)/2.0
byes = doubles_week - courts
if byes == 0:
bye_list = []
else:
bye_list = week[::int(round(1.072*(courts/byes)+1.0)]
playing = [u for u in week if u not in bye_list]
midd = len(playing)//2
doub_sched = zip(playing[:midd], playing[midd:])
print doub_sched, bye_list
else:
byes = len(week)- courts
if byes == 0:
bye_list = []
else:
bye_list = week[::int(round(1.072*(courts/byes)+1.0)]
playing = [u for u in week if u not in bye_list]
print playing, bye_list

Chris Rebert
Guest
Posts: n/a

 05-04-2009
On Sun, May 3, 2009 at 7:36 PM, Ross <(E-Mail Removed)> wrote:
> For the past couple weeks, I've been working on an algorithm to
> schedule tennis leagues given court constraints and league
> considerations (i.e. whether it's a singles or a doubles league). Here
> were my requirements when I was designing this algorithm:
>
> -Each player plays against a unique opponent each week.
> -Similarly, in a doubles league, each player plays with a unique
> partner each week.
> -Each player gets a fair number of bye weeks (i.e. the player with the
> most bye weeks will have no more than one bye week than the player
> with the least number of bye weeks)
>
> I'm very close to arriving at my desired solution, but I have one
> glaring flaw. When I have an even number of players sign up for my
> league and there are court constraints, my current algorithm gives the
> first player in my league a bye week every single week. I'll post my
> code below and see how you guys think I should add to/ amend my code.
>
> def round_robin(players, rounds):
> Â* Â*if len(players)%2:
> Â* Â* Â* Â*players.insert(0, None)
> Â* Â*mid = len(players)//2
> Â* Â*for i in range(rounds):
> Â* Â* Â* Â*yield zip(players[:mid], players[mid:])
> Â* Â* Â* Â*players = players[0:1] + players[mid:mid+1] + players[1:mid-1] +
> players[mid+1:] + players[mid-1:mid]
>
>
> def test_round_robin(players, rounds, courts, doubles = False):
> Â* Â*players = range(players)
> Â* Â*for week in round_robin(players,rounds,courts):
> Â* Â* Â* Â* Â* Â*if doubles == True:
> Â* Â* Â* Â* Â* Â* Â* Â* Â* Â*doubles_week = len(week)/2.0
> Â* Â* Â* Â* Â* Â* Â* Â* Â* Â*byes = doubles_week - courts
> Â* Â* Â* Â* Â* Â* Â* Â* Â* Â*if byes == 0:
> Â* Â* Â* Â* Â* Â* Â* Â* Â* Â* Â* Â* Â* Â*bye_list = []
> Â* Â* Â* Â* Â* Â* Â* Â* Â* Â*else:
> Â* Â* Â* Â* Â* Â* Â* Â* Â* Â* Â* Â* Â* Â*bye_list = week[::int(round(1.072*(courts/byes)+1..0)]
> Â* Â* Â* Â* Â* Â* Â* Â* Â* Â*playing = [u for u in week if u not in bye_list]
> Â* Â* Â* Â* Â* Â* Â* Â* Â* Â*midd = len(playing)//2
> Â* Â* Â* Â* Â* Â* Â* Â* Â* Â*doub_sched = zip(playing[:midd], playing[midd:])
> Â* Â* Â* Â* Â* Â* Â* Â* Â* Â*print doub_sched, bye_list
> Â* Â* Â* Â* Â* Â*else:
> Â* Â* Â* Â* Â* Â* Â* Â* Â* Â*byes = len(week)- courts
> Â* Â* Â* Â* Â* Â* Â* Â* Â* Â*if byes == 0:
> Â* Â* Â* Â* Â* Â* Â* Â* Â* Â* Â* Â* Â* Â*bye_list = []
> Â* Â* Â* Â* Â* Â* Â* Â* Â* Â*else:
> Â* Â* Â* Â* Â* Â* Â* Â* Â* Â* Â* Â* Â* Â*bye_list = week[::int(round(1.072*(courts/byes)+1..0)]
> Â* Â* Â* Â* Â* Â* Â* Â* Â* Â*playing = [u for u in week if u not in bye_list]
> Â* Â* Â* Â* Â* Â* Â* Â* Â* Â*print playing, bye_list

Probably not the cause of the problem, but where did the magic numbers
1.072 and 1.08 come from?

Cheers,
Chris
--
http://blog.rebertia.com

John Machin
Guest
Posts: n/a

 05-04-2009
On May 4, 12:36*pm, Ross <(E-Mail Removed)> wrote:
> For the past couple weeks, I've been working on an algorithm to
> schedule tennis leagues given court constraints and league
> considerations (i.e. whether it's a singles or a doubles league). Here
> were my requirements when I was designing this algorithm:
>
> -Each player plays against a unique opponent each week.
> -Similarly, in a doubles league, each player plays with a unique
> partner each week.
> -Each player gets a fair number of bye weeks (i.e. the player with the
> most bye weeks will have no more than one bye week than the player
> with the least number of bye weeks)
>
> I'm very close to arriving at my desired solution, but I have one
> glaring flaw. When I have an even number of players sign up for my
> league and there are court constraints, my current algorithm gives the
> first player in my league a bye week every single week. I'll post my
> code below and see how you guys think I should add to/ amend my code.
>
> def round_robin(players, rounds):
> * * if len(players)%2:
> * * * * players.insert(0, None)
> * * mid = len(players)//2
> * * for i in range(rounds):
> * * * * yield zip(players[:mid], players[mid:])
> * * * * players = players[0:1] + players[mid:mid+1] + players[1:mid-1] +
> players[mid+1:] + players[mid-1:mid]
>
> def test_round_robin(players, rounds, courts, doubles = False):
> * * players = range(players)

DON'T change the type/contents/meaning of a variable name like that.
E.g. use "nthings" for a number of things and "things" for a
collection of things.

> * * for week in round_robin(players,rounds,courts):

The round_robin() function has only TWO arguments. This code won't
even run.

are intended to do, the last hope for somebody trying to make sense of
your code is to give meaningful names to your variables. "week" and
"doubles_week" are NOT meaningful.

> * * * * * * if doubles == True:

Bletch. s/ == True//

> * * * * * * * * * * doubles_week = len(week)/2.0

I doubt very much that using floating point is a good idea here.

> * * * * * * * * * * byes = doubles_week - courts
> * * * * * * * * * * if byes == 0:
> * * * * * * * * * * * * * * bye_list = []
> * * * * * * * * * * else:
> * * * * * * * * * * * * * * bye_list = week[::int(round(1.072*(courts/byes)+1.0)]

The derivation of the constants 1.072 and 1.08 is .... what?

> * * * * * * * * * * playing = [u for u in week if u not in bye_list]
> * * * * * * * * * * midd = len(playing)//2
> * * * * * * * * * * doub_sched = zip(playing[:midd], playing[midd:])
> * * * * * * * * * * print doub_sched, bye_list
> * * * * * * else:
> * * * * * * * * * * byes = len(week)- courts
> * * * * * * * * * * if byes == 0:
> * * * * * * * * * * * * * * bye_list = []
> * * * * * * * * * * else:
> * * * * * * * * * * * * * * bye_list = week[::int(round(1.072*(courts/byes)+1.0)]
> * * * * * * * * * * playing = [u for u in week if u not in bye_list]
> * * * * * * * * * * print playing, bye_list

John Yeung
Guest
Posts: n/a

 05-04-2009
On May 3, 10:36*pm, Ross <(E-Mail Removed)> wrote:

> def round_robin(players, rounds):

[snip]

>
> def test_round_robin(players, rounds, courts, doubles = False):
> * * players = range(players)
> * * for week in round_robin(players,rounds,courts):

[snip]

First things first: I take it the call to round_robin is only
supposed to take two parameters? Or do you have a version that takes
3?

John

John Yeung
Guest
Posts: n/a

 05-04-2009
On May 3, 11:29 pm, Chris Rebert <(E-Mail Removed)> wrote:

> Probably not the cause of the problem, but where
> did the magic numbers 1.072 and 1.08 come from?

It is perhaps not the most direct cause of the problem, in the sense
that the magic numbers could take various values and the problem would
still be there. But the magic numbers appear to be used for
"spreading out" bye selection, and that's broken.

The extended slice as written will always pick the first element,
since the step is guaranteed to be positive. Since the first player
(or None, when there are an odd number of players) stays put in the
first position during the round_robin shuffle, that player will always
be selected for a bye.

Further, as written, the calculated number of byes has no bearing on
the actual number of byes selected.

I think what I would do is adjust the shuffling algorithm in such a
way that everyone moves through the various positions in the list
(would it be as simple as adding a shift at the end of
round_robin???). Then I could simply select the byes from one end of
the list (with a regular slice instead of an extended slice).

John

Ross
Guest
Posts: n/a

 05-04-2009
On May 3, 10:16*pm, John Yeung <(E-Mail Removed)> wrote:
> On May 3, 11:29 pm, Chris Rebert <(E-Mail Removed)> wrote:
>
> > Probably not the cause of the problem, but where
> > did the magic numbers 1.072 and 1.08 come from?

>
> It is perhaps not the most direct cause of the problem, in the sense
> that the magic numbers could take various values and the problem would
> still be there. *But the magic numbers appear to be used for
> "spreading out" bye selection, and that's broken.
>
> The extended slice as written will always pick the first element,
> since the step is guaranteed to be positive. *Since the first player
> (or None, when there are an odd number of players) stays put in the
> first position during the round_robin shuffle, that player will always
> be selected for a bye.
>
> Further, as written, the calculated number of byes has no bearing on
> the actual number of byes selected.
>
> I think what I would do is adjust the shuffling algorithm in such a
> way that everyone moves through the various positions in the list
> (would it be as simple as adding a shift at the end of
> round_robin???). *Then I could simply select the byes from one end of
> the list (with a regular slice instead of an extended slice).
>
> John

The "magic numbers" that everyone is wondering about are indeed used
for spreading out the bye selection and I got them by simply
calculating a line of best fit when plotting several courts: byes
ratios.

The "byes = #whatever" in my code calculate the number of tuples that
need to be placed in the bye_list.

At first glance, the suggestion of adding a simple shift at the end of
round_robin doesn't seem to work since round_robin already shifts
I'm wrong because you might have been suggesting something different.

Ross
Guest
Posts: n/a

 05-04-2009
On May 4, 7:01*am, Ross <(E-Mail Removed)> wrote:
> On May 3, 10:16*pm, John Yeung <(E-Mail Removed)> wrote:
>
>
>
> > On May 3, 11:29 pm, Chris Rebert <(E-Mail Removed)> wrote:

>
> > > Probably not the cause of the problem, but where
> > > did the magic numbers 1.072 and 1.08 come from?

>
> > It is perhaps not the most direct cause of the problem, in the sense
> > that the magic numbers could take various values and the problem would
> > still be there. *But the magic numbers appear to be used for
> > "spreading out" bye selection, and that's broken.

>
> > The extended slice as written will always pick the first element,
> > since the step is guaranteed to be positive. *Since the first player
> > (or None, when there are an odd number of players) stays put in the
> > first position during the round_robin shuffle, that player will always
> > be selected for a bye.

>
> > Further, as written, the calculated number of byes has no bearing on
> > the actual number of byes selected.

>
> > I think what I would do is adjust the shuffling algorithm in such a
> > way that everyone moves through the various positions in the list
> > (would it be as simple as adding a shift at the end of
> > round_robin???). *Then I could simply select the byes from one end of
> > the list (with a regular slice instead of an extended slice).

>
> > John

>
> The "magic numbers" that everyone is wondering about are indeed used
> for spreading out the bye selection and I got them by simply
> calculating a line of best fit when plotting several courts: byes
> ratios.
>
> The "byes = #whatever" in my code calculate the number of tuples that
> need to be placed in the bye_list.
>
> At first glance, the suggestion of adding a simple shift at the end of
> round_robin doesn't seem to work since round_robin already shifts
> everything except for the first position already. Please correct me if
> I'm wrong because you might have been suggesting something different.

And also, as you all have pointed out, my inclusion of

> def test_round_robin(players, rounds, courts, doubles = False):
> players = range(players)
> for week in round_robin(players,rounds,courts):

should have been

> def test_round_robin(players, rounds, courts, doubles = False):
> players = range(players)
> for week in round_robin(players,rounds):

I forgot to erase that extra parameter when I was playing around with
my code.

Ross
Guest
Posts: n/a

 05-04-2009
On May 3, 8:29*pm, John Machin <(E-Mail Removed)> wrote:
> On May 4, 12:36*pm, Ross <(E-Mail Removed)> wrote:
>
>
>
> > For the past couple weeks, I've been working on an algorithm to
> > schedule tennis leagues given court constraints and league
> > considerations (i.e. whether it's a singles or a doubles league). Here
> > were my requirements when I was designing this algorithm:

>
> > -Each player plays against a unique opponent each week.
> > -Similarly, in a doubles league, each player plays with a unique
> > partner each week.
> > -Each player gets a fair number of bye weeks (i.e. the player with the
> > most bye weeks will have no more than one bye week than the player
> > with the least number of bye weeks)

>
> > I'm very close to arriving at my desired solution, but I have one
> > glaring flaw. When I have an even number of players sign up for my
> > league and there are court constraints, my current algorithm gives the
> > first player in my league a bye week every single week. I'll post my
> > code below and see how you guys think I should add to/ amend my code.

>
> > def round_robin(players, rounds):
> > * * if len(players)%2:
> > * * * * players.insert(0, None)
> > * * mid = len(players)//2
> > * * for i in range(rounds):
> > * * * * yield zip(players[:mid], players[mid:])
> > * * * * players = players[0:1] + players[mid:mid+1] + players[1:mid-1] +
> > players[mid+1:] + players[mid-1:mid]

>
> > def test_round_robin(players, rounds, courts, doubles = False):
> > * * players = range(players)

>
> DON'T change the type/contents/meaning of a variable name like that.
> E.g. use "nthings" for a number of things and "things" for a
> collection of things.
>
> > * * for week in round_robin(players,rounds,courts):

>
> The round_robin() function has only TWO arguments. This code won't
> even run.
>
> When you document neither your data structures nor what your functions
> are intended to do, the last hope for somebody trying to make sense of
> your code is to give meaningful names to your variables. "week" and
> "doubles_week" are NOT meaningful.
>
> > * * * * * * if doubles == True:

>
> Bletch. s/ == True//
>
> > * * * * * * * * * * doubles_week = len(week)/2.0

>
> I doubt very much that using floating point is a good idea here.
>
> > * * * * * * * * * * byes = doubles_week - courts
> > * * * * * * * * * * if byes == 0:
> > * * * * * * * * * * * * * * bye_list = []
> > * * * * * * * * * * else:
> > * * * * * * * * * * * * * * bye_list = week[::int(round(1.072*(courts/byes)+1.0)]

>
> The derivation of the constants 1.072 and 1.08 is .... what?
>
> > * * * * * * * * * * playing = [u for u in week if u not in bye_list]
> > * * * * * * * * * * midd = len(playing)//2
> > * * * * * * * * * * doub_sched = zip(playing[:midd], playing[midd:])
> > * * * * * * * * * * print doub_sched, bye_list
> > * * * * * * else:
> > * * * * * * * * * * byes = len(week)- courts
> > * * * * * * * * * * if byes == 0:
> > * * * * * * * * * * * * * * bye_list = []
> > * * * * * * * * * * else:
> > * * * * * * * * * * * * * * bye_list = week[::int(round(1.072*(courts/byes)+1.0)]
> > * * * * * * * * * * playing = [u for u in week if u not in bye_list]
> > * * * * * * * * * * print playing, bye_list

For everybody's enlightenment, I have gone through and commented my
code so you can better understand what I'm doing. Here it is:

def round_robin(players, rounds):
# if number of players odd, insert None at first position
if len(players)%2:
players.insert(0, None)
mid = len(players)//2
for i in range(rounds):
yield zip(players[:mid], players[mid:])
players = players[0:1] + players[mid:mid+1] + players[1:mid-1] +
players[mid+1:] + players[mid-1:mid]
""" rotates players like this: 1 2 -> 3 -> 4

/ |

5 <- 6 <-7 <- 8 """

def test_round_robin(players, rounds, courts, doubles = False):
players = range(players)
for week in round_robin(players,rounds):
if doubles == True: #for doubles pairings
doubles_week = len(week)/2.0
byes = doubles_week - courts #number of tuples to be put into
bye_list
if byes == 0:
bye_list = []
else: """ following formula equally spaces out tuples selected
for bye_list and selects appropriate number according to length of the
league"""
bye_list = week[::int(round(1.072*(courts/byes)+1.0)]
playing = [u for u in week if u not in bye_list]
midd = len(playing)//2
doub_sched = zip(playing[:midd], playing[midd:])#matches the
remaining tuples into doubles matches
print doub_sched, bye_list
else:
byes = len(week)- courts
if byes == 0:
bye_list = []
else:
bye_list = week[::int(round(1.072*(courts/byes)+1.0)]
playing = [u for u in week if u not in bye_list]
print playing, bye_list

Aahz
Guest
Posts: n/a

 05-04-2009
In article <(E-Mail Removed)>,
Ross <(E-Mail Removed)> wrote:
>
>def test_round_robin(players, rounds, courts, doubles = False):
> players = range(players)
> for week in round_robin(players,rounds,courts):
> if doubles == True:
> doubles_week = len(week)/2.0
> byes = doubles_week - courts

Side note: thou shalt indent four spaces, no more, no fewer

--
Aahz ((E-Mail Removed)) <*> http://www.pythoncraft.com/

"It is easier to optimize correct code than to correct optimized code."
--Bill Harlan

Ross
Guest
Posts: n/a

 05-04-2009
On May 4, 12:15*pm, (E-Mail Removed) (Aahz) wrote:
> In article <(E-Mail Removed)>,
>
> Ross *<(E-Mail Removed)> wrote:
>
> >def test_round_robin(players, rounds, courts, doubles = False):
> > * *players = range(players)
> > * *for week in round_robin(players,rounds,courts):
> > * * * *if doubles == True:
> > * * * * * * * *doubles_week = len(week)/2.0
> > * * * * * * * *byes = doubles_week - courts

>
> Side note: thou shalt indent four spaces, no more, no fewer
>
> --
> Aahz ((E-Mail Removed)) * * * * * <*> * * * *http://www.pythoncraft.com/
>
> "It is easier to optimize correct code than to correct optimized code."
> --Bill Harlan

Yes... I know this. Unfortunately, copy/pasting my code from the IDE
into the google group messes with indentations.