ThaBomb
ThaBomb

Reputation: 722

Finding structure with highest energy screeps

So I have this creep role called storer that is supposed to go fetch energy from containers and bring it to the storage. However, currently, it finds the container closest by Path and with an energy level greater to a certain threshold so that it doesn't wait there for hours every time a miner refills the container.

The problem I have is if I lower the threshold, the storer will run back and forth to the same containers, ignoring any containers further in the room and letting them fill up.
And raising the threshold will make him sit out and wait for too long, not giving him enough time to empty containers and thus the storage will be empty almost all the time.

I need a way for the creep to determine the container with the highest energy and fill up from there.

Here's the code its running:

if ((source = creep.pos.findClosestByPath(FIND_STRUCTURES, {filter: (s) => {return (s.structureType == STRUCTURE_CONTAINER && s.store[RESOURCE_ENERGY] >= 150)}})) != undefined) {
    if (creep.withdraw(source, RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
        creep.moveTo(source);
    }
}

EDIT: here's the code I tried, but I feel like it is using too much CPU power and can be done in a better way:

for (let i = 2000; i>=0; i=i-100) {
    source = creep.pos.findClosestByPath(FIND_STRUCTURES, {filter: (s) => {return s.structureType == STRUCTURE_CONTAINER && s.store[RESOURCE_ENERGY] >= i}});
        if (source != undefined) {
            break;
        }
    }
    if (creep.withdraw(source, RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
        creep.moveTo(source);
    }
}

Upvotes: 3

Views: 4296

Answers (3)

user7242005
user7242005

Reputation: 21

I do not know if this method uses more CPU, but it is much simpler to use JavaScript's built in sort method. It allows for the objects in an array to be sorted based on any property or calculation involving it. If you'd like to see the full syntax and some examples: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

This code should work for your purposes. A and B are the two pieces of the array it compares. The return portion tells it the comparison to do on the array elements.

var sources = creep.pos.findClosestByPath(FIND_STRUCTURES, 
{filter: (s) => {return (s.structureType == STRUCTURE_CONTAINER && 
 s.store[RESOURCE_ENERGY] >= 150)
}});
sources.sort(function(a, b)  {return b.store[RESOURCE_ENERGY] - a.store[RESOURCE_ENERGY]});

Then just run your normal code to take energy from the sources. If it starts taking energy from the one with the least amount of energy, I probably got the order of a and b wrong in the return portion so just flip them.

Upvotes: 2

Calame
Calame

Reputation: 76

What you can do is loop trough all the containers once, get their energy level and pick the highest one. Set a value when the creep is working so the creep dosen't move to another container if he get higher.

This is the code i made for the storer role:

module.exports = {

  run: function( creep ) {

    // Setting the working variable so the creep focus
    // on getting the ressource or returning it.
    if ( creep.memory.working && creep.carry.energy == 0 ) {
        creep.memory.working = false;
    }

    if ( ! creep.memory.working && creep.carry.energy == creep.carryCapacity ) {
        creep.memory.working = true;
        creep.memory.targetContainer = false;
    }

    if ( creep.memory.working ) {

        // Bring the ressources to the storage.
        var theStorage = creep.pos.findClosestByRange(FIND_MY_STRUCTURES, {
            filter: (structure) => {
                return (structure.structureType == STRUCTURE_STORAGE );
            }
        });

        if ( creep.transfer( theStorage, RESOURCE_ENERGY) == ERR_NOT_IN_RANGE) {
            creep.moveTo( theStorage );
        }

    } else {

        // If the creep have a target.
        if ( creep.memory.targetContainer ) {

            // Go to the container.
            var theContainer = Game.getObjectById( creep.memory.targetContainer );

            if ( creep.withdraw( theContainer, RESOURCE_ENERGY ) == ERR_NOT_IN_RANGE ) {
                creep.moveTo( theContainer );
            }

        } else {

            // Find the container with the most energy.
            var target = creep.room.find( FIND_STRUCTURES, {
                filter: (structure) => {
                    return (structure.structureType == STRUCTURE_CONTAINER );
                }
            });

            if ( target.length ) {

                var allContainer = [];

                // Calculate the percentage of energy in each container.
                for ( var i = 0; i < target.length; i++ ) {

                    allContainer.push( { energyPercent: ( ( target[i].store.energy / target[i].storeCapacity ) * 100 ), id: target[i].id } );

                }

                // Get the container containing the most energy.
                var highestContainer = _.max( allContainer, function( container ){ return container.energyPercent; });

                console.log( 'Going for the container id "' + highestContainer.id + '" at ' + highestContainer.energyPercent + '% full.' );

                // set the target in memory so the creep dosen't
                // change target in the middle of the room.
                creep.memory.targetContainer = highestContainer.id;

            }
        }
    }
  }
};

Upvotes: 6

Adam
Adam

Reputation: 7207

Instead of having the filter do everything for you, why not return a list of structures that match your criteria and then figure out which structure in the list has the most energy? Something like this will find all containers, figure out which has the most energy, and if you have a tie for energy pick the closest one (direct line, doesn't account for obstacles).

var sources = creep.room.find(FIND_STRUCTURES, {
    filter: (structure) => {
        return (structure.structureType == STRUCTURE_CONTAINER);
    }
});
var maxAmount = -1;
var maxSource = null;
var maxRange = 100;
for (var i = 0; i < sources.length; i++) {
    if (sources[i].store[RESOURCE_ENERGY] >= maxAmount) {
        var range = creep.pos.getRangeTo(sources[i]);
        if (sources[i].store[RESOURCE_ENERGY] > maxAmount || range < maxRange) {
            maxAmount = sources[i].store[RESOURCE_ENERGY];
            maxSource = sources[i];
            maxRange = range;
        }
    }
}
console.log(maxAmount);
console.log(maxSource);
console.log(maxRange);

Upvotes: 0

Related Questions