JS (p5.js) canvas multiplying bug and being drawn in weird resolution - javascript

I'm experiencing a bug in my code that doubles the display and ends up drawing it twice, besides itself in a weird resolution. After changing a global variable (total_sand) to a different integer, and changing it back, the display has actually tripled.
The intended result is for it to display just once in full resolution (in this case, 301x301 pixels). This bug didn't happen immediately and seemed to happen randomly upon changing the code one day.
total_sand = 100000;
sandpiles = [];
var next_sandpiles;
function setup() {
createCanvas(301, 301);
for (var x = 0; x < width; x++) {
sandpiles[x] = [];
for (var y = 0; y < height; y++) {
sandpiles[x][y] = 0;
}
}
next_sandpiles = sandpiles;
//STARTING CONDITIONS
if (width % 2 == 0) {
sandpiles[width/2][height/2] = total_sand;
} else {
sandpiles[(width-1)/2][(height-1)/2] = total_sand;
}
}
function topple() {
for (var x = 0; x < width; x++) {
for (var y = 0; y < height; y++) {
if (sandpiles[x][y] > 3) {
toppling = true;
next_sandpiles[x][y] = next_sandpiles[x][y] - 4;
if (x > 0) {
next_sandpiles[x-1][y]++;
}
if (x < width - 1) {
next_sandpiles[x+1][y]++;
}
if (y > 0) {
next_sandpiles[x][y-1]++;
}
if (y < height - 1) {
next_sandpiles[x][y+1]++;
}
}
}
}
sandpiles = next_sandpiles;
}
function update() {
loadPixels();
var r;
var g;
var b;
for (var x = 0; x < width; x++) {
for (var y = 0; y < height; y++) {
if (sandpiles[x][y] == int(0)) {
r = 255;
g = 255;
b = 0;
} else if(sandpiles[x][y] == 1) {
r = 0;
g = 185;
b = 63;
} else if(sandpiles[x][y] == 2) {
r = 0;
g = 104;
b = 255;
} else if(sandpiles[x][y] == 3) {
r = 122;
g = 0;
b = 229;
} else {
r = 255;
g = 0;
b = 0;
}
var index = (x + y * width)*4;
pixels[index] = r;
pixels[index+1] = g;
pixels[index+2] = b;
pixels[index+3] = 255; // alpha
}
}
updatePixels();
}
function draw() {
background(0);
topple();
update();
}

Related

Game of life bug

