I'm developing a game like Clash of Clan (just an exercise). And I use a* algorithm for soldier to find the path to target. The size of map is 120 x 120.
But when a soldier find his target, it takes 4 to 5 second to find out his path. (the result is appropximately 120 steps, 5xxx node in open list).
That code when i run on browser, it just some miliseconds.
findPath: function (startTile, endTile, id, isIgnoreWall) {
if (startTile.x === endTile.x && startTile.y === endTile.y)
return [];
if (!id)
id = 0;
var openPath = [], closePath = [];
openPath[0] = {
pos: startTile,
parent: null,
g: 0,
f: this.calculateH(startTile, endTile)
};
var matrix = SceneMgr.getCurrentScene().getMapView().matrix;
var isFound = false, k = 0;
var _path = [];
while (openPath.length) {
var minIndex = this.findMin(openPath);
var minNode = openPath[minIndex];
openPath.splice(minIndex, 1);
closePath.push(minNode);
var aroundNode = this.findAroundNode(minNode.pos);
for (var i = 0; i < aroundNode.length; i++) {
var pos = aroundNode[i];
var indexClose = this.getNodeIndex(pos, closePath);
if (indexClose != -1 || !this.canMove(pos, isIgnoreWall, id, matrix))
continue;
if (pos.x === endTile.x && pos.y === endTile.y) {
var node = {
pos: pos,
parent: minNode
};
var path = [];
cc.log("tim thay: ", closePath.length);
while (node.parent) {
path.unshift(node);
node = node.parent;
}
return path;
break;
}
var cost = this.calculateH(minNode.pos, pos);
var g = minNode.g + cost;
var h = this.calculateH(pos, endTile);
var f = g + h;
var newNode = {
pos: pos,
g: g,
f: f,
parent: minNode
};
var indexOpen = this.getNodeIndex(pos, openPath);
//if node with the same pos is already in open list
if (indexOpen != -1) {
//if node in open list has f less than f, then re-assign, else skip it
if (openPath[indexOpen].g > g) {
openPath[indexOpen] = newNode;
}
} else {
openPath.push(newNode);
//_path.push({pos});
//this.draw([{pos}]);
}
}
}
return [];
}
I'd like to extend javascript to add custom type checking.
e.g.
function test(welcome:string, num:integer:non-zero) {
console.log(welcome + num)
}
which would compile into:
function test(welcome, num) {
if(Object.prototype.toString.call(welcome) !== "[object String]") {
throw new Error('welcome must be a string')
}
if (!Number.isInteger(num)) {
throw new Error('num must be an integer')
}
console.log(welcome + num)
}
What's the most straightforward way of doing this?
So far i've looked at:
sweet.js (online documentation looks out of date as I think it's going through some sort of internal rewrite)
esprima and escodegen (not sure where to start)
manually parsing using regular expressons
After evaluating all the various options, using sweet.js appears to be the best solution. It's still fairly difficult to get working (and I am probably doing stuff the wrong way) but just in case someone want's to do something similar this here was my solution.
'use strict'
syntax function = function(ctx) {
let funcName = ctx.next().value;
let funcParams = ctx.next().value;
let funcBody = ctx.next().value;
//produce the normal params array
var normalParams = produceNormalParams(funcParams)
//produce the checks
var paramChecks = produceParamChecks(funcParams)
//produce the original funcBody code
//put them together as the final result
var params = ctx.contextify(funcParams)
var paramsArray = []
for (let stx of params) {
paramsArray.push(stx)
}
var inner = #``
var innerStuff = ctx.contextify(funcBody)
for (let item of innerStuff) {
inner = inner.concat(#`${item}`)
}
var result = #`function ${funcName} ${normalParams} {
${paramChecks}
${inner}
}`
return result
function extractParamsAndParamChecks(paramsToken) {
var paramsContext = ctx.contextify(paramsToken)
//extracts the actual parameters
var paramsArray = []
var i = 0;
var firstItembyComma = true
for (let paramItem of paramsContext) {
if (firstItembyComma) {
paramsArray.push({
param: paramItem,
checks: []
})
firstItembyComma = false
}
if (paramItem.value.token.value === ',') {
firstItembyComma = true
i++
} else {
paramsArray[i].checks.push(paramItem.value.token.value)
}
}
for (var i = 0; i < paramsArray.length; i++) {
var checks = paramsArray[i].checks.join('').split(':')
checks.splice(0, 1)
paramsArray[i].checks = checks
}
return paramsArray
}
function produceNormalParams(paramsToken) {
var paramsArray = extractParamsAndParamChecks(paramsToken)
//Produces the final params #string
var inner = #``
var first = true
for (let item of paramsArray) {
if (first === true) {
inner = inner.concat(#`${item.param}`)
} else {
inner = inner.concat(#`,${item.param}`)
}
}
return #`(${inner})`
}
function produceParamChecks(paramsToken) {
var paramsArray = extractParamsAndParamChecks(paramsToken)
var result = #``
for (let paramObject of paramsArray) {
var tests = produceChecks(paramObject)
result = result.concat(#`${tests}`)
}
return result
}
function produceChecks(paramObject) {
var paramToken = paramObject.param
var itemType = paramObject.checks[0]
var checks = paramObject.checks
if (itemType === undefined) return #``
if (itemType === 'array') {
return #`if (Object.prototype.toString.call(${paramToken}) !== "[object Array]") throw new Error('Must be array:' + ${paramToken})`
else {
throw new Error('item type not recognised: ' + itemType)
}
}
}
For example, if I have a string:
var foo = 'a.b.c';
... and Object:
var bar = {
a: {
b: {
c: null
}
}
}
How can I use the string to set the value of 'c' to 'Hello World!"?
Here's one of those not so simple or consistent ways
var bar = {
a: {
b: {
c: 'test'
}
}
}
var foo = 'a.b.c',
arr = foo.split('.'),
o = bar;
arr.forEach(function(key, i) {
if (i === arr.length-1) {
o[key] = 'Hello World'
}else{
o = o[key];
}
});
FIDDLE
Another possible solution is to use eval, but it is unsafe and mostly discouraged:
var foo = "a.b.c";
var bar = {
a: {
b: {
c: null
}
}
}
eval("bar." + foo + " = 'Hello World'; ");
alert(bar.a.b.c);
FIDDLE
Another example with a small function (DEMO):
function setVal(obj, accessors, val) {
var parts = accessors.split('.');
for(var i = 0; i < parts.length-1; i++) {
obj = obj[parts[i]]
}
obj[parts[parts.length-1]] = val;
}
setVal(bar, foo, 'Hello World');
Also to get the value:
function getVal(obj, accessors) {
var parts = accessors.split('.');
for(var i = 0; i < parts.length; i++) {
obj = obj[parts[i]]
}
return obj;
}
var val = getVal(bar, foo);
I'm trying to write a function that can look up a namespace and value in a JavaScript object and return the key.
Image this data:
var o = {
map: {
lat : -33.86749,
lng : 151.20699,
zoom : 12
},
filters : {
animals : {
dogs: {
myDog : 'fido'
}
}
}
};
function get(namespace, key){
//TODO
}
get('filters.animals.dogs', 'myDog')
How would you build a function that does this dynamically - no matter the depth of the namespace?
This function is somewhat close, only it modifies the original object which we don't want ofcourse:
var get = function(obj, namespace, key, value) {
var parts = namespace.split('.');
for(var i = 0; i < parts.length; i++) {
if(typeof obj[parts[i]] == 'undefined'){
obj[parts[i]] = {};
}
obj = obj[parts[i]];
}
return obj[key] = value;
};
Reason for the madness is that I cannot expose the object. It must remain private and a public method must spit out a result.
Give this a try.
function get(namespace, key) {
var parts = namespace.split('.'),
i = 0,
l = parts.length,
obj = o;
while ( i < l ) {
obj = obj[parts[i]];
if ( ! obj ) break;
i++;
}
return obj && obj[key] ? obj[key] : null;
}
I have created a fiddle with working code. Hope that helps.
http://jsfiddle.net/RdhJF/2/
var o = {
map: {
lat : -33.86749,
lng : 151.20699,
zoom : 12
},
filters : {
animals : {
dogs: {
myDog : 'fido'
}
}
}
};
function get(obj, namespace)
{
var parts = namespace.split('.');
if(parts.length==0)
return -1;
var previousValue = obj;
for(var i = 0; i < parts.length; i++)
{
if(typeof previousValue[parts[i]] == 'undefined')
return -1;
else
previousValue = previousValue[parts[i]];
}
return previousValue;
}
var myValue= get(o,'filters.animals.dogs.myDog');
alert(myValue);
After updating my code based on answers to this previous question, I came up with the following solution:
var Coder = (function() {
var controlWords = [
['ONE','OO'],
['TWO','TT'],
['THREE','RR'],
//['...','..'],
['END','NN']
],
map = {
'0':' ', '1':'_', '2':',',
'3':'.', '4':'?', '5':'!',
'6':'\'','7':'"', '8':'(',
'9':')', 'a':'o', 'b':'d',
'c':'a', 'd':'e', 'e':'p',
'f':'i', 'g':'f', 'h':'v',
'i':'u', 'j':'l', 'k':'m',
'l':'y', 'm':'q', 'n':'x',
'o':'b', 'p':'j', 'q':'t',
'r':'n', 's':'z', 't':'w',
'u':'k', 'v':'h', 'w':'s',
'x':'c', 'y':'r', 'z':'g'
},
reverseMap = (function() {
var j, tmp = {};
for (j in map){
if (Object.prototype.hasOwnProperty.call(map, j))
tmp[map[j]] = j;
}
return tmp;
})(),
value, i,
encode = function(data) {
var input = (typeof data == 'string' ? data : '');
console.log('Input to encode: '+input);
for (i = 0; i < controlWords.length; i++) {
value = new RegExp(controlWords[i][0],'g');
input = input.replace(value,controlWords[i][1]);
}
console.log('Encode step 1: '+input);
input = input.replace(/./g, function(c){
return reverseMap[c]
|| reverseMap[c.toLowerCase()].toUpperCase();
});
console.log('Encoding output: '+input);
return {length: input.length, data: input};
},
decode = function(data) {
var input = (typeof data == 'string' ? data : '');
console.log('Input to decode: '+input);
input = input.replace(/./g, function(c){
return map[c]
|| map[c.toLowerCase()].toUpperCase();
});
console.log('Decode step 1: '+input);
for (i = 0; i < controlWords.length; i++) {
value = new RegExp(controlWords[i][1],'g');
input = input.replace(value,controlWords[i][0]);
}
console.log('Decoding output: '+input);
return {length: input.length, data: input};
};
return {encode: encode, decode: decode};
})();
var str = 'ONE Hello, TWO JavaScript THREE World! END',
enc = Coder.encode(str).data,
dec = Coder.decode(enc).data;
As you can see, there's a lot of fully- or nearly-repeated code. The only meaningful differences are the order in which the two transformations happen, whether map or reverseMap is used, and which index of each control word array is used as the regex and which as the replacement value.
To abide by the concept of wrapping repeated code in a sub-function and calling that function, I made the following attempt. It defines the two transformations as internal functions, and then based on the value of the type argument, decides the rest.
var Coder = (function() {
var controlWords = [ /* same */ ],
map = { /* same */ },
reverseMap = /* same */,
code = function(data, type) {
var input = (typeof data == 'string' ? data : ''),
mapping, x, y, value, i,
transform = function() {
return input.replace(/./g, function(c){
return mapping[c]
|| mapping[c.toLowerCase()].toUpperCase();
});
},
replace = function() {
for (i = 0; i < controlWords.length; i++) {
value = new RegExp(controlWords[i][x],'g');
input = input.replace(value,controlWords[i][y]);
}
return input;
};
if (type == 'decode') {
mapping = map;
x = 1;
y = 0;
input = transform();
input = replace();
} else if (type == 'encode') {
mapping = reverseMap;
x = 0;
y = 1;
input = replace();
input = transform();
} else {
throw new Error('Invalid type argument!');
}
return {data: input, length: input.length};
};
return {code: code};
})();
var str = 'ONE Hello, TWO JavaScript THREE World! END',
enc = Coder.code(str, 'encode').data,
dec = Coder.code(enc, 'decode').data;
However, you might notice that this code is actually longer. It's still more easily extended, if I wanted to add more types than 'encode' and 'decode' (not going to). But currently less efficient?
I then went back to the version with two functions (to avoid the passing of and check of 'type'):
var Coder = (function() {
var controlWords = [ /* same */ ],
map = { /* same */ },
reverseMap = { /* same */ },
input, mapping, x, y, value, i,
transform = function() {
return input.replace(/./g, function(c){
return mapping[c]
|| mapping[c.toLowerCase()].toUpperCase();
});
},
replace = function() {
for (i = 0; i < controlWords.length; i++) {
value = new RegExp(controlWords[i][x],'g');
input = input.replace(value,controlWords[i][y]);
}
return input;
},
encode = function(data) {
input = (typeof data == 'string' ? data : '');
mapping = reverseMap;
x = 0;
y = 1;
input = replace();
input = transform();
return {length: input.length, data: input};
},
decode = function(data) {
input = (typeof data == 'string' ? data : '');
mapping = map;
x = 1;
y = 0;
input = transform();
input = replace();
return {length: input.length, data: input};
};
return {encode: encode, decode: decode};
})();
// Call methods same as first example
So lengthy post to basically ask, which is better, repeated code or extra functions/checks, when it doesn't really help code length and there's no plans to extend the code or release it as a public project? Which of these is the most elegant solution, or is there an even better?
EDIT
One way I thought of to clean it up in general is to remove the variable declarations of mapping, x, and y and just pass them as arguments to replace and transform. This would yield
decode = function(data) {
var input = (typeof data == 'string' ? data : '');
input = transform(map);
input = replace(1,0);
return {length: input.length, data: input};
}