2D dynamic javascript matrix for coordinates object - javascript

I'm trying to make a 2D matrix dynamic system which identifies whether there is an "object" at X,Y coordinates (true), or not (false).
Simplified example code:
var coords = [[]]; // Matrix is over 10,000 x 10,000
var objectX = 76;
var objectY = 54;
coords[objectX][objectY] = true;
//Check to see if there is an object # coordinates
if(coords[100][65] == false || coords[100][65] === undefined)
{
//There is no object # 100 x 65
}
else
{
//Object detected # 100 x 65
}
But it seems I can't do it this way, since I think I have to start from [0][0], [0][1], [0][2], ... , ect; or something..
Also, matrix is too large to define via putting it in a loop. I can't have it loading for hours.
I won't mind keeping an array segment 'undefined', as I treat it as false in my code.
How can I accomplish this?

You need to make sure the first dimension array exists before you address the second dimension:
if (coords[objectX] === undefined) coords[objectX] = [];
coords[objectX][objectY] = true;
If upfront you know you actually need an element for each X,Y position (which will consume more memory), then initialise the matrix first with a loop:
for (var objectX=0; objectX <= maxX; objectX++) {
coords[objectX] = [];
for (var objectY=0; objectY <= maxY; objectY++) {
coords[objectX][objectY] = false;
}
}
Depending on your needs, you might get better memory usage and performance if you would use a different structure:
var coords = [];
coords[objectX * (maxX + 1) + objectY] = true;
Or if you do not know the range of X nor Y:
coords = {}; // object whose properties will be X,Y strings:
coords[objectX + ',' + objectY] = true;

Related

Calculating sine values in javascript using for loop, but it keeps crashing. Why?

So I'm trying to calculate values of the function sin(x) by inputting a domain parameter and how many steps to calculate the y values for each respective x value. I know the for loop is the problem because when I comment it out, the page loads fine. However, if the loop is active, then the page crashes.
I thought, "oh, maybe it's because I am looping numbers that are irrational such as PI". Well, I changed the domain to [0, 2] so that the numbers are more "nice", but I still get the same issue.
I tried looking up possible reasons why this is happening, and it seems to be because of some sort of recursion happening somewhere. I don't know where. The code looks right as far as I can tell. Is it possibly be because I don't have enough memory or something?
By the way, I am doing this because I am making a graphing program using HTML5 canvas just for fun and practice.
//domain is the closed interval you want the function to be calculated on [a,b]
//numSteps is the accuracy of your graph
function sinGraph(domain, numSteps) {
//prepare x and y value arrays
var yVal = [];
var xVal = [];
//check if the function parameters are acceptable
if (domain[0] == domain[1] || numSteps <= 0) {
alert("Invalid inputs. Domain must be in format [a, b] where a does not equal b. Number of steps must be greater than zero.");
} else {
//define interval length
var intLength = Math.abs(domain[1] - domain[0]);
//find the number of steps
var stepSize = intLength / numSteps;
//calculate y values based on x values
//push x and y values into arrays based on numSteps
for (var i = domain[0]; i<=domain[1]; i+stepSize) {
var xTemp = i;
var yTemp = Math.sin(i);
xVal.push(xTemp);
yVal.push(yTemp);
}
//return x and y value arrays
return {
xVal: xVal,
yVal: yVal
};
}
}
//test
var graph = sinGraph([0, Math.PI], 20);
alert(graph.yVal);
Just a minor typo in the incremental portion of the for loop:
//calculate y values based on x values
//push x and y values into arrays based on numSteps
for (var i = domain[0]; i<=domain[1]; i += stepSize) {
var xTemp = i;
var yTemp = Math.sin(i);
xVal.push(xTemp);
yVal.push(yTemp);
}

Knapsack variant in JavaScript

