Simulation of mouses moving, don't work - javascript

I'm trying to create a simulation of 150 mouses moving inside a 20x20 grid in p5.js (A processing like libary). First I'm spawning 150 mouses random places and everything goes fine. But after I have spawned the mouses I am trying to make them move to one of their neighbors. Instead of moving to one of the neighbors and make the current square empty it stays on the one that it already was one + it moves to the next one so instead of having 150 mouses i suddenly have 300... I have tried changing the code for hours but I can't find the proplem... Here is my code:
var w = 40;
var grid = [];
var mouses = 10;
var mouseAmount = [];
var Mouse;
var current;
function setup() {
createCanvas(800, 800);
cols = floor(width/w)
rows = floor(height/w)
// frameRate(60);
for (var j = 0; j < rows; j++) {
for ( var i = 0; i < cols; i++) {
var cell = new Cells(i,j);
grid.push(cell);
}
}
amount = new Amount;
}
function draw() {
background(51);
for ( var i = 0; i < grid.length; i++) {
grid[i].show();
}
amount.run();
}
function index(i, j) {
if (i < 0 || j < 0 || i > cols-1 || j > rows-1 ) {
return -1;
}
return i + j * cols;
}
function Cells(i, j) {
this.i = i;
this.j = j;
this.active = false;
this.moveCell = function() {
var neighbors = [];
var top = grid[index(i, j -1)];
var right = grid[index(i+1, j)];
var bottom = grid[index(i, j+1)];
var left = grid[index(i-1, j)];
if (top) {
neighbors.push(top)
}
if (right) {
neighbors.push(right)
}
if (bottom) {
neighbors.push(bottom)
}
if (left) {
neighbors.push(left)
}
if(neighbors.length > 0) {
var r = floor(random(0, neighbors.length));
return neighbors[r];
} else {
return undefined;
}
}
this.show = function() {
var x = this.i*w;
var y = this.j*w;
stroke(255);
noFill();
rect(x,y,w,w);
if(this.active == true) {
fill(155, 0, 255, 100)
rect(x, y, w, w)
}
}
}
function Amount() {
this.run = function() {
var r = floor(random(grid.length))
for (var i = 0; i < mouses; i++) {
var mouse = grid[r];
mouseAmount.push(mouse)
}
if (mouseAmount.length < 1499) {
for (var i = 0; i < mouseAmount.length; i++) {
mouseAmount[i].active = true;
}
}
if (mouseAmount.length > 1499) {
Next();
}
}
}
function Next(i,j) {
for (var i = 0; i < mouseAmount.length; i++) {
current = mouseAmount[i];
var nextCell = current.moveCell();
if (nextCell) {
nextCell.active = true;
current.active = false;
current = nextCell;
}
}
}
Thank you in advance :)

I don't really understand exactly what your code is supposed to do, but a few things stand out to me about your code:
Problem One: I don't understand how you're iterating through your grid array. You seem to be iterating over mouseAmount, which seems to hold random cells from the grid for some reason? That doesn't make a lot of sense to me. Why don't you just iterate over the grid array directly?
Problem Two: You then move the cells randomly to a neighbor, but you don't take into account whether the neighbor is already active or not. I'm not sure what you want to happen, but this seems a bit strange.
Problem Three: Usually with simulations like this, you have to copy the next generation into a new data structure instead of modifying the data structure as you step through it.
The biggest problem is that you haven't really explained what you want your code to do, or what this code does instead, or how those two things are different. But if I were you, I'd make the following changes:
Step One: Iterate over your grid array in a more reasonable way. Just iterate over every index and take the appropriate action for every cell. If I were you I would just use a 2D array and use a nested for loop to iterate over it.
Step Two: Make sure your logic for moving to a neighbor is correct. Do you want cells to move to already active cells?
Step Three: Make a copy of the grid before you modify it. Think about it this way: as you iterate over the grid, let's say you move a cell down one row. Then you continue iterating, you'll reach the newly active cell again. In other words, you'll touch the same active cell twice in one generation, which is definitely going to mess you up.
A word of advice: get this working for a single active cell first. It's really hard to tell what's going on since you have so many things going on at one time. Take a step back and make sure it works for one active cell before moving up to having a whole grid.

Related

PaperJs Add 2 raster as 2 symbols in the same project

