예제 #1
0
def get_holes(interpreter,
              speaker,
              location,
              limit=1,
              all_proximity=10) -> List[Tuple[XYZ, Hole]]:
    holes: List[Hole] = perception.get_all_nearby_holes(
        interpreter.agent, location)
    candidates: List[Tuple[XYZ, Hole]] = [
        (to_block_pos(np.mean(hole[0], axis=0)), hole) for hole in holes
    ]
    if len(candidates) > 0:
        # NB(demiguo): by default, we fill the hole the player is looking at
        player = interpreter.memory.get_player_struct_by_name(speaker)
        centroid_hole = object_looked_at(interpreter.agent,
                                         candidates,
                                         player,
                                         limit=limit)
        if centroid_hole is None or len(centroid_hole) == 0:
            # NB(demiguo): if there's no hole in front of the player, we will fill the nearest hole
            speaker_pos = interpreter.memory.get_player_struct_by_name(
                speaker).pos
            speaker_pos = to_block_pos(pos_to_np(speaker_pos))
            if limit == "ALL":
                return list(
                    filter(
                        lambda c: euclid_dist(c[0], speaker_pos) <=
                        all_proximity, candidates))
            else:
                candidates.sort(key=lambda c: euclid_dist(c[0], speaker_pos))
                return candidates[:limit]
        else:
            return centroid_hole
    else:
        return []
예제 #2
0
    def test_action_sequence_order(self):
        target1 = (3, 63, 2)
        target2 = (7, 63, 7)
        d = {
            "dialogue_type":
            "HUMAN_GIVE_COMMAND",
            "action_sequence": [
                {
                    "action_type": "MOVE",
                    "location": {
                        "location_type": "COORDINATES",
                        "coordinates": str(target1)
                    },
                },
                {
                    "action_type": "MOVE",
                    "location": {
                        "location_type": "COORDINATES",
                        "coordinates": str(target2)
                    },
                },
            ],
        }

        self.handle_logical_form(d)
        self.assertLessEqual(euclid_dist(self.agent.pos, target2), 1)
예제 #3
0
    def test_come_here(self):
        chat = "come here"
        self.add_incoming_chat(chat, self.speaker)
        self.flush()

        self.assertLessEqual(
            euclid_dist(self.agent.pos, self.get_speaker_pos()), 1)
예제 #4
0
    def test_stop(self):
        # start moving
        target = (20, 63, 20)
        d = {
            "dialogue_type": "HUMAN_GIVE_COMMAND",
            "action": {
                "action_type": "MOVE",
                "location": {
                    "location_type": "COORDINATES",
                    "coordinates": str(target)
                },
            },
        }
        self.handle_action_dict(d, max_steps=5)

        # stop
        d = {
            "dialogue_type": "HUMAN_GIVE_COMMAND",
            "action": {
                "action_type": "STOP"
            }
        }
        self.handle_action_dict(d)

        # assert that move did not complete
        self.assertGreater(euclid_dist(self.agent.pos, target), 1)
예제 #5
0
    def test_come_here(self):
        chat = "come here"
        self.add_incoming_chat(chat)
        self.dialogue_manager.step((self.speaker, chat))
        self.flush()

        self.assertLessEqual(
            euclid_dist(self.agent.pos, self.get_speaker_pos()), 1)
예제 #6
0
    def test_build_sphere_move_here(self):
        d = COMBINED_COMMANDS["build a small sphere then move here"]
        changes = self.handle_logical_form(d)

        # check that a small object was built
        self.assertGreater(len(changes), 0)
        self.assertLess(len(changes), 30)

        # check that agent moved
        self.assertLessEqual(euclid_dist(self.agent.pos, self.get_speaker_pos()), 1)
예제 #7
0
    def test_move_here(self):
        d = {
            "dialogue_type": "HUMAN_GIVE_COMMAND",
            "action": self.possible_actions["move_speaker_pos"],
        }
        self.handle_logical_form(d)

        # check that agent moved
        self.assertLessEqual(
            euclid_dist(self.agent.pos, self.get_speaker_pos()), 1)
예제 #8
0
    def perceive(self, force=False):
        # FIXME (low pri) remove these in code, get from sql
        self.agent.pos = to_block_pos(pos_to_np(self.agent.get_player().pos))

        if self.agent.count % self.perceive_freq == 0 or force:
            for mob in self.agent.get_mobs():
                if euclid_dist(self.agent.pos, pos_to_np(
                        mob.pos)) < self.memory.perception_range:
                    self.memory.set_mob_position(mob)
            for item_stack in self.agent.get_item_stacks():
                if (euclid_dist(self.agent.pos, pos_to_np(item_stack.pos)) <
                        self.memory.perception_range):
                    self.memory.set_item_stack_position(item_stack)

        # note: no "force"; these run on every perceive call.  assumed to be fast
        self.update_self_memory()
        self.update_other_players(self.agent.get_other_players())

        # use safe_get_changed_blocks to deal with pointing
        for (xyz, idm) in self.agent.safe_get_changed_blocks():
            self.on_block_changed(xyz, idm)