I have tried to implement this knapsack problem solution algorithm in JavaScript, but the solutions s_opt I get has a total weight greater than the L_max.
What am I doing wrong?
I suspect it could be something related to Closures in recursion.
/*
GENERAL:
Assume we have a knapsack and we want to bring as much stuff as possible.
Of each thing we have several variants to choose from. Each of these variants have
different value and takes different amount of space.
DEFINITIONS:
L_max = integer, size of the knapsack for the entire problem having N items
l = matrix, having the elements l[i-1][j-1] representing the space taken
by variant j of item i (-1 since indexing the matrices has index starting on zero, i.e. item i is stored at position i-1)
p = matrix, having the elements p[i-1][j-1] representing the value given by
by variant j of item i
n = total number of items (used in a sub-problem)
N = total number of items (used in the full problem, N >= n)
s_opt = vector having the optimal combination of variant selections s_i, i.e. s_opt = arg max p_sum
*/
function knapsack(L_max,l,p) {
// constructing (initializing) - they are private members
var self = this; // in order for private functions to be able read variables
this.N = l.length;
var DCached = []; // this is only used by a private function so it doesnt need to made public using this.*
this.s_opt = [];
this.p_mean = null;
this.L_max = L_max;
// define public optimization function for the entire problem
// when this is completed the user can read
// s_opt to get the solution and
// p_mean to know the quality of the solution
this.optimize = function() {
self.p_mean = D(self.N,self.L_max) / Math.max(1,self.N);
}
// define private sub-problem optimization function
var D = function(n,r) {
if (r<0)
return -Infinity;
if (n==0)
return 0;
if(DCached[n-1] != null) {
if(DCached[n-1][r-1] != null) {
return DCached[n-1][r-1];
}
}
var p_max = -Infinity;
var p_sum;
var J = l[n-1].length;
for(var j = 0; j < J; j++) {
p_sum = p[n-1][j] + D( n-1 , r - l[n-1][j] );
if(p_sum>p_max) {
p_max = p_sum;
self.s_opt[n-1] = j;
}
}
DCached[n-1] = [];
DCached[n-1][r-1] = p_max;
return p_max;
}
}
The client using this knapsack solver does the following:
var knapsackSolution = new knapsack(5,l,p);
knapsackSolution.optimize();
// now the client can access knapsackSolution.s_opt containing the solution.
I found a solution. When solving a sub-problem D(n,r) the code in the question returned the optimized value, but it didn't really manage the array s_opt in a proper way. In the modified solution, pasted below, I fixed this. Instead of only returning the optimized value of the knapsack also an array of chosen variants (e.g. the arg of the max) are returned. The cache is also modified to manage these two parts of the solution (both max value and arg max value).
The code below also contains an additional feature addition. The user can now also pass a value maxComputingComplexity controlling the computational size of the problem in some kind of heuristic manner.
/*
GENERAL:
Assume we have a knapsack and we want to bring as much stuff as possible.
Of each thing we have several variants to choose from. Each of these variants have
different value and takes different amount of space.
The quantity of each variant is one.
DEFINITIONS:
L_max = integer, size of the knapsack, e.g. max number of letters, for the entire problem having N items
l = matrix, having the elements l[i-1][j-1] representing the space taken
by variant j of item i (-1 since indexing the matrices has index starting on zero, i.e. item i is stored at position i-1)
p = matrix, having the elements p[i-1][j-1] representing the value given by
by variant j of item i
maxComputingComplexity = value limiting the product L_max*self.N*M_max in order to make the optimization
complete in limited amount of time. It has a serious implication, since it may cut the list of alternatives
so that only the first alternatives are used in the computation, meaning that the input should be well
ordered
n = total number of items (used in a sub-problem)
N = total number of items (used in the full problem, N >= n)
M_i = number of variants of item i
s_i = which variant is chosen to pack of item i
s = vector of elements s_i representing a possible solution
r = maximum total space in the knapsack, i.e. sum(l[i][s_i]) <= r
p_sum = sum of the values of the selected variants, i.e. sum(p[i][s_i]
s_opt = vector having the optimal combination of variant selections s_i, i.e. s_opt = arg max p_sum
In order to solve this, let us see p_sum as a function
D(n,r) = p_sum (just seeing it as a function of the sub-problem n combined with the maximum total space r)
RESULT:
*/
function knapsack(L_max,l,p,maxComputingComplexity) {
// constructing (initializing) - they are private members
var self = this; // in order for private functions to be able read variables
this.N = l.length;
var DCached = []; // this is only used by a private function so it doesnt need to made public using this.*
//this.s_opt = [];
//this.p_mean = null;
this.L_max = L_max;
this.maxComputingComplexity = maxComputingComplexity;
//console.log("knapsack: Creating knapsack. N=" + N + ". L_max=" + L_max + ".");
// object to store the solution (both big problem and sub-problems)
function result(p_max,s_opt) {
this.p_max = p_max; //max value
this.s_opt = s_opt; //arg max value
}
// define public optimization function for the entire problem
// when this is completed the user can read
// s_opt to get the solution and
// p_mean to know the quality of the solution
// computing complexity O(L_max*self.N*M_max),
// think O=L_max*N*M_max => M_max=O/L_max/N => 3=x/140/20 => x=3*140*20 => x=8400
this.optimize = function() {
var M_max = Math.max(maxComputingComplexity / (L_max*self.N),2); //totally useless if not at least two
console.log("optimize: Setting M_max =" + M_max);
return D(self.N,self.L_max,M_max);
//self.p_mean = mainResult.D / Math.max(1,self.N);
// console.log...
}
// Define private sub-problem optimization function.
// The function reads to "global" variables, p and l
// and as arguments it takes
// n delimiting the which sub-set of items to be able to include (from p and l)
// r setting the max space that this sub-set of items may take
// Based on these arguments the function optimizes D
// and returns
// D the max value that can be obtained by combining the things
// s_opt the selection (array of length n) of things optimizing D
var D = function(n,r,M_max) {
// Start by checking whether the value is already cached...
if(DCached[n-1] != null) {
if(DCached[n-1][r-1] != null) {
//console.log("knapsack.D: n=" + n + " r=" + r + " returning from cache.");
return DCached[n-1][r-1];
}
}
var D_result = new result(-Infinity, []); // here we will manage the result
//D_result.s_opt[n-1] = 0; // just put something there to start with
if (r<0) {
//D_result.p_max = -Infinity;
return D_result;
}
if (n==0) {
D_result.p_max = 0;
return D_result;
}
var p_sum;
//self.s_opt[n] = 0; not needed
var J = Math.min(l[n-1].length,M_max);
var D_minusOneResult; //storing the result when optimizing all previous items given a max length
for(var j = 0; j < J; j++) {
D_minusOneResult = D( n-1 , r - l[n-1][j] , M_max)
p_sum = p[n-1][j] + D_minusOneResult.p_max;
if(p_sum > D_result.p_max) {
D_result.p_max = p_sum;
D_result.s_opt = D_minusOneResult.s_opt;
D_result.s_opt[n-1] = j;
}
}
DCached[n-1] = [];
DCached[n-1][r-1] = D_result;
//console.log("knapsack.D: n=" + n + " r=" + r + " p_max= "+ p_max);
return D_result;
}
}

