Javascript requiring a dummy call to "this" to work - javascript

I have a mighty strange JavaScript problem. I have made an object oriented maze generator, which works well, but only if I call "this" (or the alias "self") right before the generator.
See code below:
// Constructor for a maze
function Maze(mazeWidth, mazeHeight) {
// Always working reference to this
var self = this;
// Has the maze been generated?
var generated = false;
// Default dimensions
var width = 20;
var height = 20;
// Check if dimensions are given
if (!isNaN(mazeWidth) && mazeWidth >= 1) {
width = parseInt(mazeWidth);
}
if (!isNaN(mazeHeight) && mazeHeight >= 1) {
height = parseInt(mazeHeight);
}
// The maze itself
var maze = {};
// Populate the maze
for (var y = 0; y < height; y++) {
maze[y] = {};
for (var x = 0; x < width; x++) {
maze[y][x] = new MazeCell(x, y);
}
}
// Function to get a cell
this.getCell = function(x, y) {
return maze[y][x];
}
// For some mighty strange reason "self" (or "this") needs to be called here for the code below to work
self;
// Generate the maze
(function generateMaze() {
// Map directions to its reverse
var directionMap = {};
directionMap[Maze.prototype.N] = Maze.prototype.S;
directionMap[Maze.prototype.E] = Maze.prototype.W;
directionMap[Maze.prototype.S] = Maze.prototype.N;
directionMap[Maze.prototype.W] = Maze.prototype.E;
// Depth-first search to generate the maze
(function DFS(cell, entryDirection) {
// Set the cell as discovered and open the entry direction
cell._setDiscovered();
cell._open(entryDirection);
// Find the neighbour cells
var neighbours = {};
neighbours[Maze.prototype.N] = cell.getNeighbourCell(Maze.prototype.N);
neighbours[Maze.prototype.E] = cell.getNeighbourCell(Maze.prototype.E);
neighbours[Maze.prototype.S] = cell.getNeighbourCell(Maze.prototype.S);
neighbours[Maze.prototype.W] = cell.getNeighbourCell(Maze.prototype.W);
// Check the neighbour cells in random order
for (var i = 0; i < 4; i++) {
var direction = (function() {
var result;
var count = 0;
for (var direction in neighbours) {
if (Math.random() < 1/++count)
result = direction;
}
return result;
})();
var nextCell = neighbours[direction];
delete neighbours[direction];
if (nextCell == false)
continue;
if (nextCell._isDiscovered())
continue;
// Set exit opening of this cell
cell._open(direction);
// Process next cell
DFS(nextCell, directionMap[direction]);
}
})(self.getCell(Math.floor(Math.random()*width), Math.floor(Math.random()*height)), null); // This line is the problem
})();
// ......
If I don't call "self" above the generation code, this.getCell will be called, but the first parameter will be a reference to the generateMaze-function itself. The second parameter will be unset.
It also work if I change the dummy line from "self" to "this".
Just writing "self" (or "this") on an otherwise empty line doesn't really do anything, does it? Why is it needed?

You should add semicolons after assigning a value to an attribute or variable, even if the value is a function, like here:
// Function to get a cell
this.getCell = function(x, y) {
return maze[y][x];
}
It should look like this:
// Function to get a cell
this.getCell = function(x, y) {
return maze[y][x];
};
I think that might be the cause of your problem.

Related

faild to move the element in between?

i have been try to solve the sudoku with Blacktracking algo, everything is good, canvar is called and i able to see the number but the things is number are not moving i.e the logic is not exectuing
current.i === 0; is where i'm get the error! even i have declared a sperate variable for the num also the problem is not sloved. only if i remove the .num current == 0 than its not showing any error but still the number is not moving
enter image description here
var cell = [];
var stack = [];
var sudoku = [2,3,0,9,4,0,6,7,0,
8,0,0,3,2,5,9,1,4,
9,0,0,7,6,0,3,2,0,
1,0,0,0,0,0,7,9,2,
5,0,3,2,1,0,4,8,6,
4,0,0,6,8,0,5,3,1,
7,0,0,1,0,0,0,0,9,
6,5,9,8,7,2,1,4,3,
3,0,0,0,9,0,0,0,7];
var current;
var number = 1;
function setup(){
createCanvas(450,450);
var a=0;
var b=0;
for(var i=0;i<81;i++){
if(a%9==0 && i!=0){
b = b+50;
a = 0;
}
each[i] = new each(a,b,i,sudoku[i]);
a = a+50;
}
current = cell[0];
}
function draw(){
background(10);
for(var i=0;i<81;i++){
each[i].show();
}
if(current.num === 0){ //the error is typeerror can't read the property of num
if(! sameColumn(current.i,number) && ! sameRow(current.i,number) && ! sameSquare(current.i,number) && number<(10)){
current.num = number;
stack.push(current);
number = 0;
current.each[current.i+1];
}
else {
if(number > 8){
current.num = 0;
current = stack.pop();
number = current.num;
current.num = 0;
}
}
}
else{
current = each[current+1];
number = 0;
}
number++;
}
function each(a,b,i,num){
this.a = a;
this.b = b;
this.i = i;
this.num = num;
this.show = function(){
noFill();
stroke(255);
rect(this.a,this.b,50,50);
textSize(32);
text(this.num,a+12,b+40);
}
}
The error is pretty much straight forward. current = cell[0]; becomes undefined since you defined cell as an empty array and didn't manipulated it after that.
From what I have observed so far, many parts of your code logically does not work, for example,
same Column(current.i,number) && ! sameRow(current.i,number) && ! sameSquare(current.i,number)
will definitely throw you an error is it is executed (it is not since the execution does not reach to that line), unless you have a separate js file that contains these functions.
Another one is
current = cell[current+1];
if the current variable is to store the cell object, it does not make sense to add 1 to it, and vice versa.
Now I believe this is how setup function was meant to look like:
function setup(){
createCanvas(450,450);
var a=0;
var b=0;
for(var i=0;i<81;i++){
if(a%9==0 && i!=0){
b = b+50;
a = 0;
}
cell[i] = new Cell(a,b,i,sudoku[i]); //changed each[i] to cell[i], also renamed the 'each' class
a = a+50;
}
current = cell[0];
}
If possible, please edit in a little more information about what exactly does your code do. Cheers :)

