Why does X equal to max length on each iteration? - javascript

I've been trying to generate a two dimensional array of objects. Each object contains it's own internal position in the array in two variables called X and Y. When I instantiate the object, I can see through console logging that it's being instantiated with the proper X and Y values, this can also be validated through the fact that position in the array corresponds perfectly to those values.
However, when I log the final array after iterating through and saving each position in the array two an instance of the object, they have identical X coordinates, yet the Y coordinates are perfect.
let coordinates = Array(30).fill(Array(40)) // just creates an empty two dimensional array.
class Tile {
constructor(x,y){
this.x = x;
this.y = y;
}
}
for (let x = 0; x < coordinates.length; x++) {
for (let y = 0; y < coordinates[x].length; y++) {
console.log({x,y}) // logs {x: 0, y: 0} -> {x: 29, y:39}
coordinates[x][y] = new Tile(x,y)
}
}
console.log(coordinates) // logs two dimensional array with {x: 29, y:0} -> {x: 29, y:39}
I'm going mentally crazy trying to figure out why it does that. I've tried researching bindings, scope, objects instead of classes and I cannot find a way around it. I believe figuring this out will result in solving several of my problems, as I've run into other properties on the actual Tile class being randomly set despite not touching it at all. I am referring to creating a maze using deep traveling and recursion, and having each tile contain a property called "Visited" and setting it to true once it's been traversed once.
When doing that, I run into that my maze suddenly stops as it decides that every tile around it has been "visited" as they are all equal to true, yet I've never touched them.
Anything that you guys would have that would explain what I am running into would be helpful, it's no doubt something really simple and stupid.
Thank you in advance.

for (let y = 0; x < coordinates[x].length; y++) is your problem.
Your loop definitely cannot work if you are comparing to X for your Y loops, it won't ever get out.

Related

How to store and access objects with x,y coordinates by x,y value?

I want to store tiles (50x50 pixel rectangles, and later display them on canvas), but have no idea what data structure should I use.
I need to access it by x,y value, and also need to move them by changing the x,y value.
a single object would look like this:
tile = { x:1, y:2, color:1 }
I need hundreds of them.
I've considered simple array, however tiles[id].x is the only way to access them, so I need to know the ID first, before i can access them x.
2D array, seems better, since I can make tiles[y][x], but the values of the x,y coordinates where tiles are displayed are not necessarily the same numbers if the coordinates changed. aka: tile[1][2].x = 1.5 so, accessing the tile at x = 1.5 become tricky.
Objects in objects essentially the same problem as an array, since it requires to have a key so: tiles = { tile1:{x:1,y:2,color:1}, tile2:{x:3,y:4,color:2} } still have no way to access tiles at x1,y2 without knowing its under tile1 key.
I know I can use any of the above and loop trough them until I find the key, but is it really the only solution?
I've been reading tutorials today about javascript classes, and seems like its somewhat what I need, but haven't found a relevant example.
What would be the best way to store and access a tile's objects by x,y coordinate?
If you want O(1) (aka "very fast") lookup time the only option is to use a hashtable with a composed key of x andy:
const map = new Map;
for(const tile of tiles)
map.set(tile.x + "|" + tile.y, tile);
To get the tile at, e.g. x = 5, y = 6 you just do:
map.get(5 + "|" + 6)
When moving a tile however you also have to move it in the hashtable:
function moveTile(tile, toX, toY) {
map.delete(tile.x + "|" + tile.y);
tile.x = toX; tile.y = toY;
map.set(tile.x + "|" + tile.y, tile);
}
put all of your tiles in an array, and then use array.filter to get the tile(s) you want. Something like:
var tilesFilter = function(x,y) {
return this.x == 1 && this.y == 2;
}
var tiles = [...];
var myTile = tiles.filter(tilesFilter)[0];

Find adjacent tiles in a two-dimensional grid

