How to implement inheritance in Screeps objects? - javascript

I've been toying around with Screeps for a while now and last night I decided to work out some of my behaviors into a class hierarchy by deriving two classes, Miner and Transporter from a Creep main class. However, whenever I do
console.log(_.functions(minerInstance));
I get the exact same function list as when I do
console.log(_.functions(transporterInstance));
Could someone tell me if I'm doing something wrong OR if I'm actually running into a limitation of the environment my code runs in?
This is my code:
////////////////////////////
// Creep.js
var Creep = function(creep, room) {
this.creep = creep;
this.room = room;
this.name = creep.name;
this.id = creep.id;
};
module.exports = Creep;
Creep.prototype = {
tick: function() {
console.log("Base class implementation of tick(), should never happen.");
},
getRole: function() {
return this.creep.memory.role;
}
};
////////////////////////////
// Miner.js
var Creep = require("Creep");
var Miner = function(creep, room) {
this.base = Creep;
this.base(creep, room);
//Creep.call(this, creep, room);
};
module.exports = Miner;
Miner.prototype = Creep.prototype;
Miner.prototype.tick = function() {
var creep = this.creep;
if (creep.memory.activity === undefined || creep.memory.activity === "") {
var target = creep.pos.findNearest(Game.SOURCES_ACTIVE);
this.mine(creep, target);
}
var act = creep.memory.activity;
if (act == "mine") {
var target = this.getTarget(creep);
if (target !== undefined) {
if (creep.energy < creep.energyCapacity) {
creep.moveTo(target);
creep.harvest(target);
} else {
console.log("Write dump to truck code");
/*var trucks = find.transporterInRange(creep, 1);
if (trucks.length) {
creep.moveTo(trucks[0]);
var amount = trucks[0].energyCapacity - trucks[0].energy;
creep.transferEnergy(trucks[0], amount);
}*/
}
}
}
};
Miner.prototype.mine = function(creep, target) {
creep.memory.target = target.id;
creep.memory.activity = "mine";
};
Miner.prototype.getTarget = function(creep) {
return Game.getObjectById(creep.memory.target);
};
////////////////////////////
// Transporter.js
var Creep = require("Creep");
var Transporter = function(creep, room) {
Creep.call(this, creep, room);
};
module.exports = Transporter;
Transporter.prototype = Creep.prototype;
Transporter.prototype.tick = function() {
var creep = this.creep;
if (creep.energy < creep.energyCapacity) {
var miner = this.room.findByRole(creep, "miner");
console.log(miner);
if (miner !== null) {
//console.log(miner[0].name);
//creep.moveTo(miner);
} else
console.log("no miners found");
} else {
console.log("moving to drop");
//var drop = find.nearestEnergyDropOff(creep);
//creep.moveTo(drop);
//creep.transferEnergy(drop);
}
};

With this line...
Miner.prototype = Creep.prototype;
... you tell JS that both prototypes are actually the same object. Hence any update for Miner.prototype will affect Creep.prototype too.
One possible approach is using Object.create when establishing the link between prototypes. Here goes a simplified example:
function Foo(a) {
this.a = a;
}
Foo.prototype.tick = function() { console.log('Foo ticks'); };
Foo.prototype.tock = function() { console.log('Foo tocks'); };
function Bar(a, b) {
this.base = Foo;
this.base(a);
this.b = b;
}
Bar.prototype = Object.create(Foo.prototype);
// as you inherit all the properties, you'll have to reassign a constructor
Bar.prototype.constructor = Bar;
Bar.prototype.tick = function() { console.log('Bar ticks'); };
var f = new Foo(1);
f.tick(); // Foo ticks
f.tock(); // Foo tocks
console.log(f); // Foo { a=1, ... }
var b = new Bar(1, 2);
b.tick(); // Bar ticks
b.tock(); // Foo tocks
console.log(b); // Bar { a=1, b=2, ... }

Related

javascript - private/public members/functions