Passing arguments down to nested functions Google Maps v3

Sorry for the newb question here, but Im new to javascript. Ideally I would like to call for myLoop(latLong); but unless I make the variables outside of the function, I can't seem to have .setPosition() recognize the variable.
var x = 0;
var y = 0;
var z = 0;
var v = 0;
function xy(a,b,c,d) {
var longDistance = Math.abs(a-d);
var longTime = longDistance/0.1*0.5;
var latDistance = b-c;
var latRate = latDistance/longTime*0.5;
x = a; //origin long
y = b; //oringin lat
z = latRate;
w = d; //destination long
v = c; //destination lat
}
function myLoop () {
setTimeout(function () {
var latLong = new google.maps.LatLng(y,x);
marker.setPosition(latLong);
x = x + 0.1;
y = y - z;
if (x < w && y < v) {
myLoop();
} else {
alert('finished');
}
}, 0.5)
}
xy(-118,33,40,-73);
myLoop();
You simply need to pass the latLong variable into the myLoop() function recursively.
To do this, you can create your first latLong variable outside of the function, then call the function (passing in the first latLong variable), then within the latLong function, check for your conditions, and if you need to call the myLoop function again, update the latLong variable and then call the myLoop function again.
Here is what your recursive code would look like:
var x = 0;
var y = 0;
var z = 0;
var v = 0;
// Your first latLong
var latLong = new google.maps.LatLng(y,x);
function xy(a,b,c,d) {
// ...
}
// Pass in the latLong variable
function myLoop (latLong) {
setTimeout(function () {
marker.setPosition(latLong);
x = x + 0.1;
y = y - z;
if (x < w && y < v) {
// now create a new latLong, and pass it
// back into this function recursively
latLong = new google.maps.LatLng(y,x);
myLoop(latLong);
} else {
alert('finished');
}
}, 0.5)
}
xy(-118,33,40,-73);
// Now call the myLoop function to get the recursion started
myLoop(latLong);
Alternatively, you can wrap all the code up into one function
Using the revealing module pattern, you can wrap up all your loop functionality in one place (within a function object called latLongGenerator), allowing for a nice separation in your code logic, but still giving you a clean interface to use. The restructured "revealing module" code would look like this:
var latLongGenerator = (function () {
var x = 0;
var y = 0;
var z = 0;
var v = 0;
var latLong;
function setXY(a,b,c,d) {
var longDistance = Math.abs(a-d);
var longTime = longDistance/0.1*0.5;
var latDistance = b-c;
var latRate = latDistance/longTime*0.5;
x = a; //origin long
y = b; //oringin lat
z = latRate;
w = d; //destination long
v = c; //destination lat
// pass in the initial latLong to myLoop(latLong) from here
latLong = new google.maps.LatLng(y,x);
myLoop(latLong);
}
// This is the only function that will
// be exposed publicly on this function
// Example usage: latLongGenerator.startLoopWith(0,0,0,0);
function startLoopWith(a,b,c,d){
setXY(a,b,c,d);
}
function myLoop (latLong) {
setTimeout(function () {
marker.setPosition(latLong);
x = x + 0.1;
y = y - z;
if (x < w && y < v) {
// recursively call the loop from here
latLong = new google.maps.LatLng(y,x);
myLoop(latLong);
} else {
alert('finished');
}
}, 0.5);
}
return {
startLoopWith:startLoopWith
};
})();
// Finally, you can start your loop by passing in
// your initial values to latLongGenerator.startLoopWith(...)
latLongGenerator.startLoopWith(-118,33,40,-73);
This structure gives you a clean way of encapsulating all your calculation logic, while also giving you a nice, clean entry point. Using this new refactor, you can get your loop started with one line:
latLongGenerator.startLoopWith(-118,33,40,-73);
I haven't tested this code, but it should help you get on the right track.
Hope this helps!

