parameters: (self, state, player, waiting_substitute=False)
return_statement: return player_actions
docstring: Determine valid medium level actions for a player.
          
          Args:
              state (OvercookedState): current state
              player (PlayerState): the player's current state
              waiting_substitute (bool): add a substitute action that takes the place of 
                                         a waiting action (going to closest feature)
          
          Returns:
              player_actions (list): possible motion goals (pairs of goal positions and orientations)
docstring_summary: Determine valid medium level actions for a player.
          
          Args:
              state (OvercookedState): current state
              player (PlayerState): the player's current state
              waiting_substitute (bool): add a substitute action that takes the place of 
                                         a waiting action (going to closest feature)
          
          Returns:
              player_actions (list): possible motion goals (pairs of goal positions and orientations)
docstring_tokens: Determine valid medium level actions for a player . Args : state ( OvercookedState ) : current state player ( PlayerState ) : the player s current state waiting_substitute ( bool ) : add a substitute action that takes the place of a waiting action ( going to closest feature ) Returns : player_actions ( list ) : possible motion goals ( pairs of goal positions and orientations )
function: def get_medium_level_actions(self, state, player, waiting_substitute=False):
          """
          Determine valid medium level actions for a player.
          
          Args:
              state (OvercookedState): current state
              player (PlayerState): the player's current state
              waiting_substitute (bool): add a substitute action that takes the place of 
                                         a waiting action (going to closest feature)
          
          Returns:
              player_actions (list): possible motion goals (pairs of goal positions and orientations)
          """
          player_actions = []
          counter_pickup_objects = self.mdp.get_counter_objects_dict(state, self.counter_pickup)
          if not player.has_object():
              onion_pickup = self.pickup_onion_actions(counter_pickup_objects)
              tomato_pickup = self.pickup_tomato_actions(counter_pickup_objects)
              dish_pickup = self.pickup_dish_actions(counter_pickup_objects)
              soup_pickup = self.pickup_counter_soup_actions(counter_pickup_objects)
  
              pot_states_dict = self.mdp.get_pot_states(state)
              start_cooking = self.start_cooking_actions(pot_states_dict)
              player_actions.extend(onion_pickup + tomato_pickup + dish_pickup + soup_pickup + start_cooking)
  
          else:
              player_object = player.get_object()
              pot_states_dict = self.mdp.get_pot_states(state)
  
              # No matter the object, we can place it on a counter
              if len(self.counter_drop) > 0:
                  player_actions.extend(self.place_obj_on_counter_actions(state))
  
              if player_object.name == 'soup':
                  player_actions.extend(self.deliver_soup_actions())
              elif player_object.name == 'onion':
                  player_actions.extend(self.put_onion_in_pot_actions(pot_states_dict))
              elif player_object.name == 'tomato':
                  player_actions.extend(self.put_tomato_in_pot_actions(pot_states_dict))
              elif player_object.name == 'dish':
                  # Not considering all pots (only ones close to ready) to reduce computation
                  # NOTE: could try to calculate which pots are eligible, but would probably take
                  # a lot of compute
                  player_actions.extend(self.pickup_soup_with_dish_actions(pot_states_dict, only_nearly_ready=False))
              else:
                  raise ValueError("Unrecognized object")
  
          if self.wait_allowed:
              player_actions.extend(self.wait_actions(player))
  
          if waiting_substitute:
              # Trying to mimic a "WAIT" action by adding the closest allowed feature to the avaliable actions
              # This is because motion plans that aren't facing terrain features (non counter, non empty spots)
              # are not considered valid
              player_actions.extend(self.go_to_closest_feature_actions(player))
  
          is_valid_goal_given_start = lambda goal: self.motion_planner.is_valid_motion_start_goal_pair(player.pos_and_or, goal)    
          player_actions = list(filter(is_valid_goal_given_start, player_actions))
          return player_actions
function_tokens: def get_medium_level_actions ( self , state , player , waiting_substitute = False ) : player_actions = [ ] counter_pickup_objects = self . mdp . get_counter_objects_dict ( state , self . counter_pickup ) if not player . has_object ( ) : onion_pickup = self . pickup_onion_actions ( counter_pickup_objects ) tomato_pickup = self . pickup_tomato_actions ( counter_pickup_objects ) dish_pickup = self . pickup_dish_actions ( counter_pickup_objects ) soup_pickup = self . pickup_counter_soup_actions ( counter_pickup_objects ) pot_states_dict = self . mdp . get_pot_states ( state ) start_cooking = self . start_cooking_actions ( pot_states_dict ) player_actions . extend ( onion_pickup + tomato_pickup + dish_pickup + soup_pickup + start_cooking ) else : player_object = player . get_object ( ) pot_states_dict = self . mdp . get_pot_states ( state ) # No matter the object, we can place it on a counter if len ( self . counter_drop ) > 0 : player_actions . extend ( self . place_obj_on_counter_actions ( state ) ) if player_object . name == 'soup' : player_actions . extend ( self . deliver_soup_actions ( ) ) elif player_object . name == 'onion' : player_actions . extend ( self . put_onion_in_pot_actions ( pot_states_dict ) ) elif player_object . name == 'tomato' : player_actions . extend ( self . put_tomato_in_pot_actions ( pot_states_dict ) ) elif player_object . name == 'dish' : # Not considering all pots (only ones close to ready) to reduce computation # NOTE: could try to calculate which pots are eligible, but would probably take # a lot of compute player_actions . extend ( self . pickup_soup_with_dish_actions ( pot_states_dict , only_nearly_ready = False ) ) else : raise ValueError ( "Unrecognized object" ) if self . wait_allowed : player_actions . extend ( self . wait_actions ( player ) ) if waiting_substitute : # Trying to mimic a "WAIT" action by adding the closest allowed feature to the avaliable actions # This is because motion plans that aren't facing terrain features (non counter, non empty spots) # are not considered valid player_actions . extend ( self . go_to_closest_feature_actions ( player ) ) is_valid_goal_given_start = lambda goal : self . motion_planner . is_valid_motion_start_goal_pair ( player . pos_and_or , goal ) player_actions = list ( filter ( is_valid_goal_given_start , player_actions ) ) return player_actions