I have this project in paperjs:
var url = "http://www.clker.com/cliparts/q/I/s/P/E/3/yellow-umbrella-md.png";
raster = new Raster(url);
raster.rotate(10);
raster.scale(0.4);
var url2 = "https://images.vexels.com/media/users/3/145373/isolated/preview/98721f602aa3fadb040e0a161ab3f966-waterdrop-vislumbrante-vis-o-ilustra--o-by-vexels.png";
secondRaster = new Raster(url);
secondRaster.scale(0.9);
var count = 150;
var symbol = new Symbol(raster);
var secondSymbol = new Symbol(secondRaster);
for (var i = 0; i < count; i++) {
// The center position is a random point in the view:
var center = Point.random() * view.size;
var placedSymbol = symbol.place(center);
placedSymbol.scale(i / count);
}
function onFrame(event) {
// Run through the active layer's children list and change
// the position of the placed symbols:
for (var i = 0; i < count; i++) {
var item = project.activeLayer.children[i];
// Move the item 1/20th of its width to the right. This way
// larger circles move faster than smaller circles:
item.position.y += item.bounds.width / 80;
// If the item has left the view on the right, move it back
// to the left:
if (item.bounds.bottom > view.size.width) {
item.position.y = -item.bounds.width;
}
}
}
The first raster has a symbol works good, but the second can't make it work... I read about to add more than one symbol to project.activeLayer.children but don't work. Even if I do a group of an array with both symbols also don't show up.
I read in a post that symbols can't be added as a group. Being that be true, it should be ok to be added even though isolated...
Anybody had done something similar?
Thank you
There are some mistakes in your code:
The most important one, that make you think that the second raster doesn't work, is that you are creating the second raster with the variable url instead of url2. So both rasters use the same image as source...
You need to place the second symbol like you do with the first one otherwise it will never get rendered.
When iterating through active layer children, make sure to iterate over all children by using project.activeLayer.children.length (as you are placing count * 2 symbols).
When checking for bottom reaching items, use height instead of width.
Here is a sketch demonstrating the solution.
var COUNT = 10;
var raster = new Raster('http://www.clker.com/cliparts/q/I/s/P/E/3/yellow-umbrella-md.png');
raster.rotate(10);
raster.scale(0.4);
var secondRaster = new Raster('https://images.vexels.com/media/users/3/145373/isolated/preview/98721f602aa3fadb040e0a161ab3f966-waterdrop-vislumbrante-vis-o-ilustra--o-by-vexels.png');
secondRaster.scale(0.15);
var symbol = new Symbol(raster);
var secondSymbol = new Symbol(secondRaster);
for (var i = 1; i <= COUNT; i++) {
// first symbol
symbol.place(Point.random() * view.size).scale(i / COUNT);
// second symbol
secondSymbol.place(Point.random() * view.size).scale(i / COUNT);
}
function onFrame(event) {
for (var i = 0; i < project.activeLayer.children.length; i++) {
var item = project.activeLayer.children[i];
item.position.y += item.bounds.height / 80;
if (item.bounds.bottom > view.size.height) {
item.position.y = -item.bounds.height;
}
}
}

Javascript: How to display next array value on button click

I am trying to write a code in javascript/jquery and html which I thought would be fairly simple, but turns out to be quite challenging (to me). I have a program which computes the first x numbers of the fibonacci sequence, and stores it in an array. What I am trying to do is make two buttons that will display the next or previous number in the sequence. This is what I have so far.
Javascript:
var all = new Array();
fib = function (numMax) {
for (i = 0, j = 1, k = 0; k < numMax; i = j, j = x, k++) {
x = i + j;
//window.document.write(x + " ");
all[k] = x;
}
};
fib(1000);
fibon = function () {
getElementById("mynum").innerHTML = "all[+1]";
};
HTML:
<input type="text" id="mynum">
<button onclick="fibon();">Next</button>
You need a variable that contains the current index, and then increment it each time you click.
fibindex = 0;
function fibon() {
if (fibindex >= all.count) {
document.getElementById("mynum").value = "We've run out of Fibonacci numbers";
} else {
document.getElementById("mynum").value = all[fibindex];
fibindex++;
}
}
Also, notice that you should not put quotes around a use of a variable. Add you use .value to fill in an input, not .innerHTML.
DEMO

Javascript Array Sorting and splicing