Value not getting added to array?

Simple question which seems impossible for me because I'm just staring in the code.
Basicly I have this function, I call it X amount of times and it should put all the created divs in a array called world which I've declared outside of the function.
However, if I try to use one of these values they are "undefined".
var world = [];
function newTile(x, y, size, rotX, rotY, rotZ, tranX, tranY, tranZ, color) {
var tile = document.createElement('div');
tile.className = "tile";
tile.style.width = size+"px";
tile.style.height = size+"px";
tile.style.webkitTransform =
"rotateX("+rotX+"deg)"+
"rotateY("+rotY+"deg)"+
"rotateZ("+rotZ+"deg)"+
"translateX("+tranX+"px)"+
"translateY("+tranY+"px)"+
"translateZ("+tranZ+"px)";
tile.style.transform =
"rotateX("+rotX+"deg)"+
"rotateY("+rotY+"deg)"+
"rotateZ("+rotZ+"deg)"+
"translateX("+tranX+"px)"+
"translateY("+tranY+"px)"+
"translateZ("+tranZ+"px)";
if (x == 0 && y == 0) {
color="rgba(255,255,0,0.5)";
pathStart = tile;
pathCur = tile;
}
tile.style.backgroundColor = color;
tile.data = {
x:x,
y:y,
blacklist:0
}
tile.onclick = function() {
worldOri(null,null,null, -this.data.x*128 - 64, null, -this.data.y*128 - 64);
};
if (debug) tile.textContent = x+", "+y;
document.getElementById('world').appendChild(tile);
world[x] = [];
world[x][y] = tile;
}
Lets say I do something like:
newTile(2,6,128,90,0,0,2*128,0,6*128, "rgba(255,125,0,0.5)");
This works as intended and surely creates a div, placing it "in" another div with the id "world" and SHOULD add the div to the array "world" at [2][6]. If I now try to do something with the div, for example change color:
world[2][6].style.backgroundColor = "rgba(255,0,0,0.5)";
It returns as undefined, which I assume is that the actual adding to the "world" array didn't work, please help.
world[x] = []; will assign an empty array world[x] every time you make a call to newTile, thus "removing" all existing tiles from world[x]. Only initialize it if it doesn't exist yet:
world[x] = world[x] || [];