I have a two-dimensional grid, in which all tiles are defined by two coordinates x and y. I'm storing the tiles in an array like this var tiles = [];. Each tile is an object with an x and y property:
Tile = {
x: ...,
y: ...
}
For drawing purposes (canvas) I want to find out which tiles are adjacent to each other. I could do that by looping through each element and check if it is adjacent. Since that would take n^n number of accesses I don't think this is the right way to do it. I think there would be a more efficient algorithm.
I also thought that maybe storing the data in a different way would help, but again, I wouldn't know how.
You have 2 ways to create a grid :
Using a 2 dimensional Array which must be the easier thing for a grid
Store adjacent Tile of a Tile in it with something like that :
var tile0 = {
x:0, y:1
}
var tile1 = {
x:1,y:1, tileLeft : tile0
}
It can be useful if you want to create Pentagonal or Hexagonal... grid, ofcourse create your grid automatically with a for loop.
EDIT
A two dimensional array is simply an Array of Array
var arr = new Array()
for(var i = 0 ; i < 10 ; i++){
arr[i] = new Array()
}
Now you can set value like in a grid, for example :
arr[0][2] = {x:2,y:2} //It's a bit useless since indexes can be use for x and y
In that case, i have 10 Array stored in one Array so :
arr[10][0]
Will return following error : Uncaught TypeError: Cannot set property '2' of undefined, because index of arr are only define between 0 and 9.
With your data construct I can't see a way to check for all adjacent tiles without accessing each tile.
The "tried and true" two dimensional grid data construct would be...a simple two dimensional array. Then you can access tiles directly by their coordinates.

How do I get the screen coordinates of origin after a bunch of transforms P5.js

I'm trying to track the position of an object so I can draw a trail behind it in p5.js.
I'm moving the object around the screen with the translate() and rotate() functions, and in order to draw a trail I was going to store the object's position after each update in an array. I'm aware there was something like what I'm asking for in processing 3, the model X, Y and Z functions, but as far as I can tell these haven't been implemented in the javascript version yet.
Even accessing the canvas's current transform matrix is proving problematic, and at this point I'm considering a redesign to omit the transform part of the api until this functionality is added.
So my question basically is: is there any way to determine the screen(canvas) coordinates of (0, 0) after applying a bunch of transforms?
I have a solution for this problem here:
https://github.com/ChristerNilsson/Transformer
The drawingContext actually tracks this, you can query it and map back to p5 coordinates. If you're not needing this in an inner loop it will likely be cheaper than tracking everything in a extra stack paralleling what the Canvas engine is doing anyway. And this is defined by the spec, so you can rely on it.
https://html.spec.whatwg.org/multipage/canvas.html#transformations (see the end of this chapter where the transformation semantics are defined).
2D version:
// a c e
// b d f
// 0 0 1
// x_new = a x + c y + e
// y_new = b x + d y + f
// origin - current point - is then at:
// x = a.0 + c.0 + e = e
// y = b.0 + c.0 + f = f
// However, the context has media coordinates, not p5. taking
// the distance between points lets use determine the
// scale assuming x and y scaling is the same.
let matrix = drawingContext.getTransform();
let x_0 = matrix['e'];
let y_0 = matrix['f'];
let x_1 = matrix['a'] + matrix['e'];
let y_1 = matrix['b'] + matrix['f'];
let media_per_unit = dist(x_0, y_0, x_1, y_1);
let p5_current_x = x_0 / media_per_unit;
let p5_current_y = y_0 / media_per_unit;
You should make all the transformations inside push() and pop() and store the location inside that itself so the location gets pushed into the array every frame.
And no, you can not get the canvas coordinates of (0,0) after a bunch of transforms because translate shifts the origin(0,0) of the canvas to a new point and then that point becomes the new origin.
To draw a trail, you can store the history of the object's location vector in an array. You can implement it in the update function of your animated object class. To do this, you can store P5Vector(this.pos.x, this.pos.y) and push it into an array everytime the function is called in the draw loop, then you can draw a circle or line whatever you want for the trail looping through this array.
Suppose history is an array with last 100 positions(vector objects) of the animated object, in the draw loop you can :
for(var i=0; i<obj.history.length; i++)
{
var loc = obj.history[i];
ellipse(loc.x, loc.y, 15, 15);
}

Are there specific conventions for adding attributes to Javascript objects?

