def result(self, state, action): """ Return the state that results from executing the given action in the given state. The action must be one of self.actions(state). The action can be a drop or rotation. """ currentState = list(state) if (action[0] == "rotate"): #Check if the action is a rotation action piece = TetrisPart(action[1]) piece.rotate90() currentState.append( piece.get_frozen()) #Add new rotated piece to the state currentState.remove(action[1]) #remove old piece else: newPiece = TetrisPart(action[0], action[1], action[2]) currentState.append( newPiece.get_frozen()) #Add the new piece to the state currentState.remove(action[0]) currentState.remove(action[1]) #Remove old pieces currentState = make_state_canonical(currentState) return currentState
def test_appear_as_subpart(): ''' Test 'appear_as_subpart' function on some examples ''' # no pa_1 = ((2, 2, 2), (0, 3, 0), (1, 2, 0)) # yes pa_2 = ((2, 2, 2), (0, 2, 0), (1, 2, 0)) # yes pa_3 = ((0, 2), (0, 2), (1, 1)) pb = ((9, 9, 9, 9, 9, 0, 0, 0), (0, 0, 0, 0, 1, 2, 2, 2), (0, 0, 0, 0, 1, 0, 2, 0), (0, 0, 1, 1, 1, 1, 2, 0), (0, 0, 0, 1, 0, 1, 1, 0)) # pprint.pprint(pa) # pprint.pprint(pb) ta_1 = TetrisPart(pa_1) ta_2 = TetrisPart(pa_2) ta_3 = TetrisPart(pa_3) tb = TetrisPart(pb) tb.display('\nPart b') ta_1.display('\nSubpart of part b? No') ta_2.display('\nSubpart of part b? Yes') ta_3.display('\nSubpart of part b? Yes') test_passed = (appear_as_subpart(pa_2, pb) and appear_as_subpart(pa_3, pb) and not appear_as_subpart(pa_1, pb)) return test_passed
def result(self, state, action): """ Return the state that results from executing the given action in the given state. The action must be one of self.actions(state). The action can be a drop or rotation. """ # Here a workbench state is a frozenset of parts #raise NotImplementedError part_list = list(state) pa, pu, offset = action if pu == None: part_list.remove(pa) rotated_part = TetrisPart(pa) rotated_part.rotate90() part_list.append(rotated_part.get_frozen()) return make_state_canonical(part_list) else: part_list.remove(pa) part_list.remove(pu) new_part = TetrisPart(pa, pu, offset) part_list.append(new_part.get_frozen()) return make_state_canonical(part_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. """ #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 appear_as_subpart(some_part, goal_part): ''' Determine whether the part 'some_part' appears in another part 'goal_part'. Formally, we say that 'some_part' appears in another part 'goal_part', when the matrix representation 'S' of 'some_part' is a a submatrix 'M' of the matrix representation 'G' of 'goal_part' and the following constraints are satisfied: for all indices i,j S[i,j] == 0 or S[i,j] == M[i,j] During an assembly sequence that does not use rotations, any part present on the workbench has to appear somewhere in a goal part! @param some_part: a tuple representation of a tetris part goal_part: a tuple representation of another tetris part @return True if 'some_part' appears in 'goal_part' False otherwise ''' #raise NotImplementedError #return TetrisPart.get_height #return TetrisPart.get_width ps = np.array(some_part) # pg = np.array(goal_part) psT = TetrisPart(ps) pgT = TetrisPart(pg) ps_h = psT.get_height() ps_w = psT.get_width() #get rows and cols from some_part pg_h = pgT.get_height() pg_w = pgT.get_width() #get rows and cols from goal_part #for each col of each row in goal_part for i in range(pg_h-ps_h+1): for j in range(pg_w-ps_w+1): #if the first index of some part matches a index of goal part if ps[0][0] == pg[i][j]: #numpy function of extracting a matrix from a large matrix. def submatrix ( matrix, startRow, startCol, size1, size2): return pg[startRow:startRow+size1,startCol:startCol+size2] #form matrix for comparison pm = submatrix (pg, i, j, ps_h,ps_w) # ps_nonzero_index = np.nonzero(ps) # ps_nonzero=ps[ps_nonzero_index] pm_nonzero=pm[ps_nonzero_index] #comparing if the selected matrix from goal part is equal to some part. if np.array_equal(ps_nonzero,pm_nonzero): return True# return true if appears return False
def test_action_result_broad(): #USER ADDED ''' Load some parts, choose first actions and see results. Visually inspect ''' initial_state = load_state('workbenches/wb_06_i.txt') ap = AssemblyProblem_3(initial_state) actions = ap.actions(initial_state) display_state(initial_state, "INITIAL: ") print("Num Actions: ", len(actions)) for i in range(0, len(actions)): if i >-10: #can limit how many to show, here if len(actions[i])==3: pa, pu, offset = actions[i] pa_ = TetrisPart(pa) pu_ = TetrisPart(pu) print("\n\nACTION #", i) print("Part Above:") pa_.display() print("Part Under:") pu_.display() print("Offset: ", offset) elif len(actions[i])==2: part, r = actions[i] p = TetrisPart(part) print("\n\nACTION #", i) print("Part: ") p.display() print("Rotation: ", r*90) new_state = ap.result(initial_state, actions[i]) display_state(new_state, "Result:")
def cost_rotated_subpart(some_part, goal_part): #DONE ''' Determine whether the part 'some_part' appears in another part 'goal_part' as a rotated subpart. If yes, return the number of 'rotate90' needed, if no return 'np.inf' The definition of appearance is the same as in the function 'appear_as_subpart'. -> call this function for all rotations of some_part @param some_part: a tuple representation of a tetris part goal_part: a tuple representation of another tetris part @return the number of rotation needed to see 'some_part' appear in 'goal_part' 0, 1, 2, 3 or infinity (np.inf) np.inf if no rotated version of 'some_part' appear in 'goal_part' ''' #USING HIS METHOD # Make a tetris part of all parts, rotate some part n times, test # appear_as_subpart for each rotation, if true return n. If all rotations # tested and returned false, return inf because no solution. sp = TetrisPart(some_part) gp = TetrisPart(goal_part) for num_rot in range(0,4): if appear_as_subpart(sp.get_frozen(), gp.get_frozen()): return num_rot sp.rotate90() return np.inf
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 result(self, state, action): """ Return the state (as a tuple of parts in canonical order) that results from executing the given action in the given state. The action must be one of self.actions(state). @return a state in canonical order """ # Here a workbench state is a frozenset of parts #raise NotImplementedError # pa, pu, offset = action # HINT part_list = list(state) pa, pu, offset = action part_list.remove(pa) part_list.remove(pu) new_part = TetrisPart(pa, pu, offset) part_list.append(new_part.get_frozen()) return make_state_canonical(part_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
def result(self, state, action): #DONE """ Return the state (as a tuple of parts in canonical order) that results from executing the given action in the given state. The action must be one of self.actions(state). Actions are just drops. @return a state in canonical order """ # USE THE ACTION GIVEN TO MAKE A NEW PART FROM PU AND PA # REMOVE PA AND PU FROM STATE, REPLACE WITH NEW PART # COMPUTE AND RETURN NEW STATE assert(action in self.actions(state)) #defense pa, pu, offset = action # HINT new_part = TetrisPart(pa,pu,offset) #was checked as valid before new_part_tuple = new_part.get_frozen() part_list = list(state) part_list.remove(pu) part_list.remove(pa) part_list.append(new_part_tuple) return make_state_canonical(part_list) #tuple, in canonical order
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. The actions that lead to rotation are defined as a tuple of the form: action = (rotated(piece),index(piece),magic_num) """ # First the drop of one piece into other valid_moves1 = AssemblyProblem_2.actions(self, state) # Rotation of one of the pieces of state valid_moves2 = [] # Check if all elements are equal. If all pieces are the same it does not matter which one we rotate are_equal = False if state[1:] == state[:-1]: are_equal = True for i in range(0, len(state)): tetris_piece = TetrisPart(state[i]) tetris_piece.rotate90() piece = tetris_piece.get_frozen() valid_moves2.append((piece, i, self.magic_num)) if are_equal: break valid_moves = valid_moves1 + valid_moves2 return valid_moves
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
def cost_rotated_subpart(some_part, goal_part): ''' Determine whether the part 'some_part' appears in another part 'goal_part' as a rotated subpart. If yes, return the number of 'rotate90' needed, if no return 'np.inf' The definition of appearance is the same as in the function 'appear_as_subpart'. @param some_part: a tuple representation of a tetris part goal_part: a tuple representation of another tetris part @return the number of rotation needed to see 'some_part' appear in 'goal_part' np.inf if no rotated version of 'some_part' appear in 'goal_part' ''' # Create TetrisPart object of some_part tuple, to access TetrisPart functions. make_object_part = TetrisPart(some_part) # Rotate above tetris part 90 degrees clockwise, 4 times. for rot in list(range(1, 5)): make_object_part.rotate90() # Get tuple of tetris part matrix_part_rotated = make_object_part.get_frozen() # Call appear_as_subpart and If rotated some_part appears in goal_part, # return current iteration value as it is the number of rotations. if appear_as_subpart(matrix_part_rotated, goal_part): return rot # Return np.inf if no solution found. return np.inf
def result(self, state, action): """ Return the state that results from executing the given action in the given state. The action must be one of self.actions(state). The action can be a drop or rotation. """ # Here a workbench state is a frozenset of parts #Extract the values from action pa,pu,offset=action # Make a new TetrisPart Object with the given action new_part = TetrisPart(pa, pu, offset) # Make a copy of the state as a list type state_list=list(state) # Dequeue pa,pu from the list state_list.remove(pa) state_list.remove(pu) # Queue the new_part into the list #get forzen, new part new_part = new_part.get_frozen() state_list.append(new_part) #state_list.append(tuple(new_part)) # This effectively "stacks" the pa & pu together at the specified offset # Make the state_list canonical to make sure it is in the correct order state_list = make_state_canonical(state_list) # Return a tuple of tuples return tuple(state_list)
def result(self, state, action): """ Return the state (as a tuple of parts in canonical order) that results from executing the given action in the given state. The action must be one of self.actions(state). @return a state in canonical order """ # Store action[0] - [2] in corresponding part and offset variables (pa = part above, pu = part under). pa, pu, offset = action # Resulting array of combined state. state_to_make_canonical = [] # Create TetrisPart object and return tuple of object. make_object = TetrisPart(pa, pu, offset) returned_state = make_object.get_frozen() # Loop parts in state and avoid existing parts (pa & pu), then append current part to # results array (state_make_canonical). for index in state: if index != pa and index != pu: state_to_make_canonical.append(index) # Add new Tetris part to resulting array as well and make state canonical with call to # respective function and return canonical final_state array. state_to_make_canonical.append(returned_state) final_state = make_state_canonical(state_to_make_canonical) return final_state
def cost_rotated_subpart(some_part, goal_part): ''' Determine whether the part 'some_part' appears in another part 'goal_part' as a rotated subpart. If yes, return the number of 'rotate90' needed, if no return 'np.inf' The definition of appearance is the same as in the function 'appear_as_subpart'. @param some_part: a tuple representation of a tetris part goal_part: a tuple representation of another tetris part @return the number of rotation needed to see 'some_part' appear in 'goal_part' np.inf if no rotated version of 'some_part' appear in 'goal_part' ''' ''' compare subpart to goal_part do you need to rotate? no? -> sub_part == goal part rotate_counter=np.inf yes-> rotate-> (assignment_one) -> assignment_one.rotate90() rotate_counter=rotate_counter+1 loop until sub_part == goal_part OR rotate_counter == 4 (360deg) ''' # raise NotImplementedError rotate_counter = 0 while rotate_counter < 4: ps = np.array(some_part) # pg = np.array(goal_part) psT = TetrisPart(ps) pgT = TetrisPart(pg) if appear_as_subpart(ps,pg) == False: psT.rotate90() rotate_counter += 1 #do rotation #return rotate_counter # if counter exits loop, there is no match; set value to infinity and exit rotate_counter=np.inf return rotate_counter
def test_action_result_deep(): #USER ADDED ''' Load some parts, and keep building randomly until only one part exists. ''' initial_state = load_state('workbenches/wb_08_i.txt') ap = AssemblyProblem_3(initial_state) state = initial_state display_state(state, "INITIAL: ") assert(state == initial_state) i = 1 while len(make_state_canonical(state)) is not 1: actions = ap.actions(state) action = random.choice(actions) if len(action)==3: pa, pu, offset = action pa_ = TetrisPart(pa) pu_ = TetrisPart(pu) print("\n\nACTION #", i, ", DROP") print("Part Above:") pa_.display() print("Part Under:") pu_.display() print("Offset: ", offset) elif len(action)==2: p, r = action part = TetrisPart(p) print("\n\nACTION #",i, ", ROTATION") print("Part:") part.display() print("Rotate: ", r*90) new_state = ap.result(state, action) assert(new_state != state) display_state(new_state, "Result: ") state = new_state i +=1 print("\n\nFully Built.") test_passed = len(state) == 1 print("Test Action and Result Passed: ", test_passed)
def result(self, state, action): """ Return the state that results from executing the given action in the given state. The action must be one of self.actions(state). The action can be a drop or rotation. """ # Store action[0] - [2] in corresponding part and offset variables (pa = part above, pu = part under). pa, pu, offset = action # Resulting list of combined state. Currently lists all parts in state. state_to_make_canonical = list(state) final_state = "" # Conditional statement to check if there is a part to drop onto or not. if pu is not None: # Make new part with pa and pu. make_object = TetrisPart(pa, pu, offset) # Get tuple of tetris part. returned_state = make_object.get_frozen() # Remove existing parts from list state_to_make_canonical.remove(pa) state_to_make_canonical.remove(pu) else: # Make new part with pa, rotate and get tuple of new part. make_object = TetrisPart(pa) make_object.rotate90() returned_state = make_object.get_frozen() # Remove old part above from state list. state_to_make_canonical.remove(pa) # Append new state to resulting list, make canonical and return. state_to_make_canonical.append(returned_state) final_state = make_state_canonical(state_to_make_canonical) return final_state
def test3(): initial_state = load_state('workbenches/wb_09_i.txt') c = initial_state[0] print(initial_state) print(c) d = TetrisPart(c) d.rotate90() print(d.get_frozen()) display_state((d.get_frozen(), c))
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 result(self, state, action): #DONE """ Return the state that results from executing the given action in the given state. The action must be one of self.actions(state). The action can be a drop or rotation. """ # Here a workbench state is a frozenset of parts assert(action in self.actions(state)) #defense part_list = list(state) if len(action)==2: #THIS IS A ROTATION part, rot = action assert (rot in range(1,4)) #defense # ROTATE PART NUM_ROT TIMES 90 DEGREES # REMOVE PART FROM PART LIST # APPEND ROTATED PART TO PART LIST new_part = TetrisPart(part) for i in range(0, rot): new_part.rotate90() new_part_tuple = new_part.get_frozen() part_list.remove(part) part_list.append(new_part_tuple) elif len(action) == 3: # THIS IS A DROP # USE THE ACTION GIVEN TO MAKE A NEW PART FROM PU AND PA # REMOVE PA AND PU FROM STATE, REPLACE WITH NEW PART # COMPUTE AND RETURN NEW STATE pa, pu, offset = action new_part = TetrisPart(pa,pu,offset) new_part_tuple = new_part.get_frozen() part_list.remove(pu) part_list.remove(pa) part_list.append(new_part_tuple) return make_state_canonical(part_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. 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
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
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): #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
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
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 result(self, state, action): """ Return the state (as a tuple of parts in canonical order) that results from executing the given action in the given state. The action must be one of self.actions(state). @return a state in canonical order """ assert action in self.actions(state) pa, pu, offset = action # Rename variables with meaningful names tetris = TetrisPart(part_above=pa, part_under=pu, offset=offset) new_part = tetris.get_frozen() tetris.frozen = None updated_state = [a for a in state if a not in [pa, pu]] updated_state.append(new_part) return make_state_canonical(tuple(updated_state))
def result(self, state, action): """ Return the state (as a tuple of parts in canonical order) that results from executing the given action in the given state. The action must be one of self.actions(state). @return a state in canonical order """ currentState = list(state) newPiece = TetrisPart(action[0], action[1], action[2]) currentState.append( newPiece.get_frozen()) #Add the new piece to the state currentState.remove(action[0]) currentState.remove(action[1]) #Remove the old pieces currentState = make_state_canonical(currentState) return currentState