findClosestByPath/Range from a list of items in memory



  • Hello everyone,

    Even though you will notice soon, i have to say i'm pretty bad at programming, so excuse me if your eyes hurt.

    The following is the code i use for my builders

        let targets = creep.room.find(FIND_CONSTRUCTION_SITES);
        if(targets.length > 0) {
            let target = creep.pos.findClosestByPath(FIND_CONSTRUCTION_SITES);
            if(CREEPS_SPEAK){
                creep.say('🚧');
            }
    
            if(creep.build(target) == ERR_NOT_IN_RANGE) {
                creep.moveTo(target, {reusePath: REUSE_PATH, visualizePathStyle: {stroke: '#ffffff'}});
            }
        }else{
            return 'noTarget';
        }
    

    I don't really like it because i....

    find(FIND_CONSTRUCTION_SITES);
    

    and then i...

    findClosestByPath(FIND_CONSTRUCTION_SITES);
    

    ....and i don't think it's the best way, but the only way i know.

    However, i decided to store a list of Construction Sites in each room's memory, for performance sake.

    This is what i came up with in my "setMemory" method:

        let consSites = [];
        let sites = [];
            
        consSites = thisRoom.find(FIND_CONSTRUCTION_SITES);
        if(consSites.length > 0){
            for(let i in consSites){
                sites.push({    id: consSites[i].id,
                                pos: {x: consSites[i].pos.x, y: consSites[i].pos.y},
                                structureType: consSites[i].structureType});
            }
        }
        thisRoom.memory.constructionSites = sites;
    

    The problem i have now is how do i do to find the closest construction site to the creep without doing a big lot of code that ends being more cpu expensive than my original code.



  • You can use PathFinder to find closed by path. To use this you need to prepare list of targets with goal range. Some thing like this:

    let targets = thisRoom.memory.constructionSites.map(sites=>{
       return {pos: new RoomPosition(sites.pos.x,sites.pos.y,roomName), range:3, id:sites.id}
    })
    

    You need to use RoomPosition but you can't store it on the memory. So we created it for each construction sites. You want to build so we use 3 for target range.

    Then when you need to find closed by path you need to use this code:

    let result = PathFinder.search(creep.pos, targets,{<other search parameters>})
    if(result.incomplete)
    {
    //not found path
       return null
    }
    let lastPosition = _.last(result.path)
    let target = _.find(targets,test=>test.pos.inRangeTo(lastPosition,3))
    return target.id
    

    I did not test this code it's can have some errors.

    👍🙈


  • You can also just use findClosestByRange(targets).

    👍☝


  • if you store all your objects in memory, you can use findPath for arrays.

    So let's say you do targets = room.find(FIND_CONSTRUCTION_SITES);

    targets is now an array. You can do findClosestByPath(targets) instead of doing the call again, because findClosestByPath also works for arrays

    👍


  • Alternatively, you can rely on RoomPosition.findClosestByPath() returning null if there are no targets in the room (or reachable by path):

    let target = creep.pos.findClosestByPath(FIND_CONSTRUCTION_SITES);
    if(target) {
        if(CREEPS_SPEAK){
            creep.say('🚧');
        }
    
        if(creep.build(target) == ERR_NOT_IN_RANGE) {
            creep.moveTo(target, {reusePath: REUSE_PATH, visualizePathStyle: {stroke: '#ffffff'}});
        }
    }else{
        return 'noTarget';
    }
    

    This way you're only calling it once, and it's fine as long as you don't do anything else with targets.

    👍


  • Hello again,

    @Flyasd1 I can say nothing but thank you, but that code i read is at a complexity level higher than i can manage. I can guess what it does, but it seems pointless to me to use code i wouldn't be able to write myself. It would just be copy/pasting.

    Still, thanks a bunch!

    @JBYoshi, @Famine, @Orlet You are right, guys. The reason i wasn't doing this is because i wasn't storing the whole objects, but a few of their properties (such as id, pos...) so findClosestByRange(targets); wasn't working, and "the ball" became so big in my brain that i couldn't think anymore.

    Now, in setMemory (1call/room) i do...

    thisRoom.memory.constructionSites = thisRoom.find(FIND_CONSTRUCTION_SITES);
    

    And then, for each builder....

    let targets = creep.room.memory.constructionSites;
    let target = creep.pos.findClosestByPath(targets);


  • I think this code will not work. No it's will be work if you runing save block and search block in the same tick. Because path finder need to have RoomPosition but between ticks are memory is saved and RoomPosition class will transformed into object. You need to recreate this class before you will start to search. some think like this:

    let targets = creep.room.memory.constructionSites.map(object=>{
       object.pos = new RoomPosition(object.pos.x, object.pos.y, object.pos.roomName)
       return object
    })