7
\$\begingroup\$

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!!")
toolic
14.7k5 gold badges29 silver badges204 bronze badges
asked May 29 at 20:23
\$\endgroup\$
0

3 Answers 3

8
\$\begingroup\$

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:
answered May 29 at 21:20
\$\endgroup\$
0
8
\$\begingroup\$

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")
answered May 30 at 12:11
\$\endgroup\$
0
4
\$\begingroup\$

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!!")
answered May 30 at 12:27
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.