Exemple #1
0
 def actions(self, state):
     """
     Return the actions that can be executed in the given
     state. The result would typically be a list, but if there are
     many actions, consider yielding them one at a time in an
     iterator, rather than building them all at once.
     
     @param
       state : a state of an assembly problem.
     
     @return 
        the list of all legal drop actions available in the 
         state passed as argument.
     
     """
     # Check if all elements from state are equal
     # In case yes use itertools.combinations to avoid repetitions.
     if state[1:] == state[:-1]:
         valid_moves = [
             (a, b, c) for a, b in itertools.combinations(state, 2)
             for c in range(offset_range(a, b)[0],
                            offset_range(a, b)[1]) if c is not None
         ]
     else:
         valid_moves = [
             (a, b, c) for a, b in itertools.permutations(state, 2)
             for c in range(offset_range(a, b)[0],
                            offset_range(a, b)[1]) if c is not None
         ]
     return valid_moves
Exemple #2
0
    def actions(self, state):
        """Return the actions that can be executed in the given
        state. The result would typically be a list, but if there are
        many actions, consider yielding them one at a time in an
        iterator, rather than building them all at once.
        
        Rotations are allowed, but no filtering out the actions that 
        lead to doomed states.
        
        """
        actionList = []
        partList = list(state)

        possibleCombinations = it.permutations(
            partList, 2)  #Get all possible combinations
        for combination in possibleCombinations:
            start, end = offset_range(combination[0],
                                      combination[1])  #Get all possible offset
            for offset in range(start, end):
                actionList.append(
                    (combination[0], combination[1], offset)
                )  #Add the part above, part below and offset to the action list

        for part in partList:  #loop though each part
            actionList.append(
                ("rotate",
                 part))  #add rotation action for each piece to action list

        return actionList
Exemple #3
0
    def actions(self, state):
        """
        Return the actions that can be executed in the given
        state. The result would typically be a list, but if there are
        many actions, consider yielding them one at a time in an
        iterator, rather than building them all at once.
        
        @param
          state : a state of an assembly problem.
        
        @return 
           the list of all legal drop actions available in the 
            state passed as argument.
        
        """
        actionList = []
        partList = list(state)

        possibleCombinations = it.permutations(
            partList, 2)  #Get all possible combinations
        for combination in possibleCombinations:
            start, end = offset_range(
                combination[0], combination[1])  #Get all possible offsets
            for offset in range(start, end):
                actionList.append(
                    (combination[0], combination[1], offset)
                )  #Add the part above, part below and offset to the action list

        return actionList
Exemple #4
0
    def actions(self, state):
        """
        Return the actions that can be executed in the given
        state. The result would typically be a list, but if there are
        many actions, consider yielding them one at a time in an
        iterator, rather than building them all at once.
        
        @param
          state : a state of an assembly problem.
        
        @return 
           the list of all legal drop actions available in the 
            state passed as argument.
        
        """
        #Make a copy of the state as a list
        part_list=list(state)
        # Make an empty array to append all legal actions (pa,pu, offset)
        action_list = []

        for pa,pu in itertools.permutations(part_list,2):
        # returns the permutation of the pa, pu pair
          start, end = offset_range(pa, pu)
          # Returns start, end
          for offset in range(start, end):
            action_list.append((pa, pu, offset))
  
        # This nested for loop will return all permutation of the pairs with a valid offset range[)
        # The range will include the start value and exclude the end value (to help with pythonic indexing)
    
        return action_list
    def actions(self, state):
        """
        Return the actions that can be executed in the given
        state. The result would typically be a list, but if there are
        many actions, consider yielding them one at a time in an
        iterator, rather than building them all at once.
        
        A candidate action is eliminated if and only if the new part 
        it creates does not appear in the goal state.
        """
        #

        #raise NotImplementedError

        part_list = list(state)

        filtered_actions = []

        for pa, pu in itertools.product(part_list, repeat=2):
            if pa != pu:
                start, end = offset_range(pa, pu)
                for offset in range(start, end):
                    new_part = TetrisPart(pa, pu, offset)
                    if new_part.offset != None:
                        for goal in self.goal:
                            if appear_as_subpart(new_part.get_frozen(), goal):
                                filtered_actions.append((pa, pu, offset))

        return filtered_actions
    def actions(self, state):
        """Return the actions that can be executed in the given
        state. The result would typically be a list, but if there are
        many actions, consider yielding them one at a time in an
        iterator, rather than building them all at once.
        
        Rotations are allowed, but no filtering out the actions that 
        lead to doomed states.
        
        """
        #

        #raise NotImplementedError

        part_list = list(state)

        all_legal_actions = []

        for pa_index in range(len(part_list)):
            all_legal_actions.append((part_list[pa_index], None, None))
            for pu_index in range(len(part_list)):
                if pa_index != pu_index:
                    start, end = offset_range(part_list[pa_index],
                                              part_list[pu_index])
                    for offset in range(start, end):
                        all_legal_actions.append(
                            (part_list[pa_index], part_list[pu_index], offset))

        return all_legal_actions