Javascript - generating random pairs of numbers if pair doesn't already exist

Edit: If you read Matt Bryant's answer, you'll see that it should work but he uses indexOf() method and that method doesn't work with I.E 8 or later and I need it to work on I.E 8. I tried doing this as a work around to the indexOf() method but it's not working.
var tester = -1;
for (var test=0; test<xposition.length; test++) {
if (x == xposition[0]) {
tseter = x;
}
}
Any idea why it doesn't work?
Original question:
So I want to generate random pairs of numbers but only if the pairs of number didn't already be generated. Here is what I tried, hopefully if you read what I tried, you will understand what it is exactly which I need.
function randomPairs() {
var xposition = []; //array which holds all x coordinates
var yposition = []; //array which holds all y coordinates
for (var i=0; i<5; i++) { //do everything below 5 times (generate 5 pairs)
var x = getRandom(1,7); //generate new x point
var y = getRandom(2,7); //generate new y point
if ( jQuery.inArray(x, xposition) ) { //if newly generated x point is already in the xposition array (if it was already previously generated
var location = xposition.indexOf(x) //find the index of the existing x
if (y == yposition[location]) { //if the newly generated y points equals the same y point in the same location as x, except in the yposition array
while ( y == yposition[location]) {
y = getRandom(2, 7); //change y
}
}
}
}
xposition.push(x); //put x into the array
yposition.push(y); //put y into the array
}
So, any idea why it isn't working? Am I using the jQuery.inArray() and the .indexOf() method properly?
Oh, and getRandom is
function getRandom(min, max) {
return min + Math.floor(Math.random() * (max - min + 1));
}
basically, it generates a number between the min and max.
Also, when I tried to do
alert(xposition);
alert(yposition);
it is blank.
The issue is that you are adding x and y to the array outside of the loop. A fix for this (plus a removal of the unneeded jQuery) is:
function randomPairs() {
var xposition = []; //array which holds all x coordinates
var yposition = []; //array which holds all y coordinates
for (var i=0; i<5; i++) { //do everything below 5 times (generate 5 pairs)
var x = getRandom(1,7); //generate new x point
var y = getRandom(2,7); //generate new y point
var location = xposition.indexOf(x);
if (location > -1) { //if newly generated x point is already in the xposition array (if it was already previously generated
if (y == yposition[location]) { //if the newly generated y points equals the same y point in the same location as x, except in the yposition array
while ( y == yposition[location]) {
y = getRandom(2, 7); //change y
}
}
}
xposition.push(x); //put x into the array
yposition.push(y); //put y into the array
}
}
Note that you should probably return something from this function.
If you have to support old browsers, replace the line
var location = xposition.indexOf(x);
with
var location = jQuery.inArray(x, xposition);
One of the main issue with this approach is that you have to think of cases when there are multiple unique pairs with the same x or y value.
x = [1, 1, 1], y = [1, 2, 3]
Note that Array.indexOf only returns the first index when the given element can be found in the array. So you would have to recursively run it beginning from the index you found the match from.
A simple approach of generating a unique pair of integers can be done without jquery:
http://jsfiddle.net/WaFqv/
I'm assuming the order does matter, so the x = 4, y = 3 & x = 3, y = 4 would be considered as two unique pairs.

