def h(self, node): # We implemented a simple heuristic that estimates the cost to reach the goal # by multiplying the number of remaining moves to the avg_time of our moves set state_dict = from_state_to_dict(node.state) goal_dict = from_state_to_dict(self.goal) return (goal_dict['moves_done'] - state_dict['moves_done']) * self.avg_time
def result(self, state, action): # Given state and action, return a new state that is the result of the action. # Action is assumed to be a valid action in the state nao_move = self.available_moves[action] state_dict = from_state_to_dict(state) # Here we compute the new 'entropy' value full_choreography = [ *self.previous_moves_done, *state_dict['choreography'], action ] new_entropy = entropy(full_choreography) # Here we compute the new 'standing' value if 'standing' in nao_move.postconditions: # Apply the postconditions of this move new_standing = nao_move.postconditions['standing'] else: # This move doesn't affect the 'standing' value new_standing = state_dict['standing'] return (('choreography', (*state_dict['choreography'], action)), ('standing', new_standing), ('remaining_time', state_dict['remaining_time'] - nao_move.duration), ('moves_done', state_dict['moves_done'] + 1), ('entropy', new_entropy))
def result(self, state, action): # We already checked the action in the actions function so they are valid nao_move = self.available_moves[action] # We used a util function to convert the state in a dictionary state_dict = from_state_to_dict(state) # We create a temp choreography, including past steps, to later calculate its entropy temp_choreography = [ *self.previous_moves, *state_dict['choreography'], action ] # Now we calculate the entropy of the temp choreography using a util function temp_entropy = entropy_calc(temp_choreography) # We set the postcondition of this action if 'standing' in nao_move.postconditions: temp_standing = nao_move.postconditions['standing'] else: # If the action don't modify the standing state we keep the last one temp_standing = state_dict['standing'] return (('choreography', (*state_dict['choreography'], action)), ('standing', temp_standing), ('remaining_time', state_dict['remaining_time'] - nao_move.duration), ('moves_done', state_dict['moves_done'] + 1), ('entropy', temp_entropy))
def goal_test(self, state): # Given a state, return True if state is a goal state or False, otherwise # We used a util function to convert the state in a dictionary state_dict = from_state_to_dict(state) goal_dict = from_state_to_dict(self.goal) # We create an interval to check if we filled the time slot for this step goal_remaining_time = goal_dict['remaining_time'] a = goal_remaining_time b = goal_remaining_time + 1 # We check if all our condition are met # Check if we filled the time slot for this step time_constraint = (a <= state_dict['remaining_time'] <= b) # Check if we chose enough moves for this step moves_done_constraint = (state_dict['moves_done'] >= goal_dict['moves_done']) # Check if we chose moves that are diverse enough entropy_constraint = (state_dict['entropy'] >= goal_dict['entropy']) # Check if we reached our goal standing state standing_constraint = (state_dict['standing'] == goal_dict['standing']) return time_constraint and moves_done_constraint and entropy_constraint and standing_constraint
def goal_test(self, state): # Given a state, return True if state is a goal state or False, otherwise state_dict = from_state_to_dict(state) goal_dict = from_state_to_dict(self.goal) goal_remaining_time = goal_dict['remaining_time'] a = goal_remaining_time b = goal_remaining_time + self.time_threshold # Here we test all the existing constraints time_constraint = (a <= state_dict['remaining_time'] <= b) moves_done_constraint = (state_dict['moves_done'] >= goal_dict['moves_done']) entropy_constraint = (state_dict['entropy'] >= goal_dict['entropy']) standing_constraint = (state_dict['standing'] == goal_dict['standing']) if goal_dict['standing'] is None: # No standing precondition was explicitly stated: then, # we can safely ignore the standing_constraint return time_constraint and moves_done_constraint and entropy_constraint else: # In this case we must consider also the standing_constraint return time_constraint and moves_done_constraint and entropy_constraint and standing_constraint
def is_move_applicable(self, state, move_name, move): # Here we exclude some moves from the available ones. state_dict = from_state_to_dict(state) # Criterion 1: is 'remaining_time' enough to complete the move? if state_dict['remaining_time'] < move.duration: return False # Criterion 2: are the preconditions of the move respected in the current state? if 'standing' in move.preconditions: if state_dict['standing'] != move.preconditions['standing']: # If a 'standing' precondition is set, ensure that it's satisfied return False # Criterion 3: is the move different from the one which was performed last? last_move = state_dict['choreography'][-1] if move_name == last_move: return False # If no criterion was matched, we accept the move return True
def move_usable(self, state, move_name, move): # We used a util function to convert the state in a dictionary state_dict = from_state_to_dict(state) # Check if there is enough time in the current step to chose this move if state_dict['remaining_time'] < move.duration: return False # Check if the preconditions are satisfied (standing/sitting) if 'standing' in move.preconditions: if state_dict['standing'] != move.preconditions['standing']: return False # Check if the move is different from the last two in the choreography size = len(state_dict['choreography']) if size > 1: if move_name == state_dict['choreography'][ -1] or move_name == state_dict['choreography'][-2]: return False if len(self.previous_moves) > 5: if move_name == self.previous_moves[-1] or move_name == self.previous_moves[-2] or move_name == self.previous_moves[-3] or \ move_name == self.previous_moves[-4] or move_name == self.previous_moves[-5]: return False return True