Exemple #7
0
 def actions(self, state):
     """
     Return the actions that can be executed in the given
     state. The result would typically be a list, but if there are
     many actions, consider yielding them one at a time in an
     iterator, rather than building them all at once.
     
     A candidate action is eliminated if and only if the new part 
     it creates does not appear in the goal state.
     """
     #Make an empty list to append pruned actions
     action_list=[]
     # Make a copy of the state as a list
     state_list=list(state)
     
     # Make a similar nested for loop as AssemblyProblem_1
     for pa,pu in itertools.permutations(state_list,2):
       
       start, end = offset_range(pa, pu)
       # Returns start, end
       for offset in range(start, end):
         # Make a TetrisPart of the pa,pu and offset to get a value for TetrisPart.offset
         temp_piece=TetrisPart(pa,pu,offset)
         
         # Pruning
         # If valid piece, append the action
         # Does it appear in the goal state?
         # self.goal is NOT a part -> how to convert state to part?
         if temp_piece.offset!=None and appear_as_subpart(temp_piece,TetrisPart(self.goal)):
           action_list.append((pa, pu, offset))
     
     return action_list
 def actions(self, state):                                           #DONE
     """Return the actions that can be executed in the given
     state. The result would typically be a list, but if there are
     many actions, consider yielding them one at a time in an
     iterator, rather than building them all at once.
     
     Rotations are allowed, but no filtering out the actions that 
     lead to doomed states.
     
     """
     # EACH COMBINATION OF 2 PARTS AND AN OFFSET, OR 
         # A PART AND A ROTATION IS AN ACTION
     # EACH DROP CAN EXIST WITH OFFSETS IN ALLOWABLE RANGE
     # RETURN LIST OF TUPLES: (pa, pu, offset) or (part, rotation)
     actions = []
     part_list = list(make_state_canonical(state))  #    HINT
     for u in range(0, len(part_list)): #under
         for a in range(0, len(part_list)): #above
             if u == a: # APPEND A ROTATION
                 p = part_list[u]
                 for rot in range(1,4):
                     actions.append((p, rot))
             else: # APPEND A DROP
                 pa = part_list[a]
                 pu = part_list[u]
                 offsets = offset_range(pa, pu)
                 for o in range(offsets[0], offsets[1]):
                     new_part = TetrisPart(pa,pu,o)
                     # No pruning, but check valid offset value
                     if new_part.offset is not None:
                         actions.append((pa, pu, o)) #tuple
                 
     return actions
Exemple #9
0
    def actions(self, state):
        """
        Return the actions that can be executed in the given
        state. The result would typically be a list, but if there are
        many actions, consider yielding them one at a time in an
        iterator, rather than building them all at once.
        
        A candidate action is eliminated if and only if the new part 
        it creates does not appear in the goal state.
        """
        actionList = []
        partList = list(state)
        goals = np.array(self.goal)

        possibleCombinations = it.permutations(
            partList, 2)  #Get all possible combinations
        for combination in possibleCombinations:
            start, end = offset_range(
                combination[0], combination[1])  #Get all possible offsets
            for offset in range(start, end):
                resultPiece = TetrisPart(combination[0], combination[1],
                                         offset)
                for goal in goals:  #Loop through each goal piece
                    if (
                            appear_as_subpart(resultPiece.get_frozen(), goal)
                    ):  #Check if the combination is in the current goal piece
                        actionList.append(
                            (combination[0], combination[1], offset)
                        )  #Add part above, part below and offset to action list

        return actionList