I am testing what happens when I declare variables/methods with var, this, and global, and am wondering what is the best approach. I have the following code:
myApp.ConfirmationWindow = function (temptype) {
var _type = temptype;
this.type = temptype;
type2 = temptype;
this.getType = function () {
return _type;
}
this.showConfirmationWindow = function (message) {
var a = _type; //valid
var b = this.type; //valid
var c = type2; // valid
var d = this.getType(); // valid
this.showWindow(message);
showWindow2(message);
showWindow3(message);
}
this.showWindow = function (message) {
var a = _type; //valid
var b = this.type; //valid
var c = type2; // valid
var d = this.getType(); // valid
}
showWindow2 = function (message) {
var a = _type; //valid
var b = this.type; //invalid
var c = type2; // valid
var d = this.getType(); // invalid
}
var showWindow3 = function (message) {
var a = _type; //valid
var b = this.type; //invalid
var c = type2; // valid
var d = this.getType(); // invalid
}
};
Usage:
myApp.ConfirmationWindow1 = new myApp.ConfirmationWindow(1);
myApp.ConfirmationWindow1.showConfirmationWindow('Are you sure?');
The goal is to have the type variable and the showWindow function private. As you can see from my example, there are a lot of ways to achieve this. What is the recommended way?
I would suggest to use the module reveal pattern, where you keep the private variable in a closure. Here below a generic example. You can read more about the revealing pattern here:
let myVar = true;
let module = (function() {
// these are private variables (in a closure)
let _privateVariable = 'private',
_privateFunction = function() {
alert(_privateVariable);
};
let _publicVariable = 'public',
_publicFunctionGet = function() {
alert(_publicVariable);
},
_publicFunctionSet = function(value) {
_publicVariable = value;
};
// provide public functions to set the private variables
return {
publicFunctionSet: _publicFunctionSet,
publicFunctionGet: _publicFunctionGet
};
})();
module.publicFunctionSet('new public');
module.publicFunctionGet();
alert(myVar); // available to other part of your code
You can hide your private code using the var pattern in your example. To expose your private variables you use your instance functions. If you make them global or members of the function then they are public.
myApp.ConfirmationWindow = function (temptype) {
var _type = temptype;
this.getType = function () {
return _type;
}
var showWindow = function (message) {
var d = _type
}
this.showConfirmationWindow = function (message) {
showWindow(message);
}
};

Passing references of a class to another class and using its methods

Let's say you're making a game. You want to try and not pollute the global scope and possibly limit the user's ability to easily alter the game (doubtful with client-side). You feel like modules might be unnecessary for your purposes. Is it bad practice to pass references to a class to another class during instantiation to access its methods?
Contrived example:
//game.js
var Game = (function () {
function Game() {
this.currentLevel = null;
this.score = 0;
}
Game.prototype.addScore = function (num) {
this.score += num;
};
Game.prototype.goToLevel = function (diff) {
this.currentLevel = new Level(this, diff);
};
Game.prototype.returnHome = function (level) {
this.currentLevel = null;
};
return Game;
})();
//level.js
var Level = (function () {
function Level(game, difficulty) {
this.game = game; //reference to game
this.difficulty = difficulty;
this.entities = [];
this.load();
}
Level.prototype.load = function () {
this.addEntity({name: 'tim', power: 23, difficulty: this.difficulty});
};
Level.prototype.leave = function () {
this.game.returnHome();
};
Level.prototype.addEntity = function (options) {
this.entities.push(new Entity(this, options));
};
Level.prototype.removeEntity = function (entity) {
for(var x = 0; x < this.entities.length; x++) {
if(this.entities[x] === entity) this.entities.splice(x, 1);
}
};
return Level;
})();
//level.js
var Entity = (function () {
function Entity(level, options) {
this.level = level; //reference to level
this.options = options;
}
Entity.prototype.kill = function () {
this.level.removeEntity(this); // anti-pattern?
this.level.game.addScore(34.53); // too closely coupled?
};
return Entity;
})();
//main.js
var Main;
(function (Main) {
var game = null;
function documentIsReady() {
start(); // Start the game
}
function start() {
game = new Game();
game.goToLevel('hard');
}
return {
documentIsReady: documentIsReady
}
})(Main || (Main = {}));
$(document).ready(function () {
Main.documentIsReady();
});
Forgive the half-baked example. If you end up with many instances of the 'Entity' class, do all the references to 'Level', though the same instance, start taking more memory? Are there other pitfalls? Another method would be to implement some kind of interface that you can access that allow classes to talk to each other.

accessing static (class) variables defined in a subclass from a superclass