예제 #9
0
    def test_stop(self):
        # start moving
        target = (20, 63, 20)
        d = MOVE_COMMANDS["move to 20 63 20"]
        self.handle_logical_form(d, max_steps=5)

        # stop
        d = OTHER_COMMANDS["stop"]
        self.handle_logical_form(d)

        # assert that move did not complete
        self.assertGreater(euclid_dist(self.agent.pos, target), 1)
예제 #10
0
 def _is_placed_block_interesting(self, xyz: XYZ, bid: int) -> Tuple[bool, bool]:
     """Return two values:
     - bool: is the placed block interesting?
     - bool: is it interesting because it was placed by a player?
     """
     if xyz in self.pending_agent_placed_blocks:
         self.pending_agent_placed_blocks.remove(xyz)
         return True, True
     for player in self.other_players.values():
         if util.euclid_dist(util.pos_to_np(player.pos), xyz) < 5 and player.mainHand.id == bid:
             return True, True
     if bid not in BORING_BLOCKS:
         return True, False
     return False, False
예제 #11
0
    def test_move_here(self):
        d = {
            "dialogue_type": "HUMAN_GIVE_COMMAND",
            "action": {
                "action_type": "MOVE",
                "location": {
                    "location_type": "SPEAKER_POS"
                }
            },
        }
        self.handle_action_dict(d)

        # check that agent moved
        self.assertLessEqual(
            euclid_dist(self.agent.pos, self.get_speaker_pos()), 1)
예제 #12
0
    def test_move_coordinates(self):
        d = {
            "dialogue_type": "HUMAN_GIVE_COMMAND",
            "action": {
                "action_type": "MOVE",
                "location": {
                    "location_type": "COORDINATES",
                    "coordinates": "-7 63 -8"
                },
            },
        }
        self.handle_action_dict(d)

        # check that agent moved
        self.assertLessEqual(euclid_dist(self.agent.pos, (-7, 63, -8)), 1)
예제 #13
0
def find_inside(entity):
    """Return a point inside the entity if it can find one.
    TODO: heuristic quick check to find that there aren't any,
    and maybe make this not d^3"""
    l = util.get_locs_from_entity(entity)
    if l is None:
        return None
    m = np.round(np.mean(l, axis=0))
    maxes = np.max(l, axis=0)
    mins = np.min(l, axis=0)
    inside = []
    for x in range(mins[0], maxes[0] + 1):
        for y in range(mins[1], maxes[1] + 1):
            for z in range(mins[2], maxes[2] + 1):
                if check_inside([(x, y, z), entity]):
                    inside.append((x, y, z))
    return sorted(inside, key=lambda x: util.euclid_dist(x, m))
예제 #14
0
    def test_build_sphere_move_here(self):
        d = {
            "dialogue_type":
            "HUMAN_GIVE_COMMAND",
            "action_sequence": [
                self.possible_actions["build_small_sphere"],
                self.possible_actions["move_speaker_pos"],
            ],
        }
        changes = self.handle_logical_form(d)

        # check that a small object was built
        self.assertGreater(len(changes), 0)
        self.assertLess(len(changes), 30)

        # check that agent moved
        self.assertLessEqual(
            euclid_dist(self.agent.pos, self.get_speaker_pos()), 1)
예제 #15
0
 def _is_placed_block_interesting(self, xyz: XYZ,
                                  bid: int) -> Tuple[bool, bool, bool]:
     """Return three values:
     - bool: is the placed block interesting?
     - bool: is it interesting because it was placed by a player?
     - bool: is it interesting because it was placed by the agent?
     """
     interesting = False
     player_placed = False
     agent_placed = False
     # TODO record *which* player placed it
     if xyz in self.pending_agent_placed_blocks:
         self.pending_agent_placed_blocks.remove(xyz)
         interesting = True
         agent_placed = True
     for player in self.other_players.values():
         if util.euclid_dist(util.pos_to_np(player.pos),
                             xyz) < 5 and player.mainHand.id == bid:
             interesting = True
             player_placed = True
     if bid not in BORING_BLOCKS:
         interesting = True
     return interesting, player_placed, agent_placed
예제 #16
0
def find_inside(entity):
    """Return a point inside the entity if it can find one.
    TODO: heuristic quick check to find that there aren't any,
    and maybe make this not d^3"""

    # is this a negative object? if yes, just return its mean:
    if hasattr(entity, "blocks"):
        if all(b == (0, 0) for b in entity.blocks.values()):
            m = np.mean(list(entity.blocks.keys()), axis=0)
            return [util.to_block_pos(m)]
    l = util.get_locs_from_entity(entity)
    if l is None:
        return None
    m = np.round(np.mean(l, axis=0))
    maxes = np.max(l, axis=0)
    mins = np.min(l, axis=0)
    inside = []
    for x in range(mins[0], maxes[0] + 1):
        for y in range(mins[1], maxes[1] + 1):
            for z in range(mins[2], maxes[2] + 1):
                if check_inside([(x, y, z), entity]):
                    inside.append((x, y, z))
    return sorted(inside, key=lambda x: util.euclid_dist(x, m))