Check an array of x y grid co-ordinates for duplicates and remove

I have a grid based game 8 squares by 8 squares giving 64 pieces in total, these pieces are stored in an array. I'm having a problem where certain grid squares are being populated twice so I need to check the array for duplicate co-ordinates.
Below code gives the x, y grid co-ordinates of each piece - testX and testY, I'm not sure how I would go about running through this array to remove duplicates. If there are duplicates pieces I need to keep the first encountered and remove any subsequent duplicates. I'm using jQuery if that helps.
function checkGrid() {
var x;
for (x = 0; x < grid.length; x++) {
var testY= grid[x].getY();
var testX = grid[x].getX();
}
}
You could consider using an object instead of an array:
var grid = {};
function setGridValue(x,y, value){
var key = x + '-' + y;
grid[key] = value;
}
function getGridValue(x,y){
var key = x + '-' + y;
return grid[key];
}
Something like this. Then if you change the value of a grid location, you don't need to check for duplicates.
EDIT.
Since you can't change to object, you should find an existing item when you insert them. You didn't post the code where you add items to the grid, but can you do something like this:
function setItem(x, y, value){
var item;
// check for existing item in array
for(var i = 0; i < grid.length; i++){
if(grid[i].getX() === x && grid[i].getY() === y){
item = grid[i];
break;
}
}
// if no existing item, create new one
if(!item){
item = new GridItem(x,y,value); // dont know what is in the grid...
grid.push(item);
} else {
// update existing item here...
}
}

How could I generate random locations with distances between each other in javascript?

