def find_terrible_wiring(loc_pairs, start_proto_board):
  """
  Finds a terrible wiring without penalizing anything at all.
  To be used as a fall-back option.
  """
  proto_board = start_proto_board
  connect_loc_pairs = []
  resistor_r1 = PROTO_BOARD_HEIGHT / 2 - 1
  resistor_r2 = resistor_r1 + 1
  def find_free_c():
    c = PROTO_BOARD_WIDTH / 2
    for dc in xrange(PROTO_BOARD_WIDTH / 2):
      for sign in (-1, 1):
        _c = c + sign * dc
        locs = ((resistor_r1, _c), (resistor_r2, _c))
        if all(proto_board.rep_for(loc) is None and proto_board.free(loc) for
            loc in locs):
          return _c
    return None
  for loc_1, loc_2, resistor, node in loc_pairs:
    if resistor:
      c = find_free_c()
      if c is None:
        print 'Terrible wiring failed: no space for resistor'
        return None
      resistor_piece = Resistor_Piece(resistor.n1, resistor.n2, resistor.r,
          True, resistor.label)
      resistor_piece.top_left_loc = (resistor_r1, c)
      proto_board = proto_board.with_piece(resistor_piece)
      proto_board = proto_board.with_loc_repped(proto_board.rep_for(
          resistor.n1), (resistor_r1, c))
      proto_board = proto_board.with_loc_repped(proto_board.rep_for(
          resistor.n2), (resistor_r2, c))
      connect_loc_pairs.append((loc_1, (resistor_r1, c), resistor.n1))
      connect_loc_pairs.append((loc_2, (resistor_r2, c), resistor.n2))
    else:
      connect_loc_pairs.append((loc_1, loc_2, node))
  for loc_1, loc_2, node in connect_loc_pairs:
    candidates = list(product(filter(proto_board.free,
        proto_board.locs_connected_to(loc_1)), filter(proto_board.free,
        proto_board.locs_connected_to(loc_2))))
    if not candidates:
      print 'Terrible wiring failed: could not connect %s and %s' % (loc_1,
          loc_2)
      return None
    def cost((l1, l2)):
      wire = Wire(l1, l2, node)
      num_wires_crossed = sum(_wire.crosses(wire) for _wire in
          proto_board.get_wires())
      num_pieces_crossed = sum(piece.crossed_by(wire) for piece in
          proto_board.get_pieces())
      return 100 * (num_wires_crossed + num_pieces_crossed) + dist(l1, l2)
    l1, l2 = min(candidates, key=cost)
    proto_board = proto_board.with_wire(Wire(l1, l2, node))
  return proto_board
Example #2
0
def resistor_piece_from_resistor(resistor):
    """
  Returns a Resistor_Piece constructed using |resistor|, an instance of
      Resistor.
  """
    assert isinstance(resistor, Resistor), 'resistor must be a Resistor'
    return Resistor_Piece(resistor.n1, resistor.n2, resistor.r, True,
                          resistor.label)
 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 find_terrible_wiring(loc_pairs, start_proto_board):
    """
  Finds a terrible wiring without penalizing anything at all.
  To be used as a fall-back option.
  """
    proto_board = start_proto_board
    connect_loc_pairs = []
    resistor_r1 = PROTO_BOARD_HEIGHT / 2 - 1
    resistor_r2 = resistor_r1 + 1

    def find_free_c():
        c = PROTO_BOARD_WIDTH / 2
        for dc in xrange(PROTO_BOARD_WIDTH / 2):
            for sign in (-1, 1):
                _c = c + sign * dc
                locs = ((resistor_r1, _c), (resistor_r2, _c))
                if all(
                        proto_board.rep_for(loc) is None
                        and proto_board.free(loc) for loc in locs):
                    return _c
        return None

    for loc_1, loc_2, resistor, node in loc_pairs:
        if resistor:
            c = find_free_c()
            if c is None:
                print 'Terrible wiring failed: no space for resistor'
                return None
            resistor_piece = Resistor_Piece(resistor.n1, resistor.n2,
                                            resistor.r, True, resistor.label)
            resistor_piece.top_left_loc = (resistor_r1, c)
            proto_board = proto_board.with_piece(resistor_piece)
            proto_board = proto_board.with_loc_repped(
                proto_board.rep_for(resistor.n1), (resistor_r1, c))
            proto_board = proto_board.with_loc_repped(
                proto_board.rep_for(resistor.n2), (resistor_r2, c))
            connect_loc_pairs.append((loc_1, (resistor_r1, c), resistor.n1))
            connect_loc_pairs.append((loc_2, (resistor_r2, c), resistor.n2))
        else:
            connect_loc_pairs.append((loc_1, loc_2, node))
    for loc_1, loc_2, node in connect_loc_pairs:
        candidates = list(
            product(
                filter(proto_board.free, proto_board.locs_connected_to(loc_1)),
                filter(proto_board.free,
                       proto_board.locs_connected_to(loc_2))))
        if not candidates:
            print 'Terrible wiring failed: could not connect %s and %s' % (
                loc_1, loc_2)
            return None

        def cost((l1, l2)):
            wire = Wire(l1, l2, node)
            num_wires_crossed = sum(
                _wire.crosses(wire) for _wire in proto_board.get_wires())
            num_pieces_crossed = sum(
                piece.crossed_by(wire) for piece in proto_board.get_pieces())
            return 100 * (num_wires_crossed + num_pieces_crossed) + dist(
                l1, l2)

        l1, l2 = min(candidates, key=cost)
        proto_board = proto_board.with_wire(Wire(l1, l2, node))
    return proto_board
 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