I have following recursive function which should call itself unless coordinates goes beyond DOM table or unless distance between starting point and point of current recursion is greater than distance given by user. However function falls into infinite loop switching infinitely between several points and I can't figure out what I have done wrong.
function fillSquare(a,b,dist){
var xStart = parseInt(a);
var yStart = parseInt(b);
var distance = dist;
function fill(c,d){
var x = parseInt(c);
var y = parseInt(d);
if(x<0 || y<0 || x>boardWidth-1 || y>boardHeight-1){
return;
}else if(getDistance(cells[getFieldId(xStart,yStart)], cells[getFieldId(x,y)]) > dist){
return;
}else{
cells[getFieldId(x,y)].hasWall = false;
document.getElementById(x+'x'+y).backgroundColor = 'gray';
console.log(x+' '+y);
fill(x-1,y);
fill(x+1,y);
fill(x,y-1);
fill(x,y+1);
}
}
fill(xStart,yStart);
}
Any help will be greatly appreciated.
The problem is that the recursive calls will go back to the same elements. For instance, when you do fill(4, 5), it calls fill(x-1, y), which is fill(3, 5). Then that calls fill(x+1, y), which goes back to fill(4, 5). It will keep cycling between them.
You need to check whether you've already filled an element, and not repeat it.
function fill(c,d){
var x = parseInt(c);
var y = parseInt(d);
if(cells[getFieldId(x, y)].hasWall === false || x<0 || y<0 || x>boardWidth-1 || y>boardHeight-1){
return;
}else if(getDistance(cells[getFieldId(xStart,yStart)], cells[getFieldId(x,y)]) > dist){
return;
}else{
cells[getFieldId(x,y)].hasWall = false;
document.getElementById(x+'x'+y).backgroundColor = 'gray';
console.log(x+' '+y);
fill(x-1,y);
fill(x+1,y);
fill(x,y-1);
fill(x,y+1);
}
}
Since I don't have the rest of your code, what is the console output of this:
// for debugging
var i = 0;
// helper function to parse into integers
function fillSquare(xStart, yStart, distance)
{
// kick it off
// on the first run the current is the start
fill(parseInt(xStart), parseInt(yStart), parseInt(xStart), parseInt(yStart), distance);
}
function fill(xCurrent, yCurrent, xStart, yStart, distance)
{
// the next two lines are temporary just for debugging purposes
++i;
if(i > 100) return;
// log where we are so we can see progress
console.log({ "xCurrent" : xCurrent, "yCurrent" : yCurrent, "xStart" : xStart, "yStart" : yStart, "distance" : distance, "getDistance" : getDistance(cells[getFieldId(xStart,yStart)], cells[getFieldId(xCurrent, yCurrent)]) });
// no need to parse since you did that on the initial run and the recursive calls are all basic math
if(xCurrent < 0 || yCurrent < 0 || xCurrent > boardWidth - 1 || yCurrent > boardHeight - 1)
{
return;
}
else if(getDistance(cells[getFieldId(xStart,yStart)], cells[getFieldId(xCurrent, yCurrent)]) > distance)
{
return;
}
else
{
cells[getFieldId(xCurrent,yCurrent)].hasWall = false;
document.getElementById(xCurrent + 'x' + yCurrent).backgroundColor = 'gray';
fill(xCurrent - 1, yCurrent, xStart, yStart, distance)
fill(xCurrent + 1, yCurrent, xStart, yStart, distance)
fill(xCurrent, yCurrent - 1, xStart, yStart, distance)
fill(xCurrent, yCurrent + 1, xStart, yStart, distance)
}
}
Related
I'm learning algorithms and doing JavaScript exercise questions, and I don't understand how one reaches the correct answer for a particular algorithm.
The question provided in the exercise is:
Have the function CorrectPath(str) read the str parameter being
passed, which will represent the movements made in a 5x5 grid of cells
starting from the top left position. The characters in the input
string will be entirely composed of: r, l, u, d, ?. Each of the
characters stand for the direction to take within the grid, for
example: r = right, l = left, u = up, d = down. Your goal is to
determine what characters the question marks should be in order for a
path to be created to go from the top left of the grid all the way to
the bottom right without touching previously travelled on cells in the
grid.
For example, the input drdr??rrddd? should ouptut drdruurrdddd
I've not found a solution on my own. I'm taking a look at a solution provided, and I'm bothered because:
A. pure functions are not used to manipulate values within the CorrectPath function (note the addX() and addY() methods contained within). I'm not convinced the solution provided is using best practices, especially coming from a functional programming background.
B. I don't understand how the steps taken, specifically in the while block and the succeeding for block, are taken to reach the correct answer and why sometimes the missingLetters array has letters remaining and other times not
The working solution provided is below
function CorrectPath(str) {
let x = 0, //start x coord
y = 0, //start y coord
missingLetters = []
const unknowns = str.match(/\W/g)
function addX() {
while(x !== 4) {
if (x > 4) {
x--;
missingLetters.push('l');
} else {
x++;
missingLetters.push('r');
}
}
}
function addY() {
while (y !== 4) {
if (y > 4) {
y--;
missingLetters.push('u');
} else {
y++;
missingLetters.push('d');
}
}
}
//tallies current number of x and y movements
for (let i=0; i<str.length; i++) {
switch (str[i]) {
case 'd':
y += 1;
break;
case 'u':
y -= 1;
break;
case 'l':
x -= 1;
break;
case 'r':
x += 1;
break;
}
}
if (x > y) { addX(); addY(); }
if (y >= x) { addY(); addX(); }
while (missingLetters.length < unknowns.length) {
var pos = missingLetters.length - 1;
if (missingLetters[pos] === 'r') {x += 1; missingLetters.push('r'); addX()}
if (missingLetters[pos] === 'l') {x -= 1; missingLetters.push('l'); addX()}
if (missingLetters[pos] === 'd') {y += 1; missingLetters.push('d'); addY()}
if (missingLetters[pos] === 'u') {y -= 1; missingLetters.push('u'); addY()}
}
var newStr = str.split('');
for (var j=0; j<str.length; j++) {
if (newStr[j] === '?') {
newStr[j] = missingLetters.shift()
}
}
return newStr.join('');
}
CorrectPath(readline());
Here's a solution I found
const dirMap = {
u: { x: 0, y: -1 },
r: { x: 1, y: 0 },
d: { x: 0, y: 1 },
l: { x: -1, y: 0 }
}
function CorrectPath(pathString) {
const map = Array(5*5)
return trace(pathString, map)
}
function trace(path, [...map], x = 0, y = 0, newPath = "") {
const steps = path.split(""),
nextMove = steps.shift()
if (nextMove === undefined) {
if (5 * y + x === (5*5-1)) return newPath
return "Bad move"
}
if (nextMove === "?") {
const moves = availableMoves(x,y,map)
if (!moves.length) return "Bad move"
for(let i = 0; i<moves.length; i++) {
let move = moves[i],
trySteps = [move,...steps].join("")
res = trace(trySteps,map,x,y,newPath)
if (!res || res === "Bad move") continue
else return res
}
return "Bad move"
} else {
if (!canMove(nextMove, x, y, map)) return "Bad move"
const pos = dirMap[nextMove],
newX = pos.x + x,
newY = pos.y + y
newPath += nextMove
map[5*newY+newX] = nextMove
return trace(steps.join(""),map,newX,newY,newPath)
}
}
function availableMoves(x,y,map) {
const steps = []
Object.keys(dirMap).forEach(z => {
if (canMove(z,x,y,map)) steps.push(z)
})
return steps
}
function canMove(dir, xPath, yPath, map) {
const pos = dirMap[dir],
x = pos.x + xPath,
y = pos.y + yPath
if (x > 4 || x < 0 || y > 4 || y < 0) return false
if (map[5*y+x] !== undefined) return false
return true
}
CorrectPath(readline());
I'm struggling to find the logic to output a series of pen positions based on some input format.
The pen's position data should be converted in a way that maintains a state of 'pen-down' and 'pen-up' (I have that working), and that clips any pen-movement beyond the rectangle area for the input (x = -8192, y = -8192) .. (8191, 8191). I could not make that clipping work.
See below instructions for how that clipping is supposed to happen:
Instructions
Example of expected output
inputData:
F0A0417F40004000417FC067086708804001C0670840004000187818784000804000
inputData:
F0A0417F41004000417FC067086708804001C067082C3C18782C3C804000
//For decode inputData//
let commands =[] , command , allPos = "", lastPos;
function proDecode(hex) {
for (let i = 0, len; i < hex.length; i+=len) {
// Opcodes take 1 byte (i.e. 2 hex characters), and
// numbers take 2 bytes (4 characters)
len = hex[i] >= '8' ? 2:4;
let num = hex.slice(i,i+len)
if (len === 2) { // opcode
command = []
commands.push(command)
}
else{
num = penDecode(num);
console.log(num);
}
command.push(num)
}
console.log(commands);
return commands;
}
//for outPut//
unction proOutput(commands){
let isPenDown = false;
let x = 0, y = 0;
let output = "";
let color = ""
for (let [opcode, ...args] of commands) {
if (opcode === 'F0') {
x = y = 0;
isPenDown = false;
color = "CO" + 0 + 0 + 0 + 255 + ";\n";
output += "CLR;\n";
} else if (opcode === '80') {
isPenDown = args[0] > 0;
output += "PEN " + (isPenDown ? "DOWN" : "UP") + ";\n";
} else if (opcode === 'A0') {
color = "CO " + args.join(" ") + ";\n";
output += color
} else if (opcode === 'C0') {
let allPos = "", lastPos;
for (let i = 0; i < args.length; i+=2) {
x += args[i];
y += args[i+1];
if(x <-8192){
x= -8192
} else if (x>8191){
x= 8191
lastPos = ` (${x}, ${y})`;
}else if (y<-8192){
y= -8192
}else if (y>8191){
y= 8191
output += "y PEN UP" + ";\n";
} else{
}
lastPos = ` (${x}, ${y})`;
if (isPenDown) allPos += lastPos;
}
output += "MV" + (allPos || lastPos) + ";\n";
} // else: ignore unknown commands
}
Expected Result
Create the same output of the example above.
You would need to find the intersection point with the bounding box whenever the coordinates move out of bounds (or come back within bounds). In some cases a line segment could even both enter and exit the box, giving two intersections.
To calculate an intersection point between a line segment (from x1, y1 to x2, y2) and a horizontal line at y, you would use this formula for the x-coordinate:
x = x1 + (y - y1) * (x2 - x1) / (y2 - y1)
Obviously the y coordinate of the intersection point is already given by y.
There would be no intersection when one of the following conditions is true:
y1 < y and y2 < y
y1 > y and y2 > y
y1 = y2
So to determine whether a line segment crosses one of the four sides of the bounding box (-8192, -8192) to (8191, 8191), you would check for 4 intersections. You could then find 0, 1 or 2 of such intersections.
Here is the code, which I adapted from my answer to your previous question (on hex encoding):
function intersectionWithAxis(x1, y1, x2, y2, y) {
if (y1 < y && y2 < y || y1 > y && y2 > y || y1 === y2) return []; // No intersection
return [Math.round(x1 + (y - y1) * (x2 - x1) / (y2 - y1)), y];
}
function decode(hex) {
let commands = [];
for (let i = 0, len, command; i < hex.length; i += len) {
// Opcodes take 1 byte (i.e. 2 hex characters), and
// numbers take 2 bytes (4 characters)
len = hex[i] >= "8" ? 2 : 4;
let num = parseInt(hex.slice(i, i+len), 16);
if (len === 2) { // Opcode
command = []; // start a new command
commands.push(command);
} else { // Number. Encoded in offset-binary, using 2 x 7 bits
num = ((num & 0x7F00) >> 1) + (num & 0x7F) - 0x2000;
}
command.push(num); // Push opcode or argument in current command
}
return commands;
}
function disassemble(hex) {
let isPenDown = false;
let isPenInBox = true;
let x = 0, y = 0;
let output = "";
let commands = decode(hex);
for (let [opcode, ...args] of commands) {
if (opcode === 0xF0) {
x = y = 0;
isPenDown = false;
isPenInBox = true;
output += "CLR;\n";
} else if (opcode === 0x80) {
isPenDown = args[0] > 0;
if (isPenInBox) output += "PEN " + (isPenDown ? "DOWN" : "UP") + ";\n";
} else if (opcode === 0xA0) {
output += "CO " + args.join(" ") + ";\n";
} else if (opcode === 0xC0) {
if (!isPenDown) {
for (let i = 0; i < args.length; i += 2) {
let [dx, dy] = args.slice(i, i + 2);
x += dx;
y += dy;
}
output += `MV (${x}, ${y});\n`;
} else {
let buffer = "";
for (let i = 0; i < args.length; i += 2) {
let [dx, dy] = args.slice(i, i + 2);
let toX = x + dx;
let toY = y + dy;
// Get intersections with top, bottom, left and right side of box:
let intersections = [
intersectionWithAxis(x, y, toX, toY, -8192),
intersectionWithAxis(x, y, toX, toY, 8191),
intersectionWithAxis(y, x, toY, toX, -8192).reverse(),
intersectionWithAxis(y, x, toY, toX, 8191).reverse()
].filter(p =>
// Only keep the intersection points
p.length && p.every(x => x >= -8192 && x <= 8191)
);
if (intersections.length === 0) { // Position remains at same side of the box (inside or outside)
if (isPenInBox) buffer += ` (${x}, ${y})`;
} else if (intersections.length === 1) { // Moving from outside to inside of box, or vice versa
// Flush previous positions to output, move to the intersection point, and toggle the pen
output += `MV${buffer} (${intersections[0].join(", ")});\nPEN ${(isPenInBox ? "UP" : "DOWN")};\n`
isPenInBox = !isPenInBox;
// Start new series with positions
buffer = isPenInBox ? ` (${toX}, ${toY})` : "";
} else { // Moving from outside the box, through the box, and outside again
output += `MV (${intersections[0].join(", ")});\nPEN DOWN;\nMV (${intersections[1].join(", ")});\nPEN UP;\n`;
}
x = toX;
y = toY;
}
// Flush previous positions to output
if (buffer) output += `MV${buffer};\n`;
}
} // else: ignore unknown commands
}
return output;
}
// Two samples as in question:
console.log(disassemble("F0A0417F40004000417FC067086708804001C0670840004000187818784000804000"));
console.log("---");
console.log(disassemble("F0A0417F41004000417FC067086708804001C067082C3C18782C3C804000"));
The code you posted in your question has some issues (which is why I used the original code without your changes to it):
It is bad practice to use global variables like commands, command, allPos and lastPos: you change their values within your functions, which gives those functions side effects;
The color variable is set in the following statement, but this value is never used:
color = "CO" + 0 + 0 + 0 + 255 + ";\n";
Also, that value does not follow the required syntax (spaces are missing between the RGB values). Anyway, it serves no purpose in your function, so you can omit it.
The following string does not include the value of y, but a literal "y":
output += "y PEN UP" + ";\n";
Also, generating the output at that spot in the code is wrong: you would need to flush the already gathered coordinates to the output first. And outputting y or its value at this point is not in line with the output syntax either.
I'm trying to get a factorial number in the JS console in Chrome.
Obviously, there is something wrong with my understanding of the for loop, and I'd like to know what part of it is not logical to me.
Thank you very much for answers <3
var newX
function factorial(x) {
if(x > 0){
for(i = 1;i <= x;i++){
var newX = x * i ;
} return newX;
};
};
Where you said var newX = x * i;, that declares a new variable. Remove var.
x * i will return the square of x because lastly i is x.
function factorial(x) {
var newX = 1;
if(x > 0){
for(var i = 1;i <= x;i++){
newX = newX * i;
}
return newX;
} else {
return 1;
}
};
console.log(factorial(5));
console.log(factorial(4));
console.log(factorial(0));
You have to remove var inside the for loop. Also, you should move the declaration of newX inside the function. And there's some other errors too.
function factorial(x) {
var newX = 1
if(x > 0){
for(i = 1;i <= x;i++){
newX = newX * i ;
}
return newX;
}
}
Also, for completeness, you should return 1 when x is 0 and NaN when x is negative or not an integer.
You could rewrite it as a recursive function:
function factorial(x) {
if(x == 0) return 1;
return x*factorial(x-1);
}
Looks way cleaner.
writing var newX in loop means making new variable every time till loop is executing and another thing is you are multiplying x*i but it should be newX *= i to satisfy the condition of factorial (i.e every time you have to multiply the result with next number ).
var newX=1;
function factorial(x) { if(x > 0){
for(i = 1;i <= x;i++){ newX *= i ;
} return newX; }; };
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
i am writing a code for conway game of life...... i am taking 2> arrays one fr old generation. and one for 2 nd genration.
**rules are : The universe of the Game of Life is an infinite two-dimensional orthogonal grid of square cells, each of which is in one of two possible states, alive or dead. Every cell interacts with its eight neighbours, which are the cells that are horizontally, vertically, or diagonally adjacent. At each step in time, the following transitions occur: **1.Any live cell with fewer than two live neighbours dies, as if caused by under-population.
2.Any live cell with two or three live neighbours lives on to the next generation.
3.Any live cell with more than three live neighbours dies, as if by overcrowding.
4.Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.**
The initial pattern constitutes the seed of the system. The first generation is created by applying the above rules simultaneously to every cell in the seed—births and deaths occur simultaneously, and the discrete moment at which this happens is sometimes called a tick (in other words, each generation is a pure function of the preceding one). The rules continue to be applied repeatedly to create further generations.**
here is the code
I am getting a soln but i guess its not giving me the correct solution becuase its not checking the neighbors of the corners. i have marked that part
**
window.conway =
{
};
window.conway.maingame =
{
};
conway.maingame = function(width, height)
{
window.a = [];
this.width = width;
this.height = height;
this.map = new Array(width);
for( i = 0; i < this.width; i++)
{
this.map[i] = new Array(height);
}
console.log(this.map, "map")
}
conway.maingame.prototype.randomize = function()
{
for( y = 0; y < this.height; y++)
{
//console.log("enter for loop")
for( x = 0; x < this.width; x++)
{
if(Math.random() > .5)
{
i =true;
}
else
{
i = false;
}
//console.log("enter function")
this.set(x, y, i);
}
}
}
conway.maingame.prototype.set = function(x, y, val)
{
x = x % this.width;
y = y % this.height;
this.map[x][y] = val;
console.log(this.map, "map2");
}
conway.maingame.prototype.get = function(x, y)
{
x = x % this.width;
y = y % this.height;
return this.map[x][y];
}
*********************************************************************************
conway.maingame.prototype.neighbors = function(x, y)
{
count = 0;
if(x > 0 && y > 0 && this.get(x + 1, y + 1))
{
console.log(this.get(x + 1, y + 1), "value neighbor");
count++;
console.log(count);
}
if(x > 0 && y > 0 && this.get(x + 1, y))
{
console.log(this.get(x + 1, y), "vallue neighbor");
count++;
console.log(count);
}
if(x > 0 && y > 0 && this.get(x + 1, y - 1))
{
console.log(this.get(x + 1, y - 1), "vallue neighbor");
count++;
console.log(count);
}
if(x > 0 && y >=0 && this.get(x, y - 1))
{
console.log(this.get(x + 1, y - 1), "vallue neighbor");
count++;
console.log(count);
}
if(x > 0 && y > 0 && this.get(x - 1, y - 1))
{
console.log(this.get(x + 1, y - 1), "vallue neighbor");
count++;
console.log(count);
}
if(x > 0 && y > 0 && this.get(x - 1, y))
{
console.log(this.get(x + 1, y - 1), "vallue neighbor");
count++;
console.log(count);
}
if(x > 0 && y > 0 && this.get(x - 1, y + 1))
{
console.log(this.get(x + 1, y - 1), "vallue neighbor");
count++;
console.log(count);
}
if(x > 0 && y > 0 &&this.get(x, y + 1))
{
console.log(this.get(x + 1, y - 1), "vallue neighbor");
count++;
console.log(count);
}
return count;
}***
conway.maingame.prototype.newgeneration = function()
{
var newMap = new Array(this.width);
for( i = 0; i < this.width; i++)
{
newMap[i] = new Array(this.height);
}
for(var y = 0; y < this.height; y++)
{
for(var x = 0; x < this.width; x++)
{
console.log("enter all for");
newMap[x][y] = this.get(x, y);
console.log(newMap, "newarray");
//Rule 1: any live cell with fewer than two live neighbors dies
if(this.get(x, y) == true && this.neighbors(x, y) < 2)
{
newMap[x][y] = false;
console.log("rule1");
}
//Rule 2: Any live cell with two or three live neighbours lives on to the next generation
if(this.get(x, y) == true && this.neighbors(x, y) == 2 || this.neighbors(x, y) == 3)
{
newMap[x][y] = true
console.log("rule2");
}
//Rule 3: any live cell with more than three live neighbors dies
if(this.get(x, y) == true && this.neighbors(x, y) > 3)
{
newMap[x][y] = false;
console.log("rule3");
}
//Rule 4: any dead cell with exactly three live neighbors becomes a live cell
if(this.get(x, y) == false && this.neighbors(x, y) == 3)
{
newMap[x][y] = true;
console.log("rule4");
}
}
}
this.map = newMap;
console.log(this.map,"new generation")
}
**
I trawled through your code in JSHint and fixed all of the issues, wrote some glue to test it in the browser and here's the result: jsfiddle.
It looks like it's working to me, so I think the problem must have been due to one of the dozens of warnings that JSHint flagged up.
Re: your assertion that the issue was due to the corners, that's what these lines are for:
x = x % this.width;
y = y % this.height;
In my test case I'm using a 10 x 10, so when it comes to check the neighbours of (9,9) it looks at (10, 10) and (10 % 10, 10 % 10) is (0, 0), thus avoiding looking outside the array. I believe this is what's known as a toroidal array.
The lesson we learn from this? Keep on top of the small issues, and the big issues will take care of themselves.
I was starting to teach myself how to work with HTML5 Canvas and decided to learn by making a short game/demo.
I wanted to make a simple blocks bounce around the screen, bounce off the walls, and bounce off each other.
I'm stuck on getting them to bounce off each other. It seems like code that makes it bounce away is making it bounce back immediately after. I see where the code fails but I don't know how to fix it :( Can anyone help?
(Side question: I know I'm not working as clean/efficiently/professionally as possible in this example but if I wanted to improve with feedback and opinions about the 'best' method for this type of example, like a code review or something, is it ok to ask a question on stackoverflow?)
jsfiddle:
http://jsfiddle.net/vdcSv/
HTML:
<canvas id="canvas" Width="400" Height="300"></canvas>
Javscript:
function CheckBallCollision(BallsArray, index) {
for (var i = 0; i < BallsArray.length; i++) {
if (index != i) {
if (BallsArray[index].Xdir == 1) {
if ((BallsArray[index].Xmax >= BallsArray[i].Xmin)) {
if ((BallsArray[index].Ymin <= BallsArray[i].Ymin) && (BallsArray[index].Ymax >= BallsArray[i].Ymin) ||
((BallsArray[index].Ymax >= BallsArray[i].Ymax) && (BallsArray[index].Ymin <= BallsArray[i].Ymax))) {
BallsArray[index].Xdir = -BallsArray[index].Xdir;
}
}
} else if (BallsArray[index].Xdir == -1) {
if ((BallsArray[index].Xmin <= BallsArray[i].Xmax)) {
if ((BallsArray[index].Ymin <= BallsArray[i].Ymin) && (BallsArray[index].Ymax >= BallsArray[i].Ymin) ||
((BallsArray[index].Ymax >= BallsArray[i].Ymax) && (BallsArray[index].Ymin <= BallsArray[i].Ymax))) {
BallsArray[index].Xdir = -BallsArray[index].Xdir;
}
}
}
}
}
}
Ball Object:
function Ball() {
this.Xmin = 0;//top left X coord
this.Ymin = 0;//top left y coord
this.Height = 25;
this.Width = 25;
this.Xmax = this.Xmin + this.Width;
this.Ymax = this.Ymin + this.Height;
this.Xdir = 0; // 0 not moving, 1 moving right, -1 moving left
this.Ydir = 0;
this.Red = 0;
this.Green = 0;
this.Blue = 200;
this.Opacity = 1;
this.Speed = 1;
}
Got it working by changing the <= to ==
It's messy and things often miss the necessary bounce off a block :( I'm sure part of the reason is falling back on the == instead of <=. If anyone has a better solution - I'm all ears :)
http://jsfiddle.net/vdcSv/1/
function CheckBallCollision(BallsArray, index) {
for (var i = 0; i < BallsArray.length; i++) {
if (index != i) {
if (BallsArray[index].Xdir == 1) {
if ((BallsArray[index].Xmax == BallsArray[i].Xmin)) {
if ((BallsArray[index].Ymin <= BallsArray[i].Ymin) && (BallsArray[index].Ymax >= BallsArray[i].Ymin) ||
((BallsArray[index].Ymax >= BallsArray[i].Ymax) && (BallsArray[index].Ymin <= BallsArray[i].Ymax))) {
BallsArray[index].Xdir = -BallsArray[index].Xdir;
}
}
} else if (BallsArray[index].Xdir == -1) {
if ((BallsArray[index].Xmin == BallsArray[i].Xmax)) {
if ((BallsArray[index].Ymin <= BallsArray[i].Ymin) && (BallsArray[index].Ymax >= BallsArray[i].Ymin) ||
((BallsArray[index].Ymax >= BallsArray[i].Ymax) && (BallsArray[index].Ymin <= BallsArray[i].Ymax))) {
BallsArray[index].Xdir = -BallsArray[index].Xdir;
}
}
}
}
}
}
Here are a couple hit detection snippets you might want to look into:
ball.hitTestCircle = function(obj) {
var dx = this.x - obj.x;
var dy = this.y - obj.y;
var distance = (dx * dx) + (dy * dy);
var area = (this.radius + obj.radius)*(this.radius + obj.radius);
return (area / distance);
};
if the call returns 1 or greater your colliding, and you can even use that info to fix the difference.
Here is basic rect hit detections script:
ball.hitTestRect = function(b) {
var difference = {};
difference.x = this.x - b.x - b.width;
difference.y = this.y - b.y - b.height;
difference.height = this.height + b.height;
difference.width = this.width + b.width;
if (difference.x < 0 && difference.y <= 0 && difference.height + difference.y >= 0 && difference.width + difference.x >= 0) return true;
return false;
};
I would call either of these with something like :
for(var i=0;i!=balls.length;i++){
for(var j=0;j!=balls.length;j++){
if(j!=i){
if(balls[i].hitTestRect(balls[j])){
// all your reversing motion code
}
}
}
}
It looks like you forgot to check if
BallsArray[index].Xmin <= BallsArray[i].Xmax)
If you add this in it works. It's also worth noting that you don't need different code for the two different X directions as this behaviour is symmetrical. Regardless of which way it is travelling to begin with you have it reversing direction. It's also symmetrical in the Y direction so if you just add:
BallsArray[index].Ydir = -BallsArray[index].Ydir;
to the 'then' part of the if you'll only need one if to take care of all four kinds of collisions.
You may also want to add a break statement so that if a ball happens to collide with two other balls at the same time it will only reverse direction once.
For a more realistic simulation you can multiply by a negative number in the (0, 1) interval, however if you don't do something else your system will slowly settle into a steady state until the rounding errors kick in and it freaks out.