I have some classes that share identical methods and are distinguished only by a few static (aka class) variables. My thought is to put the common methods into a base class that accesses the static variables.
Here is a solution that works, but it seems like a real cough kludge. Is there a better / more idiomatic way to do this?
"use strict";
// common code
function Base() { }
Base.prototype.f1 = function() {
console.log(Object.getPrototypeOf(this).constructor.VAR1); // this feels really really wrong!
}
Base.prototype.f2 = function() {
console.log(Object.getPrototypeOf(this).constructor.VAR2); // ditto
}
// specialization A
function SubA() { Base.call(this); }
SubA.prototype = Object.create(Base.prototype);
SubA.prototype.constructor = SubA;
SubA.VAR1 = "suba v1";
SubA.VAR2 = "suba v2";
// specialization B
function SubB() { Base.call(this); }
SubB.prototype = Object.create(Base.prototype);
SubB.prototype.constructor = SubB;
SubB.VAR1 = "subb v1";
SubB.VAR2 = "subb v2";
This works as expected:
> var a = new SubA();
> var b = new SubB();
> a.f1()
suba v1
undefined
> b.f2()
subb v2
undefined
an alternative
Of course I could write methods to encapsulate the differences between SubA and SubB. The syntax is less tortured, but it still feels wrong to write methods that are essentially behaving like static variables:
"use strict";
function Base() { }
Base.prototype.f1 = function() {
console.log(this.getVar1());
}
Base.prototype.f2 = function() {
console.log(this.getVar2());
}
function SubA() { Base.call(this); }
SubA.prototype = Object.create(Base.prototype);
SubA.prototype.constructor = SubA;
SubA.prototype.getVar1 = function() { return 'suba v1'; }
SubA.prototype.getVar2 = function() { return 'suba v2'; }
function SubB() { Base.call(this); }
SubB.prototype = Object.create(Base.prototype);
SubB.prototype.constructor = SubB;
SubB.prototype.getVar1 = function() { return 'subb v1'; }
SubB.prototype.getVar2 = function() { return 'subb v2'; }
> var a = new SubA();
> var b = new SubB();
> a.f1()
suba v1
undefined
> b.f2()
subb v2
undefined
Is there a particular reason to put VAR1 and VAR2 in the class objects themselves rather than in their prototypes? If not, things become much simpler:
function Base() { }
Base.prototype.f1 = function() {
console.log(this.VAR1);
};
Base.prototype.f2 = function() {
console.log(this.VAR2);
};
// specialization A
function SubA() { Base.call(this); }
SubA.prototype = Object.create(Base.prototype);
SubA.prototype.constructor = SubA;
SubA.prototype.VAR1 = "suba v1";
SubA.prototype.VAR2 = "suba v2";
// specialization B
function SubB() { Base.call(this); }
SubB.prototype = Object.create(Base.prototype);
SubB.prototype.constructor = SubB;
SubB.prototype.VAR1 = "subb v1";
SubB.prototype.VAR2 = "subb v2";
The above code passes your tests.

JavaScript: Prevent Array.push()