I'm coding Conways game of life in P5JS, but I got a wierd bug. It seems to "work" but it looks all wrong. I'm not sure if it has t do with finding the neighbors, because when I call the function manually, it works. I even copied a second neighbor-counting function of the internet in there, and it works, too.
Maybe it's a visual glitch, but I'm not sure of that either, because the code looks fine.
/// <reference path="../TSDef/p5.global-mode.d.ts" />
let gridSize = 10;
let arrCurrent = create2dArray(gridSize);
let arrNext = create2dArray(gridSize);
function setup() {
createCanvas(800, 800, WEBGL);
background(0);
stroke(0, 255, 0);
noFill();
initGame();
}
function draw() {
displayCells();
calcNextGen();
}
//Returns a 2D Array
function create2dArray(size) {
let newArray = new Array(size);
for (let i = 0; i < newArray.length; i++) {
newArray[i] = new Array(1);
}
return newArray;
}
//Fills initial array with random values
function initGame() {
for (let x = 0; x < arrCurrent.length; x++) {
for (let y = 0; y < arrCurrent.length; y++) {
arrCurrent[x][y] = Math.round((Math.random()));
}
}
}
//Calculates next generation
function calcNextGen() {
for (let x = 0; x < gridSize; x++) {
for (let y = 0; y < gridSize; y++) {
let neighbors = countNeighbors1(arrCurrent, x, y);
let state = arrCurrent[x][y];
//If cell is dead and has exactly 3 neighbors, it starts living
if (state === 0 && neighbors === 3) {
arrNext[x][y] = 1;
}
//If cell lives and has too few or too many neighbors, it dies
else if (state === 1 && (neighbors < 2 || neighbors > 3)) {
arrNext[x][y] = 0;
}
else {
arrNext[x][y] = state;
}
}
}
arrCurrent = arrNext.slice();
}
//Count neighbors
function countNeighbors(x, y) {
return arrCurrent[(x + 1) % gridSize][y] +
arrCurrent[x][(y + 1) % gridSize] +
arrCurrent[(x + gridSize - 1) % gridSize][y] +
arrCurrent[x][(y + gridSize - 1) % gridSize] +
arrCurrent[(x + 1) % gridSize][(y + 1) % gridSize] +
arrCurrent[(x + gridSize - 1) % gridSize][(y + 1) % gridSize] +
arrCurrent[(x + gridSize - 1) % gridSize][(y + gridSize - 1) % gridSize] +
arrCurrent[(x + 1) % gridSize][(y + gridSize - 1) % gridSize];
}
function countNeighbors1(grid, x, y) {
let sum = 0;
for (let i = -1; i < 2; i++) {
for (let j = -1; j < 2; j++) {
let col = (x + i + gridSize) % gridSize;
let row = (y + j + gridSize) % gridSize;
sum += grid[col][row];
}
}
sum -= grid[x][y];
return sum;
}
function displayCells() {
background(0);
translate(-300, -300, 0);
for (let x = 0; x < arrCurrent.length; x++) {
for (let y = 0; y < arrCurrent.length; y++) {
push();
translate(x * 50, y * 50, 0);
if (arrCurrent[x][y] === 1) box(50);
pop();
}
}
}
function logGrid() {
console.log(arrCurrent[0]);
console.log(arrCurrent[1]);
console.log(arrCurrent[2]);
console.log(arrCurrent[3]);
console.log(arrCurrent[4]);
console.log(arrCurrent[5]);
console.log(arrCurrent[6]);
console.log(arrCurrent[7]);
console.log(arrCurrent[8]);
console.log(arrCurrent[9]);
}
I know I'm very close, but I'm banging my head against this one since 2 hours.
Here's a little P5JS Web Editor, you can copy the code over and visually see the problem.
Any help is appreciated - thank you!
arrCurrent = arrNext.slice(); doesn't create a deep copy of the grid, it just creates a shallow copy of the first dimension.
It creates a grid, where columns of arrCurrent refers to the rows of arrNext.
You've to create a completely new grid:
arrCurrent = []
for (let x = 0; x < gridSize; x++)
arrCurrent.push(arrNext[x].slice());
let gridSize = 10;
let arrCurrent = create2dArray(gridSize);
let arrNext = create2dArray(gridSize);
function setup() {
createCanvas(800, 800, WEBGL);
background(0);
stroke(0, 255, 0);
noFill();
initGame();
frameRate(10)
}
function draw() {
displayCells();
calcNextGen();
}
//Returns a 2D Array
function create2dArray(size) {
let newArray = new Array(size);
for (let i = 0; i < newArray.length; i++) {
newArray[i] = new Array(1);
}
return newArray;
}
//Fills initial array with random values
function initGame() {
for (let x = 0; x < arrCurrent.length; x++) {
for (let y = 0; y < arrCurrent.length; y++) {
arrCurrent[x][y] = Math.round((Math.random()));
}
}
}
//Calculates next generation
// - A live cell dies if it has fewer than two live neighbors.
// - A live cell with two or three live neighbors lives on to the next generation.
// - A live cell with more than three live neighbors dies.
// - A dead cell will be brought back to live if it has exactly three live neighbors.
function calcNextGen() {
for (let x = 0; x < gridSize; x++) {
for (let y = 0; y < gridSize; y++) {
let neighbors = countNeighbors1(arrCurrent, x, y);
let state = arrCurrent[x][y];
//If cell is dead and has exactly 3 neighbors, it starts living
if (state === 0 && neighbors === 3) {
arrNext[x][y] = 1;
}
//If cell lives and has too few or too many neighbors, it dies
else if (state === 1 && (neighbors < 2 || neighbors > 3)) {
arrNext[x][y] = 0;
}
else {
arrNext[x][y] = state;
}
}
}
arrCurrent = []
for (let x = 0; x < gridSize; x++)
arrCurrent.push(arrNext[x].slice());
}
function countNeighbors1(grid, x, y) {
let sum = 0;
for (let i = -1; i < 2; i++) {
for (let j = -1; j < 2; j++) {
let col = (x + i + gridSize) % gridSize;
let row = (y + j + gridSize) % gridSize;
sum += grid[col][row];
}
}
sum -= grid[x][y];
return sum;
}
function displayCells() {
background(0);
translate(-75, -75, 0);
stroke(128);
box(50*gridSize, 50*gridSize, 50);
translate(-225, -225, 0);
stroke(0, 255, 0);
for (let x = 0; x < arrCurrent.length; x++) {
for (let y = 0; y < arrCurrent.length; y++) {
push();
translate(x * 50, y * 50, 0);
if (arrCurrent[x][y] === 1) box(50);
pop();
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.9.0/p5.js"></script>

Making a canvas using p5.js

enter image description hereI got an exercise , where i have to create a rectangle-canvas using p5.js , but that canvas will consist small rects ,so i do it , but there is also 1 point in the exrecise . How can i get those small rects in 2 different colors , but 50% of those colores must be green and the other red , using matrix .
Here is the code .
var matrix = [
];
var ab = 36;
for (var y = 0; y < ab; y++) {
matrix.push([])
for (var x = 0; x < 36; x++) {
matrix[y][x] = Math.floor(Math.random() * 2)
}
}
console.log(matrix)
var side = 16;
function setup() {
createCanvas(matrix[0].length * side, matrix.length * side);
background('#acacac');
frameRate()
}
function draw() {
for (var y = 0; y < matrix.length; y++) {
for (var x = 0; x < matrix[y].length; x++) {
if (matrix[y][x] == 0) {
fill(0, 255, 0)
rect(y * side, x * side, side, side)
}
else if (matrix[y][x] == 1) {
fill("red")
rect(y * side, x * side, side, side)
}
function Shuffle (arguments) {
for(var k = 0; k < arguments.length; k++){
var i = arguments[k].length;
if ( i == 0 ) return false;
else{
while ( --i ) {
var j = Math.floor( Math.random() * ( i + 1 ) );
var tempi = arguments[k][i];
var tempj = arguments[k][j];
arguments[k][i] = tempj;
arguments[k][j] = tempi;
}
return arguments;
}
}
}
so as discussed in comments , the problem reduces to filling exactly half the matrix with one color and other half with other.
your matrix is in two dimension i will give a solution in one dimension, which should be quite easy to extend to 2-d
var count = 0;
var arr = [];
for( var i = 0 ;i < ab;i++){
arr[i] = 0;
}
while(true) {
var i = floor(random(ab));
if(arr[i] !==1) {
arr[i] = 1;
count++;
}
if(count === ab/2) break; // assume ab is even
}
there is one more way
fill half the array with 1 and half with 0 and then shuffle the array
you can very easily google algorithms for shuffling,
one pseudocode i could find
// after filling half elements with 1 and half with zero
// To shuffle an array a of n elements (indices 0..n-1):
for i from n - 1 downto 1 do
j = random integer with 0 <= j <= i
exchange a[j] and a[i]
source: https://www.geeksforgeeks.org/shuffle-a-given-array/
There it is my problem
var matrix = [
];
var ab = 36;
for (var y = 0; y < ab; y++) {
matrix.push([])
for(var x = 0 ; x<ab;x++){
matrix[y][x] = Math.floor(Math.random()*1)
}
for(var x = 0 ; x<ab/2;x++){
matrix[y][x] = 1
}
}
var count = 0;
var arr = [];
for( var i = 0 ;i < ab;i++){
arr[i] = 0;
}
while(true) {
var i = Math.floor(Random(ab));
if(arr[i] !==1) {
arr[i] = 1;
count++;
}
if(count === ab/2) break; // assume ab is even
}
console.log(arr)
var side = 16;
function setup() {
createCanvas(arr[0].length * side, arr.length * side);
background('#acacac');
frameRate()
}
function draw() {
for (var y = 0; y < arr.length; y++) {
for (var x = 0; x < arr[y].length; x++) {
if (matrix[y][x] == 0) {
fill(0, 255, 0)
rect(y * side, x * side, side, side)
}
else if (matrix[y][x] == 1) {
fill("red")
rect(y * side, x * side, side, side)
}
else if (matrix[y][x] == 2) {
fill(255, 255, 0)
rect(y * side, x * side, side, side)
}
else if (matrix[y][x] == 3) {
fill(255, 0, 0)
rect(y * side, x * side, side, side)
}
}
}
}

Fast way scaling arrays (2d matrix of ones and zeros) with a specific factor

I have an array (2d matrix of ones and zeros) like below and like to change it's size and so I've developed a function you can also find below.
'011111' '001111111111'
'000000' '001111111111'
'000011' ---> '000000000000'
'000001' '000000001111'
'000000001111'
'000000000011'
'011111' '001111111111'
'000000' '001111111111'
'000011' <--- '000000000000'
'000001' '000000001111'
'000000001111'
'000000000011'
So the example task above is working fine with the code below. But scaling down a big matrix (2000*1000) to (40*20) takes a LONG time. Also in the other direction (40*20) to (2000*1000)
So does anybody has an idea how to edit my code to make it working way faster?
So I would be very thankful if somebody shares some working code matching my problem, however.. Thanks a million in advance,
Nina.
var matrix=[
'011111000000000000000000001111000000000000000000000000000000000000000011111110000000000000001011',
'001111000000000000000000011110000000000000000011111000000000000000000001111111000000000000011101',
'001111100000000000000000111110000000000000111111111111100000000000000000011111100000000000010100',
'011111000000000000000000111100000000000111111111111111111000000000000000000111110000000000111000',
'000000000000000000000001111100000000001111111111111111111110000000000000000001100000000000111000',
'000000000000000000000001111000000000111111111111111111111111000000000000000000000000000001110000',
'000000000000000000000011110000000001111111111111111111111111100000000000000000000000000001110000',
'000000000000000000000111110000000011111111111111111111111111111000000000000000000000000011100000',
'000000000000000000000111100000000111111111111111111111111111111000000000000000000000000111000000',
'000000000000000000001111100000001111111111111111111111111111111100000000000000000000000111000001',
'000000000000000000011111000000011111111111111111111111111111111110000000000000000000001110000001',
'000000000000000000011110000000011111111111111111111111111111111111000000000000000000001110000000',
'000000000000000000111110000000111111111111111111111111111111111111110000000000000000000111000000',
'000000000000000000111100000001111111111111111111111111111111111111100000000000000000011000000001',
'000000000000000001111100000001111111111111111111111111111111111111111000000000000000001110000000',
'000000000000000011111000000001111111111111111111111111111111111111111000000000000000011100000000',
'000000000000000011111000000011111111111111111111111111111111111111111110000000000000001111000001',
'000000000000000111110000000011111111111111111111111111111111111111111110000000000000011100000001',
'000000000000001111100000000011111111111111111111111111111111111111111100000000000001110000000001',
'000000000000001111100000000011111111111111111111111111111111111111111110000000000000011100000001',
'000000000000011111000000000111111111111111111111111111111111111111111110000000000001110000000001',
'000000000000011111000000000111111111111111111111111111111111111111111110000000000111000000000001',
'000000000000111110000000000111111111111111111111111111111111111111111110000000000011000000000001',
'000000000000111100000000000111111111111111111111111111111111111111111110000000000011000000000001',
'000000000000111100000000000111111111111111111111111111111111111111111110000000111000000000000001',
'000000000001111000000000000111111111111111111111111111111111111111111110000000010100000000000001',
'000000000001111000000000000111111111111111111111111111111111111111111100011100000000000000000001',
'000000000111110000000000000111111111111111111111111111111111111111111000001111000000000000000001',
'000000000111100000000000000011111111111111111111111111111111111111111000000011100000000000000001',
'000000000111100000000000000011111111111111111111111111111111111111110000001111000000000000000001',
'000000000111100000000000000011111111111111111111111111111111111111100000000111000000000000000001',
'000000101111110000000000000001111111111111111111111111111111111111100000000110000000000000000001',
'000000001111111000000000000001111111111111111111111111111111111111000000111000000000000000000001',
'000000000111111110000000000000111111111111111111111111111111111110000000011110000000000000000001',
'000000000011111111100000000000111111111111111111111111111111111100000000011100000000000000000001',
'000000000001111111110000000000011111111111111111111111111111111100000000111000000000000000000001',
'000000000000011111111000000000001111111111111111111111111111111000000001111000000000000000000001',
'000000000000001111111100000000001111111111111111111111111111110000000001110000000000000000000001',
'000000000000000011111111000000000011111111111111111111111111100000000001110000000000000000000001',
'000000000000000001111111110000000001111111111111111111111111000000000010000000000000000000000001',
'000000000000000000111111111000000000111111111111111111111100000000000111100000000000000000000001',
'000000000000000000001111111110000000001111111111111111111000000000000111000000000000000000000001',
'000000000000000000000011111111100000000011111111111111000000000000001111000000000000000000000001',
'000000000000000000000001111111111000000000001111111000000000000000001110000000000000000000000001',
'000000000000000000000000011110111100000000000000000000000000000000011100000000000000000000000001'
]
Array.prototype.scale_matrix = function(scale_factor) {
var matrix = this;
var scale = 1 / scale_factor;
var array = duplicate_matrix(Math.round(this.length * scale_factor), Math.round(this[0].length * scale_factor), '0').map(str => Array.from(str, String))
if (scale_factor < 1) {
for (var y = 0; y < array.length; y++) {
for (var x = 0; x < array[0].length; x++) {
_y = Math.round(y / scale_factor);
_x = Math.round(x / scale_factor);
var old_values = []
for (var oldx = _x; oldx < _x + scale; oldx++) {
for (var oldy = _y; oldy < _y + scale; oldy++) {
try {
old_values.push(matrix[oldy][oldx]);
}
catch (e) {}
}
}
var new_value = old_values.sort((a, b) => old_values.filter(v => v === a).length - old_values.filter(v => v === b).length).pop();
array[y][x] = matrix[_y][_x];
}
}
}
else {
for (var y = 0; y < matrix.length; y++) {
for (var x = 0; x < matrix[0].length; x++) {
_y = Math.round(y * scale_factor);
_x = Math.round(x * scale_factor);
for (var newx = _x; newx < _x + scale_factor; newx++) {
for (var newy = _y; newy < _y + scale_factor; newy++) {
try {
array[newy][newx] = matrix[y][x];
}
catch (e) {}
}
}
}
}
}
return array.map(a => [a.join('')]).concat.apply([], array.map(a => [a.join('')]));
}
function duplicate_matrix(rows, cols, value) {
var arr = [];
for (var i = 0; i < rows; i++) {
arr.push([]);
arr[i].push(new Array(cols));
for (var j = 0; j < cols; j++) arr[i][j] = value;
};
return arr;
}
console.log(matrix.scale_matrix(0.3).join('\n'));
console.log('\n\n>------<\n\n');
console.log(matrix.scale_matrix(1.3).join('\n'));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Adjusting the scope of the callback function of onclick

I'm trying to solve a programming exercise in which there are several bugs to be fixed. Ultimately, it is supposed to represent an animation with a grid of cells where at each time step, if a cell has exactly three neighbors which are alive (each cell has 8 neighbors), it 'comes to life', and if it has less than 2 or more than 3 neighbors, it 'dies' (where the neighbors 'wrap around' the grid). The initial script is as follows:
<html>
<head>
<script type="text/javascript">
var Board;
var xsize = 10;
var ysize = 10;
var dead = 0;
var alive = 1;
function Neighbors(Board, x, y)
{
var n = 0
for(dx=-1;dx < 1; ++dx)
for(dy=-1;dy < 1; ++dy)
{
var ax = x+dx;
var ay = y+dy;
if(Board[ax][ay]==alive) ++n;
}
return n;
}
function Kill(Board,x,y)
{
if(Board[x][y] == alive)
Board[x][y] = dead;
}
function MakeLive(Board,x,y)
{
if(Board[x][y] == dead)
Board[x][y] = alive;
}
function NextStep(Board)
{
for(var x = 0; x <= xsize; ++x)
{
for(var y = 0; y <= ysize; ++x)
{
n = Neighbors(Board,x,y);
if(n=3) MakeLive(Board,x,y);
if((n<2)||(n>3)) Kill(Board,x,y);
}
}
}
function DrawBoard(Board)
{
var Text = "";
for(var y = 0; y < ysize; ++y)
{
for(var x = 0; x < xsize; ++x)
Text += Board[x][y]==alive ? "o":"_";
Text += "<br/>";
}
document.getElementById("board").innerHTML = Text;
}
function Main()
{
// *** Change this variable to choose a different baord setup from below
var BoardSetup = "blinker";
Board = new Array(xsize);
for(var x = 0; x < xsize; ++x)
{
Board[x] = new Array(ysize);
for(var y = 0; y < ysize; ++y)
Board[x][y] = 0;
}
if(BoardSetup == "blinker")
{
Board[1][0] = 1;
Board[1][1] = 1;
Board[1][2] = 1;
}
else if(BoardSetup == "glider")
{
Board[2][0] = 1;
Board[2][1] = 1;
Board[2][2] = 1;
Board[1][2] = 1;
Board[0][1] = 1;
}
else if(BoardSetup == "flower")
{
Board[4][6] = 1;
Board[5][6] = 1;
Board[6][6] = 1;
Board[7][6] = 1;
Board[8][6] = 1;
Board[9][6] = 1;
Board[10][6] = 1;
Board[4][7] = 1;
Board[6][7] = 1;
Board[8][7] = 1;
Board[10][7] = 1;
Board[4][8] = 1;
Board[5][8] = 1;
Board[6][8] = 1;
Board[7][8] = 1;
Board[8][8] = 1;
Board[9][8] = 1;
Board[10][8] = 1;
}
DrawBoard(Board);
}
</script>
</head>
<body onload="Main()">
<div id="board">
</div>
Next ->
</body>
</html>
The problem is that if I press the 'Next' button, in the console I see the following error:
Uncaught TypeError: Cannot read property '-1' of undefined
at Neighbors (life_broken__281_29.html:19)
at Function.NextStep (life_broken__281_29.html:42)
at HTMLAnchorElement.onclick (life_broken__281_29.html:117)
Neighbors # life_broken__281_29.html:19
NextStep # life_broken__281_29.html:42
onclick # life_broken__281_29.html:117
The problem, I believe, is that the Board is defined in the Main() function, which is not in the scope of the onclick callback function.
My initial approach was to move the initialization of the Board outside of the Main() function, making it a global variable, and removing Board from all function calls. This does not seem like an elegant approach, however. Instead, I tried using Function.prototype.call() as follows:
Next ->
Further, I implemented a wrapAround function to avoid the indices going out of bounds:
function Neighbors(Board, x, y)
{
var n = 0
for(dx=-1;dx < 1; ++dx)
for(dy=-1;dy < 1; ++dy)
{
var ax = x+dx;
var ay = y+dy;
ax = wrapAround(ax, xsize);
ay = wrapAround(ay, ysize);
if(Board[ax][ay]==alive) ++n;
}
return n;
}
function wrapAround(coordinate, size) {
var result = coordinate % size;
if (result < 0) {
result += size;
}
return result;
}
However, now I get a new error:
life_broken__281_29.html:42 Uncaught TypeError: Cannot read property '0' of undefined
at MakeLive (life_broken__281_29.html:42)
at Function.NextStep (life_broken__281_29.html:53)
at HTMLAnchorElement.onclick (life_broken__281_29.html:127)
Apparently, the Neighbors function is now not raising any errors, but the next function in NextStep, MakeLive, is. This I don't understand however because they are both defined at the same 'level' and have similar invocations in NextStep. Can anyone explain what the issue is here?
Update
Indeed Board is declared in the global scope, so there was no need for Function.prototype.call(). (I'm used to Python where declaration and definition are always in the same place). I also changed the Boolean expression to (x === 3).
However, for some reason x is still going up to 10 even if I replace the <= by a <. Here is the updated code, with a console.log statement for debugging:
<html>
<head>
<script type="text/javascript">
var Board;
var xsize = 10;
var ysize = 10;
var dead = 0;
var alive = 1;
function Neighbors(Board, x, y)
{
var n = 0
for(dx=-1;dx < 1; ++dx)
for(dy=-1;dy < 1; ++dy)
{
var ax = x+dx;
var ay = y+dy;
ax = wrapAround(ax, xsize);
ay = wrapAround(ay, ysize);
if(Board[ax][ay]==alive) ++n;
}
return n;
}
function wrapAround(coordinate, size) {
var result = coordinate % size;
if (result < 0) {
result += size;
}
return result;
}
function Kill(Board, x, y)
{
if (Board[x][y] == alive)
Board[x][y] = dead;
}
function MakeLive(Board, x, y)
{
if (Board[x][y] == dead)
Board[x][y] = alive;
}
function NextStep(Board)
{
for(var x = 0; x < xsize; ++x)
{
for(var y = 0; y < ysize; ++x)
{
n = Neighbors(Board,x,y);
console.log("x = " + x + ", y = " + y + ", n = " + n);
if (n===3) MakeLive(Board,x,y);
if ((n<2)||(n>3)) Kill(Board,x,y);
}
}
}
function DrawBoard(Board)
{
var Text = "";
for(var y = 0; y < ysize; ++y)
{
for(var x = 0; x < xsize; ++x)
Text += Board[x][y]==alive ? "o":"_";
Text += "<br/>";
}
document.getElementById("board").innerHTML = Text;
}
function Main()
{
// *** Change this variable to choose a different baord setup from below
var BoardSetup = "blinker";
Board = new Array(xsize);
for(var x = 0; x < xsize; ++x)
{
Board[x] = new Array(ysize);
for(var y = 0; y < ysize; ++y)
Board[x][y] = 0;
}
if(BoardSetup == "blinker")
{
Board[1][0] = 1;
Board[1][1] = 1;
Board[1][2] = 1;
}
else if(BoardSetup == "glider")
{
Board[2][0] = 1;
Board[2][1] = 1;
Board[2][2] = 1;
Board[1][2] = 1;
Board[0][1] = 1;
}
else if(BoardSetup == "flower")
{
Board[4][6] = 1;
Board[5][6] = 1;
Board[6][6] = 1;
Board[7][6] = 1;
Board[8][6] = 1;
Board[9][6] = 1;
Board[10][6] = 1;
Board[4][7] = 1;
Board[6][7] = 1;
Board[8][7] = 1;
Board[10][7] = 1;
Board[4][8] = 1;
Board[5][8] = 1;
Board[6][8] = 1;
Board[7][8] = 1;
Board[8][8] = 1;
Board[9][8] = 1;
Board[10][8] = 1;
}
DrawBoard(Board);
}
</script>
</head>
<body onload="Main()">
<div id="board">
</div>
Next ->
</body>
</html>
and here is the result of the console when I click 'Next':
x = 0, y = 0, n = 0
life_broken__281_29.html:53 x = 1, y = 0, n = 1
life_broken__281_29.html:53 x = 2, y = 0, n = 0
life_broken__281_29.html:53 x = 3, y = 0, n = 0
life_broken__281_29.html:53 x = 4, y = 0, n = 0
life_broken__281_29.html:53 x = 5, y = 0, n = 0
life_broken__281_29.html:53 x = 6, y = 0, n = 0
life_broken__281_29.html:53 x = 7, y = 0, n = 0
life_broken__281_29.html:53 x = 8, y = 0, n = 0
life_broken__281_29.html:53 x = 9, y = 0, n = 0
life_broken__281_29.html:53 x = 10, y = 0, n = 0
life_broken__281_29.html:36 Uncaught TypeError: Cannot read property '0' of undefined
at Kill (life_broken__281_29.html:36)
at NextStep (life_broken__281_29.html:55)
at HTMLAnchorElement.onclick (life_broken__281_29.html:128)
I'm a bit nonplussed why this is happening because a simple for loop in this fashion does work:
for (var i = 0; i < 10; ++i) {
console.log("i = " + i);
}
VM158:2 i = 0
VM158:2 i = 1
VM158:2 i = 2
VM158:2 i = 3
VM158:2 i = 4
VM158:2 i = 5
VM158:2 i = 6
VM158:2 i = 7
VM158:2 i = 8
VM158:2 i = 9
undefined
Is the console somehow using a cached version of the old code? (I'm using the Live Preview in Brackets).
Update 2
This is because I should use a post-increment instead of a pre-increment (cf. http://jsforallof.us/2014/07/10/pre-increment-vs-post-increment/). Changing the ++x to x++ solved the problem.
The error has nothing to do with variable scope. Board is a global variable, so it's accessible to any function.
Your original problem was because you were accessing outside the Board array when x = 0 and dx = -1, and you fixed that with your wrapAround() function.
The next problem is that your loops in NextStep go too far. The row indexes go from 0 to xsize-1 and the columns go from 0 to ysize-1. But the loop there uses x <= xsize and y <= ysize, so it will try to access Board[xsize], which doesn't exist. Change those <= to <, just like the loop in Main().
if(n=3) MakeLive(Board,x,y);, your n = 3 should be n === 3, I'm sure you don't want to assign 3 to n which would cause a truthy value, which will call MakeLive(Board,x,y); every time.
Also, in NextStep you have your x and y go all the way up to xsize and ysize (<=) whereas everywhere else you use <, think that causes your undefined value in Board[x]

setInterval javascript memory leak

I can't figure out why the memory is increasing and it stays there each time I run this code:
easingFunction = function (t, b, c, d) {
if ((t /= d / 2) < 1) return c / 2 * t * t * t * t * t + b;
return c / 2 * ((t -= 2) * t * t * t * t + 2) + b;
}
processFrame = function () {
for (var i = 0; i < tiles.length; i++) {
var tile = tiles[i];
tile.percent += 4;
if (tile.percent > 0) {
var TH = Math.max(0, Math.min(TILE_HEIGHT, targetObj.height - tile.imageY));
var TW = Math.max(0, Math.min(TILE_WIDTH, targetObj.width - tile.imageX));
var SW, SH, SX, SY, amount;
draw.save();
draw.translate(tile.imageX, tile.imageY);
if (direction == "tb" || direction == "bt") {
amount = easingFunction(tile.percent, 0, TW, 100);
SW = Math.min(TW, amount);
SH = TH;
SX = 0;
SY = 0;
} else {
amount = easingFunction(tile.percent, 0, TH, 100);
SW = TW;
SH = Math.min(TH, amount);
SX = 0;
SY = 0;
}
draw.drawImage(copycanvas, tile.imageX, tile.imageY, SW, SH, SX, SY, SW, SH);
draw.restore();
}
}
var ok = true;
for (i = 0; i < tiles.length; i++) {
if (tiles[i].percent < 100) {
ok = false;
break;
}
}
if (ok) {
clearInterval(interval);
showComplete();
}
};
this.show = function (target, hideTarget) {
createTiles();
for (var i = 0; i < tiles.length; i++) {
var tile = tiles[i];
tile.percent = 0 - i * 10;
}
}
var intervalDelay = (config.duration * 1000) / (tiles.length * 3 + 25);
interval = setInterval(function () {
processFrame();
}, intervalDelay);
};
function Tile() {
this.imageX = 0;
this.imageY = 0;
this.percent = 0;
};
};
I left out some unimportant code. The ideea is that I call externally the show() function. The setInterval is initialized and runs processFrame() about 100 times.
I've tried to leave some code outside from processFrame, and I got to :
processFrame = function () {
for (var i = 0; i < tiles.length; i++) {
var tile = tiles[i];
tile.percent += 4;
}
var ok = true;
for (i = 0; i < tiles.length; i++) {
if (tiles[i].percent < 100) {
ok = false;
break;
}
}
if (ok) {
clearInterval(interval);
showComplete();
}
};
But the memory still increases.
Try validating your code with JSLint. http://www.jslint.com/
Right now your adding easingFunction & processFrame to the Global object (which isn't a good thing). Not that this is the cause of the problem, but I've found that mismanagement of my objects is the usual cause of memory leaks.
You'll want to do something like:
var MyObject = {};
MyObject.easingFunction = function(){};
MyObject.processFrame = function(){};
In short make sure you declare all objects with var before using them.
I found the problem. I was continuously redrawing the canvas. To resolve this problem I had to erase the canvas each time before modifying it.

Categories

Resources