I want to design a function that can generate a 'map' of sorts.
For example:
Location A is created, it is located at some position X
Location B is created, it is located at some position Y, we know the distance between X, Y
Location C is created, we know the distance from C to B, how do we calculate C to A?
Using a triangle method, I suppose I could also assign a random angle and calculate the third side, but what would I do if I added a Location D, E, F randomly? Would I be calculating multiple triangles that get exponentially worse with every addition?
Say you want to generate a list of locations L[1..n], you just randomly pick next location and scan over the L to guarantee the distance is over a threshold, otherwise, pick again.
Then, push this into your list L. So the total run time of generating a n elements list is O(n^2). When n < 1000, this is fast enough. The following method is guaranteed to terminate, which is designed for a relatively small read-to-pick list, say up to 1,000,000.
function generateList(orgList, numberToOutput) {
if (orgList.length < numberToOutput)
return false;
var orgListClone = orgList.slice(0);
var L = [];
while (L.length < numberToOutput && orgListClone.length > 0) {
var n = parseInt(Math.random() * orgListClone.length);
// Assume we pick n-th element in the list.
var ok = true;
for (var j = 0; j < L.length; j++)
if (distance(orgListClone[n], L[j]) < kThreshold) {
// n is not an option, swap orgListClone[n] with the last element and pop it out.
orgListClone[n] = orgListClone[orgListClone.length - 1];
orgListClone.pop();
ok = false;
break;
}
if (ok) {
// All tests passed
L.push(orgListClone[n]);
orgListClone[n] = orgListClone[orgListClone.length - 1];
orgListClone.pop();
}
}
if (L.length == numberToOutput)
return L;
// Failed to find the list
return null;
}
Another solution is to calcuate distances between each of the locations ahead, and make a list of too close locations for each location.
So that after each pick, just merge the too close locations to the current set, which takes O(n). And then pick another location which is not included in this set. This method only works when the read-to-pick list is large enough, so that the probability (1 - |too close list| / |read-to-pick list|) of choosing a location not included in the set is large. This will take up to O(nm) in total, where m is the average |too close list|.
function generateList(orgList, numberToOutput) {
if (orgList.length < numberToOutput)
return false;
var tooCloseSet = {};
var L = [];
var lastLengthOfL = 0;
var repickCount = 0;
for (L.length < numberToOutput) {
if (l.length == lastLengthOfL) {
if (++repickCount > 10)
return false;
} else {
lastLengthOfL = l.length;
repickCount = 0;
}
var n = parseInt(Math.random() * orgList.length);
if (n in tooCloseSet)
continue;
L.push(orgList[n]);
mergeSet(tooCloseSet, orgList[n].tooCloseList);
}
return L;
}
You could try something like this, I haven't tested it, so it's just conceptual at this point.
You could just generate an array of randomly placed points, and each point could hold it's own array of distances, calculated using basic trigonometry.
function Point(x, y) {
return {
x: x,
y:y,
addRelative: function(pt) {
this.realtivePoints[pt] = abs(sqrt(pow((this.x-pt.x),2) + pow((this.y-pt.y),2)));
},
relativePoints: {}
};
var randPoints = []; // Lets assume this has a collection of random Point objects
for(var i=0; i<randPoints.length; i++) {
for(var j=0; j<randPoints.length; j++) {
randPoint[i].addRelative(randPoints[j]);
}
}
randPoints[0].relativePoints[randPoints[1]]; // Dist from first to second point.
Yes, it gets geometrically more complicated with each point you add.
The problem is that even if you know the lengths of all three sides of a triangle, you still don't know the orientation. To illustrate your example:
You're defining ABC by specifying distances dAB and dBC (which gives you dAC). But you actually have two possible triangles, ABC and ABC'. Which means if you add a fourth point, D, by specifying it's distance to one of the points on ABC (e.g. dCD), you've added a 2nd triangle, which can also have one of two orientations, making for a total of four possible solutions. As you can see, orientation doesn't matter for determining distance between two points on the same triangle, but for determining distances between points on different triangles, it does.

Categories