1

I have this object

            Memory.creepsConf = {
            //The role by which we will refer to the creep
            roles: {
                harvester: "Harvester",//Harvests energy and gives it to the spawn
                upgrader: "Upgrader",//Harvests energy and gives it to the Controller
                builder: "Builder",// Harvests energy and builds stuff
                healer: "Healer"// Harvests energy and heals
            },
            //the maximum number of creeps. Used by ControllerCreeps
            maximum: {
                harvester: 100,
                upgrader: 100,
                builder: 100,
                healer: 100
            },
            //The bare minimum needed. Used by ControllerCreeps
            minimum: {
                harvester: 20,
                upgrader: 10,
                builder: 5,
                healer: 2,
            },
            //Since not all creeps roles will be filled the Colony needs to know
            //which creeps are a priority.
            priority: {
                harvester: 10,
                upgrader: 20,
                builder: 8,
                healer: 7
            },
            build: {
                harvester: [CARRY,WORK,MOVE],
                upgrader: [CARRY,WORK,MOVE],
                builder: [CARRY,WORK,MOVE],
                healer: [MOVE,HEAL,MOVE]
            }
        }

As you can notice in roles I define the roles and in other parts I refer to each creep by role.

Another thing you can notice is that I am always using the key defined in roles and never the value. This is a problem, because if somebody provides me with "Harvester" i need to get the key out of roles and then use the key...making the value obsolete.

What I want to do is instead of saying harvester which is a key in roles I want to call the value of that key as a key in other objects

Something like this

            Memory.creepsConf = {
            //The role by which we will refer to the creep
            roles: {
                harvester: "Harvester",//Harvests energy and gives it to the spawn
                upgrader: "Upgrader",//Harvests energy and gives it to the Controller
                builder: "Builder",// Harvests energy and builds stuff
                healer: "Healer"// Harvests energy and heals
            },
            //the maximum number of creeps. Used by ControllerCreeps
            maximum: {
                Memory.creepsConf.roles.harvester: 100,
                Memory.creepsConf.roles.upgrader: 100,
                Memory.creepsConf.roles.builder: 100,
                Memory.creepsConf.roles.healer: 100
            },
            //The bare minimum needed. Used by ControllerCreeps
            minimum: {
                Memory.creepsConf.roles.harvester: 20,
                Memory.creepsConf.roles.upgrader: 10,
                Memory.creepsConf.roles.builder: 5,
                Memory.creepsConf.roles.healer: 2,
            },
            //Since not all creeps roles will be filled the Colony needs to know
            //which creeps are a priority.
            priority: {
                Memory.creepsConf.roles.harvester: 10,
                Memory.creepsConf.roles.upgrader: 20,
                Memory.creepsConf.roles.builder: 8,
                Memory.creepsConf.roles.healer: 7
            },
            build: {
                Memory.creepsConf.roles.harvester: [CARRY,WORK,MOVE],
                Memory.creepsConf.roles.upgrader: [CARRY,WORK,MOVE],
                Memory.creepsConf.roles.builder: [CARRY,WORK,MOVE],
                Memory.creepsConf.roles.healer: [MOVE,HEAL,MOVE]
            }
        }

What I want to end up with is the value of Memory.creepsConf.roles.* as a key represented in other objects so that if somebody provides me with the value Harvester I can actually use it as a key to get all needed information.

However this second piece of code doesn't work. I get

Unexpected token .

Is there a way to use the value of Memory.creepsConf.roles.* as a key in Memory.creepsConf.maximum, Memory.creepsConf.minimum, Memory.creepsConf.priority and Memory.creepsConf.build ?

In case this example is too big and hard to follow I will try to simplify it

var obj = {
    foo:"Foooo",
    obj.foo: "Wohooo"
}

This object now should have a key which is Foooo and obj['Foooo'] should return "Wohooo"

