A
Aaron Brady
7 teams/3 courts is the same as 8 teams/4 courts, where the extra
player is named "bye". In other words, it's an uncontrained problem.
For 9 teams, there are (9*8/2), or 36 pairs, so 36!, or
371993326789901217467999448150835200000000, or 3.7e+41 permutations of
arranging them. (Thanks to Python's long ints.) Many of them work on
2 courts.
There are 5x10^68 hydrogen atoms in a galaxy.
There was a discussion on python-ideas about whether ran.shuffle( ) is
even guaranteed to find a solution eventually. I forget if 36! was
within its bounds. It may run for years and fail.
On the 8 teams/3 courts trial, a depth-first search can improve your
results in a few seconds, but only by getting one team in one round
earlier. That figure is interesting, because there are 28! or 3e+29
possible permutations. It seems many of them work.
The rest of the combinations are impractical to try with a DFS, or
your algorithm does just as good. Here is the DFS. Mine is currently
tinkering around on the 25th place of 36 total slots.
The Pinewood Derby case doesn't show much more promise, though you can
eliminate more possibilities from your round, which may speed it up.
from itertools import combinations, permutations
import string
from copy import deepcopy
def circulate( num_players, num_courts ):
''' 2 players per court '''
assert num_players<= 26, '26 players max'
player_set= sorted( string.ascii_lowercase[ :num_players ] )
combs= sorted( ''.join( x ) for x in combinations( player_set,
2 ) )
print( combs )
obs= [ [ x, 0 ] for x in combs ]
# obs[ 1 ]-- 0: not used, 1: one player of combination
# used in round, 2: combination used
stack= [ None ]* len( combs )
def rec( obs, dep ):
if dep< len( combs )- 12:
print( '%i teams %i courts dep %i\nobs %r\nstack %r\n'%
( num_players, num_courts, dep, obs, stack ) )
if all( [ x[ 1 ]== 2 for x in obs ] ):
return True
if ( dep+ 1 )% num_courts== 0:
for x in obs: # new round, clear 'obs'
if x[ 1 ]== 1:
x[ 1 ]= 0
else:
for x in obs: # mark 'obs' so player not tried again
if x[ 1 ]!= 0:
continue
for y in stack[ dep ]:
if y in x[ 0 ]:
x[ 1 ]= 1
for i in range( len( combs ) ):
if obs[ i ][ 1 ]== 0:
obs[ i ][ 1 ]= 2
stack[ dep+ 1 ]= obs[ i ][ 0 ]
res= rec( deepcopy( obs ), dep+ 1 )
if res: return True
obs[ i ][ 1 ]= 0
stack[ dep+ 1 ]= None
return False
rec( deepcopy( obs ), -1 )
return [ stack[ i: i+ num_courts ] for i in range( 0, len
( stack ), num_courts ) ]