Exemple #1
0
def _astar(X, start, goal, approx=0):
    """Find a path through X from start to goal.

    Args:
    - X: a 3d array of obstacles, i.e. False -> passable, True -> not passable
    - start/goal: relative positions in X
    - approx: proximity to goal before search is complete (0 = exact)

    Returns: a list of relative positions, from start to goal
    """
    start = tuple(start)
    goal = tuple(goal)

    visited = set()
    came_from = {}
    q = PriorityQueue()
    q.push(start, util.manhat_dist(start, goal))
    G = np.full_like(X, np.iinfo(np.uint32).max, "uint32")
    G[start] = 0

    while len(q) > 0:
        _, p = q.pop()

        if util.manhat_dist(p, goal) <= approx:
            path = []
            while p in came_from:
                path.append(p)
                p = came_from[p]
            return [start] + list(reversed(path))

        visited.add(p)
        for a in util.adjacent(p):
            if (a in visited or a[0] < 0 or a[0] >= X.shape[0] or a[1] < 0
                    or a[1] >= X.shape[1] or a[2] < 0 or a[2] >= X.shape[2]
                    or X[a]):
                continue

            g = G[p] + 1
            if g >= G[a]:
                continue
            came_from[a] = p
            G[a] = g
            f = g + util.manhat_dist(a, goal)
            if q.contains(a):
                q.replace(a, f)
            else:
                q.push(a, f)

    return None
Exemple #2
0
 def step(self, agent):
     if util.manhat_dist(agent.pos, self.pos) > self.PLACE_REACH:
         task = Move(agent, {"target": self.pos, "approx": self.PLACE_REACH})
         agent.memory.task_stack_push(task, parent_memid=self.memid)
     else:
         agent.set_held_item(self.object_idm)
         if np.equal(self.pos, agent.pos).all():
             agent.step_neg_z()
         agent.place_block(self.pos[0], self.pos[1] + 1, self.pos[2])
         time.sleep(0.1)
         agent.memory.update(agent)
         x, y, z = self.pos
         mobtype = MOBS_BY_ID[self.object_idm[1]]
         mobmem = agent.memory.get_mobs(
             spatial_range=[x - 5, x + 5, y - 5, y + 5, z - 5, z + 5],
             spawntime=[time.time() - 2, -1],
             mobtype=mobtype,
         )
         if len(mobmem) > 0:
             mobmem = mobmem[0]
             agent.memory.update_recent_entities(mems=[mobmem])
             if self.memid is not None:
                 agent.memory.add_triple(self.memid, "task_effect_", mobmem.memid)
                 # the chat_effect_ triple was already made when the task is added if there was a chat...
                 # but it points to the task memory.  link the chat to the mob memory:
                 chat_mem_triples = agent.memory.get_triples(
                     subj=None, pred="chat_effect_", obj=self.memid
                 )
                 if len(chat_mem_triples) > 0:
                     chat_memid = chat_mem_triples[0][0]
                     agent.memory.add_triple(chat_memid, "chat_effect_", mobmem.memid)
         self.finished = True
Exemple #3
0
 def step(self, agent):
     if util.manhat_dist(agent.pos, self.pos) > self.PLACE_REACH:
         task = Move(agent, {
             "target": self.pos,
             "approx": self.PLACE_REACH
         })
         agent.memory.task_stack_push(task, parent_memid=self.memid)
     else:
         agent.set_held_item(self.object_idm)
         if np.equal(self.pos, agent.pos).all():
             agent.step_neg_z()
         x, y, z = self.pos
         y = y + 1
         agent.place_block(x, y, z)
         time.sleep(0.1)
         mindist, placed_mob = self.find_nearby_new_mob(agent)
         if mindist < 3:
             memid = MobNode.create(agent.memory,
                                    placed_mob,
                                    agent_placed=True)
             mobmem = agent.memory.get_mob_by_id(memid)
             agent.memory.update_recent_entities(mems=[mobmem])
             if self.memid is not None:
                 agent.memory.add_triple(self.memid, "task_effect_",
                                         mobmem.memid)
                 # the chat_effect_ triple was already made when the task is added if there was a chat...
                 # but it points to the task memory.  link the chat to the mob memory:
                 chat_mem_triples = agent.memory.get_triples(
                     subj=None, pred="chat_effect_", obj=self.memid)
                 if len(chat_mem_triples) > 0:
                     chat_memid = chat_mem_triples[0][0]
                     agent.memory.add_triple(chat_memid, "chat_effect_",
                                             mobmem.memid)
         self.finished = True
