Game of Life custom algorithm won't work properly - javascript

For some reason, my Game of Life algorithm for JavaScript won't work. I tried to test it with a Blinker
but it very quickly did not work
(note, this is an infinite plane so those 2 at the bottom are actually above the top.)
It makes a very interesting design, but it isn't the Game of Life.
My code runs as
var RxC = []; //the array to hold information about the plane
var drawGame = function(first) {
for (var i=0;10000>i;i++) {//for each box
var x = i%100;//gets what x block it is
var y = Math.floor((i-x)/100);//gets what y block it is
var box = canvas.getContext('2d');
if (first) {
if (!RxC[y]) RxC[y] = [];
RxC[y][x] = Math.round(Math.random()) === 1;//random alive or dead
}else {
//get all neighbors
//I am using 99 because the plane is 100 wide and 100 tall, but since arrays count from 0, I have to use 99 instead of 100
var neighbors = 0;
var topY = (y-1 < 0) ? 99 : y-1;
var bottomY = (y+1 > 99) ? 0 : y+1;
var leftX = (x-1 < 0) ? 99 : x-1;
var rightX = (x+1 > 99) ? 0 : x+1;
//N
if (RxC[topY][x]) neighbors++;
//NE
if (RxC[topY][rightX]) neighbors++;
//E
if (RxC[y][rightX]) neighbors++;
//SE
if (RxC[bottomY][rightX]) neighbors++;
//S
if (RxC[bottomY][x]) neighbors++;
//SW
if (RxC[bottomY][leftX]) neighbors++;
//W
if (RxC[y][leftX]) neighbors++;
//NW
if (RxC[topY][leftX]) neighbors++;
if (RxC[y][x]) {//if block is alive
if (neighbors === 0 || neighbors >= 4) //kill block?
RxC[y][x] = false;
}else {//block is dead
if (neighbors === 3) //revive block?
RxC[y][x] = true;
}
}
if (RxC[y][x]) {//block is alive
box.fillStyle = '#000';
}else {//block is dead
box.fillStyle = '#eee';
}
box.fillRect(5*x,5*y,5,5);
box.strokeRect(5*x,5*y,5,5);
}
};
drawGame(true);//run game for first time, this will create the board originally
setInterval(drawGame, 25);
The code will basically
make the board randomly
run the rules
if the block is alive, and it has 0 neighbors or 4 or more neighbors, it will die
if the block is dead, and it has 3 neighbors, it will revive
I got the rules from here, but the rules seem to not work...at all.
I have tried to remove the infinite plane (the shorthand if else statements in the neighbor section), checked my code repeatedly, and I have tried to use Google and Wikipedia etc. to see if the rules I am using is incorrect, but I can't find anything saying different.
So my question is, are the rules I am using correct? If they are correct, is there something obviously incorrect in my code?

your rules are wrong. conways game of life.
if on then if(neighbors >3||neighbors<2) turn off.
if off then if(neighbors==3) turn on.

Related

Why is my maze generator not detecting if a cell has been visited in p5.js?