I have a sealed object with an array member on which I want to prevent direct pushes.
var myModule = (function () {
"use strict";
var a = (function () {
var _b = {},
_c = _c = "",
_d = [];
Object.defineProperty(_b, "c", {
get: function () { return _c; }
});
Object.defineProperty(_b, "d", {
get { return _d; }
});
_b.addD = function (newD) {
_d.push(newD);
};
Object.seal(_b);
return _b;
}());
var _something = { B: _b };
return {
Something: _something,
AddD: _b.addD
};
}());
myModule.Something.c = "blah"; // doesn't update = WIN!!
myModule.AddD({}); // pushed = WIN!
myModule.Something.d.push({}); // pushed = sadness
How can I prevent the push?
UPDATE:
Thanks for all the thoughts. I eventually need the JSON to send to the server. It looks like I might need to use an object for the array then figure out a way to generate and return the JSON needed, or change _something to use .slice(). Will play and report.
you could override the push method:
var _d = [];
_d.__proto__.push = function() { return this.length; }
and when you need to use it in your module, call Array.prototype.push:
_b.addD = function (newD) {
Array.prototype.push.call(_d, newD);
};
I haven't done any performance tests on this, but this certainly helps to protect your array.
(function(undefined) {
var protectedArrays = [];
protectArray = function protectArray(arr) {
protectedArrays.push(arr);
return getPrivateUpdater(arr);
}
var isProtected = function(arr) {
return protectedArrays.indexOf(arr)>-1;
}
var getPrivateUpdater = function(arr) {
var ret = {};
Object.keys(funcBackups).forEach(function(funcName) {
ret[funcName] = funcBackups[funcName].bind(arr);
});
return ret;
}
var returnsNewArray = ['Array.prototype.splice'];
var returnsOriginalArray = ['Array.prototype.fill','Array.prototype.reverse','Array.prototype.copyWithin','Array.prototype.sort'];
var returnsLength = ['Array.prototype.push','Array.prototype.unshift'];
var returnsValue = ['Array.prototype.shift','Array.prototype.pop'];
var funcBackups = {};
overwriteFuncs(returnsNewArray, function() { return []; });
overwriteFuncs(returnsOriginalArray, function() { return this; });
overwriteFuncs(returnsLength, function() { return this.length; });
overwriteFuncs(returnsValue, function() { return undefined; });
function overwriteFuncs(funcs, ret) {
for(var i=0,c=funcs.length;i<c;i++)
{
var func = funcs[i];
var funcParts = func.split('.');
var obj = window;
for(var j=0,l=funcParts.length;j<l;j++)
{
(function() {
var part = funcParts[j];
if(j!=l-1) obj = obj[part];
else if(typeof obj[part] === "function")
{
var funcBk = obj[part];
funcBackups[funcBk.name] = funcBk;
obj[part] = renameFunction(funcBk.name, function() {
if(isProtected(this)) return ret.apply(this, arguments);
else return funcBk.apply(this,arguments);
});
}
})();
}
}
}
function renameFunction(name, fn) {
return (new Function("return function (call) { return function " + name +
" () { return call(this, arguments) }; };")())(Function.apply.bind(fn));
};
})();
You would use it like so:
var myArr = [];
var myArrInterface = protectArray(myArr);
myArr.push(5); //Doesn't work, but returns length as expected
myArrInterface.push(5); //Works as normal
This way, you can internally keep a copy of the interface that isn't made global to allow your helper funcs to modify the array as normal, but any attempt to use .push .splice etc will fail, either directly, or using the .bind(myArr,arg) method.
It's still not completely watertight, but a pretty good protector. You could potentially use the Object.defineProperty method to generate protected properties for the first 900 indexes, but I'm not sure of the implications of this. There is also the method Object.preventExtensions() but I'm unaware of a way to undo this effect when you need to change it yourself
Thank you, dandavis!
I used the slice method:
var myModule = (function () {
"use strict";
var a = (function () {
var _b = {},
_c = _c = "",
_d = [];
Object.defineProperty(_b, "c", {
get: function () { return _c; }
});
Object.defineProperty(_b, "d", {
get { return _d.slice(); } // UPDATED
});
_b.updateC = function (newValue) {
_c = newValue;
};
_b.addD = function (newD) {
_d.push(newD);
};
Object.seal(_b);
return _b;
}());
var _something = { B: _b };
return {
Something: _something,
AddD: _b.addD
};
}());
myModule.Something.c = "blah"; // doesn't update = WIN!!
myModule.AddD({}); // pushed = WIN!
myModule.Something.d.push({}); // no more update = happiness
This allows me to protect from direct push calls enforcing some logic.

Javascript functional inheritance with prototypes