Exemple #4
0
    def step(self, agent):
        self.interrupted = False
        # wait certain amount of ticks until issuing next step
        # while not (agent.memory.get_time() - self.last_stepped_time) > self.throttling_tick:
        #    pass

        # replace blocks if possible
        R = self.replace.copy()
        self.replace.clear()
        for (pos, idm) in R:
            agent.set_held_item(idm)
            if agent.place_block(*pos):
                logging.info("Move: replaced {}".format((pos, idm)))
            else:
                # try again later
                self.replace.add((pos, idm))
        if len(self.replace) > 0:
            logging.info("Replace remaining: {}".format(self.replace))

        # check if finished
        if util.manhat_dist(tuple(agent.pos), self.target) <= self.approx:
            if len(self.replace) > 0:
                logging.error(
                    "Move finished with non-empty replace set: {}".format(
                        self.replace))
            self.finished = True
            if self.memid is not None:
                locmemid = agent.memory.add_location(self.target)
                locmem = agent.memory.get_location_by_id(locmemid)
                agent.memory.update_recent_entities(mems=[locmem])
                agent.memory.add_triple(subj=self.memid,
                                        pred_text="task_effect_",
                                        obj=locmemid)
                chat_mem_triples = agent.memory.get_triples(
                    subj=None, pred_text="chat_effect_", obj=self.memid)
                if len(chat_mem_triples) > 0:
                    chat_memid = chat_mem_triples[0][0]
                    agent.memory.add_triple(subj=chat_memid,
                                            pred_text="chat_effect_",
                                            obj=locmemid)
            return

        # get path
        if self.path is None or tuple(agent.pos) != self.path[-1]:
            self.path = search.astar(agent, self.target, self.approx)
            if self.path is None:
                self.handle_no_path(agent)
                return

        # take a step on the path
        assert tuple(agent.pos) == self.path.pop()
        step = tuple(self.path[-1] - agent.pos)
        step_fn = getattr(agent, self.STEP_FNS[step])
        step_fn()

        self.last_stepped_time = agent.memory.get_time()
Exemple #5
0
    def get_target(self, agent):
        p = agent.pos
        for i, c in enumerate(sorted(self.xyz_remaining, key=lambda c: util.manhat_dist(p, c))):
            path = search.astar(agent, c, approx=2)
            if path is not None:
                if i > 0:
                    logging.debug("Destroy get_target wasted {} astars".format(i))
                return c

        # No path to any of the blocks
        return None
Exemple #6
0
def closest_nearby_object(get_blocks, pos):
    """Find the closest interesting object to pos

    Returns a list of ((x,y,z), (id, meta)), or None if no interesting objects are nearby
    """
    objects = all_nearby_objects(get_blocks, pos)
    if len(objects) == 0:
        return None
    centroids = [np.mean([pos for (pos, idm) in obj], axis=0) for obj in objects]
    dists = [util.manhat_dist(c, pos) for c in centroids]
    return objects[np.argmin(dists)]
Exemple #7
0
def find_closest_component(mask, relpos):
    """Find the connected component of nonzeros that is closest to loc

    Args:
    - mask is a 3d array
    - relpos is a relative position in the mask, with the same ordering

    Returns: a list of indices of the closest connected component, or None
    """
    components = connected_components(mask)
    if len(components) == 0:
        return None
    centroids = [np.mean(cs, axis=0) for cs in components]
    dists = [util.manhat_dist(c, relpos) for c in centroids]
    return components[np.argmin(dists)]