I am making a game and I need sprites to find the closest "food" and head towards them. I am having trouble finding the right code to make this happen. They seem to get the first food just fine but when there are multiple food items the sprite is indecisive between each one and doesn't go far enough to eat any of them. Still don't have much deep experience with arrays to understand.
I'm using cocos2d framework.
update:function (dt) {
for (var i = 0; i < this._gubz.length; i++)
{
var gub = this._gubz[i];
if (this._food.length>0)
{
var distances = new Array();
for (var w = 0; w < this._food.length; w++)
{
var food = this._food[w];
var location = food.getPosition();
var distance = cc.pDistance(location,gub.getPosition());
}
var smallestDistance = Math.min.apply(Math,distances);
var indexOfNumber = distances.indexOf(smallestDistance);
var closestFood = this._food[indexOfNumber];
gub.currentTarget = indexOfNumber;
}
}
for (var i = 0; i < this.foodToRemove.length; i++)
{
this.removeChild(this.foodToRemove[i].GetUserData());
this._food.splice(this._food.indexOf(this.foodToRemove[i].GetUserData()),1)
this.world.DestroyBody(this.foodToRemove[i]);
}
}
If you want to apply sorting to a javascript array use the sort variable.
this._food = this._food.sort(function(a, b) {
return a.smallestDistance > b.smallestDistance ? -1 : a.smallestDistance < b.smallesDistance ? 1 : 0;
});
to remove items use the filter item:
this._food = this._food.filter(function(element) {
return elementDoesNotExist(element);
});
Should get you started.
HTH

Resetting the iterator in a for...in loop

This is part of the code I am using to draw some random circles:
if(circles.length != 0) { //1+ circles have already been drawn
x = genX(radius);
y = genY(radius);
var i = 0;
iCantThinkOfAGoodLabelName:
for(i in circles) {
var thisCircle = circles[i];
if(Math.abs(x-thisCircle["x"])+Math.abs(y-thisCircle["y"])>radius*2) {
//overlaps
} else {
//overlaps
x = genX(radius);
y = genY(radius);
continue iCantThinkOfAGoodLabelName;
}
if(i == circles.length - 1) { //Last iteration
//Draw circle, add to array
}
}
}
The problem is that when there is an overlap, the circle with the newly generated coordinates is not checked for overlap with the circles that the overlapping circle had already been checked with. I have tried setting i to 0 before using the continue statement but that did not work. Please help, I am really confused.
You should not use for ... in on arrays.
Use for(var i = 0; i < circles.length; ++i) instead. Then you can reset by setting i = 0.
Why not use a standard for loop
for (var i=0,l = circles.length;i < l; i++) {
....
if (i === l) {
// draw
}
}
I'm not fully understanding the question, but I do not believe you can reset the iterations of a for..in. You'll need to go to a for(var i=0;...;i++).

Ordering z-indexes in an array