So I have an array (of length 1 for the moment) in Javascript. It contains an Image object for the moment. Basically, I made an animation that works perfectly with this code :
ants[0]._x = 5;
ants[0]._y = 5;
and then, in my updating function :
function animate() {
context.drawImage(ants[0], 0, 0, 158, 160, ants[0]._x, ants[0]._y, 158, 160);
ants[0]._x += 5;
ants[0]._y += 5;
}
The problem is, when I change _x and _y to x and y (like so :
ants[0].x = 5;
ants[0].y = 5;
and everywhere else in the code)
The animation won't work. Moreover, x and y equal to 0 even if I initialized them to 5.
So my question is, is it because my images are Images objects and to add new attributes to a built-in object, you have to add underscores ?
An Image object already has it's own readonly x and y properties. These correspond to the image width and height. Edit: actually corresponds to the position on the page If you're trying to set arbitrary values in your image, you need to create new variables. Previously you were doing this with the underscore character (_x), but you can do it with other characters too
For example:
ants[0].myProperty = 'stackoverflow';
console.log(ants[0].myProperty); // will print 'stackoverflow
You can view all the properties contained in an object with
var ants = new Image;
for (var p in ants) {
console.log(p);
}
MDN has more information on the Image element
There is nothing stopping you from assigning x and y under regular circumstances (ie: if you're using home-made objects, and not built-in language/browser objects).
When you start playing with reserved properties of protected objects, there are all kinds of weird things that can happen, from a browser letting you break the page completely until you refresh, or a browser letting you try for hours to change the definition of window.
It all comes down to how you assign them, how you use them after, whether you're swapping objects out of your array...
...and it's an Image object, so you need to make sure that the image is actually loaded before you can do much with it.
There's really nothing stopping you from doing things like:
var my_character = {
x : 0,
y : 0,
width : 32,
height : 64,
sprite_sheet : loadedImage,
current_frame : 6,
update : function () {
my_character.current_frame += 1;
my_character.x += 3;
my_character.y -= 2;
}
};
context.drawImage(
my_character.sprite_sheet,
x - my_character.width/2,
y - my_character.height/2,
my_character.width,
my_character.height,
my_character.width * current_frame,
0,
my_character.width,
my_character.height
);
That's not a particularly elegant way of doing it, but seriously, if you wanted to then add a my_character.$ = "35.99";, you could.
It's something more than "x" and "y".
If you wanted to use something like my_character.° = 32.5; I believe you'd have to use my_character["°"] = 32.5;
Yes, there's a convention, called Custom Data Attributes. Attributes that begin with data- are reserved for the application, they're guaranteed never to affect the semantics of the elements in the browser.
ant[0].setAttribute("data-x", 5);
ant[0].setAttribute("data-y", 5);
See the official W3C documentation and this blog post by John Resig summarizing it.

Searching/Sorting Multidimensional Arrays

I've created a multi-dimensional array based on the x/y coords of the perimeter of a circle. An object can be dragged along the arc (in javascript) and then 'dropped' anywhere on it. The problem is, I need to find the closest x and y coordinate to where the object is 'dropped.'
My current solution involves looping through an array and finding the closest value to x, and then looping again to find the y coordinate, but it doesn't seem very clean and there are problems with it.
Does anyone have any suggestions?
Thanks!
So, let's see. We assume a predefined set of (x, y) coordinates. You are given another point and have to find the nearest element of the array to that given point. I am going to assume "nearest" means the smallest Pythagorean or Euclidean distance from the given point to each of the other points.
The simplest algorithm is probably the best (if you want to look at others in Wikipedia, have at it). Since you didn't give us any code for the structure, I'm going to assume an array of objects, each object having an x and a y property, ditto for the given point.
var findNearestPoint = function (p, points) {
var minDist = Number.POSITIVE_INFINITY,
minPoint = -1,
i,
l,
curDist,
sqr = function(x) { return x * x; };
for (i = 0, l = points.length; i < l; i++) {
curDist = sqr(p.x - points[i].x) + sqr(p.y - points[i].y);
if (curDist < minDist) {
minDist = curDist;
minPoint = i;
}
}
return points[i];
};
(Untested, but you get the idea.)
If your arrays are created in sequential order (that is from smallest to greatest or greatest to smallest), you could use introduce a Binary Search Algorithm.
Get middle element of x array.
If x equals your value, stop and look for y, otherwise.
If x is lower, search in the lower half of the array (starting from step 1).
If x is higher, search in the upper half of the array (starting from step 1).
Then use the same formula on y. You might have to change to algorithm a bit to make it so it works with the closest matching element. Having not seen your array, I can't offer code to solve to problem.

Categories