Uncaught TypeError while generating a random position for the food in a HTML5 snake game

I am currently working on making a multiplayer Snake game in HTML5 Canvas with Javascript.
The code below is function that handles the random placement of food for the snake. The problem with the piece of code is that it give me the x and y in while(map[x][y]); back as something he can not read even though it does generate a random number.
This is the exact error:
"Uncaught TypeError: Cannot read property '20' of undefined"
The '20' is the random generated number (and will be the grid position of the food in a two dimensional array) and changes every time I restart the program or refresh the webpage. Can someone explain what I need the change in order to define x and y and place my food?
function rand_food(){
var x, y;
do {
x = MR() * this.rect_w|0;
y = MR() * this.rect_h|0;
}
while (map[x][y]); <-- Here is the error
map[x][y] = 1;
this.ctx.strokeRect(x * 10+1, y * 10+1, 8, 8);
}
Here is another code snippet which defines the map.
this.map = [];
// Map positions
//*
for (i = 0; i < this.rect_w; i++){
map[i] = [];
}//*/
After trying Sean's suggestion my code now looks like this: But it still gives me same error. Any other suggestion?
function SnakeGame(){
this.map = [];
for (i = 0; i < this.rect_w; i++){
this.map[i] = [];
}
function rand_food(){
var x, y;
console.log("Map length: " + this.map.length);
do {
x = MR() * this.rect_w|0;
y = MR() * this.rect_h|0;
console.log("x: " + x);
console.log("y: " + y);
}
while (this.map[x][y]);
this.map[x][y] = 1;
this.ctx.strokeRect(x * 10+1, y * 10+1, 8, 8);
}
this.map and map are not the same thing.
If you are inside an object then this.map is a public variable of the object, and map is a local variable.
Try something like this:
this.map = [];
// Map positions
for (var i = 0; i < 10; i++){
this.map[i] = [];
}
and in the rand_food function also use this.map.
Here are two possible ways you can go:
//using public variable
function SnakeGame() {
this.map = [];
// Map positions
for (var i = 0; i < 10; i++){
this.map[i] = [];
}
function rand_food() {
// refer to this.map here
this.map[0];
}
};
// using local variable
function SnakeGame() {
var map = [];
// Map positions
for (var i = 0; i < 10; i++){
map[i] = [];
}
function rand_food() {
// refer to map here
map[0];
}
};
If map was not defined you would normally get a ReferenceError, so map is defined but probably:
not assigned to anything
defined/assigned after beeing used
hoisted by beeing defined in a condition that do not execute
example
if (0) {
var foo = 1;
}
console.log(foo) //= undefined
console.log(foo[20]) // TypeError…
console.log(bar) // ReferenceError…

js build object path in property assignment

is there a way to automatically create subobjects in an assignment after construction, i.e.
var obj = {};
obj.a.b.c=13;
the above gives me a "obj.a is undefined" error
i wrote a function to do this, but wondered if there was an easier way
_setObjectProperty(obj,13,['a','b','c']);
function _setObjectProperty(obj,value,loc)
{
if(loc.length>1) {
obj[loc[0]] = obj[loc[0]] || {};
_setObjectProperty(obj[loc[0]],value,loc.splice(1));
}
else if(loc.length===1) {
obj[loc[0]]=value;
}
}
No, there's no built in way to do this in JavaScript. The only way is to create your own function like you did. If you want the convenience of the dot operator/notation you can use the following function:
var set = function(path, value, root) {
var segments = path.split('.'),
cursor = root || window,
segment,
i;
for (i = 0; i < segments.length - 1; ++i) {
segment = segments[i];
cursor = cursor[segment] = cursor[segment] || {};
}
return cursor[segments[i]] = value;
};
set("a.b.c", 2);
console.log(a.b.c) // => 2

Categories