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 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 """ # 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 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 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 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): #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 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
def h(self, n): #DONE ''' This heuristic computes the following cost; Let 'k_n' be the number of parts of the state associated to node 'n' and 'k_g' be the number of parts of the goal state. (self.goal) The cost function h(n) must return k_n - k_g + max ("cost of the rotations") where the list of cost of the rotations is computed over the parts in the state 'n.state' according to 'cost_rotated_subpart'. @param n : node of a search tree ''' # Save current state and goal state as lists state_list = list(make_state_canonical(n.state)) #state_list = n goal_list = list(make_state_canonical(self.goal)) # Num parts is the length of the state lists k_n = len(state_list) k_g = len(goal_list) # For all the parts in current state, get the cost_rotated_subpart r_costs = [] #make it a list, and append as we calculate for i in range(0, k_g): # for all the goal parts for j in range(0, k_n): # check all the current parts r_costs.append(cost_rotated_subpart(state_list[j], goal_list[i])) print(k_n,",",k_g,",",max(r_costs)) return k_n - k_g + max(r_costs)
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 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 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 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) if self.magic_num in action: rotated_piece = action[0] idx_rot = action[1] # Index of rotated piece updated_state = [ state[i] if i != idx_rot else rotated_piece for i in range(0, len(state)) ] return make_state_canonical(updated_state) else: return AssemblyProblem_2.result(self, state, action)
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 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