Pavlin Petkov
  • 1,022
  • 3
  • 17
  • 38
  • My question is not a dublicate of the other question. The other guy asks how to refer to a object property by string value...I want to refer to object property INSIDE THE OBJECT DECLARATION. I know perfectly well how to get a value out of the object by given key...IF I AM OUTSIDE THE OBJECT. The problem is - how to do so...INSIDE THE OBJECT – Pavlin Petkov Feb 11 '18 at 09:09
  • 1
    I would recommend a different layout. Make conf objects like this: `{role: "Harvester", maximum: 100, minimum: 20, priority: 10, build: [CARRY,WORK,MOVE]}` and then put them into an array. This will be much easier to handle. – Tomalak Feb 11 '18 at 09:09
  • Oh, I thought you *actually* try to do `Memory.creepsConf.roles.*`. The error you get *`"Unexpected token ."`* indicates that you did. You can't refer to an object "inside its declaration". The object is not done yet, so there is nothing to refer to yet. – Tomalak Feb 11 '18 at 09:11
  • @Tomalak That would do the work, but then...I need to search the array by given role. And then get the another value which I am interested in. Currently If I am given a Role I get the key of the role and use the key to get the values...which is annoying. Searching an array by role to get the other properties would be annoying as well. It solves my current problem but doesn't improve the situation. Aand could you remove the dublicate, because the other question provides no useful information. – Pavlin Petkov Feb 11 '18 at 09:13
  • Searching the array by role is fast, don't worry. You can create a `getByRole` function to do it. – Tomalak Feb 11 '18 at 09:15
  • The relevant duplicate is: https://stackoverflow.com/questions/12789141/access-object-properties-within-object - There are many such questions, this is a wide-spread beginner mistake. – Tomalak Feb 11 '18 at 09:16
  • @Tomalak The idea is that when I am provided with a role "Harvester" I want to be able to just call `Memory.creepsConf.priority[givenRole]` where `givenRole` is in this case `Harvester`. Because I pass around the values, and not the keys. So I need the value of `roles` to be a key in `priority`. The idea is to not need anything else to get the value out of `priority` expect the value of `roles`. Making taking information out of this big object more easy to do – Pavlin Petkov Feb 11 '18 at 09:17
  • Well, you'll see what happens. I realize why it seems to be the better solution to you. It will work, but it has its drawbacks. – Tomalak Feb 11 '18 at 09:23
  • 1
    The "roles" map is useless, simply ask "somebody" to provide you with the key, and you are done. –  Feb 11 '18 at 09:26

3 Answers3

2

Why not use the roles as keys of the main configuration object:

Memory.config.creeps = {
    "Harvester": {
        maximum: 100, 
        minimum: 20, 
        priority: 10, 
        build: [CARRY, WORK, MOVE]
    }, {
    "Upgrader": {
        maximum: 100, 
        minimum: 10, 
        priority: 20, 
        build: [CARRY, WORK, MOVE]
    }
    ///...
};

Now you can just access the properties like this:

function getMinimumForRole(role){
    if (role in Memory.config) {
        return Memory.config[role].minimum;
    }
    throw "role " + role + " not found";
}

If you still want to go on the way you were working, then you could do it with two assignments using some ES6 syntax features:

const roles = { // temporary variable for keeping the rest short
    harvester: "Harvester",
    upgrader: "Upgrader",
    builder: "Builder",
    healer: "Healer"
};
Memory.creepsConf = {
    roles, // ES6 short notation
    maximum: {
        [roles.harvester]: 100, // ES6 computed property syntax
        [roles.upgrader]: 100,
        [roles.builder]: 100,
        [roles.healer]: 100
    },
    // ...etc
};
trincot
  • 317,000
  • 35
  • 244
  • 286
  • Thank you for your answer. Actually I did use [] to get the keys. You can view my answer. Though I don't know why it works. I was told that you can't refer an object during declaration inside the object. If you see my answer I didn't remove roles from inside the object and it still worked with this syntax...don't know why, though – Pavlin Petkov Feb 11 '18 at 10:02
  • Your version only works if `Memory.creepsConf.roles` was already defined before. – trincot Feb 11 '18 at 10:05
  • Did you take the time to *consider* the benefits of the alternative? Or are you just looking to get your code running despite the comments you have received on your design? – trincot Feb 11 '18 at 10:12
0

If I were you, I would follow Tomalak's suggestion, it's not necessarilly more logical but it looks more "object oriented", hence it might be easier to work with :

Memory.config.creeps = [{
  role: "Harvester", 
  maximum: 100, 
  minimum: 20, 
  priority: 10, 
  build: [CARRY, WORK, MOVE]
}, {
  role: "upgrader",
  ...
}];

Think of how you would do it in Java, often you need to make collections of objects of the same type, as it happens, we have a collection of creeps configs.

If you want to ease access to the objects, you could use an additional map, which looks perfectly fine to me (note that I would keep the array since you might need to search for specific configs based on some criteria) :

Memory.config.maps.creeps = {
  "Harvester": Memory.config.creeps[0],
  "Upgrader": ...
};
-1

Thank you all for your suggestions, but I have found the answer with some experimenting. Though I must say...I don't know why it works...

         Memory.creepsConf = {
        //The role by which we will refer to the creep
        roles: {
            harvester: "Harvester",//Harvests energy and gives it to the spawn
            upgrader: "Upgrader",//Harvests energy and gives it to the Controller
            builder: "Builder",// Harvests energy and builds stuff
            healer: "Healer"// Harvests energy and heals
        },
        //the maximum number of creeps. Used by ControllerCreeps
        maximum: {
            [Memory.creepsConf.roles.harvester]: 100,
            [Memory.creepsConf.roles.upgrader]: 100,
            [Memory.creepsConf.roles.builder]: 100,
            [Memory.creepsConf.roles.healer]: 100
        },
        //The bare minimum needed. Used by ControllerCreeps
        minimum: {
            [Memory.creepsConf.roles.harvester]: 20,
            [Memory.creepsConf.roles.upgrader]: 10,
            [Memory.creepsConf.roles.builder]: 5,
            [Memory.creepsConf.roles.healer]: 2,
        },
        //Since not all creeps roles will be filled the Colony needs to know
        //which creeps are a priority.
        priority: {
            [Memory.creepsConf.roles.harvester]: 10,
            [Memory.creepsConf.roles.upgrader]: 20,
            [Memory.creepsConf.roles.builder]: 8,
            [Memory.creepsConf.roles.healer]: 7
        },
        build: {
            [Memory.creepsConf.roles.harvester]: [CARRY,WORK,MOVE],
            [Memory.creepsConf.roles.upgrader]: [CARRY,WORK,MOVE],
            [Memory.creepsConf.roles.builder]: [CARRY,WORK,MOVE],
            [Memory.creepsConf.roles.healer]: [MOVE,HEAL,MOVE]
        }
    }

This works perfectly fine. The only difference between what I posted second as wrong is that I have surrounded the Memory.creepsConf.roles.* with [] and it works.

So apparently...you can refer an object inside the object while declaring it...you just need to add [] around it

What is the benefit of all this?

Well the benefit is that if I need to get information about creeps by provided role (lets say "Harvester") I can do this Memory.creepsConf.maximum[role] and it will give me the information needed.

I don't need to use a map or to get the key when I have the value or to ask somebody to provide me with the key instead of the value or do anything like that.

Simple on 1 line of code I can get the information needed. This was what I wanted in the first place.

Now...some of you mentioned that it is not possible to refer to an object inside the object during declaration so I have another question - Why does this work?

Pavlin Petkov
  • 1,022
  • 3
  • 17
  • 38
  • 2
    I'm afraid you are overcomplicating things... :-| –  Feb 11 '18 at 09:55
  • Surely so, but the result is simple and elegant. Just one line of code everywhere to get information needed and - even if you change the value of some role. Rename "Harvester" to "John Wick" it will work perfectly fine as the key in other properties would also change to "John Wick" so it is even bug proof (so far). Yet I admit it is little over complicated than it needs to be. – Pavlin Petkov Feb 11 '18 at 09:59
  • 2
    There is no real benefit, only a point of view. Using an object oriented approach you get a more conventional code (hence more readable), and you can still access the informations easily using a map (which is also a conventional way of doing things). –  Feb 11 '18 at 10:00
  • I agree with leaf: there is no additional benefit. This is not best practice. Renaming only works if you run the code again that initialises the configuration object. Which is true for the better solutions as well. – trincot Feb 11 '18 at 10:02
  • The game this runs on (Screeps") does just that. Each tick of iteration repeats the configuration as well as every command. So If I was to change the values they would immediately be changed and the code would start working with the new values. This is why I am trying to make it so the values will always be correct even if I for some reason change them. – Pavlin Petkov Feb 11 '18 at 10:04
  • 1
    This solution needs more code preceding it, as it will not work if `Memory.creepsConf.roles` was not defined before: https://jsfiddle.net/zxqo4dev/ or also: https://jsfiddle.net/zxqo4dev/1/. Both give run time errors on `[Memory.creepsConf.roles.harvester]: 100` – trincot Feb 11 '18 at 10:08
  • 2
    Ok, I just hope you don't confuse technical requirements with personal preferences. Decades of programming have yield reliable conventions that you should NOT brush away :-P –  Feb 11 '18 at 10:09
  • "Why does this work?" I guess this is part of the latest JS features, I will check that, just keep in mind that this is not valid in JSON (if you care about that). –  Feb 13 '18 at 06:40
  • @leaf With little more debugging I found out that it works only in the scope of the game Screeps. The reason being that the code is repeated every second all of it. Configuration as well as commands. So when I invoke [Memory.creepsConf.roles] it doesn't invoke the roles I have set but the ones already in memory. Something like cache. So...it works..but only if the properties are already set in memory. Its like cache - if you have cache it works, if you don't - bad news for ya.Well..me in this case – Pavlin Petkov Feb 13 '18 at 07:32
  • Thanks for the feedback @ЛуциПетков. –  Feb 14 '18 at 15:27