14

When playing the game screeps.com I want to calculate the cost of building the required body. See my attempt below, where cfg.body is the bodypart array, e.g. [Game.ATTACK, Game.MOVE, Game.WORK, Game.CARRY, Game.MOVE]:

var buildCost = 0;

for(var bodypart in cfg.body){
  switch(bodypart){
    case "MOVE":
    case "CARRY":
       buildCost+=50;
       break;
    case "WORK":
       buildCost+=20;
       break;
    case "HEAL":
       buildCost+=200;
       break;
    case "TOUGH":
       buildCost+=20;
       break;
    case "ATTACK":
       buildCost+=80;
       break;
    case "RANGED_ATTACK":
       buildCost+=150;
       break;
  }
  console.log(bodypart + " costs " + buildCost);
}

When printing bodypart to the console it shows the indexes (0, 1, 2, 3, ...) and the buildCost remains 0.

The cost and parts are described on the Screeps page.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Anima-t3d
  • 3,431
  • 6
  • 38
  • 56

6 Answers6

25

Maybe the BODYPART_COST constant wasn't available before, but with that you can do this:

function bodyCost (body) {
    return body.reduce(function (cost, part) {
        return cost + BODYPART_COST[part];
    }, 0);
}
Wes Todd
  • 346
  • 4
  • 3
7

A more JavaScripty like solution, eliminating the need for a switch, could look like this:

var _ = require("lodash");
var body = [Game.WORK, Game.CARRY, Game.MOVE, Game.TOUGH];
var bodyCost = {
  "move": 50,
  "carry": 50,
  "work": 20,
  "heal": 200,
  "tough": 20,
  "attack": 80,
  "ranged_attack": 150
};
var cost = 0;
_.forEach(body, function(part) { cost += bodyCost[part]; });
console.log("Cost of construction: " + cost);

In fact, I'm going to use this thing for my own creepfactory to calculate cost. Thanks for figuring out the various costs :)

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Toolmaker
  • 554
  • 6
  • 22
  • Cost changed in game mechanics, updated my answer to reflect the change in costs. Attack went from 100 to 80 [refer to gamedocs](http://screeps.com/docs/Creep.php) – Anima-t3d Dec 27 '14 at 10:03
  • Updated my sample as well. – Toolmaker Jan 02 '15 at 12:17
  • 1
    Cost changed in game mechanics, updated my answer to reflect the change in costs. Tough went from 5 to 20 [refer to gamedocs](http://screeps.com/docs/Creep.php). – Anima-t3d Jan 24 '15 at 22:49
  • The cost has changed again, instead of the object literal you can use the BODYPART_COST constant in the API (it's exactly the same, with current values). –  Apr 04 '17 at 15:07
5

Using lodash's sum method, it's even easier:

let cost = _.sum(creep.body.map(function (b) {
               return BODYPART_COST[b];
           }));

The arrow method makes it more elegant:

let cost = _.sum(creep.body.map((b) => BODYPART_COST[b]));
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
jfren484
  • 960
  • 10
  • 13
4

I've updated my solution with using constants as @Brett does. However I changed the for in loop to a for loop because of performance as seen in this StackOverflow question

for (var index = 0; index < cfg.body.length; ++index) {
  var bodypart = cfg.body[index];
    switch(bodypart){
      case MOVE:
      case CARRY:
        buildCost += 50;
        break;
      case WORK:
        buildCost += 100;
        break;
      case ATTACK:
        buildCost += 80;
        break;
      case RANGED_ATTACK:
        buildCost += 150;
        break;
      case HEAL:
        buildCost += 250;
        break;
      case TOUGH:
        buildCost += 10;
        break;
      case CLAIM:
        buildCost += 600;
        break;
    }
  console.log(bodypart.toUpperCase()+" costs "+buildCost);
}

I also want to note that you should not use this loop each time you build a creep, you better hardcode the value. However it might be handy in case such value does not exist or you need to double check.

Community
  • 1
  • 1
Anima-t3d
  • 3,431
  • 6
  • 38
  • 56
  • Why should you not use this loop each time? – Robert Aug 09 '15 at 00:50
  • @Robert Because it would cost processor power. A better way to do is to make like a preconfigured setup and calculate the total body cost once and hardcode that value in. – Anima-t3d Aug 17 '15 at 10:04
2

I'm pretty sure you should be comparing the strings in lower case, not upper. Failing that, try using things like Game.MOVE, Game.WORK, etc.

btd
  • 684
  • 6
  • 15
2

I updated your script to do what you wanted.

The bodypart in for(var bodypart in cfg.body) is only an index

var body = [Game.ATTACK,Game.MOVE,Game.WORK,Game.CARRY,Game.MOVE];
var buildCost = 0;
for(var bodypart in body){
    var bodymodule = body[bodypart];
    switch(bodymodule){
        case Game.MOVE:
        case Game.CARRY:
           buildCost+=50;
           break;
        case Game.WORK:
           buildCost+=20;
           break;
        case Game.HEAL:
           buildCost+=200;
           break;
        case Game.TOUGH:
           buildCost+=5;
           break;
        case Game.ATTACK:
           buildCost+=100;
           break;
        case Game.RANGED_ATTACK:
           buildCost+=150;
           break;
    }
}
console.log(body+" costs "+buildCost);
Brett
  • 99
  • 5
  • I found the answer myself before you answered, which I now have posted here as well. I used a part of your answer in it and voted you up, however I will accept my answer as I find it more suited. But thanks for your help! – Anima-t3d Nov 24 '14 at 15:50