I am trying to make a maze generator, and almost everything is working so far. I have been able to set my position to a random pos, and then I repeat the standard() function. In the function, I add pos to posList, and then I choose a random direction. Next, I check if the cell has been visited by running through all of the posList vectors in reverse. I haven't executed the code that backtracks yet. If visited = false then I move to the square and execute the yet-to-be-made path() function. However, for some reason, the mover just doesn't detect if a cell has been visited or not. I am using p5.js. What am I doing wrong?
var posList = [];
var pos;
var tempo;
var boole = false;
var direc;
var mka = 0;
function setup() {
createCanvas(400, 400);
//Set up position
pos = createVector(floor(random(3)), floor(random(3)));
frameRate(1)
}
//Choose a direction
function direct(dire) {
if(dire === 0) {
return(createVector(0, -1));
} else if(dire === 1) {
return(createVector(1, 0));
} else if(dire === 2) {
return(createVector(0, 1));
} else {
return(createVector(-1, 0));
}
}
/foLo stands fo forLoop
function foLo() {
//If we have checked less than three directions and know there is a possibility for moving
if(mka < 4) {
//tempoRARY, this is what we use to see if the cell has been visited
tempo = createVector(pos.x + direct(direc).x, pos.y + direct(direc).y);
//Go through posList backwards
for(var i = posList.length - 1; i >= 0; i --) {
//If the cell has been visited or the cell is off of the screen
if(tempo === posList[i]) {
//Change the direction
direc ++;
//Roll over direction value
if(direc === 4) {
direc = 0;
}
//Re-execute on next frame
foLo();
//The cell has been visited
boole = false;
//Debugging
console.log(direc)
mka++;
} else if(tempo.x < 0 || tempo.x > 2 || tempo.y < 0 || tempo.y > 2) {
direc ++;
if(direc === 4) {
direc = 0;
}
foLo();
boole = false;
console.log(direc)
mka++;
}
}
//If it wasn't visited (Happens every time for some reason)
if(boole === true) {
//position is now the temporary value
pos = tempo;
console.log("works")
mka = 0;
}
}
}
function standard() {
//Add pos to posList
posList.push(pos);
//Random direction
direc = floor(random(4));
//Convert to vector
direct(direc);
foLo();
//Tracks pos
fill(255, 255, 0);
rect(pos.x*100+50, pos.y*100+50, 50, 50)
}
function draw() {
background(255);
fill(0);
noStroke();
//draw grid
for(var i = 0; i < 4; i ++) {
rect(i*100,0,50,350);
rect(0, i*100, 350, 50);
}
standard();
boole = true;
console.log(pos)
console.log(posList);
}
Your issue is on the line where you compare two vectors if(tempo === posList[i]) {: This will never be true.
You can verify that with the following code (in setup() for example):
const v1 = new p5.Vector(1, 0);
const v2 = new p5.Vector(1, 0);
const v3 = new p5.Vector(1, 1);
console.log(v1 === v2) // false
console.log(v1 === v3) // false
This is because despite having the same value v1 and v2 are referencing two different objects.
What you could do is using the p5.Vector.equals function. The doc has the following example:
let v1 = createVector(10.0, 20.0, 30.0);
let v2 = createVector(10.0, 20.0, 30.0);
let v3 = createVector(0.0, 0.0, 0.0);
print(v1.equals(v2)); // true
print(v1.equals(v3)); // false
This might not give you a working algorithm because I suspect you have other logical errors (but I could be wrong or you will debug them later on) but at least this part of the code will do what you expect.
Another solution is to use a Set instead of your list of positions. The cons of this solution is that you will have to adapt your code to handle the "out of grid" position situation. However when you want to keep track of visited items a Set is usually a great solution because the access time is constant. That this means is that to define is a position has already been visited it will always take the same time (you'll do something like visitedSet.has(positionToCheck), whereas with your solution where you iterate through a list the more cells you have visited to longer it will take to check if the cell is in the list.
The Set solution will require that you transform your vectors before adding them to the set though sine, has I explained before you cannot simply compare vectors. So you could check for their string representation with something like this:
const visitedCells = new Set();
const vectorToString = (v) => `${v.x},{$v.y}` // function to get the vector representation
// ...
visitedCells.add(vectorToString(oneCell)); // Mark the cell as visited
visited = visitedCells.has(vectorToString(anotherCell))
Also has a general advice you should pay attention to your variables and functions name. For example
// foLo stands fo forLoop
function foLo() {
is a big smell: Your function name should be descriptive, when you see your function call foLo(); having to find the comment next to the function declaration makes the code less readable. You could call it generateMaze() and this way you'll know what it's doing without having to look at the function code.
Same for
//tempoRARY, this is what we use to see if the cell has been visited
tempo = createVector(pos.x + direct(direc).x, pos.y + direct(direc).y);
You could simply rename tempo to cellToVisit for example.
Or boole: naming a boolean boole doesn't convey a lot of information.
That could look like some minor details when you just wrote the code but when your code will be several hundred lines or when you read it again after taking several days of break, you'll thank past you for taking care of that.

HTML, JS Logic not working

I am trying to create a js logic function to solve the variables in an equation like this: 2x+5x=16. The problem is that it is supposed to output x=3 y=2, but instead, it outputs x=-11 y=1.
function solver(){
//Get c1, c2, and the answer
var c1=parseInt(prompt("Enter the coefficient of x:", "Example: 2 if you have 2x"));
var c2=parseInt(prompt("Enter the coefficient of y:", "Example: 3 if you have 3y"));
var answer=parseInt(prompt("Enter the answer:", "Example: 2x=4 it would be 4"));
//set other variables
var x;
var y;
var m;
//setup
x=answer/c1;
m=answer%c1;
//loop
while(true){
//if it is not an integer or it is 0
if (isInt(m/c2) === false || m/c2 == 0){
x=x-1;
m=answer%x;
}else if (isInt(m/c2)===true && m/c2 != 0){
x=x;
y=m/c2;
break;
}
}
alert("x="+x+" y="+y);
}
function isInt(n) {
return n % 1 === 0;
}
<h1>EXAMPLE: 2x+5y=16</h1>
<button onclick="solver()">Solve!</button>
Because if
nx+ky=a and x=a/n,
ky=a-(na)/n=0,
but if
x=f, y=(a-nf)/k.
You have infinitely many solutions for linear function with two unknowns.
Are you aware that there are infinite amounts of solutions?
and any given X and y that sastisfy x = 8 - 2.5y will be true?, in fact you can program the algorithm fixing y = 0, and you will get x = 8.
so you can either input two sets of xy solutions or you have infinite answers.
As a thumb rule, you need as much equations as vars
PD: I dont really get what are you doing inside the loop

Collision check loop stops looping after enemy is spawned

So I have been making this little shooter game with javascript and I have ran to a problem I cant figure out.
I have a collision check which checks if any alive enemy collides with the player or a bullet using a for loop. The loop runs fine until I spawn an enemy.
In the beginning of the for loop you can see console.log, it logs numbers only ti­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­ll the first alive enemy's index. For example if enemies[4] is alive and no other enemies with index before that are alive, it keeps logging 0, 1, 2, 3 and 4. If I then kill all the enemies the loop runs full 50 times again (which is the length of the array) until an enemy spawns.­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
checkCollision: function(){
function calculate(enemy, other){
var r = enemy.r + other.r;
var dx = enemy.posX - other.posX;
var dy = enemy.posY - other.posY;
var d = Math.sqrt((dx * dx) + (dy * dy));
if(r > d){
enemy.alive = false;
other.alive = false;
return true;
}
return false;­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
}
for (var i = 0, max = this.enemies.length; i < max; i++) {
console.log(i);
if(this.e­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­nemies[i].alive){
if(calculate(this.enemies[i], this.player)){
continue;
}
for (var i = 0, max = this.player.weapon.bullets.length; i < max; i++){
if(this.player.weapon.bullets[i].alive){
if(calculate(this.enemies[i], this.player.weapon.bullets[i])){
break;­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
}
}­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
}
}
} ­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
}
Here is a little visualization:
[0] = !alive
[1] = alive
[2] = !alive
[3] = alive
[4] = alive
Now the for loop would run only 2 times, therefore not checking the collision for 3 and 4, which is what i want it to do.
Well, you have a loop, which loops over all enemies, but checks only one enemy at a time and only against the player, not against each other.
So try something like:
for (var i = 0, max = this.enemies.length; i < max; i++) {
for (var j = 0, max = this.enemies.length; j < max; j++) {
if(calculate(this.enemies[i], this.enemies[j]){
doSomething();
}
}
}
// Don't forget the player.
In case you are interested, there is a quite good HTML5 Game Development course which teaches you how to use an open source physics engine, which takes care of those things.
While looking for a job, I made a small version of Mario, using that open source project, and the info from that course. You can see the game on my website under "projects".
Edit
So after your example I understood your question. You are reusing the i and max variables in the inner loop about bullets. So if the inner loop finishes, the outer loop will also terminate as they both check i < max.

Javascript recursion variable scope

I have a recursive function(see code), if i start with depth 5
When branch
execute(depth-1,x,y,width/2,height/2);
finishes, depth is not 5 for
execute(depth-1,midX,y,width/2,height/2);
but 1, and it produces mess. You can see algorithm here: http://jsfiddle.net/g4p66/
It supposed to produce something that looks like a maze(a poorly designed maze, hah)
function execute(depth,x,y,width,height){
if(depth > 0){
var midX = (x+width)/2;
var midY = (y+height)/2;
c.save();
c.beginPath();
c.moveTo(midX,midY);
var from = Math.floor(Math.random()*4);
if(from === 0){
c.lineTo(midX,y);
} else if(from === 1){
c.lineTo(x+width,midY);
} else if(from === 2){
c.lineTo(midX,y+height);
} else if(from === 3){
c.lineTo(x,midY);
}
c.stroke();
c.restore();
execute(depth-1,x,y,width/2,height/2);
console.log(depth);
execute(depth-1,midX,y,width/2,height/2);
execute(depth-1,x,midY,width/2,height/2);
execute(depth-1,midX,midY,width/2,height/2);
}
}
EDIT:
I was reading console.log wrongly, so it got me confused.
The main reason is my midX midY calculation was wrong, should be:
var midX = (x+(x+width))/2;
var midY = (y+(y+height))/2;
You don't have a variable scope problem but a problem of logic in interpreting the log.
The first console.log you see isn't the one at the top level of the recursion but the one at the deepest level, because that's the execution order.
Here's what happens :
execute(5)
execute(4)
execute(3)
execute(2)
execute(1)
execute(0) : depth <=0 -> return
console.log(depth) -> logs 1
You can check on your own screeshot that you're deep in the recursion when you get to the log :

Cellular automata implemented in JavaScript and HTML5 Canvas

I implemented a Conway's Game of Life in JavaScript but I'm not seeing the same patterns such as Gosper's Glider Gun. I seed the grid the ways it's depicted in the Wikipedia article but, the gun never happens.
Will someone look at my code and see if there's anything wrong with it, any suggestions to the implementation?
https://github.com/DiegoSalazar/ConwaysGameOfLife
You are not updating all of the cells simultaneously, rather sequentially. A cell that is born in the first generation will not appear alive to the calculation of other cells of the first generation (it still counts as dead).
Create a new property called willBeAlive and use that to hold the cell's new calculated alive state. Once all the calculations for that generation are done, set each cell's alive property to its willBeAlive property and redraw.
Here are the changes:
Automaton.prototype.update = function() {
for (var x = 0; x < this.w; x++) {
for (var y = 0; y < this.h; y++) {
this.grid[x][y].killYourselfMaybe();
}
}
// set the alive property to willBeAlive
for (var x = 0; x < this.w; x++) {
for (var y = 0; y < this.h; y++) {
this.grid[x][y].alive = this.grid[x][y].willBeAlive;
}
}
}
Cell.prototype.killYourselfMaybe = function(grid) {
var num = this.numLiveNeighbors();
this.willBeAlive = false;
if (this.alive) {
// 1. Any live cell with fewer than two live neighbours dies, as if caused by under-population.
if (num < 2) this.willBeAlive = false;
// 2. Any live cell with two or three live neighbours lives on to the next generation.
if (num == 2 || num == 3) { this.willBeAlive = true}
// 3. Any live cell with more than three live neighbours dies, as if by overcrowding.
if (num > 3) this.willBeAlive = false;
} else {
// 4. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
if (num == 3) this.willBeAlive = true;
}
}
and here is a seed array for "Gosper's Glider Gun":
[[2,6],[2,7],[3,6],[3,7],[12,6],[12,7],[12,8],[13,5],[13,9],[14,4],[14,10],[15,4],[15,10],[16,7],[17,5],[17,9],[18,6],[18,7],[18,8],[19,7],[22,4],[22,5],[22,6],[23,4],[23,5],[23,6],[24,3],[24,7],[26,2],[26,3],[26,7],[26,8],[36,4],[36,5],[37,4],[37,5]]

Categories

Resources