Exemple #8
0
 def find_nearby_new_mob(self, agent):
     mindist = 1000000
     near_new_mob = None
     x, y, z = self.pos
     y = y + 1
     for mob in agent.get_mobs():
         if MOBS_BY_ID[mob.mobType] == self.mobtype:
             dist = util.manhat_dist((mob.pos.x, mob.pos.y, mob.pos.z),
                                     (x, y, z))
             # hope this doesn;t take so long mob gets away...
             if dist < mindist:
                 #                    print(MOBS_BY_ID[mob.mobType], dist)
                 if not agent.memory.get_entity_by_eid(mob.entityId):
                     mindist = dist
                     near_new_mob = mob
     return mindist, near_new_mob
Exemple #9
0
    def step(self, agent):
        self.interrupted = False
        if len(self.xyz_remaining) == 0:
            self.finished = True
            if self.dig_message:
                agent.send_chat("I finished digging this.")
            return

        target = self.get_target(agent)
        if target is None:
            logging.info("No path from {} to {}".format(agent.pos, self.xyz_remaining))
            agent.send_chat("There's no path, so I'm giving up")
            self.finished = True
            return

        if util.manhat_dist(agent.pos, target) <= self.DIG_REACH:
            agent.dig(*target)
            self.xyz_remaining.remove(target)
            return
        else:
            mv = Move(agent, {"target": target, "approx": self.DIG_REACH}, self.featurizer)
            agent.memory.task_stack_push(mv, parent_memid=self.memid)
Exemple #10
0
    def get_next_place_target(self, agent, current, diff):
        """Return the next block that will be targeted for placing

        In order:
        1. don't build over your own body
        2. build ground-up
        3. try failed blocks again at the end
        4. build closer blocks first

        Args:
        - current: yzxb-ordered current state of the region
        - diff: a yzx-ordered boolean mask of blocks that need addressing
        """
        relpos_yzx = (agent.pos - self.origin)[[1, 2, 0]]

        diff_yzx = list(np.argwhere(diff))
        diff_yzx.sort(key=lambda yzx: util.manhat_dist(yzx, relpos_yzx))  # 4
        diff_yzx.sort(key=lambda yzx: -self.attempts[tuple(yzx)])  # 3
        diff_yzx.sort(key=lambda yzx: yzx[0])  # 2
        diff_yzx.sort(key=lambda yzx: tuple(yzx) in
                      (tuple(relpos_yzx), tuple(relpos_yzx + [1, 0, 0])))  # 1
        return diff_yzx[0]