Exemple #10
0
    def actions(self, state):
        """
        Return the actions that can be executed in the given
        state. The result would typically be a list, but if there are
        many actions, consider yielding them one at a time in an
        iterator, rather than building them all at once.
        
        A candidate action is eliminated if and only if the new part 
        it creates does not appear in the goal state.
        """

        valid_moves = [
            (a, b, c) for a, b in itertools.permutations(state, 2)
            for c in range((offset_range(a, b)[0]), (offset_range(a, b)[1]))
            if c is not None and appear_as_subpart(
                TetrisPart(part_under=b, part_above=a, offset=c).get_frozen(),
                self.goal[0])
        ]
        return valid_moves
    def actions(self, state):                                           #DONE
        """
        Return the actions that can be executed in the given
        state. The result would typically be a list, but if there are
        many actions, consider yielding them one at a time in an
        iterator, rather than building them all at once.
        
        A candidate action is eliminated if and only if the new part 
        it creates does not appear in the goal state.

        Actions are just drops
        """
        # EACH COMBINATOIN OF 2 PARTS IS AN ACTION
        # EACH COMBINATION CAN EXIST IN ONE OF TWO ORDERS 
        # EACH COMBINATION CAN EXIST WITH OFFSETS IN ALLOWABLE RANGE
        # RETURN ACTIONS AS A TUPLE: (pa, pu, offset)
        actions = []
        part_list = list(make_state_canonical(state))  #    HINT
        
        '''
        # SLOWER -> didnt use
        for part1, part2 in itertools.combinations(part_list, 2):
            for pa, pu in itertools.permutations((part1, part2)):
                offsets = offset_range(pa, pu)
                for o in range(offsets[0], offsets[1]):
                    new_part = TetrisPart(pa,pu,o)
                    # Check valid offset and not a duplicate
                    if (new_part.offset is not None and (pa, pu, o) not in actions):
                        # P R U N I N G
                        # Check new part exists in goal, and action is unique
                        for part in self.goal:
                            if appear_as_subpart(new_part.get_frozen(), part):
                                actions.append((pa, pu, o)) #tuple
                                break #do not keep checking and appending
                    
        '''
        for u in range(0, len(part_list)): #under
            for a in range(0, len(part_list)): #above
                if u != a: # check index isnt the same, because actual part can be
                    pa = part_list[a]
                    pu = part_list[u]
                    offsets = offset_range(pa, pu)
                    for o in range(offsets[0], offsets[1]):
                        new_part = TetrisPart(pa,pu,o)
                        # Check valid offset and not a duplicate
                        if (new_part.offset is not None and (pa, pu, o) not in actions):
                            # P R U N I N G
                            # Check new part exists in goal, and action is unique
                            for part in self.goal:
                                if appear_as_subpart(new_part.get_frozen(), part):
                                    actions.append((pa, pu, o)) #tuple
                                    break #do not keep checking and appending
               
        
        return actions
 def actions(self, state):                                       #DONE
     """Return the actions that can be executed in the given
     state. The result would typically be a list, but if there are
     many actions, consider yielding them one at a time in an
     iterator, rather than building them all at once.
     
     Filter out actions (drops and rotations) that are doomed to fail 
     using the function 'cost_rotated_subpart'.
     A candidate action is eliminated if and only if the new part 
     it creates does not appear in the goal state.
     This should  be checked with the function "cost_rotated_subpart()'.
             
     """
     # EACH COMBINATION OF 2 PARTS AND AN OFFSET, OR 
         # A PART AND A ROTATION IS AN ACTION
     # EACH DROP CAN EXIST WITH OFFSETS IN ALLOWABLE RANGE
     # EACH ROTATION CAN EXIST WITH ROTATIONS 1, 2, OR 3 
     # RETURN LIST OF TUPLES: (pa, pu, offset) or (part, rotation)
     actions = []
     part_list = list(make_state_canonical(state))  #    HINT
     for u in range(0, len(part_list)): #under
         for a in range(0, len(part_list)): #above
             if u == a:                  # APPEND A ROTATION
                 p = part_list[u]
                 #Do not want to prune rotations, otherwise it will fail
                     #to detect parts (especially if the goal is rotated after
                         # it has been completely assembled)
                 for r in range(1,4):
                     if (p,r) not in actions:
                         actions.append((p,r))                       
                     
                     
             else:                       # APPEND A DROP
                 pa = part_list[a] # u!= a
                 pu = part_list[u]
                 offsets = offset_range(pa, pu)
                 for o in range(offsets[0], offsets[1]):
                     # P R U N I N G
                     # COMPUTE NEW PART
                     # IF NEW PART EXISTS IN GOAL, APPEND THE ACTION
                     # ROTATION IS ALLOWED (COST != INF)
                     new_part = TetrisPart(pa,pu,o)
                     if (new_part.offset is not None and (pa, pu, o) not in actions):
                         # P R U N I N G
                         # NEW PART EXISTS IN GOAL (C_R_S != INF)
                         for part in self.goal:
                             if (cost_rotated_subpart(new_part.get_frozen(), part) < 5):
                                 actions.append((pa, pu, o)) #tuple
                                 break #do not keep checking and appending
     
     return actions
