The Great Robot Race

Link to Material: https://www.codecademy.com/courses/learn-intermediate-python-3/projects/the-great-robot-race-python-project

Specific Question: My code keeps running forever. Codecademy instructions tell me to paste the print results code on the second to last step and that should fix things but it does not. I also do not understand step 11. It keeps running forever and never prints the scores. Any advice?

import robot_race_functions as rr
from collections import deque, Counter, namedtuple
from time import time, sleep

maze_file_name = 'maze_data_1.csv'
seconds_between_turns = 0.3
max_turns = 35

# Initialize the robot race
maze_data = rr.read_maze(maze_file_name) 
# we take the function read_maze and pass in maze_file_name as an argument for python to read the file name.  
rr.print_maze(maze_data)
walls, goal, bots = rr.process_maze_init(maze_data)
# looks like the robots are stored in the bots variable here. 
# it looks like multiple things are stored here. 

# Populate a deque of all robot commands for the provided maze
robot_moves = deque() # holds the robot command data. 
num_of_turns = 0 # starts the game at 0 turns. 
while not rr.is_race_over(bots) and num_of_turns < max_turns: # conditions below to run while true. 
# while the robot race is over function in rr which requires the bot argument andd the num of turns is less than the number of turns. 

  # Add your code below!
  for bot in bots:
    if bot.has_finished == False:
      robot_moves.append(rr.compute_robot_logic(walls, goal, bot))
  num_of_turns += 1

  # For every bot in the list of bots, if the bot has not reached the end, add a new move to the robot_moves deque

# step 5, already imported robot_race_functions as rr so I put down file_name_or_how_it_was_imported, than function name, than what the instructions told me to do.
# pay attention to the for loop placement. since we are learning to append outcomes of the function call we include the append instruction inside of the for loop so it will append it each time. 

# Count the number of moves based on the robot names
# Add your code below!
robot_move_counter = Counter(robot_name for robot_name, action, has_collided  in robot_moves)
# We are telling python on this line of code to search for robot_name data over the robot_name, action, and has_collided data in the robot_moves deque. 

print(robot_move_counter)
# had to input robot_name with action, has_collided because this loop requires everything to be searched in robot_moves. it searches action and has_collided unecessarily. 

# Count the number of collisions by robot name
# Add your code below!
robot_collisions_counter = Counter(robot_name for robot_name, action, has_collided in robot_moves if has_collided == True)
print(robot_collisions_counter)

# Create a namedtuple to keep track of our robots' points
# Add your code below!
BotScoreData = namedtuple('BotScoreData',['name', 'num_moves', 'num_collisions', 'score'])

# Calculate the scores (moves + collisions) for each robot and append it to bot_scores 
bot_scores = []
# Add your code below!
for bot in bots:
  bot_scores.append(BotScoreData(bot.name, robot_move_counter[bot.name], robot_collisions_counter[bot.name], robot_move_counter[bot.name] + robot_collisions_counter[bot.name]))




# Populate a dict to keep track of the robot movements
bot_data = {}
# Add your code below!
for bot in bots:
  bot_data[bot.name] = bot

# step 10 we are adding to a dictionary here so  object.attribute

# Move the robots and update the map based on the moves deque
while len(robot_moves) > 0:

  # Make sure to pop moves from the front of the deque
  # Add your code below!
  robot_moves.popleft()
  bot_name, direction, has_collided = robot_moves.popleft()
  bot_data[bot_name].process_move(direction)

  # bot data is a dictionary on line 61.
  # process_move is a function in robot_race_functions.
  # I am taking the moves from the robot_moves deque and than putting them in the process move function. 

  # Update the maze characters based on the robot positions and print it to the console
  rr.update_maze_characters(maze_data, bots)
  rr.print_maze(maze_data)
  sleep(seconds_between_turns - time() % seconds_between_turns)
  
rr.print_results(bot_scores)
# Print out the results!
#rr.print_results(bot_scores)

I haven’t done this project, but this looks problematic. What happens to the first move popped?

Apparently I didn’t indent it in the while loop and that’s why

The final printing of the results should not be inside the while loop. It would print at each iteration instead of just once after all of the race moves have been printed.

I have now completed the project. I altered the print_maze function in the robot_race_functions.py file supplied by CC, so that the maze prints correctly.

print_maze code
def print_maze(maze_data):
    for row in maze_data:
        for col in row:
            print(col + ' ', end=""),
        print('\n', end="")
    print('\n', end="")

I ran your code in place of mine with the following result:

# # # # # # # # # # 
# _ _ _ _ A B _ $ # 
# _ _ _ _ _ # _ _ # 
# _ _ _ _ C # _ _ # 
# _ _ _ # _ _ _ _ # 
# # # # # # # # # # 

Traceback (most recent call last):
  File "robot_race.py", line 156, in <module>
    bot_name, direction, has_collided = robot_moves.popleft()
IndexError: pop from an empty deque

The issue is the line I mentioned in my previous reply where you are popping moves from the deque, but not processing the move. Every other move is discarded, and the deque is empty before the final assignments here robot_name, direction, has_collided = robot_moves.popleft() can be made.

2 Likes

thank you midlinder! I think I still have an error. I have tried updating the code as you said and moving the print results out of the while loop. Is there anything else that I am doing wrong?