Exemple #11
0
    def step(self, agent):
        self.interrupted = False

        # get blocks occupying build area
        ox, oy, oz = self.origin
        sy, sz, sx, _ = self.schematic.shape
        current = agent.get_blocks(ox, ox + sx - 1, oy, oy + sy - 1, oz, oz + sz - 1)

        # save state for undo()
        if self.old_blocks_list is None:
            self.old_blocks_list = npy_to_blocks_list(current, self.origin)
            if len(self.old_blocks_list) > 0:
                self.old_origin = np.min(util.strip_idmeta(self.old_blocks_list), axis=0)

        # are we done?
        # TODO: diff ignores block meta right now because placing stairs and
        # chests in the appropriate orientation is non-trivial
        diff = (
            (current[:, :, :, 0] != self.schematic[:, :, :, 0])
            & (self.attempts > 0)
            & np.isin(current[:, :, :, 0], BUILD_IGNORE_BLOCKS, invert=True)
        )
        if self.embed:
            diff &= self.schematic[:, :, :, 0] != 0  # don't delete blocks
        for pair in BUILD_INTERCHANGEABLE_PAIRS:
            diff &= np.isin(current[:, :, :, 0], pair, invert=True) | np.isin(
                self.schematic[:, :, :, 0], pair, invert=True
            )
        if not np.any(diff):
            self.finish(agent)
            return

        # blocks that would need to be removed
        remove_mask = diff & (current[:, :, :, 0] != 0)

        # destroy any blocks in the way first
        rel_yzxs = np.argwhere(remove_mask)
        xyzs = [
            (x + self.origin[0], y + self.origin[1], z + self.origin[2]) for (y, z, x) in rel_yzxs
        ]
        if xyzs:
            logging.info("Excavating {} blocks first".format(len(xyzs)))
            agent.memory.task_stack_push(
                Destroy(agent, {"schematic": util.fill_idmeta(agent, xyzs)}),
                parent_memid=self.memid,
            )
            return

        # get next block to place
        yzx = self.get_next_target(agent, current, diff)
        idm = self.schematic[tuple(yzx)]
        current_idm = current[tuple(yzx)]

        # try placing block
        target = yzx[[2, 0, 1]] + self.origin
        logging.debug("trying to place {} @ {}".format(idm, target))
        if tuple(target) in (tuple(agent.pos), tuple(agent.pos + [0, 1, 0])):
            # can't place block where you're standing, so step out of the way
            self.step_any_dir(agent)
            return
        if util.manhat_dist(agent.pos, target) <= self.PLACE_REACH:
            # block is within reach
            assert current_idm[0] != idm[0], "current={} idm={}".format(current_idm, idm)
            if current_idm[0] != 0:
                logging.debug(
                    "removing block {} @ {} from {}".format(current_idm, target, agent.pos)
                )
                agent.dig(*target)
            if idm[0] != 0:
                agent.set_held_item(idm)
                logging.debug("placing block {} @ {} from {}".format(idm, target, agent.pos))
                x, y, z = target
                if agent.place_block(x, y, z):
                    B = agent.get_blocks(x, x, y, y, z, z)
                    if B[0, 0, 0, 0] == idm[0]:
                        agent.memory.pending_agent_placed_blocks.add((x, y, z))
                    else:
                        logging.error(
                            "failed to place block {} @ {}, but place_block returned True. \
                                Got {} instead.".format(
                                idm, target, B[0, 0, 0, :]
                            )
                        )
                    self.new_blocks.append(((x, y, z), idm))
                else:
                    logging.warn("failed to place block {} from {}".format(target, agent.pos))
            self.attempts[tuple(yzx)] -= 1
            if self.attempts[tuple(yzx)] == 0 and not self.giving_up_message_sent:
                agent.send_chat(
                    "I'm skipping a block because I can't place it. Maybe something is in the way."
                )
                self.giving_up_message_sent = True
        else:
            # too far to place; move first
            task = Move(agent, {"target": target, "approx": self.PLACE_REACH}, self.featurizer)
            agent.memory.task_stack_push(task, parent_memid=self.memid)
