I've made a program for randomly splitting game participants into different teams. The code works and solves the problem. I'm interested in advice on what you'd do differently or better.
import random
# Lists to store team members
team_1 = []
team_2 = []
# List of all available players
available_players = [
"Anastasia", "Eli", "Jamal", "Jada", "Theo", "Michelle", "Adam",
"Rhea", "Charlie", "Jasmine", "Marley", "Kenji", "Sydney", "Yara"
]
# Loop until both teams have 8 players
while len(team_1) < 8 and len(team_2) < 8:
# Team 1 selection
if team_1:
if len(team_1) < 8:
pick = random.choice(available_players)
team_1.append(pick)
available_players.remove(pick)
else:
x = input("Hello Team 1\nChoose your captain: ")
while x == "":
x = input("Team 1 Captain Needed!: ")
team_1.append(x)
# Team 2 selection
if team_2:
if len(team_2) < 8:
pick = random.choice(available_players)
team_2.append(pick)
available_players.remove(pick)
else:
x = input("Hello Team 2\nChoose your captain: ")
while x == "":
x = input("Team 2 Captain Needed!: ")
team_2.append(x)
# Game starts when both teams are full
else:
print("All Teams Full:")
print("Team 1:", team_1)
print("Team 2:", team_2)
print("\nIt's Game Time!!")
3 Answers 3
DRY
The code for picking the 2 teams is mostly duplicated. You could move some of the code into a function, and call the function once for each team.
For example, to input the team captain, here is the function:
def get_captain(team):
"""
Ask user to input a team captain name for a specified team number.
Input: team is an integer
Returns a string
"""
captain = input(f"Hello Team {team}\nChoose your captain: ")
while captain == "":
captain = input(f"Team {team} Captain Needed!: ")
return captain
and here is how to call it:
# Team 1 selection
if team_1:
if len(team_1) < 8:
pick = random.choice(available_players)
team_1.append(pick)
available_players.remove(pick)
else:
team_1.append(get_captain(1))
For Team 2, use:
team_2.append(get_captain(2))
You may be able to eliminate the duplication with the pick
code as well. Alternately, you could eliminate the multiple calls to choice
if you shuffle
the array before the while
loop:
random.shuffle(available_players)
# Loop until both teams have 8 players
while len(team_1) < 8 and len(team_2) < 8:
# Team 1 selection
if team_1:
if len(team_1) < 8:
team_1.append(available_players.pop())
else:
Documentation
The PEP 8 style guide recommends adding docstrings for functions. The function above shows an example docstring.
You could also add a docstring at the top of the code to summarize its purpose.
Naming
x
is not a meaningful variable name in this context. As shown above,
captain
is a more meaningful name.
Input
Consider using pyinputplus for input. It has standard ways of checking for valid input.
Magic number
The number 8
shows up several times. You could create a constant instead:
TEAM_SIZE = 8
if len(team_1) < TEAM_SIZE:
The if
/else
within the loop are not needed - since they are true only on the first iteration, we can move them before the loop:
def start_team(team_name):
print(f"Hello {team_name}")
captain = str.strip(input("Choose your captain: "))
while not captain:
captain = input("{team_name} Captain Needed!: ")
return [captain]
team_1 = start_team("Team 1")
team_2 = start_team("Team 2")
# Loop until both teams have 8 players
while len(team_1) < 8 and len(team_2) < 8:
Alternating choices for each team matters for fairness when humans are choosing. But when we're making a random choice, the order of selection doesn't matter at all. So we can choose all of Team 1's members before those of Team 2. We could do this using random.sample()
, but I think a simpler method is just to shuffle the "available" list and allocate the first seven members to Team 1 and the next seven to Team 2:
team_1 = start_team("Team 1")
team_2 = start_team("Team 2")
random.shuffle(available_players)
team_1 += available_players[:7]
team_2 += available_players[7:14]
We might choose to incorporate the selection of players into start_team()
(which then needs a different name, of course):
random.shuffle(available_players)
def make_team(team_name):
print(f"Hello {team_name}")
captain = str.strip(input("Choose your captain: "))
while not captain:
captain = input("{team_name} Captain Needed!: ")
team = [captain] + available_players[:7]
del available_players[:7]
return team
team_1 = make_team("Team 1")
team_2 = make_team("Team 2")
Moving actions out of the loop
Since picking team captains only happens once per program run, there's no need to have it inside the main loop. I'll use the get_captain()
function and the TEAM_SIZE
constant from @toolic's answer.
team_1.append(get_captain(1))
team_2.append(get_captain(2))
while len(team_1) < TEAM_SIZE and len(team_2) < TEAM_SIZE:
# Team 1 selection
if len(team_1) < TEAM_SIZE:
pick = random.choice(available_players)
team_1.append(pick)
available_players.remove(pick)
# Team 2 selection
if len(team_2) < TEAM_SIZE:
pick = random.choice(available_players)
team_2.append(pick)
available_players.remove(pick)
Notice that we no longer need to check if team_1:
and if team_2:
because these are always true.
Furthermore, the remaining if
conditions here are redundant due to the while
condition, so we can delete those, too.
team_1.append(get_captain(1))
team_2.append(get_captain(2))
while len(team_1) < TEAM_SIZE and len(team_2) < TEAM_SIZE:
# Team 1 selection
pick = random.choice(available_players)
team_1.append(pick)
available_players.remove(pick)
# Team 2 selection
pick = random.choice(available_players)
team_2.append(pick)
available_players.remove(pick)
Separating actions
Picking players for both teams in a single loop is part of why there is so much code duplication. It doesn't matter if players are picked for each team in turns or if team 1 picks seven random players all at once. Let's see what happens when we pick teams in two loops.
while len(team_1) < TEAM_SIZE:
pick = random.choice(available_players)
team_1.append(pick)
available_players.remove(pick)
while len(team_2) < TEAM_SIZE:
pick = random.choice(available_players)
team_2.append(pick)
available_players.remove(pick)
But, because there are 14 players in the available players
list, all of the remaining players will be put on team 2. So the second loop can be replaced with team_2.extend(available_players)
.
while len(team_1) < TEAM_SIZE:
pick = random.choice(available_players)
team_1.append(pick)
available_players.remove(pick)
team_2.extend(available_players)
Replacing loops
Starting here, I'm going to be introducing new functions that can replace loops.
Is there a different way to create team 1 without a loop? There is a random
function called sample()
that can make multiple random choices without duplicates. So, team 1 can be created by
team_1.extend(random.sample(available_players, TEAM_SIZE - 1))
Now we have a problem forming team 2 since the players on team 1 were not removed from the available players. One way to fix this is to remove them directly.
team_1.extend(random.sample(available_players, TEAM_SIZE - 1))
for player in team_1[1:]: # Skipping the captain
available_players.remove(player)
team_2.extend(available_players)
To do this with less work, we can use the set
container. These can do a lot of work easily and efficiently when we want to add or remove items from collections. In this case, we create a set
from the available players, and then subtract the team 1 players to arrive at team 2.
team_2.extend(set(available_players) - set(team_1))
Putting everything together
For the final program, I initialized both team lists with their captains.
import random
def get_captain(team):
"""
Ask user to input a team captain name for a specified team number.
Input: team is an integer
Returns a string
"""
captain = input(f"Hello Team {team}\nChoose your captain: ")
while captain == "":
captain = input(f"Team {team} Captain Needed!: ")
return captain
# List of all available players
available_players = [
"Anastasia", "Eli", "Jamal", "Jada", "Theo", "Michelle", "Adam",
"Rhea", "Charlie", "Jasmine", "Marley", "Kenji", "Sydney", "Yara"
]
TEAM_SIZE = 8
# Lists to store team members
team_1 = [get_captain(1)]
team_2 = [get_captain(2)]
team_1.extend(random.sample(available_players, TEAM_SIZE - 1))
team_2.extend(set(available_players) - set(team_1))
# Game starts when both teams are full
print("All Teams Full:")
print("Team 1:", team_1)
print("Team 2:", team_2)
print("\nIt's Game Time!!")
Explore related questions
See similar questions with these tags.