def locs_connected_to(self, loc): """ Returns a set of the locations on this proto board that are connected ( internally or by wires) to |loc|. """ connected_locs = set() queue = set(section_locs(loc)) while queue: connected_loc = queue.pop() connected_locs.add(connected_loc) if connected_loc in self._wire_mappings: for wire_neighbor in section_locs(self._wire_mappings[connected_loc]): if wire_neighbor not in connected_locs: queue.add(wire_neighbor) return connected_locs
def with_wire(self, new_wire): """ Returns a new Proto_Board containing the |new_wire|. If the wire connects nodes that are already connected, this method returns this proto board. If the wire connects nodes that are meant not to be connected, as per |self._loc_disjoint_set_forest|, this method returns None. If the wire's locations don't match the wire's node, this method returns None. """ # if locations are already connected, no need for the wire if self.connected(new_wire.loc_1, new_wire.loc_2): return self # if the wire results in a short, no new proto board new_wire_node_rep = self.rep_for(new_wire.node) group_1 = self.rep_for(new_wire.loc_1) if group_1 and group_1 is not new_wire_node_rep: return None group_2 = self.rep_for(new_wire.loc_2) if group_2 and group_2 is not new_wire_node_rep: return None if group_1 and group_2 and group_1 != group_2: return None new_wire_mappings = self._wire_mappings.copy() new_wire_mappings[new_wire.loc_1] = new_wire.loc_2 new_wire_mappings[new_wire.loc_2] = new_wire.loc_1 new_loc_disjoint_set_forest = self._loc_disjoint_set_forest.copy() # update to avoid shorts that may result via the new wire if bool(group_1) != bool(group_2): present_loc = new_wire.loc_1 if group_1 else new_wire.loc_2 absent_loc = new_wire.loc_1 if present_loc == new_wire.loc_2 else ( new_wire.loc_2) for loc in section_locs(absent_loc): new_loc_disjoint_set_forest.make_set(loc) new_loc_disjoint_set_forest.union(present_loc, loc) return Proto_Board(new_wire_mappings, self._wires + [new_wire], self._pieces, new_loc_disjoint_set_forest)
def with_wire(self, new_wire): """ Returns a new Proto_Board containing the |new_wire|. If the wire connects nodes that are already connected, this method returns this proto board. If the wire connects nodes that are meant not to be connected, as per |self._loc_disjoint_set_forest|, this method returns None. If the wire's locations don't match the wire's node, this method returns None. """ # if locations are already connected, no need for the wire if self.connected(new_wire.loc_1, new_wire.loc_2): return self # if the wire results in a short, no new proto board new_wire_node_rep = self.rep_for(new_wire.node) group_1 = self.rep_for(new_wire.loc_1) if group_1 and group_1 is not new_wire_node_rep: return None group_2 = self.rep_for(new_wire.loc_2) if group_2 and group_2 is not new_wire_node_rep: return None if group_1 and group_2 and group_1 != group_2: return None new_wire_mappings = self._wire_mappings.copy() new_wire_mappings[new_wire.loc_1] = new_wire.loc_2 new_wire_mappings[new_wire.loc_2] = new_wire.loc_1 new_loc_disjoint_set_forest = self._loc_disjoint_set_forest.copy() # update to avoid shorts that may result via the new wire if bool(group_1) != bool(group_2): present_loc = new_wire.loc_1 if group_1 else new_wire.loc_2 absent_loc = new_wire.loc_1 if present_loc == new_wire.loc_2 else (new_wire.loc_2) for loc in section_locs(absent_loc): new_loc_disjoint_set_forest.make_set(loc) new_loc_disjoint_set_forest.union(present_loc, loc) return Proto_Board(new_wire_mappings, self._wires + [new_wire], self._pieces, new_loc_disjoint_set_forest)
def node_for(self, loc): """ If |loc| is internally connected to one of the locations on the proto board occupied by this piece, returns the node for |loc|. Returns None otherwise. """ for node in self.nodes: for node_loc in self.locs_for(node): if loc in section_locs(node_loc): return node return None
def _connected(self, loc_1, loc_2, visited): """ Helper for self.connected, see below. """ if loc_1 in visited: return False group = set(section_locs(loc_1)) new_visited = visited | group return loc_2 in group or any(map(lambda new_loc_1: self._connected( new_loc_1, loc_2, new_visited), (self._wire_mappings[loc] for loc in group if loc in self._wire_mappings)))
def with_loc_repped(self, rep, loc): """ Returns a new Proto_Board with the given |loc| and the locations internally connected to it being members of the group of locations represented by |rep|. """ assert self.rep_for(rep) assert not self.rep_for(loc) new_loc_disjoint_set_forest = self._loc_disjoint_set_forest.copy() for section_loc in section_locs(loc): new_loc_disjoint_set_forest.make_set(section_loc) new_loc_disjoint_set_forest.union(rep, section_loc) return self.with_loc_disjoint_set_forest(new_loc_disjoint_set_forest)
def _connected(self, loc_1, loc_2, visited): """ Helper for self.connected, see below. """ if loc_1 in visited: return False group = set(section_locs(loc_1)) new_visited = visited | group return loc_2 in group or any( map( lambda new_loc_1: self._connected(new_loc_1, loc_2, new_visited), (self._wire_mappings[loc] for loc in group if loc in self._wire_mappings), ) )
def with_piece(self, piece): """ Returns a new Proto_Board containing the given |piece|. If the piece collides with another object on the board, this method raises an Exception. """ # check for intersections with current objects on the board if any(piece.crossed_by(wire) for wire in self._wires) or any( piece.overlaps_with(other_piece) for other_piece in self._pieces): raise Exception('new piece overlaps with existing piece') # add new piece to pieces new_pieces = self._pieces.copy() new_pieces.add(piece) # account for piece sacred locations, i.e. make sure these locations never # get connected to another node in the circuit new_loc_disjoint_set_forest = self._loc_disjoint_set_forest.copy() for loc in piece.get_sacred_locs(): new_loc_disjoint_set_forest.make_set(loc) for section_loc in section_locs(loc): new_loc_disjoint_set_forest.make_set(section_loc) new_loc_disjoint_set_forest.union(loc, section_loc) return Proto_Board(self._wire_mappings, self._wires, new_pieces, new_loc_disjoint_set_forest)
def with_piece(self, piece): """ Returns a new Proto_Board containing the given |piece|. If the piece collides with another object on the board, this method raises an Exception. """ # check for intersections with current objects on the board if any(piece.crossed_by(wire) for wire in self._wires) or any( piece.overlaps_with(other_piece) for other_piece in self._pieces ): raise Exception("new piece overlaps with existing piece") # add new piece to pieces new_pieces = self._pieces.copy() new_pieces.add(piece) # account for piece sacred locations, i.e. make sure these locations never # get connected to another node in the circuit new_loc_disjoint_set_forest = self._loc_disjoint_set_forest.copy() for loc in piece.get_sacred_locs(): new_loc_disjoint_set_forest.make_set(loc) for section_loc in section_locs(loc): new_loc_disjoint_set_forest.make_set(section_loc) new_loc_disjoint_set_forest.union(loc, section_loc) return Proto_Board(self._wire_mappings, self._wires, new_pieces, new_loc_disjoint_set_forest)