예제 #17
0
def check_between(entities, fat_scale=0.2):
    """ Heuristic check if entities[0] is between entities[1] and entities[2]
    by checking if the locs of enitity[0] are in the convex hull of
    union of the max cardinal points of entity[1] and entity[2]"""
    locs = []
    means = []
    for e in entities:
        l = util.get_locs_from_entity(e)
        if l is not None:
            locs.append(l)
            means.append(np.mean(l, axis=0))
        else:
            # this is not a thing we know how to assign 'between' to
            return False
    mean_separation = util.euclid_dist(means[1], means[2])
    fat = fat_scale * mean_separation
    bounding_locs = []
    for l in locs:
        if len(l) > 1:
            bl = []
            idx = np.argmax(l, axis=0)
            for i in range(3):
                f = np.zeros(3)
                f[i] = fat
                bl.append(np.array(l[idx[i]]) + fat)
            idx = np.argmin(l, axis=0)
            for i in range(3):
                f = np.zeros(3)
                f[i] = fat
                bl.append(np.array(l[idx[i]]) - fat)
            bounding_locs.append(np.concatenate(bl))
        else:
            bounding_locs.append(np.array(l))
    x = np.mean(bounding_locs[0], axis=0)
    points = np.concatenate(bounding_locs[1], bounding_locs[2])
    return in_hull(points, x)
예제 #18
0
def filter_by_sublocation(
    interpreter,
    speaker,
    candidates: List[Tuple[XYZ, T]],
    location: Dict,
    limit=1,
    all_proximity=10,
    loose=False,
) -> List[Tuple[XYZ, T]]:
    """Select from a list of candidate (xyz, object) tuples given a sublocation

    If limit == 'ALL', return all matching candidates

    Returns a list of (xyz, mem) tuples
    """

    # handle SPEAKER_LOOK separately due to slightly different semantics
    # (proximity to ray instead of point)
    if location.get("location_type") == "SPEAKER_LOOK":
        player = interpreter.memory.get_player_struct_by_name(speaker)
        return object_looked_at(interpreter.agent,
                                candidates,
                                player,
                                limit=limit,
                                loose=loose)

    reldir = location.get("relative_direction")
    if reldir:
        if reldir == "INSIDE":
            if location.get("reference_object"):
                # this is ugly, should probably return from interpret_location...
                ref_mems = interpret_reference_object(
                    interpreter, speaker, location["reference_object"])
                for l, candidate_mem in candidates:
                    if perception.check_inside([candidate_mem, ref_mems[0]]):
                        return [(l, candidate_mem)]
            raise ErrorWithResponse("I can't find something inside that")
        elif reldir == "AWAY":
            raise ErrorWithResponse("I don't know which object you mean")
        elif reldir == "NEAR":
            pass  # fall back to no reference direction
        else:
            # reference object location, i.e. the "X" in "left of X"
            ref_loc = interpret_location(interpreter,
                                         speaker,
                                         location,
                                         ignore_reldir=True)
            # relative direction, i.e. the "LEFT" in "left of X"
            reldir_vec = rotation.DIRECTIONS[reldir]

            # transform each object into the speaker look coordinate system,
            # and project onto the reldir vector
            look = interpreter.memory.get_player_struct_by_name(speaker).look
            proj = [
                rotation.transform(np.array(l) - ref_loc, look.yaw, 0)
                @ reldir_vec for (l, _) in candidates
            ]

            # filter by relative dir, e.g. "left of Y"
            proj_cands = [(p, c) for (p, c) in zip(proj, candidates) if p > 0]

            # "the X left of Y" = the right-most X that is left of Y
            if limit == "ALL":
                limit = len(proj_cands)
            return [c for (_, c) in sorted(proj_cands, key=lambda p: p[0])
                    ][:limit]
    else:
        # no reference direction: choose the closest
        if limit == "ALL":
            return list(
                filter(lambda c: euclid_dist(c[0], ref_loc) <= all_proximity,
                       candidates))
        else:
            candidates.sort(key=lambda c: euclid_dist(c[0], ref_loc))
            return candidates[:limit]
    return []  # this fixes flake but seems awful?
예제 #19
0
    def test_move_here(self):
        d = MOVE_COMMANDS["move here"]
        self.handle_logical_form(d)

        # check that agent moved
        self.assertLessEqual(euclid_dist(self.agent.pos, self.get_speaker_pos()), 1)
예제 #20
0
    def test_move_coordinates(self):
        d = MOVE_COMMANDS["move to -7 63 -8"]
        self.handle_logical_form(d)

        # check that agent moved
        self.assertLessEqual(euclid_dist(self.agent.pos, (-7, 63, -8)), 1)
예제 #21
0
 def test_action_sequence_order(self):
     d = COMBINED_COMMANDS["move to 3 63 2 then 7 63 7"]
     self.handle_logical_form(d)
     self.assertLessEqual(euclid_dist(self.agent.pos, (7, 63, 7)), 1)