So I've tried to implement the floodfill algorithm in js and came up with the following:
function floodAreaFromPoint(x,y) {
if(typeof pixel[x] == "undefined") pixel[x] = [];
pixel[x][y] = 1; // 1 for alpha
if(!coordsInPixelArray(x + 1,y)) floodAreaFromPoint(x + 1,y);
if(!coordsInPixelArray(x,y + 1)) floodAreaFromPoint(x,y + 1);
if(!coordsInPixelArray(x - 1,y)) floodAreaFromPoint(x - 1,y);
if(!coordsInPixelArray(x,y - 1)) floodAreaFromPoint(x,y - 1);
}
It works kinda fine but I have some issues with filling larger areas (10000x10000) where this alogrithm results in the error "maximum call stack exceeded". I understand the meaning of this error but I have no idea how i could possibly fix this...
I am willing to replace this function with a more efficient algorithm but I think the solution to this problem could be end recursion (which I have no idea how to correctly implement in js).
Edit: The pixel array contains the pixels that should be filled. When the function is called it already holds all border pixels.
Solution:
function flood(x,y) {
var nodes = [];
nodes.push({"x":x,"y":y});
while(nodes.length > 0) {
var p = nodes[nodes.length - 1];
if(coordsInPixelArray(p.x, p.y)) {
nodes.pop();
continue;
}
if(typeof pixel[p.x] == "undefined") pixel[p.x] = [];
pixel[p.x][p.y] = 1; // 1 for alpha
if(!coordsInPixelArray(p.x + 1, p.y)) nodes.push({"x": p.x + 1,"y": p.y});
if(!coordsInPixelArray(p.x - 1, p.y)) nodes.push({"x": p.x - 1,"y": p.y});
if(!coordsInPixelArray(p.x, p.y + 1)) nodes.push({"x": p.x,"y": p.y + 1});
if(!coordsInPixelArray(p.x, p.y - 1)) nodes.push({"x": p.x,"y": p.y - 1});
}
}
The solution is pretty simple: remove the recursion. You can aswell use a stack and push the nodes to the stack instead of a recursive call. pseudocode:
stack nodes//create a new stack
add(nodes , startNode)//initialize the stack with the first node
while ! isEmpty(nodes)//still nodes available that haven't been processed
node p = peek(nodes)
if ! nodeInArray(p) OR getColor(p) == 1
//this node has already been visited or is not in the array
//continue with the next node in the stack
pop(nodes)
continue
color(p , 1)//mark the node as visited
push(nodes , node(x(p) - 1 , y(p))//add node to be processed in the future
...//push all other neighbours to the stack
Related
I want to invert this sequence:
Invert a function like in mathematics(is this exist in programming)
What I mean: if f(x)=y --->g(y)=x so g is the inverse function of f.
My attempt was(but still not working):
function seq(num) {
if(num < 2) {return 1; }
if(num === 2) {return 2; }
if(num % 2 === 1) {
const t = (num - 1) / 2;
return seq(t - 1) + seq(t) + 1;
}
const t = num / 2;
return seq(t) + seq(t + 1) + t;
}
document.write(_.invert(seq(4)));
There is no known algorithm to programmatically invert a function, baring brute force over the domain. Indeed, such an algorithm, if workable would be a stunning discovery, likely breaking the vast majority of cryptosystems. There are a bunch of different methods for finding the inverse of a function, but they depend on the function in question meeting specific criteria.
The lodash invert function performs an completely different function, swapping keys and values of objects.
I'm starting study about Google Apps Script, and in my first function (a simple recursive Fibonacci), I'm receiving the following error:
RangeError: Maximum call stack size exceeded
Ok, ok expected risk using a recursive approach, can anybody help me where I mistake?
My code below:
function FIBONACCI(input) {
const number = parseInt(input);
if (number < 2) { return number; }
return FIBONACCI(number - 1) + FIBONACCI(number - 2);
}
There are two recursive steps in the algorithm of the Fibunacci sequence.
return FIBONACCI(number - 1) + FIBONACCI(number - 2);
^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^
So even for a relatively small number a lot of frames are pushed onto the call stack. Here is a visualization:
const log = x => (console.log(`fib(${x})`), x);
function FIBONACCI(input) {
const number = parseInt(input);
if (number < 2) { return number; }
return log(FIBONACCI(number - 1)) + log(FIBONACCI(number - 2));
}
FIBONACCI("10");
Consequently you rather quickly exhaust the call stack.
Please note that Fibonacci numbers are more naturally expressed with corecursion a.k.a. unfolding:
const fibs = i => {
const go = (x, y, j) =>
j === 1
? [x]
: [x].concat(go(y, x + y, j - 1));
return go(1, 1, i);
};
console.log(
fibs(100)); // 55
This is still not stack safe though. Since Javascript doesn't pursue tail call elimination you would have to use a trampoline.
I have a 2D array, something like the following:
[1.11, 23]
[2.22, 52]
[3.33, 61]
...
Where the array is ordered by the first value in each row.
I am trying to find a value within the array that is close to the search value - within a certain sensitivity. The way this is set up, and the value of the sensitivity, ensure only one possible match within the array.
The search value is the current x-pos of the mouse. The search is called on mousemove, and so is being called often.
Originally I had the following (using a start-to-end for loop):
for(var i = 0; i < arr.length; i++){
if(Math.abs(arr[i][0] - x) <= sensitivity){
hit = true;
break;
}
}
And it works like a charm. So far, I've only been using small data sets, so there is no apparent lag using this method. But, eventually I will be using much larger data sets, and so want to switch this to a Binary Search:
var a = 0;
var b = arr.length - 1;
var c = 0;
while(a < b){
c = Math.floor((a + b) / 2);
if(Math.abs(arr[c][0] - x) <= sensitivity){
hit = true;
break;
}else if(arr[c][0] < x){
a = c;
}else{
b = c;
}
}
This works well, for all of 2 seconds, and then it hangs to the point where I need to restart my browser. I've used binary searches plenty in the past, and cannot for the life of me figure out why this one isn't working properly.
EDIT 1
var sensitivity = (width / arr.length) / 2.001
The points in the array are equidistant, and so this sensitivity ensures that there is no ambiguous 1/2-way point in between two arr values. You are either in one or the other.
Values are created dynamically at page load, but look exactly like what I've mentioned above. The x-values have more significant figures, and the y values are all over the place, but there is no significant difference between the small sample I provided and the generated one.
EDIT 2
Printed a list that was dynamically created:
[111.19999999999999, 358.8733333333333]
[131.4181818181818, 408.01333333333326]
[151.63636363636363, 249.25333333333327]
[171.85454545454544, 261.01333333333326]
[192.07272727272726, 298.39333333333326]
[212.29090909090908, 254.2933333333333]
[232.5090909090909, 308.47333333333324]
[252.72727272727272, 331.1533333333333]
[272.94545454545454, 386.1733333333333]
[293.16363636363633, 384.9133333333333]
[313.3818181818182, 224.05333333333328]
[333.6, 284.53333333333325]
[353.81818181818187, 278.2333333333333]
[374.0363636363637, 391.63333333333327]
[394.25454545454556, 322.33333333333326]
[414.4727272727274, 300.9133333333333]
[434.69090909090926, 452.95333333333326]
[454.9090909090911, 327.7933333333333]
[475.12727272727295, 394.9933333333332]
[495.3454545454548, 451.27333333333326]
[515.5636363636366, 350.89333333333326]
[535.7818181818185, 308.47333333333324]
[556.0000000000003, 395.83333333333326]
[576.2181818181822, 341.23333333333323]
[596.436363636364, 371.47333333333324]
[616.6545454545459, 436.9933333333333]
[636.8727272727277, 280.7533333333333]
[657.0909090909096, 395.4133333333333]
[677.3090909090914, 433.21333333333325]
[697.5272727272733, 355.09333333333325]
[717.7454545454551, 333.2533333333333]
[737.963636363637, 255.55333333333328]
[758.1818181818188, 204.7333333333333]
[778.4000000000007, 199.69333333333327]
[798.6181818181825, 202.63333333333327]
[818.8363636363644, 253.87333333333328]
[839.0545454545462, 410.5333333333333]
[859.272727272728, 345.85333333333324]
[879.4909090909099, 305.11333333333323]
[899.7090909090917, 337.8733333333333]
[919.9272727272736, 351.3133333333333]
[940.1454545454554, 324.01333333333326]
[960.3636363636373, 331.57333333333327]
[980.5818181818191, 447.4933333333333]
[1000.800000000001, 432.3733333333333]
As you can see, it is ordered by the first value in each row, ascending.
SOLUTION
Changing the condition to
while(a < b)
and
var b = positions.length;
and
else if(arr[c][0] < x){
a = c + 1;
}
did the trick.
Your binary search seems to be a bit off: try this.
var arr = [[1,0],[3,0],[5,0]];
var lo = 0;
var hi = arr.length;
var x = 5;
var sensitivity = 0.1;
while (lo < hi) {
var c = Math.floor((lo + hi) / 2);
if (Math.abs(arr[c][0] - x) <= sensitivity) {
hit = true;
console.log("FOUND " + c);
break;
} else if (x > arr[c][0]) {
lo = c + 1;
} else {
hi = c;
}
}
This is meant as a general reference to anyone implementing binary search.
Let:
lo be the smallest index that may possibly contain your value,
hi be one more than the largest index that may contain your value
If these conventions are followed, then binary search is simply:
while (lo < hi) {
var mid = (lo + hi) / 2;
if (query == ary[mid]) {
// do stuff
else if (query < ary[mid]) {
// query is smaller than mid
// so query can be anywhere between lo and (mid - 1)
// the upper bound should be adjusted
hi = mid;
else {
// query can be anywhere between (mid + 1) and hi.
// adjust the lower bound
lo = mid + 1;
}
I don't know your exact situation, but here's a way the code could crash:
1) Start with an array with two X values. This array will have a length of 2, so a = 0, b = 1, c = 0.
2) a < b, so the while loop executes.
3) c = floor((a + b) / 2) = floor(0.5) = 0.
4) Assume the mouse is not within sensitivity of the first X value, so the first if branch does not hit.
5) Assume our X values are to the right of our mouse, so the second if branch enters. This sets a = c, or 0, which it already is.
6) Thus, we get an endless loop.
So I have a problem where I have an array of some length (usually long). I have an initial start index into that array and a skip value. So, if I have this:
var initial = 5;
var skip = 10;
Then I'd iterate over my array with indexes 5, 15, 25, 35, etc.
But then I may get a new start value and I need to find the closest value to the initial plus or minus a multiple of the skip and then start my skip. So if my new value is 23 then I'd iterate 25, 35, 45, etc.
The algorithm I have for this is:
index = (round((start - initial) / skip) * skip) + initial
And then I need a check to see if index has dropped below zero:
while(index < 0) index += skip;
So my first question is if there's a name for this? A multiple with random start?
My second question is if there's a better way? I don't think what I have is terribly complicated but if I'm missing something I'd like to know about it.
If it matters I'm using javascript.
Thanks!
Edit
Instead of
while(index < 0) index += skip;
if we assume that both initial and skip are positive you can use:
if (index < 0) index = initial % skip;
To get the closest multiple of a number to a test number: See if the modulo of your test number is greater than number/2 and if so, return number - modulo:
function closestMultiple(multipleTest,number)
{
var modulo = multipleTest%number;
if(0 == modulo )
{
return multipleTest;
}
else
{
var halfNumber = number/2;
if(modulo >= halfNumber)
{
return multipleTest + (number-modulo);
}
else
{
return multipleTest - modulo;
}
}
}
To check if a number is a multiple of another then compare their modulo to 0:
function isMultiple(multipleTest,number)
{
return 0 == multipleTest%number;
}
You might want to add some validations for 0 in case you expect any inside closestMultiple.
The value of index computed as you put it
index = round((start - initial)/skip) * skip + initial
is indeed the one that minimizes the distance between the sequence with general term
aj = j * skip + initial
and start.
Therefore, index can only be negative if start lies to the left of
(a-1 + a0)/2 = initial - skip/2
in other words, if
start < initial - skip/2.
So, only in that case you have to redefine index to 0. In pseudo code:
IF (start < (initial - skip/2))
index = 0
ELSE
index = round((start - initial)/skip) * skip + initial
Alternatively, you could do
index = round((start - initial)/skip) * skip + initial
IF index < 0 THEN index = 0
which is the same.
No while loop required:
function newNum(newstart, initial, skip) {
var xLow = newstart + Math.abs(newstart - initial) % skip;
var xHi = newstart + skip;
var result = (xLow + xHi) / 2 > newstart ? xLow : xHi;
if (result < 0) result += skip;
return result;
}
Take the distance between your new starting point and your initial value, and find out what the remainder would be if you marched towards that initial value (Modulus gives us that). Then you just need to find out if the closest spot is before or after the starting point (I did this be comparing the midpoint of the low and high values to the starting point).
Test:
newNum(1, 20, 7) = 6
newNum(-1, 20, 7) = 6
newNum(180, 10, 3) = 182
(Even though you stated in your comments that the range of the new starting point is within the array bounds, notice that it doesn't really matter).
I've been trying to implement a recursive backtracking maze generation algorithm in javascript. These were done after reading a great series of posts on the topic here
While the recursive version of the algorithm was a no brainer, the iterative equivalent has got me stumped.
I thought I understood the concept, but my implementation clearly produces incorrect results. I've been trying to pin down a bug that might be causing it, but I am beginning to believe that my problems are being caused by a failure in logic, but of course I am not seeing where.
My understanding of the iterative algorithm is as follows:
A stack is created holding representations of cell states.
Each representation holds the coordinates of that particular cell, and a list of directions to access adjacent cells.
While the stack isn't empty iterate through the directions on the top of the stack, testing adjacent cells.
If a valid cell is found place it at the top of the stack and continue with that cell.
Here is my recursive implementation ( note: keydown to step forward ): http://jsbin.com/urilan/14
And here is my iterative implementation ( once again, keydown to step forward ): http://jsbin.com/eyosij/2
Thanks for the help.
edit: I apologize if my question wasn't clear. I will try to further explain my problem.
When running the iterative solution various unexpected behaviors occur. First and foremost, the algorithm doesn't exhaust all available options before backtracking. Rather, it appears to be selecting cells at a random when there is one valid cell left. Overall however, the movement doesn't appear to be random.
var dirs = [ 'N', 'W', 'E', 'S' ];
var XD = { 'N': 0, 'S':0, 'E':1, 'W':-1 };
var YD = { 'N':-1, 'S':1, 'E':0, 'W': 0 };
function genMaze(){
var dirtemp = dirs.slice().slice(); //copies 'dirs' so its not overwritten or altered
var path = []; // stores path traveled.
var stack = [[0,0, shuffle(dirtemp)]]; //Stack of instances. Each subarray in 'stacks' represents a cell
//and its current state. That is, its coordinates, and which adjacent cells have been
//checked. Each time it checks an adjacent cell a direction value is popped from
//from the list
while ( stack.length > 0 ) {
var current = stack[stack.length-1]; // With each iteration focus is to be placed on the newest cell.
var x = current[0], y = current[1], d = current[2];
var sLen = stack.length; // For testing whether there is a newer cell in the stack than the current.
path.push([x,y]); // Store current coordinates in the path
while ( d.length > 0 ) {
if( stack.length != sLen ){ break;}// If there is a newer cell in stack, break and then continue with that cell
else {
var cd = d.pop();
var nx = x + XD[ cd ];
var ny = y + YD[ cd ];
if ( nx >= 0 && ny >= 0 && nx < w && ny < h && !cells[nx][ny] ){
dtemp = dirs.slice().slice();
cells[nx][ny] = 1;
stack.push( [ nx, ny, shuffle(dtemp) ] ); //add new cell to the stack with new list of directions.
// from here the code should break from the loop and start again with this latest addition being considered.
}
}
}
if (current[2].length === 0){stack.pop(); } //if all available directions have been tested, remove from stack
}
return path;
}
I hope that helps clear up the question for you. If it is still missing any substance please let me know.
Thanks again.
I'm not very good in javascript, but I try to implement your recursive code to iterative. You need to store For index on stack also. So code look like:
function genMaze(cx,cy) {
var dirtemp = dirs; //copies 'dirs' so its not overwritten
var path = []; // stores path traveled.
var stack = [[cx, cy, shuffle(dirtemp), 0]]; // we also need to store `for` indexer
while (stack.length > 0) {
var current = stack[stack.length - 1]; // With each iteration focus is to be placed on the newest cell.
var x = current[0], y = current[1], d = current[2], i = current[3];
if (i > d.length) {
stack.pop();
continue;
}
stack[stack.length - 1][3] = i + 1; // for next iteration
path.push([x, y]); // Store current coordinates in the path
cells[x][y] = 1;
var cd = d[i];
var nx = x + XD[cd];
var ny = y + YD[cd];
if (nx >= 0 && ny >= 0 && nx < w && ny < h && !cells[nx][ny]) {
dtemp = dirs;
stack.push([nx, ny, shuffle(dtemp), 0]);
}
}
return path;
}
Does this little code could also help ?
/**
Examples
var sum = tco(function(x, y) {
return y > 0 ? sum(x + 1, y - 1) :
y < 0 ? sum(x - 1, y + 1) :
x
})
sum(20, 100000) // => 100020
**/
function tco(f) {
var value, active = false, accumulated = []
return function accumulator() {
accumulated.push(arguments)
if (!active) {
active = true
while (accumulated.length) value = f.apply(this, accumulated.shift())
active = false
return value
}
}
}
Credits, explanations ans more infos are on github https://gist.github.com/1697037
Is has the benefit to not modifying your code, so it could be applied in other situations too. Hope that helps :)