def get_children(self):
   children = []
   proto_board, loc_pairs = self.state
   for i, (loc_1, loc_2, resistor, node) in enumerate(loc_pairs):
     # can extend a wire from |loc_1| towards |loc_2| from any of the
     #     the locations |loc_1| is internally connected to
     for neighbor_loc in filter(proto_board.free,
         proto_board.locs_connected_to(loc_1)):
       # get candidate end locations for the new wire to draw
       wire_ends = (self._wire_ends_from_rail_loc(neighbor_loc,
           proto_board) if is_rail_loc(neighbor_loc) else
           self._wire_ends_from_body_loc(neighbor_loc, proto_board,
           span=dist(loc_1, loc_2)))
       for wire_end in wire_ends:
         # make sure that there is a wire to draw
         if wire_end == neighbor_loc:
           continue
         new_wire = Wire(neighbor_loc, wire_end, node)
         # track number of pieces this wire crosses
         num_piece_crossings = sum(piece.crossed_by(new_wire) for piece in
             proto_board.get_pieces())
         if not ALLOW_PIECE_CROSSINGS and num_piece_crossings:
           continue
         # track number of other wires this new wire crosses
         any_same_orientation_crossings = False
         num_wire_crossings = 0
         for wire in proto_board.get_wires():
           if wire.crosses(new_wire):
             if wire.vertical() == new_wire.vertical():
               any_same_orientation_crossings = True
               break
             else:
               num_wire_crossings += 1
         # don't allow any wire crossings where the two wires have the same
         #     orientation
         if any_same_orientation_crossings:
           continue
         # continue if we do not want to allow any crossing wires at all, even
         #     ones of different orientation
         if not ALLOW_WIRE_CROSSINGS and num_wire_crossings:
           continue
         # construct a proto board with this new wire
         wire_proto_board = proto_board.with_wire(new_wire)
         # check that adding the wire is reasonable
         wire_proto_board_valid = (wire_proto_board and wire_proto_board is
             not proto_board)
         # potentially create another proto board with a resistor in place of
         #     the new wire
         add_resistor = (resistor is not None and not num_piece_crossings and
             not num_wire_crossings and new_wire.length() == 3)
         if add_resistor:
           n1, n2, r, label = (resistor.n1, resistor.n2, resistor.r,
               resistor.label)
           # find representatives for the two nodes, they better be there
           n1_group = proto_board.rep_for(n1)
           assert n1_group
           n2_group = proto_board.rep_for(n2)
           assert n2_group
           # check that wire loc 1 is in the same group as node n1
           assert proto_board.rep_for(new_wire.loc_1) == n1_group
           # find representative for wire loc 2, might not be there
           wire_loc_2_group = proto_board.rep_for(new_wire.loc_2)
           # if it is there, it better be the same as n2_group, or we can't put
           #     a resistor here
           if (not wire_loc_2_group) or wire_loc_2_group == n2_group:
             # figure out correct orientation of Resistor_Piece n1 and n2
             vertical = new_wire.vertical()
             if new_wire.c_1 < new_wire.c_2 or new_wire.r_1 < new_wire.r_2:
               resistor_piece = Resistor_Piece(n1, n2, r, vertical, label)
               resistor_piece.top_left_loc = new_wire.loc_1
             else:
               resistor_piece = Resistor_Piece(n2, n1, r, vertical, label)
               resistor_piece.top_left_loc = new_wire.loc_2
             # create proto board with resistor
             new_proto_board = proto_board.with_piece(resistor_piece)
             if not wire_loc_2_group:
               # ensure to mark the oposite location with its apporpriate node
               new_proto_board = new_proto_board.with_loc_repped(n2_group,
                   new_wire.loc_2)
             # would no longer need a resistor for this pair of locations
             new_resistor = None
             # and the node for the rest of the wires will be the node for the
             #     other end of the resistor
             new_node = n2
           else:
             # placing the resistor would create a violating connection
             add_resistor = False
         if not add_resistor:
           if wire_proto_board_valid:
             # can still put a wire down if allowed
             new_proto_board = wire_proto_board
             new_resistor = resistor
             new_node = node
           else:
             continue
         # we have a candidate proto board, compute state and cost
         new_loc_pairs = list(loc_pairs)
         new_cost = self.cost + new_wire.length()
         if proto_board.connected(wire_end, loc_2):
           new_loc_pairs.pop(i)
           # favor connectedness a lot
           new_cost -= 100
         else:
           new_loc_pairs[i] = (wire_end, loc_2, new_resistor, new_node)
         # penalize long wires
         new_cost += new_wire.length()
         # penalize many wires
         new_cost += 10
         # penalize wires crossing pieces (if allowed at all)
         new_cost += 1000 * num_piece_crossings
         # penalize crossing wires of opposite orientation (if allowed at all)
         new_cost += 1000 * num_wire_crossings
         # favor wires that get us close to the goal, and penalize wires
         #     that get us farther away
         new_cost += dist(wire_end, loc_2) - dist(loc_1, loc_2)
         children.append(Proto_Board_Search_Node(new_proto_board,
             frozenset(new_loc_pairs), self, new_cost,
             self.filter_wire_lengths))
         # if added a resistor, also create a proto board where we use a wire
         #     instead of the resistor
         if add_resistor and wire_proto_board_valid:
           wire_loc_pairs = list(loc_pairs)
           wire_loc_pairs[i] = (wire_end, loc_2, resistor, node)
           children.append(Proto_Board_Search_Node(wire_proto_board,
               frozenset(wire_loc_pairs), self, new_cost,
               self.filter_wire_lengths))
   return children
 def get_children(self):
     children = []
     proto_board, loc_pairs = self.state
     for i, (loc_1, loc_2, resistor, node) in enumerate(loc_pairs):
         # can extend a wire from |loc_1| towards |loc_2| from any of the
         #     the locations |loc_1| is internally connected to
         for neighbor_loc in filter(proto_board.free,
                                    proto_board.locs_connected_to(loc_1)):
             # get candidate end locations for the new wire to draw
             wire_ends = (
                 self._wire_ends_from_rail_loc(neighbor_loc, proto_board)
                 if is_rail_loc(neighbor_loc) else
                 self._wire_ends_from_body_loc(
                     neighbor_loc, proto_board, span=dist(loc_1, loc_2)))
             for wire_end in wire_ends:
                 # make sure that there is a wire to draw
                 if wire_end == neighbor_loc:
                     continue
                 new_wire = Wire(neighbor_loc, wire_end, node)
                 # track number of pieces this wire crosses
                 num_piece_crossings = sum(
                     piece.crossed_by(new_wire)
                     for piece in proto_board.get_pieces())
                 if not ALLOW_PIECE_CROSSINGS and num_piece_crossings:
                     continue
                 # track number of other wires this new wire crosses
                 any_same_orientation_crossings = False
                 num_wire_crossings = 0
                 for wire in proto_board.get_wires():
                     if wire.crosses(new_wire):
                         if wire.vertical() == new_wire.vertical():
                             any_same_orientation_crossings = True
                             break
                         else:
                             num_wire_crossings += 1
                 # don't allow any wire crossings where the two wires have the same
                 #     orientation
                 if any_same_orientation_crossings:
                     continue
                 # continue if we do not want to allow any crossing wires at all, even
                 #     ones of different orientation
                 if not ALLOW_WIRE_CROSSINGS and num_wire_crossings:
                     continue
                 # construct a proto board with this new wire
                 wire_proto_board = proto_board.with_wire(new_wire)
                 # check that adding the wire is reasonable
                 wire_proto_board_valid = (wire_proto_board
                                           and wire_proto_board
                                           is not proto_board)
                 # potentially create another proto board with a resistor in place of
                 #     the new wire
                 add_resistor = (resistor is not None
                                 and not num_piece_crossings
                                 and not num_wire_crossings
                                 and new_wire.length() == 3)
                 if add_resistor:
                     n1, n2, r, label = (resistor.n1, resistor.n2,
                                         resistor.r, resistor.label)
                     # find representatives for the two nodes, they better be there
                     n1_group = proto_board.rep_for(n1)
                     assert n1_group
                     n2_group = proto_board.rep_for(n2)
                     assert n2_group
                     # check that wire loc 1 is in the same group as node n1
                     assert proto_board.rep_for(new_wire.loc_1) == n1_group
                     # find representative for wire loc 2, might not be there
                     wire_loc_2_group = proto_board.rep_for(new_wire.loc_2)
                     # if it is there, it better be the same as n2_group, or we can't put
                     #     a resistor here
                     if (not wire_loc_2_group
                         ) or wire_loc_2_group == n2_group:
                         # figure out correct orientation of Resistor_Piece n1 and n2
                         vertical = new_wire.vertical()
                         if new_wire.c_1 < new_wire.c_2 or new_wire.r_1 < new_wire.r_2:
                             resistor_piece = Resistor_Piece(
                                 n1, n2, r, vertical, label)
                             resistor_piece.top_left_loc = new_wire.loc_1
                         else:
                             resistor_piece = Resistor_Piece(
                                 n2, n1, r, vertical, label)
                             resistor_piece.top_left_loc = new_wire.loc_2
                         # create proto board with resistor
                         new_proto_board = proto_board.with_piece(
                             resistor_piece)
                         if not wire_loc_2_group:
                             # ensure to mark the oposite location with its apporpriate node
                             new_proto_board = new_proto_board.with_loc_repped(
                                 n2_group, new_wire.loc_2)
                         # would no longer need a resistor for this pair of locations
                         new_resistor = None
                         # and the node for the rest of the wires will be the node for the
                         #     other end of the resistor
                         new_node = n2
                     else:
                         # placing the resistor would create a violating connection
                         add_resistor = False
                 if not add_resistor:
                     if wire_proto_board_valid:
                         # can still put a wire down if allowed
                         new_proto_board = wire_proto_board
                         new_resistor = resistor
                         new_node = node
                     else:
                         continue
                 # we have a candidate proto board, compute state and cost
                 new_loc_pairs = list(loc_pairs)
                 new_cost = self.cost + new_wire.length()
                 if proto_board.connected(wire_end, loc_2):
                     new_loc_pairs.pop(i)
                     # favor connectedness a lot
                     new_cost -= 100
                 else:
                     new_loc_pairs[i] = (wire_end, loc_2, new_resistor,
                                         new_node)
                 # penalize long wires
                 new_cost += new_wire.length()
                 # penalize many wires
                 new_cost += 10
                 # penalize wires crossing pieces (if allowed at all)
                 new_cost += 1000 * num_piece_crossings
                 # penalize crossing wires of opposite orientation (if allowed at all)
                 new_cost += 1000 * num_wire_crossings
                 # favor wires that get us close to the goal, and penalize wires
                 #     that get us farther away
                 new_cost += dist(wire_end, loc_2) - dist(loc_1, loc_2)
                 children.append(
                     Proto_Board_Search_Node(new_proto_board,
                                             frozenset(new_loc_pairs), self,
                                             new_cost,
                                             self.filter_wire_lengths))
                 # if added a resistor, also create a proto board where we use a wire
                 #     instead of the resistor
                 if add_resistor and wire_proto_board_valid:
                     wire_loc_pairs = list(loc_pairs)
                     wire_loc_pairs[i] = (wire_end, loc_2, resistor, node)
                     children.append(
                         Proto_Board_Search_Node(wire_proto_board,
                                                 frozenset(wire_loc_pairs),
                                                 self, new_cost,
                                                 self.filter_wire_lengths))
     return children