Exemple #12
0
    def step(self, agent):
        self.interrupted = False

        # wait certain amount of ticks until issuing next step
        # while not (agent.memory.get_time() - self.last_stepped_time) > self.throttling_tick:
        #    pass

        # get blocks occupying build area
        ox, oy, oz = self.origin
        sy, sz, sx, _ = self.schematic.shape
        current = agent.get_blocks(ox, ox + sx - 1, oy, oy + sy - 1, oz,
                                   oz + sz - 1)

        # are we done?
        # TODO: diff ignores block meta right now because placing stairs and
        # chests in the appropriate orientation is non-trivial
        diff = (
            (current[:, :, :, 0] != self.schematic[:, :, :, 0])
            & (self.attempts > 0)
            & np.isin(current[:, :, :, 0], BUILD_IGNORE_BLOCKS, invert=True))

        # ignore negative blocks if there is already air there
        diff &= (self.schematic[:, :, :, 0] + current[:, :, :, 0]) >= 0

        if self.embed:
            diff &= self.schematic[:, :, :,
                                   0] != 0  # don't delete blocks if self.embed

        for pair in BUILD_INTERCHANGEABLE_PAIRS:
            diff &= np.isin(current[:, :, :, 0], pair, invert=True) | np.isin(
                self.schematic[:, :, :, 0], pair, invert=True)

        if not np.any(diff):
            self.finish(agent)
            return

        # blocks that would need to be removed
        remove_mask = diff & (current[:, :, :, 0] != 0)

        # destroy any blocks in the way (or any that are slated to be destroyed in schematic)
        # first
        rel_yzxs = np.argwhere(remove_mask)
        xyzs = set([(x + self.origin[0], y + self.origin[1],
                     z + self.origin[2]) for (y, z, x) in rel_yzxs])
        if len(xyzs) != 0:
            logging.info("Excavating {} blocks first".format(len(xyzs)))
            target = self.get_next_destroy_target(agent, xyzs)
            if target is None:
                logging.info("No path from {} to {}".format(agent.pos, xyzs))
                agent.send_chat("There's no path, so I'm giving up")
                self.finished = True
                return

            if util.manhat_dist(agent.pos, target) <= self.DIG_REACH:
                success = agent.dig(*target)
                if success:
                    agent.perception_modules[
                        "low_level"].maybe_remove_inst_seg(target)
                    if self.is_destroy_schm:
                        agent.perception_modules[
                            "low_level"].maybe_remove_block_from_memory(
                                target, (0, 0))
                    else:
                        agent.perception_modules[
                            "low_level"].maybe_add_block_to_memory(
                                target, (0, 0), agent_placed=True)
                        self.add_tags(agent, (target, (0, 0)))
                    agent.get_changed_blocks()
            else:
                mv = Move(agent, {"target": target, "approx": self.DIG_REACH})
                agent.memory.task_stack_push(mv, parent_memid=self.memid)

            return

        # for a build task with destroy schematic,
        # it is done when all different blocks are removed
        elif self.is_destroy_schm:
            self.finish(agent)
            return

        # get next block to place
        yzx = self.get_next_place_target(agent, current, diff)
        idm = self.schematic[tuple(yzx)]
        current_idm = current[tuple(yzx)]

        # try placing block
        target = yzx[[2, 0, 1]] + self.origin
        logging.debug("trying to place {} @ {}".format(idm, target))
        if tuple(target) in (tuple(agent.pos), tuple(agent.pos + [0, 1, 0])):
            # can't place block where you're standing, so step out of the way
            self.step_any_dir(agent)
            return
        if util.manhat_dist(agent.pos, target) <= self.PLACE_REACH:
            # block is within reach
            assert current_idm[0] != idm[0], "current={} idm={}".format(
                current_idm, idm)
            if current_idm[0] != 0:
                logging.debug("removing block {} @ {} from {}".format(
                    current_idm, target, agent.pos))
                agent.dig(*target)
            if idm[0] > 0:
                agent.set_held_item(idm)
                logging.debug("placing block {} @ {} from {}".format(
                    idm, target, agent.pos))
                x, y, z = target
                if agent.place_block(x, y, z):
                    B = agent.get_blocks(x, x, y, y, z, z)
                    if B[0, 0, 0, 0] == idm[0]:
                        agent.perception_modules[
                            "low_level"].maybe_add_block_to_memory(
                                (x, y, z), tuple(idm), agent_placed=True)
                        changed_blocks = agent.get_changed_blocks()
                        self.new_blocks.append(((x, y, z), tuple(idm)))
                        self.add_tags(agent, ((x, y, z), tuple(idm)))
                    else:
                        logging.error(
                            "failed to place block {} @ {}, but place_block returned True. \
                                Got {} instead.".format(
                                idm, target, B[0, 0, 0, :]))
                else:
                    logging.warn("failed to place block {} from {}".format(
                        target, agent.pos))
                if idm[0] == 6:  # hacky: all saplings have id 6
                    agent.set_held_item([351,
                                         15])  # use bone meal on tree saplings
                    if len(changed_blocks) > 0:
                        sapling_pos = changed_blocks[0][0]
                        x, y, z = sapling_pos
                        for _ in range(
                                6
                        ):  # use at most 6 bone meal (should be enough)
                            agent.use_item_on_block(x, y, z)
                            changed_blocks = agent.get_changed_blocks()
                            changed_block_poss = {
                                block[0]
                                for block in changed_blocks
                            }
                            # sapling has grown to a full tree, stop using bone meal
                            if (x, y, z) in changed_block_poss:
                                break

            self.attempts[tuple(yzx)] -= 1
            if self.attempts[tuple(
                    yzx)] == 0 and not self.giving_up_message_sent:
                agent.send_chat(
                    "I'm skipping a block because I can't place it. Maybe something is in the way."
                )
                self.giving_up_message_sent = True
        else:
            # too far to place; move first
            task = Move(agent, {"target": target, "approx": self.PLACE_REACH})
            agent.memory.task_stack_push(task, parent_memid=self.memid)