Exemple #13
0
    def actions(self, state):
        """Return the actions that can be executed in the given
        state. The result would typically be a list, but if there are
        many actions, consider yielding them one at a time in an
        iterator, rather than building them all at once.
        
        Filter out actions (drops and rotations) that are doomed to fail 
        using the function 'cost_rotated_subpart'.
        A candidate action is eliminated if and only if the new part 
        it creates does not appear in the goal state.
        This should  be checked with the function "cost_rotated_subpart()'.
                
        """

        # Declare results array to store legal actions.
        actionsToTake = []

        # Continue if there is a state.
        if state is not None:

            # Store separate parts of state in hold_state_parts array by
            # looping through state.
            hold_state_parts = []
            for part in state:
                hold_state_parts.append(part)
                actionsToTake.append((part, None, 0))

            # Store all combinations of both parts (all actions).
            permutations_hold = itertools.permutations(hold_state_parts, 2)

            # Loop through all combinations, find offset and store each part with offset
            # range in actionsToTake array.
            for part in permutations_hold:
                range_of_offset = offset_range(part[0], part[1])
                range_offset = list(
                    range(range_of_offset[0], range_of_offset[1]))

                for offset_number in range_offset:
                    make_object_part = TetrisPart(part[0],
                                                  part_under=part[1],
                                                  offset=offset_number)
                    part_object = make_object_part.get_frozen()

                    # Check if part exists in final goal part with consideration of all rotations.
                    if cost_rotated_subpart(part_object, self.goal) != np.inf:
                        actionsToTake.append((part[0], part[1], offset_number))

        # Return results array.
        return actionsToTake
Exemple #14
0
def actions(state):

    part_list = list(state)

    legal_actions = []

    for pa_index in range(len(part_list)):
        for pu_index in range(len(part_list)):
            if pa_index != pu_index:
                start, end = offset_range(part_list[pa_index],
                                          part_list[pu_index])
                for offset in range(start, end):
                    legal_actions.append(
                        (part_list[pa_index], part_list[pu_index], offset))

    return legal_actions
 def actions(self, state):                                           #DONE
     """
     Return the actions that can be executed in the given
     state. The result would typically be a list, but if there are
     many actions, consider yielding them one at a time in an
     iterator, rather than building them all at once.
     
     @param
       state : a state of an assembly problem.
     
     @return i
        the list of all legal drop actions available in the 
         state passed as argument.   
        the individual actions are tuples, contained in a list. 
     """
     # EACH COMBINATOIN OF 2 PARTS IS AN ACTION
     # EACH COMBINATION CAN EXIST IN ONE OF TWO ORDERS 
     # EACH COMBINATION CAN EXIST WITH OFFSETS IN ALLOWABLE RANGE
     # RETURN AS A LIST OF TUPLES: (pa, pu, offset)
     actions = []
     part_list = list(make_state_canonical(state))  #    HINT
     
     #cemetary:
     for u in range(0, len(part_list)): #under
         for a in range(0, len(part_list)): #above
             if u != a: # check index isnt the same, because actual part can be
                 pa = part_list[a]
                 pu = part_list[u]
                 offsets = offset_range(pa, pu)
                 for o in range(offsets[0], offsets[1]):
                     new_part = TetrisPart(pa,pu,o)
                     # No pruning, but check for valid offset value
                     if new_part.offset is not None:
                         actions.append((pa, pu, o)) #tuple
     '''
                         
     # using itertools -> SLOWER, didnt use. 
     for part1, part2 in itertools.combinations(part_list, 2):
         for pa, pu in itertools.permutations((part1, part2)):
             offsets = offset_range(pa, pu)
             for o in range(offsets[0], offsets[1]):
                 new_part = TetrisPart(pa,pu,o)
                 # Ensure valid offset value
                 if new_part.offset is not None:
                     actions.append((pa,pu,o)) #tuple
     '''
     return actions