In Douglas Crockford's JavaScript: The Good Parts he recommends that we use functional inheritance. Here's an example:
var mammal = function(spec, my) {
var that = {};
my = my || {};
// Protected
my.clearThroat = function() {
return "Ahem";
};
that.getName = function() {
return spec.name;
};
that.says = function() {
return my.clearThroat() + ' ' + spec.saying || '';
};
return that;
};
var cat = function(spec, my) {
var that = {};
my = my || {};
spec.saying = spec.saying || 'meow';
that = mammal(spec, my);
that.purr = function() {
return my.clearThroat() + " purr";
};
that.getName = function() {
return that.says() + ' ' + spec.name + ' ' + that.says();
};
return that;
};
var kitty = cat({name: "Fluffy"});
The main issue I have with this is that every time I make a mammal or cat the JavaScript interpreter has to re-compile all the functions in it. That is, you don't get to share the code between instances.
My question is: how do I make this code more efficient? For example, if I was making thousands of cat objects, what is the best way to modify this pattern to take advantage of the prototype object?
Well, you just can't do it that way if you plan on making lots of mammal or cat. Instead do it the old fashioned way (prototype) and inherit by property. You can still do the constructors the way you have above but instead of that and my you use the implicit this and some variable representing the base class (in this example, this.mammal).
cat.prototype.purr = function() { return this.mammal.clearThroat() + "purr"; }
I'd use another name than my for base access and store it in this in the cat constructor. In this example I used mammal but this might not be the best if you want to have static access to the global mammal object. Another option is to name the variable base.
Let me introduce you to Classical Inheritance that never uses prototype. This is a bad coding exercise but will teach you the real Classical Inheritance which always compared to prototypal inheritance:
Make a custructor:
function Person(name, age){
this.name = name;
this.age = age;
this.sayHello = function(){return "Hello! this is " + this.name;}
}
Make another cunstructor that inherits from it:
function Student(name, age, grade){
Person.apply(this, [name, age]);
this.grade = grade
}
Very simple! Student calls(applies) Person on itself with name and age arguments takes care of grade arguments by itself.
Now lets make an instance of Student.
var pete = new Student('Pete', 7, 1);
Out pete object will now contain name, age, grade and sayHello properties. It owns all those properties. They are not uplinked to Person through prototype. If we change Person to this:
function Person(name, age){
this.name = name;
this.age = age;
this.sayHello = function(){
return "Hello! this is " + this.name + ". I am " this.age + " years old";
}
}
pete will no recieve the update. If we call pete.sayHello, ti will return Hello! this is pete. It will not get the new update.
if you want privacy and you dont like protyping you may or may-not like this approach:
(note.: it uses jQuery.extend)
var namespace = namespace || {};
// virtual base class
namespace.base = function (sub, undefined) {
var base = { instance: this };
base.hierarchy = [];
base.fn = {
// check to see if base is of a certain class (must be delegated)
is: function (constr) {
return (this.hierarchy[this.hierarchy.length - 1] === constr);
},
// check to see if base extends a certain class (must be delegated)
inherits: function (constr) {
for (var i = 0; i < this.hierarchy.length; i++) {
if (this.hierarchy[i] == constr) return true;
}
return false;
},
// extend a base (must be delegated)
extend: function (sub) {
this.hierarchy.push(sub.instance.constructor);
return $.extend(true, this, sub);
},
// delegate a function to a certain context
delegate: function (context, fn) {
return function () { return fn.apply(context, arguments); }
},
// delegate a collection of functions to a certain context
delegates: function (context, obj) {
var delegates = {};
for (var fn in obj) {
delegates[fn] = base.fn.delegate(context, obj[fn]);
}
return delegates;
}
};
base.public = {
is: base.fn.is,
inherits: base.fn.inherits
};
// extend a sub-base
base.extend = base.fn.delegate(base, base.fn.extend);
return base.extend(sub);
};
namespace.MyClass = function (params) {
var base = { instance: this };
base.vars = {
myVar: "sometext"
}
base.fn = {
init: function () {
base.vars.myVar = params.myVar;
},
alertMyVar: function() {
alert(base.vars.myVar);
}
};
base.public = {
alertMyVar: base.fn.alertMyVar
};
base = namespace.base(base);
base.fn.init();
return base.fn.delegates(base,base.public);
};
newMyClass = new namespace.MyClass({myVar: 'some text to alert'});
newMyClass.alertMyVar();
the only downside is that because of the privacy scope you can only extend the virtual classes and not the instanceable classes.
here is an example of how i extend the namespace.base, to bind/unbind/fire custom events.
// virtual base class for controls
namespace.controls.base = function (sub) {
var base = { instance: this };
base.keys = {
unknown: 0,
backspace: 8,
tab: 9,
enter: 13,
esc: 27,
arrowUp: 38,
arrowDown: 40,
f5: 116
}
base.fn = {
// bind/unbind custom events. (has to be called via delegate)
listeners: {
// bind custom event
bind: function (type, fn) {
if (fn != undefined) {
if (this.listeners[type] == undefined) {
throw (this.type + ': event type \'' + type + '\' is not supported');
}
this.listeners[type].push(fn);
}
return this;
},
// unbind custom event
unbind: function (type) {
if (this.listeners[type] == undefined) {
throw (this.type + ': event type \'' + type + '\' is not supported');
}
this.listeners[type] = [];
return this;
},
// fire a custom event
fire: function (type, e) {
if (this.listeners[type] == undefined) {
throw (this.type + ': event type \'' + type + '\' does not exist');
}
for (var i = 0; i < this.listeners[type].length; i++) {
this.listeners[type][i](e);
}
if(e != undefined) e.stopPropagation();
}
}
};
base.public = {
bind: base.fn.listeners.bind,
unbind: base.fn.listeners.unbind
};
base = new namespace.base(base);
base.fire = base.fn.delegate(base, base.fn.listeners.fire);
return base.extend(sub);
};
To proper use Javascript-prototype based inheritance you could use fastClass https://github.com/dotnetwise/Javascript-FastClass
You have the simpler inheritWith flavor:
var Mammal = function (spec) {
this.spec = spec;
}.define({
clearThroat: function () { return "Ahem" },
getName: function () {
return this.spec.name;
},
says: function () {
return this.clearThroat() + ' ' + spec.saying || '';
}
});
var Cat = Mammal.inheritWith(function (base, baseCtor) {
return {
constructor: function(spec) {
spec = spec || {};
baseCtor.call(this, spec);
},
purr: function() {
return this.clearThroat() + " purr";
},
getName: function() {
return this.says() + ' ' + this.spec.name + this.says();
}
}
});
var kitty = new Cat({ name: "Fluffy" });
kitty.purr(); // Ahem purr
kitty.getName(); // Ahem Fluffy Ahem
And if you are very concerned about performance then you have the fastClass flavor:
var Mammal = function (spec) {
this.spec = spec;
}.define({
clearThroat: function () { return "Ahem" },
getName: function () {
return this.spec.name;
},
says: function () {
return this.clearThroat() + ' ' + spec.saying || '';
}
});
var Cat = Mammal.fastClass(function (base, baseCtor) {
return function() {
this.constructor = function(spec) {
spec = spec || {};
baseCtor.call(this, spec);
};
this.purr = function() {
return this.clearThroat() + " purr";
},
this.getName = function() {
return this.says() + ' ' + this.spec.name + this.says();
}
}
});
var kitty = new Cat({ name: "Fluffy" });
kitty.purr(); // Ahem purr
kitty.getName(); // Ahem Fluffy Ahem
Btw, your initial code doesn't make any sense but I have respected it literally.
fastClass utility:
Function.prototype.fastClass = function (creator) {
var baseClass = this, ctor = (creator || function () { this.constructor = function () { baseClass.apply(this, arguments); } })(this.prototype, this)
var derrivedProrotype = new ctor();
if (!derrivedProrotype.hasOwnProperty("constructor"))
derrivedProrotype.constructor = function () { baseClass.apply(this, arguments); }
derrivedProrotype.constructor.prototype = derrivedProrotype;
return derrivedProrotype.constructor;
};
inheritWith utility:
Function.prototype.inheritWith = function (creator, makeConstructorNotEnumerable) {
var baseCtor = this;
var creatorResult = creator.call(this, this.prototype, this) || {};
var Derrived = creatorResult.constructor ||
function defaultCtor() {
baseCtor.apply(this, arguments);
};
var derrivedPrototype;
function __() { };
__.prototype = this.prototype;
Derrived.prototype = derrivedPrototype = new __;
for (var p in creatorResult)
derrivedPrototype[p] = creatorResult[p];
if (makeConstructorNotEnumerable && canDefineNonEnumerableProperty) //this is not default as it carries over some performance overhead
Object.defineProperty(derrivedPrototype, 'constructor', {
enumerable: false,
value: Derrived
});
return Derrived;
};
define utility:
Function.prototype.define = function (prototype) {
var extendeePrototype = this.prototype;
if (prototype)
for (var p in prototype)
extendeePrototype[p] = prototype[p];
return this;
}
[* Disclaimer, I am the author of the open source package and the names of the methods themselves might be renamed in future` *]

Categories