def compute_location_heuristic(interpreter, speaker, d, mems):
    # handle relative direction
    reldir = d.get("relative_direction")
    loc = mems[0].get_pos()
    if reldir is not None:
        if reldir == "BETWEEN":
            loc = (np.add(mems[0].get_pos(), mems[1].get_pos())) / 2
            loc = (loc[0], loc[1], loc[2])
        elif reldir == "INSIDE":
            ref_obj_dict = d.get("reference_object", SPEAKERLOOK["reference_object"])
            special = ref_obj_dict.get("special_reference")
            if not special:
                for i in range(len(mems)):
                    mem = mems[i]
                    locs = heuristic_perception.find_inside(mem)
                    if len(locs) > 0:
                        break
                if len(locs) == 0:
                    raise ErrorWithResponse("I don't know how to go inside there")
                else:
                    interpreter.memory.update_recent_entities([mem])
                    loc = locs[0]
            else:
                raise ErrorWithResponse("I don't know how to go inside there")
        elif reldir == "AWAY":
            apos = pos_to_np(interpreter.agent.get_player().pos)
            dir_vec = (apos - loc) / np.linalg.norm(apos - loc)
            num_steps = word_to_num(d.get("steps", "5"))
            loc = num_steps * np.array(dir_vec) + to_block_center(loc)
        elif reldir == "NEAR":
            pass
        else:  # LEFT, RIGHT, etc...
            reldir_vec = rotation.DIRECTIONS[reldir]
            look = (
                interpreter.agent.perception_modules["low_level"]
                .get_player_struct_by_name(speaker)
                .look
            )
            # this should be an inverse transform so we set inverted=True
            dir_vec = rotation.transform(reldir_vec, look.yaw, 0, inverted=True)
            num_steps = word_to_num(d.get("steps", "5"))
            loc = num_steps * np.array(dir_vec) + to_block_center(loc)

    # if steps without relative direction
    elif "steps" in d:
        num_steps = word_to_num(d.get("steps", "5"))
        loc = to_block_center(loc) + [0, 0, num_steps]
    return post_process_loc(loc, interpreter)
def interpret_location(interpreter, speaker, d, ignore_reldir=False) -> XYZ:
    """Location dict -> coordinates
    Side effect:  adds mems to agent_memory.recent_entities
    if a reference object is interpreted;
    and loc to memory
    """
    location_type = d.get("location_type", "SPEAKER_LOOK")
    if location_type == "REFERENCE_OBJECT":
        mems = interpret_reference_object(interpreter, speaker,
                                          d["reference_object"])
        if len(mems) == 0:
            raise ErrorWithResponse("I don't know what you're referring to")
        assert len(mems) == 1, mems
        interpreter.memory.update_recent_entities(mems)
        mem = mems[0]
        loc = mem.get_pos()

    elif location_type == "SPEAKER_LOOK":
        player = interpreter.memory.get_player_struct_by_name(speaker)
        loc = capped_line_of_sight(interpreter.agent, player)

    elif location_type == "SPEAKER_POS":
        loc = pos_to_np(
            interpreter.memory.get_player_struct_by_name(speaker).pos)

    elif location_type == "AGENT_POS":
        loc = pos_to_np(interpreter.agent.get_player().pos)

    elif location_type == "COORDINATES":
        loc = cast(
            XYZ,
            tuple(
                int(float(w))
                for w in re.findall("[-0-9.]+", d["coordinates"])))
        if len(loc) != 3:
            logging.error("Bad coordinates: {}".format(d["coordinates"]))
            raise ErrorWithResponse(
                "I don't understand what location you're referring to")

    else:
        raise ValueError(
            "Can't handle Location type: {}".format(location_type))

    # handle relative direction
    reldir = d.get("relative_direction")
    if reldir is not None and not ignore_reldir:
        if reldir == "INSIDE":
            if location_type == "REFERENCE_OBJECT":
                locs = perception.find_inside(mem)
                if len(locs) == 0:
                    raise ErrorWithResponse(
                        "I don't know how to go inside there")
                else:
                    loc = locs[0]
        elif reldir == "AWAY":
            apos = pos_to_np(interpreter.agent.get_player().pos)
            dir_vec = (apos - loc) / np.linalg.norm(apos - loc)
            num_steps = word_to_num(d.get("steps", "5"))
            loc = num_steps * np.array(dir_vec) + to_block_center(loc)
        elif reldir == "NEAR":
            pass
        else:  # LEFT, RIGHT, etc...
            reldir_vec = rotation.DIRECTIONS[reldir]
            look = interpreter.memory.get_player_struct_by_name(speaker).look
            # this should be an inverse transform so we set inverted=True
            dir_vec = rotation.transform(reldir_vec,
                                         look.yaw,
                                         0,
                                         inverted=True)
            num_steps = word_to_num(d.get("steps", "5"))
            loc = num_steps * np.array(dir_vec) + to_block_center(loc)

    # if steps without relative direction
    elif "steps" in d:
        num_steps = word_to_num(d.get("steps", "5"))
        loc = to_block_center(loc) + [0, 0, num_steps]
    return to_block_pos(loc)