Exemple #16
0
    def actions(self, state):
        """
        Return the actions that can be executed in the given
        state. The result would typically be a list, but if there are
        many actions, consider yielding them one at a time in an
        iterator, rather than building them all at once.
        
        A candidate action is eliminated if and only if the new part 
        it creates does not appear in the goal state.
        """

        # Declare results array to store legal drop actions.
        actionsToTake = []

        # Continue if there is a state.
        if state != None:

            # Store separate parts of state in hold_state_parts array by
            # looping through state.
            hold_state_parts = []
            for i in state:
                hold_state_parts.append(i)

            # Store all combinations of both parts (all actions).
            permutations_hold = itertools.permutations(
                hold_state_parts, 2)  # Permutations of state parts

            # Loop through all combinations, find offset and store each part with offset
            # range in actionsToTake array.
            for part in permutations_hold:
                range_of_offset = offset_range(part[0],
                                               part[1])  # Get offset range
                range_offset = list(
                    range(range_of_offset[0], range_of_offset[1]))
                for offset_number in range_offset:
                    make_object_part = TetrisPart(part[0],
                                                  part_under=part[1],
                                                  offset=offset_number)
                    part_object = make_object_part.get_frozen()

                    # Perform search tree pruning by checking if current part appears in final
                    # goal part by calling appear_as_subpart function.
                    if appear_as_subpart(part_object, self.finalGoal):
                        actionsToTake.append((part[0], part[1], offset_number))

        # Return resulting array
        return actionsToTake
    def actions(self, state):
        """
        Return the actions that can be executed in the given
        state. The result would typically be a list, but if there are
        many actions, consider yielding them one at a time in an
        iterator, rather than building them all at once.
        
        @param
          state : a state of an assembly problem.
        
        @return 
           the list of all legal drop actions available in the 
            state passed as argument.
        
        """
        #

        #raise NotImplementedError

        # part_list = list(state)  #    HINT
        '''
        part_list = list(state)       
        
        
        all_legal_actions = []
        
        for pa_index in range(len(part_list)):
            for pu_index in range(len(part_list)):
                if pa_index != pu_index:
                    start, end = offset_range(part_list[pa_index], part_list[pu_index])
                    for offset in range(start, end):
                        all_legal_actions.append((part_list[pa_index], part_list[pu_index], offset))
        
        return all_legal_actions
    
        '''
        part_list = list(state)

        all_legal_actions = []
        for pa, pu in itertools.product(part_list, repeat=2):
            if pa != pu:
                start, end = offset_range(pa, pu)
                for offset in range(start, end):
                    all_legal_actions.append((pa, pu, offset))

        return all_legal_actions
Exemple #18
0
    def actions(self, state):
        """Return the actions that can be executed in the given
        state. The result would typically be a list, but if there are
        many actions, consider yielding them one at a time in an
        iterator, rather than building them all at once.
        
        Filter out actions (drops and rotations) that are doomed to fail 
        using the function 'cost_rotated_subpart'.
        A candidate action is eliminated if and only if the new part 
        it creates does not appear in the goal state.
        This should  be checked with the function "cost_rotated_subpart()'.
                
        """
        actionList = []
        partList = list(state)
        goals = np.array(self.goal)

        possibleCombinations = it.permutations(
            partList, 2)  #Get all possible combinations
        for combination in possibleCombinations:
            start, end = offset_range(combination[0],
                                      combination[1])  #Get all possible offset
            for offset in range(start, end):
                resultPiece = TetrisPart(combination[0], combination[1],
                                         offset)
                for goal in goals:  #Loop through each goal piece
                    cost = cost_rotated_subpart(
                        resultPiece.get_frozen(), goal
                    )  #Check if the cost of rotations of any goal for the piece is not np.inf
                    if (cost != np.inf):
                        actionList.append(
                            (combination[0], combination[1], offset)
                        )  #Add part above, part below and offset to action list

        for part in partList:  #Loop through each part
            for goal in goals:  #Loop through each goal piece
                numberOfRotations = cost_rotated_subpart(part, goal)
                if (
                        numberOfRotations != np.inf
                ):  #Check if the piece needs to be rotated to be part of a goal piece
                    actionList.append(
                        ("rotate", part)
                    )  #add rotation action for the part to the action list

        return actionList
