3

In python, I want to print a smaller list of randomly selected strings from a larger list of strings, returning n items. However, the resulting smaller list must have conditions applied to it so that certain items can't exist together in the new smaller list.

Take this example I'm working on: using python, I want to randomly generate 2 unique sports teams (team1, team2, with 5 players each) to play against each other from a combined list of available players (players_available, 10 players in total).

players_available is manually pre-defined, existing as a list of player names like 'Tom', 'Lucy' & 'James'. However, 'Tom' and 'James' can't exist in the same team (because, for example, they're both too good to play on the same team!). There are about 10 rules in total.

How would I go about doing this in python? I've managed to print 2 unique lists from a main list, but I'm not sure on the best way to apply rules & conditions to the 2 output lists. Here is where I'm at:

# Sports match team selection script (2 teams of 5 players each team)
import random

# available players (always an even number of items in this list. Could be 10, 12 or 14)
players_available = ['Tom', 'Lucy', 'James', 'Josh', 'Steve', 'Mike', 'Darren', 'Joe', 'Delia', 'Gordon']

# number of players required per team (will always be half the number of players available)
n = 5

# current top 2 players (manually chosen)
best1 = 'Steve'
best2 = 'Mike'

# selection rules (only written here as descriptive strings for clarity. NOT currently implemented in team selection code below! How would I do this properly?)
rule1 = 'Tom and James cant be on the same team'
rule2 = 'Josh must be on the same team as Gordon'
rule3 = 'best1 and best2 cant be on the same team'
# etc etc... until rule 10 (there'll be no more than 10 rules)

# generate team 1
team1 = random.sample(players_available, n)
print(team1)

# remaining players
players_remaining = players_available
for player in team1:
    if player in players_remaining:
        players_remaining.remove(player)

# create team 2
team2 = players_remaining
print(team2)

I'm no python expert, so I'm trying to figure out a solution using basic python principles (ie. a load of if/elif statements?) and core python libraries (as few as possible preferably).

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
Theo F
  • 1,197
  • 1
  • 11
  • 18
  • 1
    I would try to use list comprehension and a function for defining if a player is eligible in a given team – Cr4zyTun4 Dec 14 '21 at 14:57
  • 1
    Shameless plug, but I wrote a python solver for zebra/einstein/elimination puzzles based on the second duplicate. It's pretty simple code, which you may want to check out here: https://github.com/madphysicist/puzzle-solvers/blob/master/src/puzzle_solvers/elimination.py – Mad Physicist Dec 14 '21 at 14:58

1 Answers1

1

You can just shuffle the list, take the first half and check it against your rules. If all the rules return True you can stop shuffling.

This approach is very basic, and is not likely to scale well with large numbers of players and rules, as you are not eliminating players from the pool after each shuffle. However due to the small size and limited constraints it is not a problem.

import random

def rules(team):
    separate = ['Tom','James']
    together = ['Josh','Gordon']
    best = ['Steve','Mike']
    
    s = sum([x in team for x in separate]) == 1
    t = all([x in team for x in together]) or not all([x in team for x in together])
    b = sum([x in team for x in best]) == 1
    return s & t & b


players_available = ['Tom', 'Lucy', 'James', 'Josh', 'Steve', 'Mike', 'Darren', 'Joe', 'Delia', 'Gordon']

while True:
    random.shuffle(players_available)
    t1 = players_available[:5]
    t2 = players_available[5:]
    if rules(t1):
        break
        
        
print(t1,t2, sep='\n')

Output

['Lucy', 'Mike', 'James', 'Joe', 'Gordon']
['Delia', 'Steve', 'Tom', 'Josh', 'Darren']
Chris
  • 15,819
  • 3
  • 24
  • 37