I have an array which looks something along the lines of
resourceData[0][0] = "pic1.jpg";
resourceData[0][1] = 5;
resourceData[1][0] = "pic2.jpg";
resourceData[1][1] = 2;
resourceData[2][0] = "pic3.jpg";
resourceData[2][1] = 900;
resourceData[3][0] = "pic4.jpg";
resourceData[3][1] = 1;
The numeric represents the z-index of the image. Minimum z-index value is 1. Maximum (not really important) is 2000.
I have all the rendering and setting z-indexes done fine. My question is, I want to have four functions:
// Brings image to z front
function bringToFront(resourceIndex) {
// Set z-index to max + 1
resourceData[resourceIndex][1] = getBiggestZindex() + 1;
// Change CSS property of image to bring to front
$('#imgD' + resourceIndex).css("z-index", resourceData[resourceIndex][1]);
}
function bringUpOne(resourceIndex) {
}
function bringDownOne(resourceIndex) {
}
// Send to back z
function sendToBack(resourceIndex) {
}
So given then index [3] (900 z):
If we send it to the back, it will take the value 1, and [3] will have to go to 2, but that conflicts with [1] who has a 2 z-index so they need to go to three etc.
Is there an easy programatical way of doing this because as soon as I start doing this it's going to get messy.
It's important that the indexes of the array don't change. We can't sort the array unfortunately due to design.
Update
Thanks for answers, I'll post the functions here once they are written incase anyone comes across this in the future (note this code has zindex listed in [6])
// Send to back z
function sendToBack(resourceIndex) {
resourceData[resourceIndex][6] = 1;
$('#imgD' + resourceIndex).css("z-index", 1);
for (i = 0; i < resourceData.length; i++) {
if (i != resourceIndex) {
resourceData[i][6]++;
$('#imgD' + i).css("z-index", resourceData[i][6]);
}
}
}
Loops! This function will reorder affected images around it. It will work with images that have widely separated z-index values. It also does not perform any changes unless it needs to.
EDIT: added function to do the CSS work
EDIT 2: Corrected problem with top/bottom functions - it wasn't moving all the images affected, now it is.
var resourceData = Array();
resourceData[0] = Array();
resourceData[0][0] = "pic1.jpg";
resourceData[0][1] = 5;
resourceData[1] = Array();
resourceData[1][0] = "pic2.jpg";
resourceData[1][1] = 2;
resourceData[2] = Array();
resourceData[2][0] = "pic3.jpg";
resourceData[2][1] = 900;
resourceData[3] = Array();
resourceData[3][0] = "pic4.jpg";
resourceData[3][1] = 1;
function _doMoveImage(ptr) {
// Change CSS property of image
$('#imgD' + ptr).css("z-index", resourceData[ptr][1]);
}
// Brings image to z front
function bringToFront(resourceIndex) {
var highest_idx = 0;
for (var i = 0; i < resourceData.length; i++) {
// for all images except the target
if (i != resourceIndex) {
// preserve the highest index we encounter
if (highest_idx < resourceData[i][1])
highest_idx = resourceData[i][1];
// move any images higher than the target down by one
if (resourceData[i][1] > resourceData[resourceIndex][1]) {
resourceData[i][1]--;
_doMoveImage(i);
}
}
}
// now move the target to the highest spot, only if needed
if (resourceData[resourceIndex][1] < highest_idx) {
resourceData[resourceIndex][1] = highest_idx;
_doMoveImage(resourceIndex);
}
return;
}
function bringUpOne(resourceIndex) {
var next_idx = 2000;
var next_ptr = false;
for (var i =0; i < resourceData.length; i++) {
// for all images except the target
if (
i != resourceIndex &&
next_idx > resourceData[i][1] &&
resourceData[i][1] > resourceData[resourceIndex][1]
){
next_idx = resourceData[i][1];
next_ptr = i;
}
}
// only move if needed
if (next_ptr) {
// target takes next's index
resourceData[resourceIndex][1] = resourceData[next_ptr][1];
// next's index decreases by one
resourceData[next_ptr][1]--;
_doMoveImage(resourceIndex);
_doMoveImage(next_ptr);
}
return;
}
function bringDownOne(resourceIndex) {
var next_idx = 0;
var next_ptr = false;
for (var i =0; i < resourceData.length; i++) {
// for all images except the target
if (
i != resourceIndex &&
next_idx < resourceData[i][1] &&
resourceData[i][1] < resourceData[resourceIndex][1]
){
next_idx = resourceData[i][1];
next_ptr = i;
}
}
// only move if needed
if (next_ptr) {
// target takes next's index
resourceData[resourceIndex][1] = resourceData[next_ptr][1];
// next's index decreases by one
resourceData[next_ptr][1]++;
_doMoveImage(resourceIndex);
_doMoveImage(next_ptr);
}
}
// Send to back z
function sendToBack(resourceIndex) {
var lowest_idx = 2000;
for (var i = 0; i < resourceData.length; i++) {
// for all images except the target
if (i != resourceIndex) {
// preserve the lowest index we encounter
if (lowest_idx > resourceData[i][1])
lowest_idx = resourceData[i][1];
// move any images lower than the target up by one
if (resourceData[i][1] < resourceData[resourceIndex][1]) {
resourceData[i][1]++;
_doMoveImage(i);
}
}
}
// now move the target to the lowest spot, only if needed
if (resourceData[resourceIndex][1] > lowest_idx) {
resourceData[resourceIndex][1] = lowest_idx;
_doMoveImage(resourceIndex);
}
return;
}
There it is: copy your structure and have it properly ordered, or if you prefer call it indexed. When you need the picture find the proper z-index and proceed w/ the rendering.
You can do that dynamically and use heap, if you don't wish to copy the entire structure.
Not tested, but how about this. For bringUpOne, bringDownOne one you can swap the z-indexes, e.g:
function bringUpOne(resourceIndex) {
var myZIndex = resourceData[resourceIndex][1];
var nextZIndex = resourceData[resourceIndex + 1][1];
resourceData[resourceIndex][1] = nextZIndex;
resourceData[resourceIndex + 1][1] = myZindex;
}
For bringing to the front:
function bringToFront(resourceIndex) {
var maxZIndex = resourceData[maxResourceIndex][1];
resourceData[resourceIndex][1] = maxZIndex + 1;
}
Now that's all fine. But what happens if you want to successively set images to the back? You can either set the zIndex to 0 each time (don't know how many you'll have actually visiable at any time) or you can start with the lowest zIndex set to something like 2000 or 10000 or whatever, which will acccomodate many calls to setToBack.
Edit: This assumes the list is ordered by zIndex to start with.

Categories

Resources