Exemple #19
0
    def actions(self, state):
        """
        Return the actions that can be executed in the given
        state. The result would typically be a list, but if there are
        many actions, consider yielding them one at a time in an
        iterator, rather than building them all at once.
        
        @param
          state : a state of an assembly problem.
        
        @return 
           the list of all legal drop actions available in the 
            state passed as argument.
        
        """
        # Declare results array to store legal drop actions.
        actionsToTake = []

        # Continue if there is a state.
        if state is not None:

            # Store separate parts of state in hold_state_parts array by
            # looping through state.
            hold_state_parts = []
            for i in state:
                hold_state_parts.append(i)

            # Store all combinations of both parts (all actions).
            permutations_hold = itertools.permutations(hold_state_parts, 2)

            # Loop through all combinations, find offset and store each part with offset
            # range in actionsToTake array. Return actionsToTake array.
            for part in permutations_hold:
                range_of_offset = offset_range(part[0], part[1])
                range_offset = list(
                    range(range_of_offset[0], range_of_offset[1]))
                for offset_number in range_offset:
                    actionsToTake.append((part[0], part[1], offset_number))

        return actionsToTake
Exemple #20
0
    def actions(self, state):
        """Return the actions that can be executed in the given
        state. The result would typically be a list, but if there are
        many actions, consider yielding them one at a time in an
        iterator, rather than building them all at once.
        
        Rotations are allowed, but no filtering out the actions that 
        lead to doomed states.
        
        """
        #
        #Make a copy of the state as a list
        part_list=list(state)
        # Make an empty array to append all legal actions (pa,pu, offset)
        action_list = []

        for pa,pu in itertools.permutations(part_list,2):
        # returns the permutation of the pa, pu pair
          start, end = offset_range(pa, pu)
          # Returns start, end
          for offset in range(start, end):
            action_list.append((pa, pu, offset))
Exemple #21
0
    def actions(self, state):
        """Return the actions that can be executed in the given
        state. The result would typically be a list, but if there are
        many actions, consider yielding them one at a time in an
        iterator, rather than building them all at once.
        
        Rotations are allowed, but no filtering out the actions that 
        lead to doomed states.
        
        """

        # Declare results array to store legal actions.
        actionsToTake = []

        # Continue if there is a state.
        if state is not None:

            # Store separate parts of state in hold_state_parts array by
            # looping through state.
            hold_state_parts = []
            for part in state:
                hold_state_parts.append(part)
                actionsToTake.append((part, None, 0))

            # Store all combinations of both parts (all actions).
            permutations_hold = itertools.permutations(hold_state_parts, 2)

            # Loop through all combinations, find offset and store each part with offset
            # range in actionsToTake array.  Return actionsToTake array.
            for part in permutations_hold:
                range_of_offset = offset_range(part[0], part[1])
                range_offset = list(
                    range(range_of_offset[0], range_of_offset[1]))

                for offset_number in range_offset:
                    actionsToTake.append((part[0], part[1], offset_number))

        return actionsToTake
    def actions(self, state):
        """Return the actions that can be executed in the given
        state. The result would typically be a list, but if there are
        many actions, consider yielding them one at a time in an
        iterator, rather than building them all at once.
        
        Filter out actions (drops and rotations) that are doomed to fail 
        using the function 'cost_rotated_subpart'.
        A candidate action is eliminated if and only if the new part 
        it creates does not appear in the goal state.
        This should  be checked with the function "cost_rotated_subpart()'.
                
        """

        #raise NotImplementedError

        part_list = list(state)

        filtered_actions = []

        for pa_index in range(len(part_list)):
            filtered_actions.append((part_list[pa_index], None, None))
            for pu_index in range(len(part_list)):
                if pa_index != pu_index:
                    start, end = offset_range(part_list[pa_index],
                                              part_list[pu_index])
                    for offset in range(start, end):
                        new_part = TetrisPart(part_list[pa_index],
                                              part_list[pu_index], offset)
                        if new_part.offset != None:
                            if appear_as_subpart(new_part.get_frozen(),
                                                 self.goal[0]):
                                filtered_actions.append(
                                    (part_list[pa_index], part_list[pu_index],
                                     offset))

        return filtered_actions