--Solved by Elliot B. Thanks!
May also take int account the other modifications.
Here is the result. Thanks, everyone, for the speedy answers! http://dl.dropbox.com/u/18785762/Rust/index.html
I'm writing a game in javascript, and I want to keep the files for matching block IDs to files in a seperate .js file from the map compiler, so that I can edit things easily. However, the IDs are stored in an array, and I can't seem to get it to use the return function properly. Any help?
drawmap.js:
function drawmap() {
var images = BlockID();
var level = [
"ssssssssssssssssssssss",
"sgggggggggCCCCCdddddss",
"ssssssssss sssssss"
];
var top = 100;
var left = 100;
var mytop = top;
var myleft = left;
for (y=0; y<level.length; ++y) {
var row = level[y];
for (x=0; x < row.length; ++x) {
var c = row.charAt(x);
if(c != ' ') {
img_create(images[c], mytop, myleft);
}
mytop += 13;
myleft += 27;
}
mytop = top + (y+1)*13;
myleft = left - (y+1)*27;
}
}
mapread.js:
function BlockID() {
var IDs = new Array();
images['s'] = "Images/Block_01.png";
images['g'] = "Images/Block_02.png";
images['C'] = "Images/Block_03.png";
images['d'] = "Images/Block_04.png";
return IDs;
}
At a minimum, change this:
function BlockID() {
var IDs = new Array();
images['s'] = "Images/Block_01.png";
images['g'] = "Images/Block_02.png";
images['C'] = "Images/Block_03.png";
images['d'] = "Images/Block_04.png";
return IDs;
}
To this:
function BlockID() {
var IDs = new Object();
IDs['s'] = "Images/Block_01.png";
IDs['g'] = "Images/Block_02.png";
IDs['C'] = "Images/Block_03.png";
IDs['d'] = "Images/Block_04.png";
return IDs;
}
There are a couple fixes to point out. First, images is not defined in your original function, so assigning property values to it will throw an error. We correct that by changing images to IDs. Second, you want to return an Object, not an Array. An object can be assigned property values akin to an associative array or hash -- an array cannot. So we change the declaration of var IDs = new Array(); to var IDs = new Object();.
After those changes your code will run fine, but it can be simplified further. You can use shorthand notation (i.e., object literal property value shorthand) to create the object and return it immediately:
function BlockID() {
return {
"s":"Images/Block_01.png"
,"g":"Images/Block_02.png"
,"C":"Images/Block_03.png"
,"d":"Images/Block_04.png"
};
}
Your BlockID function uses the undefined variable images, which will lead to an error. Also, you should not use an Array here - JavaScripts key-value-maps are plain objects:
function BlockID() {
return {
"s": "Images/Block_01.png",
"g": "Images/Block_02.png",
"C": "Images/Block_03.png",
"d": "Images/Block_04.png"
};
}
neater:
function BlockID() {
return {
"s":"Images/Block_01.png",
"g":"Images/Block_02.png",
"C":"Images/Block_03.png",
"d":"Images/Block_04.png"
}
}
or just
var images = {
"s":"Images/Block_01.png",
"g":"Images/Block_02.png",
"C":"Images/Block_03.png",
"d":"Images/Block_04.png"
}
Taking in consideration that in JavaScript Array is object too this can be written as:
function BlockID() {
return new Array(
"Images/Block_01.png",
"Images/Block_02.png",
"Images/Block_03.png",
"Images/Block_04.png"
);
}
This code will display content of array in browser's window
window.onload=function(){
var s="";
var ar = BlockID(); //function return array
for(el in ar){
s+=ar[el]+"</br>";
}
document.body.innerHTML=s;
};
Related
I've searched high and wide for an answer but can't seem to find it. I am trying to alter my custom function that looks up sitemap URL's and the date they were updated to accept a range of inputs.
Here is the current function that works:
function sitemap(sitemapUrl, namespace) {
var array = [];
var xml = UrlFetchApp.fetch(sitemapUrl).getContentText();
var document = XmlService.parse(xml);
var root = document.getRootElement();
var sitemapNameSpace = XmlService.getNamespace("http://www.sitemaps.org/schemas/sitemap/0.9");
var urls = root.getChildren('url', sitemapNameSpace);
for (var i = 0; i < urls.length; i++) {
var loc = urls[i].getChild('loc', sitemapNameSpace).getText();
var lastmod = urls[i].getChild('lastmod', sitemapNameSpace).getText();
array.push([loc, lastmod]);
}
return array;
}
I've tried using Google's example below but doesn't seem to work however I incorporate it into my function. Any ideas?
function DOUBLE(input) {
if (input.map) { // Test whether input is an array.
return input.map(DOUBLE); // Recurse over array if so.
} else {
return input * 2;
}
}
Edit: This is how I tried to use Google's example for my function:
function sitemaps(sitemapUrl) {
var array = [];
var xml = UrlFetchApp.fetch(sitemapUrl).getContentText();
var document = XmlService.parse(xml);
var root = document.getRootElement()
var sitemapNameSpace = XmlService.getNamespace("http://www.sitemaps.org/schemas/sitemap/0.9")
var urls = root.getChildren('url', sitemapNameSpace)
for (var i = 0; i < urls.length; i++) {
var loc = urls[i].getChild('loc',sitemapNameSpace).getText();
var lastmod = urls[i].getChild('lastmod',sitemapNameSpace).getText();
array.push([loc, lastmod]);
}
if (sitemapUrl.map) {
return sitemapUrl.map(sitemaps);
} else {
return array
}
You are no using the same format as the Google example. As of right now you are checking if the input is an array after actually retrieving the data.
But you using fetch with an array as input could trigger an Error and the function may no get to the point where it checks if the sitemapUrl can be used with map.
Also take into account that map will call the function in every single element of the array and return an array with a result for each of element. So in your case B3:B6 would call the function for the value at B3, B4, B5 and B6 and return an array of length 4 with the result. For your case in which you want a single list you need to flattern the array afterwards
I would change your function to be like this:
function sitemaps(sitemapUrl) {
if (sitemapUrl.map) {
return sitemapUrl.map(sitemaps).flat();
} else {
var array = [];
var xml = UrlFetchApp.fetch(sitemapUrl).getContentText();
var document = XmlService.parse(xml);
var root = document.getRootElement()
var sitemapNameSpace = XmlService.getNamespace("http://www.sitemaps.org/schemas/sitemap/0.9")
var urls = root.getChildren('url', sitemapNameSpace)
for (var i = 0; i < urls.length; i++) {
var loc = urls[i].getChild('loc', sitemapNameSpace).getText();
var lastmod = urls[i].getChild('lastmod', sitemapNameSpace).getText();
array.push([loc, lastmod]);
}
return array
}
}
Although what you are doing is fine take into account that it also exists a way to retrieve all the request at the same time (
UrlFetchApp.fetch()) but for this specific case you would need to flatten a reshape the input array.
What is the best way to consolidate this code? As it is, it works perfectly, but it needs to go up to maybe 40-50 items long, so it needs to be shortened dramatically, (I assume, with a for loop).
I'm pretty much a novice when it comes to Javascript, and trying to add arrays to an array with a loop is confusing me immensely.
The "vac1.", "vac2." ...etc, variables are used later on in the code to add pointers onto a Google Maps map.
var x = count.count; // x = a value that changes (between 1 & 50)
if(x == 1){
locations = [
[vac1.vacancy_title, vac1.vacancy_latlng, vac1.vacancy_url, vac1.vacancy_location]
];
}
if(x == 2){
locations = [
[vac1.vacancy_title, vac1.vacancy_latlng, vac1.vacancy_url, vac1.vacancy_location],
[vac2.vacancy_title, vac2.vacancy_latlng, vac2.vacancy_url, vac2.vacancy_location]
];
}
if(x == 3){
locations = [
[vac1.vacancy_title, vac1.vacancy_latlng, vac1.vacancy_url, vac1.vacancy_location],
[vac2.vacancy_title, vac2.vacancy_latlng, vac2.vacancy_url, vac2.vacancy_location],
[vac3.vacancy_title, vac3.vacancy_latlng, vac3.vacancy_url, vac3.vacancy_location]
];
}
...etc etc...
I have tried using a for loop, but it doesn't work and I have no idea if I am anywhere close to figuring out how to do it correctly.
var x = count.count;
locations = [];
array = [];
for (i = 0; i < x; i++) {
array = [vac[i].vacancy_title, vac[i].vacancy_latlng, vac[i].vacancy_url, vac[i].vacancy_location];
locations.push(array);
}
Any help or advice would be greatly appreciated!
Thank you.
You need to consider them as a string:
var x = 5;
locations = [];
array = [];
for (i = 1; i <= x; i++) {
array = ['vac'+i+'.vacancy_title', 'vac'+i+'.vacancy_latlng', 'vac'+i+'.vacancy_url', 'vac'+i+'.vacancy_location'];
locations.push(array);
}
console.log(locations);
Create an array vac and use your previous code :
var x = count.count;
locations = [],
array = [],
vac = [ /* vac1, vac2, ...., vacn */ ];
for (i = 0; i < x; i++) {
array = [vac[i].vacancy_title, vac[i].vacancy_latlng, vac[i].vacancy_url, vac[i].vacancy_location];
locations.push(array);
}
You could use eval for the variable name and build an new array with another array for the wanted keys.
Basically you should reorganize yor program to use a solution without eval. An array could help. It is made for iteration.
var x = count.count,
i,
keys = ['vacancy_title', 'vacancy_latlng', 'vacancy_url', 'vacancy_location'],
locations = [];
object;
for (i = 1; i <= x; i++) {
object = eval('vac' + i);
locations.push(keys.map(function (k) { return object[k]; }));
}
Group the vac* elements in an array and then use slice to cut out as many as you want, then use map to generate the result array:
var vacs = [vac1, vac2 /*, ...*/]; // group the vacs into one single array
var x = count.count; // x is the number of vacs to generate
var locations = vacs.slice(0, x).map(function(vac) { // slice (cut out) x elements from the arrays vacs then map the cut-out array into your result array
return [vac.vacancy_title, vac.vacancy_latlng, vac.vacancy_url, vac.vacancy_location];
});
Because any global variable is a property of the global object :
var vac1 = "whatever";
console.lof(window.vac1); // => logs "whatever"
console.lof(window["vac1"]); // => accessed as an array, logs "whatever" too
You could use the global object and access it as an array to look for your vac1, vac2, vac3 variables :
var x = count.count, i;
locations = [],
array = [],
var globalObject = window; // or whatever the global object is for you
var vac; // this will be used to store your vac1, vac2, etc.
for (i = 0; i < x; i++) {
vac = globalObject["vac"+i]; // the "vac" + i variable read from the global object
if (vac !== undefined) {
array = [vac.vacancy_title, vac.vacancy_latlng, vac.vacancy_url, vac.vacancy_location];
locations.push(array);
}
}
I have an array named globalArrayAllTrades as you see below. I simply like to INVERT the date in a new copy of the array. So I loop through, create a new object and add it to the new array - simple.
Then function does exactly as expected. BUT if the array contains too many objects the code fails with a "FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory".
My laptop has 8 GB of memory...When the NODEJS process crashes it uses about 1.5 GB and about 70% of of totally amount of available memory is used.
I do run the NODEJS app with the parameter: --max_old_space_size=5000 which normally fixes every thing. But not this one and i have tried MANY different ways to code the same function - BUT each and every time - it fails...unless the original array is smaller.
How can I fix this issue?
function invertTrades(){
var original = globalArrayAllTrades.slice();
globalArrayAllTrades.length = 0;
globalListAllTrades.length = 0;
for(var i = 0; i < original.length; i++){
var objS = original[i];
var objE = original[original.length-1-i];
var objInv = new TradePoint(objS.number, objS.matchdate, objE.price, objE.size, objE.issell);
globalArrayAllTrades.push(objInv);
globalListAllTrades[objInv.matchdate] = objInv;
}
}
You can save some memory by making original just contain the properties you need to invert, not the whole TradePoint object. Then you don't need to construct new TradePoint objects, you can modify them in place.
var original = globalArrayAllTrades.map(function(trade) {
return {
trade.price,
trade.size,
trade.issell
};
}).reverse();
globalArrayAllTrades.forEach(function(trade, i) {
trade.price = original[i].price;
trade.size = original[i].size;
trade.issell = original[i].issell;
});
And since all the objects were modified in place, there's no need to update globalListAllTrades.
Another way is to swap the price, size, and issell properties in place between the pairs of elements:
var midpoint = Math.floor(globalArrayAllTrade.length/2);
for (var i = 0; i < midpoint; i++) {
var objS = globalArrayAllTrades[i];
var objE = globalArrayAllTrades[globalArrayAllTrades.length-1-i];
var temp = objS.price;
objS.price = objE.price;
objE.price = temp;
temp = objS.size;
objS.size = objE.size;
objE.size = temp;
temp = objS.issell;
objS.issell = objE.issell;
objE.issell = temp;
}
Have you considered just doing this?
// Copy array and then reverse it
var newArray = [].concat(original).reverse();
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse
I would suggest avoiding to copy that array:
function getInverse(i) {
var objS = globalArrayAllTrades[i];
var objE = globalArrayAllTrades[globalArrayAllTrades.length-1-i];
var objInv = new TradePoint(objS.number, objS.matchdate, objE.price, objE.size, objE.issell);
globalListAllTrades[objInv.matchdate] = objInv;
return objInv;
}
function invertTrades(){
globalListAllTrades.length = 0;
for (var i = 0, l = Math.floor(globalArrayAllTrades.length/2); i < l; i++) {
var j = globalArrayAllTrades.length-1-i;
var a = getInverse(i);
var b = getInverse(j);
globalArrayAllTrades[i] = a;
globalArrayAllTrades[j] = b;
}
}
I'd like to build a text string by inserting the characters at random, but in place order (as a kind of effect) . So far I've got:
// make a string and an array
var input = "Hello, world!",
output = [];
// split the string
input = input.split('');
My idea is then to call this
function addAnElement(){
// check if there are any left
if(input.length){
// pick an element at random
var rand = Math.floor(Math.random() * input.length);
// remove it, so we don't call it again
var element = input.splice(rand,1);
// insert it
output[rand] = element;
// use the string returned as new innerHTML, for example
return output.join('');
// repeat until finished
setTimeout(addAnElement,5);
}
}
I'm hoping this would return something like:
'e'
'er'
...
'Hel, or!'
...
'Helo, Word!'
... and finally ...
'Hello, World!'
The problem, of course, is that the array is re-indexed when spliced - and this yields gibberish. I think the answer must be to link the elements to their positions in input and then insert them intact, sorting by key if necessary before returning.
How do I do this?
How about something like this:
var input = 'Hello world',
inputIndexes = [],
output = [];
for (var i = 0; i < input.length; i++) {
inputIndexes[i] = i;
};
function addAnElement() {
if (inputIndexes.length) {
var rand = Math.floor(Math.random() * inputIndexes.length);
var element = inputIndexes.splice(rand, 1);
output[element] = input[element];
//console.log(output.join(' '));
document.getElementById('text').innerHTML = output.join(' ');
setTimeout(addAnElement, 2000);
}
}
addAnElement();
http://jsfiddle.net/fg2ybz8j/
You can avoid it by not using splice. Instead, clear an entry when you've used it, and keep a count of the entries you've cleared.
E.g.:
var entriesLeft = input.length;
function addAnElement(){
// pick an element at random, re-picking if we've already
// picked that one
var rand;
do {
rand = Math.floor(Math.random() * input.length);
}
while (!input[rand]);
// get it
var element = input[rand];
// clear it, so we don't use it again
input[rand] = undefined;
// insert it
output[rand] = element;
// repeat until finished
if (--entriesLeft) {
setTimeout(addAnElement,5);
}
// use the string returned as new innerHTML, for example
return output.join('');
}
Of course, that loop picking a random number might go on a while for the last couple of characters. If you're worried about that, you can create a randomized array of the indexes to use up-front. This question and its answers address doing that.
Live Example:
var input = "Hello, there!".split("");
var output = [];
var entriesLeft = input.length;
function addAnElement() {
// pick an element at random, re-picking if we've already
// picked that one
var rand;
do {
rand = Math.floor(Math.random() * input.length);
}
while (!input[rand]);
// get it
var element = input[rand];
// clear it, so we don't use it again
input[rand] = undefined;
// insert it
output[rand] = element;
// repeat until finished
if (--entriesLeft) {
setTimeout(addAnElement, 5);
}
// use the string returned as new innerHTML, for example
document.body.innerHTML = output.join('');
}
addAnElement();
Side note: Notice how I've moved the call to setTimeout before the return. return exits the function, so there wouldn't be any call to setTimeout. That said, I'm confused by the need for the return output.join(''); at all; all calls but the first are via the timer mechanism, which doesn't care about the return value. In the live example, I've replaced that return with an assignment to document.body.innerHTML.
Here's a demonstration of the method that shuffles an array of indexes instead. It uses the shuffle method from this answer, but I'm not saying that's necessarily the best shuffle method.
function shuffle(array) {
var tmp, current, top = array.length;
if (top)
while (--top) {
current = Math.floor(Math.random() * (top + 1));
tmp = array[current];
array[current] = array[top];
array[top] = tmp;
}
return array;
}
var input = "Hello, there".split("");
var output = [];
var indexes = input.map(function(entry, index) {
return index;
});
shuffle(indexes);
var n = 0;
function addAnElement() {
// get this index
var index = indexes[n];
// get this loop's element
var element = input[index];
// insert it
output[index] = element;
// repeat until finished
if (++n < indexes.length) {
setTimeout(addAnElement, 5);
}
// use the string returned as new innerHTML, for example
document.body.innerHTML = output.join("");
}
addAnElement();
I want to write a function which will allow me to "solve" an equation in js.
what I want (not in a programming language):
function f(x) { 1 + x * x }
var z = 2
var y = f(z) //y will be 5 as a number
what I have written in JS:
function P(cfg) { ....
this.equation = "1 + x";
....};
P.prototype.eqn = function(x) {
var tmp = eval(this.equation);
return tmp;
};
....
P.prototype.draw = function() {....
for(var i = 0; i < z; i++)
ctx.lineTo(i, this.eqn(i));
....};
also I've read that using eval in a loop is probably not a good idea, but I have not figured out another way (yet) (JS beginner)...
The problem with this code is, that at least in FF the var tmp will STILL contain the string from this.equation instead of the calculated value.
I would appreciate any further insight very much!
Thank you for your time :)
EDIT: because my question was not formulated very well:
after the execution of line
var tmp = eval(this.equation);
the var tmp will hold a STRING which equals the string this.equation, instead of the desired solution y value.
Also I do not mean solve but evaluate, thanks for that tip :)
Based on your example, I'd say that you want to "evaluate an expression", rather than "solve an equation". For evaluating an expression, you can probably find many tutorials. I'll break it down in brief though. You need to do a few steps.
Starting with your string "1 + x * x", you need to break it into tokens. Specifically, break it down into: "1", "+", "x", "*", "x". At this point, you can substitute your variables ("x") for their literal values ("2"), giving you "1", "+", "2", "*", "2"
Now you need to parse the expression. Based on order of operations PEMDAS you need to create a tree data structure, where parenthetical clauses (stuff surrounded by parenthesis) are executed first, multiplication and division next, and then additions and subtraction last. Parsing is often not an easy task, and you may want to put together a simpler BNF grammar (though you can probably find a grammar for simple math expressions with some googling).
Next, walk the tree, depth first, evaluating the operations as you go up the tree. Once you get to the top of the tree, you have your solution.
If instead you want to "solve an equation", you're going to need something much more sophisticated, like Sage
I have used this expression evaluator before. It seemed to work very well. It allows you to pass expressions into a Parser that returns a function object that can then evaluate inputs.
var expr = Parser.parse("2 ^ x");
expr.evaluate({ x: 3 }); // 8
It supports trig functions (sin, cos, ect...) and other handy built in functions such as abs & ciel.
var expr = Parser.parse("sin(x/2) + cos(x/2)")
expr.evaluate({x: Math.PI / 2}); // 1
Examples: http://silentmatt.com/javascript-expression-evaluator/
Code: https://github.com/silentmatt/js-expression-eval
Note that this lib does not use eval().
Not sure I entirely understand your question but how about:
var makeFunctionOfX = function(src) {
return Function('x', 'return ' + src);
};
Then you can say things like:
var g = makeFunctionOfX('2 * x')
var y = g(3); // y contains 6
The great advantage of this over eval is that the Function we create has no magic ability to see variables in the scope (hence the need to explicitly pass it x as a parameter name).
Using eval is safe if you trust the input from the user, and works just fine. (I have no idea what you mean by "the var tmp will still have the string this.equation".)
function FuncCreator(eqn){ this.eqn = eqn }
FuncCreator.prototype.run = function(x,y,z){ return eval(this.eqn) }
var add1 = new FuncCreator('1+x');
var result = add1.run(41); // 42
var complex = new FuncCreator('Math.sin(x*y) / Math.cos(z)');
var result = complex.run(3,4,5); // -1.891591285331882
If you don't trust the user input, you'll need to actually parse the input and process it yourself. This is non-trivial.
You can use the expression parser from the math.js library and do something like this:
var parser = math.parser();
var f = parser.eval('function f(x) = 1 + x * x');
// use the created function f in expressions:
parser.eval('z = 2'); // 2
parser.eval('y = f(z)'); // 5
// or use the created function f in JavaScript:
var z = 2; // 2
var y = f(z); // 5
Creating functions in math.js is quite currently limited, loops and blocks needed to define more extensive functions are not yet supported.
This is an old thread, but I wrote this equation calculator, this doesn't solve algebraic equations though. There is however a function that will allow you to provide an array containing assigned variables. But this doesn't solve for variables that don't have an assigned value.
I probably haven't permuted every test case scenario, but it seems to work pretty decent.
Edit: This would have to be modified to handle negative numbers. Other than that... works fine.
Here is a fiddle
<!doctype html>
<html>
<head>
<title>Javascript Equation Calculator</title>
</head>
<body>
<input type="button" onclick="main()" value="calculate"><br>
<input type="text" id="userinput"><br>
<span id="result">Ready.</span><br>
<script>
function Calculator(){}
String.prototype.replaceLast = function (what, replacement)
{
var pcs = this.split(what);
var lastPc = pcs.pop();
return pcs.join(what) + replacement + lastPc;
};
function inS(substr, str){return (str.indexOf(substr) > -1);}
function arrayValueOrToken(arr, key, token)
{
if(key in arr)
{
return arr[key];
}
return token;
}
function reduceEquation(inputStr)
{
console.log("reduceEquation Executed-----");
while(hasNest(inputStr))
{
if(hasNest(inputStr))
{
inputStr = inputStr.replace(")(",')*(');
for(var i=0;i<=9;i++)
{
inputStr = inputStr.replace(i+"(",i+'*(');
inputStr = inputStr.replace(")"+i,')*'+i);
}
var s = inputStr.lastIndexOf("(");
var e = 0;
for(i=s;i,inputStr.length;i++){if(inputStr[i]==")"){e=i+1;break;}}
var eq = inputStr.substring(s,e);
var replace = eq;
eq = eq.replace(/[()]/g, '');
var substitution = solveEquation(eq);
inputStr = inputStr.replaceLast(replace,substitution);
}
}
return inputStr;
}
function solveEquation(eq)
{
console.log("solveEquation Executed-----");
eq = doFirstOrder(eq);
eq = doLastOrder(eq);
return eq;
}
function doFirstOrder(eq)
{
console.log("doFirstOrder Executed-----");
for(var i=0;i<eq.length;i++)
{
if(eq[i]=="*"){eq = solve(eq,"*");return doFirstOrder(eq);}
if(eq[i]=='/'){eq = solve(eq,'/');return doFirstOrder(eq);}
}
return eq;
}
function doLastOrder(eq)
{
console.log("doLastOrder Executed-----");
for(var i=0;i<eq.length;i++)
{
if(eq[i]=="+"){eq = solve(eq,"+");return doLastOrder(eq);}
if(eq[i]=="-"){eq = solve(eq,"-");return doLastOrder(eq);}
}
return eq;
}
function solve(eq, operator)
{
var setOp = operator;
console.log("solve Executed-----");
var buildEq = "",var1 = true,done = false,char="";
var operators = "+-/*";
var ops = operators.replace(operator, '').split('');
var a=ops[0];
var b=ops[1];
var c=ops[2];
for(var i=0;i<eq.length;i++)
{
char = eq[i];
switch(true)
{
case(char==operator):if(var1===true){var1 = false;}else{done = true;}break;
case(char==a):
case(char==b):
case(char==c):if(var1){char = ""; buildEq = "";}else{done = true;}
}
if(done){break;}
buildEq = buildEq + char;
}
var parts = parts = buildEq.split(operator);
var solution = null;
if(operator=="+"){solution = parseFloat(parts[0]) + parseFloat(parts[1]);}
if(operator=="-"){solution = parseFloat(parts[0]) - parseFloat(parts[1]);}
if(operator=="*"){solution = parseFloat(parts[0]) * parseFloat(parts[1]);}
if(operator=="/"){solution = parseFloat(parts[0]) / parseFloat(parts[1]);}
return eq.replace(buildEq, solution);
}
function hasNest(inputStr){return inS("(",inputStr);}
function allNestsComplete(inputStr)
{
var oC = 0, cC = 0,char="";
for(var i=0;i<inputStr.length;i++){char = inputStr[i];if(char=="("){oC+=1;}if(char==")"){cC+=1;}}
return (oC==cC);
}
Calculator.prototype.calc = function(inputStr)
{
console.log("Calc Executed-----");
inputStr = inputStr.replace(/ /g, "");
inputStr = inputStr.replace(/\\/g, '/');
inputStr = inputStr.replace(/x/g, "*")
inputStr = inputStr.replace(/X/g, "*")
if(!allNestsComplete(inputStr)){return "Nested operations not opened/closed properly.";}
inputStr=reduceEquation(inputStr);
inputStr = solveEquation(inputStr);
return inputStr;
};
Calculator.prototype.calcWithVars = function(inputList)
{
if(inputList.length < 2){return "One or more missing arguments!";}
var vars = [];
var assocVars = [];
var lastVarIndex = inputList.length - 2;
var i = 0;
var inputStr = inputList[inputList.length-1];
for(i=0;i<=lastVarIndex;i++)
{
vars.push(inputList[i].replace(/ /g, ""));
}
for(i=0;i<=vars.length-1;i++)
{
var vParts = vars[i].split("=");
var vName = vParts[0];
var vValue = vParts[1];
assocVars[vName] = vValue;
}
inputStr = inputStr.replace(/ /g, "");
var eqVars = inputStr.replace(/\s+/g, ' ').replace(/[^a-zA-Z-]/g, ' ').replace(/\s\s+/g, ' ');
if(inS(" ", eqVars))
{
eqVars = eqVars.split(" ");
}
else{eqVars = [eqVars];}
eqVars.sort(function(a, b){return a.length - a.length;});
var tempTokens = [];
var tempCount = 1;
for(i=0;i<eqVars.length;i++)
{
var eqVname = eqVars[i];
var substitution = arrayValueOrToken(assocVars, eqVname, "<unknown>");
if(substitution != "<unknown>")
{
inputStr = inputStr.replace(eqVname,substitution);
}
else
{
var tempToken = "#______#"+tempCount+"#______#";
tempCount++;
tempTokens.push(tempToken + "?" + eqVname);
inputStr = inputStr.replace(eqVname,tempToken);
}
}
for(i=0;i<tempTokens.length;i++)
{
var tokenSet = tempTokens[i];
var tokenParts = tokenSet.split("?");
var token = tokenParts[0];
var variableName = tokenParts[1];
inputStr = inputStr.replace(token,variableName);
}
var answerName = "<unknown>";
var eq = inputStr;
if(inS("=", inputStr))
{
var eqParts = inputStr.split("=");
answerName = eqParts[0];
eq = eqParts[1];
}
eq = this.calc(eq);
var result = [];
for(i=0;i<eqVars.length;i++)
{
var v = arrayValueOrToken(assocVars, eqVars[i], "<unknown>");
if(v != "<unknown>")
{
result.push(assocVars[eqVars[i]]);
}
}
result.push(eq);
return result;
};
function main()
{
var calculator = new Calculator();
elUserInput = document.getElementById('userinput');
console.log("input: "+ elUserInput.value);
elResult = document.getElementById('result');
equation = elUserInput.value;
result = calculator.calc(equation);
console.log("result: "+ result);
elResult.innerHTML = result;
}
</script>
</body>
</html>