Link to the Codecademy Material:
https://www.codecademy.com/courses/learn-intermediate-python-3/projects/the-great-robot-race-python-project?_gl=1*51r46a*_ga*OTIzNDAxOTMwMC4xNjU2OTk4NjE2*_ga_3LRZM6TM9L*MTY4MzcwNDI5Ni4yLjEuMTY4MzcwNDM4Ni4zMC4wLjA.

import robot_race_functions as rr
from collections import deque, Counter, namedtuple
from time import time, sleep

maze_file_name = 'maze_data_1.csv'
seconds_between_turns = 0.3
max_turns = 35

# Initialize the robot race
maze_data = rr.read_maze(maze_file_name) 
# we take the function read_maze and pass in maze_file_name as an argument for python to read the file name.  
rr.print_maze(maze_data)
walls, goal, bots = rr.process_maze_init(maze_data)
# looks like the robots are stored in the bots variable here. 
# it looks like multiple things are stored here. 

# Populate a deque of all robot commands for the provided maze
robot_moves = deque() # holds the robot command data. 
num_of_turns = 0 # starts the game at 0 turns. 
while not rr.is_race_over(bots) and num_of_turns < max_turns: # conditions below to run while true. 
# while the robot race is over function in rr which requires the bot argument andd the num of turns is less than the number of turns. 

  # Add your code below!
  for bot in bots:
    if bot.has_finished == False:
      robot_moves.append(rr.compute_robot_logic(walls, goal, bot))
  num_of_turns += 1

  # For every bot in the list of bots, if the bot has not reached the end, add a new move to the robot_moves deque

# step 5, already imported robot_race_functions as rr so I put down file_name_or_how_it_was_imported, than function name, than what the instructions told me to do.
# pay attention to the for loop placement. since we are learning to append outcomes of the function call we include the append instruction inside of the for loop so it will append it each time. 

# Count the number of moves based on the robot names
# Add your code below!
robot_move_counter = Counter(robot_name for robot_name, action, has_collided  in robot_moves)
# We are telling python on this line of code to search for robot_name data over the robot_name, action, and has_collided data in the robot_moves deque. 

print(robot_move_counter)
# had to input robot_name with action, has_collided because this loop requires everything to be searched in robot_moves. it searches action and has_collided unecessarily. 

# Count the number of collisions by robot name
# Add your code below!
robot_collisions_counter = Counter(robot_name for robot_name, action, has_collided in robot_moves if has_collided == True)
print(robot_collisions_counter)

# Create a namedtuple to keep track of our robots' points
# Add your code below!
BotScoreData = namedtuple('BotScoreData',['name', 'num_moves', 'num_collisions', 'score'])

# Calculate the scores (moves + collisions) for each robot and append it to bot_scores 
bot_scores = []
# Add your code below!
for bot in bots:
  bot_scores.append(BotScoreData(bot.name, robot_move_counter[bot.name], robot_collisions_counter[bot.name], robot_move_counter[bot.name] + robot_collisions_counter[bot.name]))




# Populate a dict to keep track of the robot movements
bot_data = {}
# Add your code below!
for bot in bots:
  bot_data[bot.name] = bot

# step 10 we are adding to a dictionary here so  object.attribute

# Move the robots and update the map based on the moves deque
while len(robot_moves) > 0:

  # Make sure to pop moves from the front of the deque
  # Add your code below!
  robot_moves.popleft()
  bot_name, direction, has_collided = robot_moves.popleft()
  bot_data[bot_name].process_move(direction)

  # bot data is a dictionary on line 61.
  # process_move is a function in robot_race_functions.
  # I am taking the moves from the robot_moves deque and than putting them in the process move function. 

  # Update the maze characters based on the robot positions and print it to the console
  rr.update_maze_characters(maze_data, bots)
  rr.print_maze(maze_data)
  sleep(seconds_between_turns - time() % seconds_between_turns)
  
rr.print_results(bot_scores)
# Print out the results!
#rr.print_results(bot_scores)

Error: Traceback (most recent call last):
File “robot_race.py”, line 74, in
bot_name, direction, has_collided = robot_moves.popleft()
IndexError: pop from an empty deque

What does the line I pointed to above do?

Next Question

What happens to the move that is popped from the deque?

Answer

Nothing. It is lost, and not processed. That line should be removed from your code. The line that follows it properly pops the moves, and assigns them. The line after that processes the move. The line I’m pointing out is simply discarding a move with every iteration of your while loop.

I apologize for my delay in response midlinder.

I believe that popleft() would remove the first item in the list instead of the end where we normally remove values in a list.

I believe what you are saying is to remove that line because the line after it processes it correctly. I will attempt to remove it now.

1 Like

Hi strikeouts27, I am having the exact same problem you had. It just runs, spinning wheel, and I get no output in the console. I even tried putting some print commands at the beginning of the code to see if that would print out but it doesn’t. My code seems the same as other solution code I have seen, but I don’t get any results at all, so obviously I am missing something key! It almost seems like the console is controlled somehow so it can only receive output from a function.

The behavior you describe, sounds like you may have an infinite loop in your code. Post your code in a reply, if you’d like additional help.