Скрипы — Как сделать расчет пути согласованным?

#javascript #screeps

#javascript #скрипы

Вопрос:

У меня есть прототип для создания макета комнаты. Я пытаюсь вычислить местоположение для размещения контейнера как:

ближайшая точка между порождением и контроллером, которая находится на расстоянии одной единицы от контроллера

По какой-то причине кажется, что он дает мне несколько значений (возможно, из-за алгоритма поиска путей), который является точкой перехода в соответствии с API. Как я могу каждый раз получать один и тот же результат, а не три разные точки?

 Room.prototype.layoutRoom=function(){
    var s:Spawn=this.spawns()[0]
    var c:Controller=this.controller;

    //get path from spawn to controller
    var path = this.findPath(s.pos, c.pos, {ignoreDestructibleStructures: true});

    //place container on last part of path -3 to stay 1 away from controller, and closest to spawn
    //length-1= on endpoint, -2 is one step away, -3 is two steps away 
    var loc=path[path.length-3]
    console.log('layout room, put container: ' loc.x ' ' loc.y)
    this.createConstructionSite(loc.x, loc.y, STRUCTURE_CONTAINER);
}
 

Выполнение приведенного выше кода несколько раз (что требуется) приводит к созданию нескольких строительных площадок:

введите описание изображения здесь

Комментарии:

1. Значение по умолчанию для параметра ignoreCreeps равно false . Может быть, разница возникает из-за наличия крипов? Я также не уверен, что поиск пути полностью детерминирован.

Ответ №1:

По умолчанию поиск пути будет рассматривать крипы как непроходимую плитку. Чтобы исправить это, вы добавляете это в параметр:

ignoreCreeps: true

Ответ №2:

Итак, другой ответ охватывает это, было бы согласованно, если бы вы изменили свой findPath на что-то более похожее var path = this.findPath(s.pos, c.pos, {ignoreDestructibleStructures: true, ignoreCreeps: true});

Однако, поскольку название игры заключается в экономии процессора, вы действительно не хотите вычислять этот путь каждый тик.

Вы можете сохранить местоположение контейнера в памяти или сначала проверить, что контейнер был построен в пределах одного тайла контроллера.


Вариант A — Сохранение местоположения в памяти

Это был бы мой личный предпочтительный вариант, поскольку я довольно часто использую память. Имейте в виду, что в это решение я добавил много дополнительного кода, который вам не нужен для его работы, но сделает ваш код более безопасным и менее подверженным ошибкам в этом контексте.

 Room.prototype.layoutRoom=function(forceUpdate: boolean){
    var s: Spawn = this.spawns()[0];
    var c: Controller = this.controller;
    
    // Adding this to check that this spawn/controller exists (or code will error out if one doesn't exist)
    if(!s || !c){
        return;
    }
    // Check if a memory value has been set for this container already, and we aren't forcing the location to update via parameter; we can end early otherwise
    if(this.memory.controllerContainer amp;amp; !forceUpdate){
        // you could uncomment this out to have it place a site on the same location if we find the location is saved in memory already
        // var loc = this.memory.controllerContainer;
        // this.createConstructionSite(controllerContainer.x, controllerContainer.y, STRUCTURE_CONTAINER);
        return;
    }

    //get path from spawn to controller
    var path = this.findPath(s.pos, c.pos, {
        ignoreDestructibleStructures: true, ignoreCreeps: true
    });

    //place container on last part of path -3 to stay 1 away from controller, and closest to spawn
    //length-1= on endpoint, -2 is one step away, -3 is two steps away 
    var loc=path[path.length-3];
    console.log('layout room, put container: ' loc.x ' ' loc.y);
    
    // Note that I am not saving the RoomPosition object into memory, when the JSON parses 
    // your memory back out you won't be able to use it as a RoomPosition object, so its safer 
    // to save as a custom object that mimics Room position and have a function available to convert 
    // it to one if you need to use it as one for the purpose of passing as a parameter to something
    this.memory.controllerContainer = {x: loc.x, y: lox.y};
    this.createConstructionSite(loc.x, loc.y, STRUCTURE_CONTAINER);
}
 

Вариант B — Без использования памяти

Этот параметр будет иметь тот же эффект, что и если контейнерный сайт или контейнер уже существует контроллером, он не будет пытаться создать другой сайт.

 Room.prototype.layoutRoom=function(){
    var s: Spawn = this.spawns()[0];
    var c: Controller = this.controller;
    
    // Adding this to check that this spawn/controller exists (or code will error out if one doesn't exist)
    if(!s || !c){
        return;
    }

    // Check if a construction site or container exists near the controller, exit if so
    // For brevity, i will include here, but normally I would pull this into its own function
    var numConstructionSites = room.find(FIND_CONSTRUCTION_SITES, { filter: (site) => 
        site.isNearTo(c) amp;amp; site.structureType === STRUCTURE_CONTAINER
    }).length;
    var numExistingContainers = room.find(FIND_STRUCTURES, { filter: (struct) => 
        struct.isNearTo(c) amp;amp; struct.structureType === STRUCTURE_CONTAINER
    }).length;
    if(numConstructionSites > 0 || numExistingContainers > 0) {
        return;
    }

    //get path from spawn to controller
    var path = this.findPath(s.pos, c.pos, {
        ignoreDestructibleStructures: true, ignoreCreeps: true
    });

    //place container on last part of path -3 to stay 1 away from controller, and closest to spawn
    //length-1= on endpoint, -2 is one step away, -3 is two steps away 
    var loc=path[path.length-3];
    console.log('layout room, put container: ' loc.x ' ' loc.y);
    this.createConstructionSite(loc.x, loc.y, STRUCTURE_CONTAINER);
}