barnes hut tree endlessly looping between insert and internalInsert - algorithm

I'm trying to implement this data structure, a Barnes-Hut Octree, and I keep running into an endless loop, terminated by an out of memory exception.
The complete fiddle is here: http://jsfiddle.net/cWvex/
but the functions I'm looping between are these:
OctreeNode.prototype.insert = function (body) {
console.log('insert');
if(this.isInternal){
this.internalInsert(body);
return;
}
if(this.isExternal){
// insert the body into the spec. quadrant, call internalUpdate
for(var quadrant in this.internal.quadrants){
if(this.internal.quadrants.hasOwnProperty(quadrant)){
this.internal.quadrants[quadrant] = new OctreeNode();
}
}
this.isExternal = false;
this.isInternal = true;
this.internalInsert(this.external);
this.external = null;
this.internalInsert(body);
return;
}
if(this.isEmpty){
this.external = body;
this.isEmpty = false;
this.isExternal = true;
return;
}
};
// Precondition: quadrants' nodes must be instantiated
OctreeNode.prototype.internalInsert = function(body) {
console.log('internalInsert');
this.internal.quadrants[this.quadrant(body)].insert(body);
this.internalUpdate(body);
};
Anyone got an idea of what I'm missing?

I think the problem is to do with the quadrant function:
OctreeNode.prototype.quadrant = function (body) {
console.log('quadrant');
var pos = this.internal.pos;
var quadrant = (body.pos.x < pos ? 'l' : 'r') +
(body.pos.y < pos ? 'u' : 'd') +
(body.pos.z < pos ? 'i' : 'o');
return quadrant;
};
The chosen quadrant should be based on the centre of the quadrant, not on the centre of mass. I think you need to create a new variable to define the centre of the quadrant.
Note that when you add nodes, the centre of mass (stored in pos) can change, but the centre of the quadrant remains fixed (otherwise things will go wrong when you descend into the octtree).
At the moment, each new node is generated with a pos of 0,0,0 and so every point will always end up being assigned into the same quadrant of the node. Therefore when you try to place two bodies into the tree, you end up with an infinite recursion:
Body 1 is inserted into node x
Body 2 is inserted into node x
Node 1 is split.
Body 1 is inserted into quadrant 1 of node x
Body 2 is inserted into quadrant 1 of node x
Back to step 1 with x changed to the node at quadrant 1 of node x
EDIT
Incidentally, in the code that reads:
avgPos.x = (body.pos.x*body.mass +
avgPos.x * totalMass) / totalMass + body.mass
I think you need some more brackets to become
avgPos.x = (body.pos.x*body.mass +
avgPos.x * totalMass) / (totalMass + body.mass)
or the update of centre of mass will go wrong.

Related

Algorithm for finding the shortest straight line path between two points

I have a problem where I have a grid of points, the vertices obstructions and a starting point
I need to determine the shortest, straight line path between the starting point and each point in the grid. Of note, the points are not a graph, so traversal does not need to be graph-like such as with A* or Dijkstra. That is to say, given the following grid:
S 1 2 3
4 5 6 7
8 x 9 10
11 x 13 14
Where S is the starting point, E is the ending point, x is an obstruction and any number represents a point (consider it a waypoint), I need to determine the shortest path to reach each numbered point from S. For straight lines, this is easy, but to find the points such as 13, the path can be S - 9 - 13 and not S - 5 - 9 - 13.
The reasoning is that this problem will model flights, which don't necessarily have to abide by traveling a gride in 8 possible directions, and can fly over portions of cells; the points here representing the center of each cell.
I'm not asking for an implementation, just if a well known algorithm for such a problem exists.
My current design is based on finding the initial set of visible points from S, then building a subset of the non-visible points. From there, find the furthest point from S that is the closest to the set of points that cannot be seen, and repeat.
This is quite interesting problem, didn't know that can have so practical application. This answer is in Java, because I am most familiar in it, but algorithm is quite simple and comments in the code should help you to reimplement in any language.
I have extended your data grid with one more row, and added E (end position). So the complete grid looks like:
S 1 2 3
4 5 6 7
8 x 9 10
11 x 13 14
12 x E 15
Just few remarks:
Each cell has dimension 1 by 1. It means that each cell has diagonal equal to sqrt(2), because of d^2 = 1^2 + 1^2
Each cell is called Position(value, row, column). Row and Column values are like coordinates, and Value is just a value in the cell. So for example our start is: new Position("S", 0, 0) and end is new Position("E", 4, 2)
The proposed algorithm comes after some "shortest path algorithm", like mentioned A* or Dijkstra
The proposed algorithm looks only at the angles of the shortest path, if values on the shortest path should be considered in computation, then I could replace it with backtracking mechanism.
Algorithm setup:
// shortest path is stored in "positions" list
Position _S = new Position("S", 0, 0);
Position _5 = new Position("5", 1, 1);
...
Position _E = new Position("E", 4, 2);
List<Position> positions = new ArrayList<>();
Collections.addAll(positions, _S, _5, _9, _13, _E);
// obstruction points are stored in "xxx" list
Position x1 = new Position("x", 2, 1);
Position x2 = new Position("x", 3, 1);
Position x3 = new Position("x", 4, 1);
List<Position> xxx = new ArrayList<>();
Collections.addAll(xxx, x1, x2, x3);
Now the algorithm:
// iterate from the end
int index = positions.size()-1;
while (index > 1) {
// get three current positions
Position c = positions.get(index);
Position b = positions.get(index-1);
Position a = positions.get(index-2);
// calculate angle on point "b". Angle is constructed with a-b-c
int angle = angle(a,b,c);
if (angle == 0) { // angle = 0 means that line is straight
positions.remove(index-1); // then just remove the middle one (b)
} else { // in ELSE part check if line goes through any "x" cell
Line line = new Line(a,c);
boolean middleCanBeRejected = true;
for (Position x : xxx) {
if (line.distanceTo(x) < HALF_DIAGONAL) { // if distance from "x" to "line" is less than sqrt(2),
// it means that straight line will pass over "x",
// so we are not able to discard the middle point
middleCanBeRejected = false;
break;
}
}
if (middleCanBeRejected) { // still in ELSE
positions.remove(index-1); // check result of FOR above
}
}
index--;
}
Finally the test cases:
S 1 2 3
4 5 6 7
8 x 9 10
11 x 13 14
12 x E 15
Path:
S 0.0, 0.0
9 2.0, 2.0
E 4.0, 2.0
S 1 2 3
4 5 6 7
8 22 9 10
11 23 13 14
12 x E 15
Path:
S 0.0, 0.0
E 4.0, 2.0
Appendix, the utility methods and classes:
// -1 -> turn right
// 0 -> straight
// +1 -> turn left
// Point2D.ccw() algorithm from Sedgewick's book
public static int angle(Position a, Position b, Position c) {
double area = (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
if (area < 0.0D) { return -1; }
else { return area > 0.0D ? 1 : 0; }
}
public class Line {
// A*x + B*y + C = 0
double A;
double B;
double C;
public Line(Position p1, Position p2) {
// https://math.stackexchange.com/questions/422602/convert-two-points-to-line-eq-ax-by-c-0
this.A = p1.y - p2.y;
this.B = p2.x - p1.x;
this.C = p1.x*p2.y - p2.x*p1.y;
}
public double distanceTo(Position p) {
double nom = Math.abs(A*p.x + B*p.y + C);
double den = Math.sqrt(A*A + B*B);
return nom/den;
}
}
public class Position {
String value;
double x; // row
double y; // column
public Position(String value, double x, double y) {
this.value = value;
this.x = x;
this.y = y;
}
}

How I connect dots using A* (Astart) pathfinding system? in GODOT

I'm trying to do something a little bit different then the usual.
I have a 3D gridmap node setup and I'm trying to autogenerate the dots and connections using A*
Instead of creating obstacles tiles, I'm creating walls in between the tiles, so the tiles are still walkable, you just cannot pass through a wall . I figure it that out all already
but I have no idea how to code how to connect the points in a easy way and not connect points that has walls in between...
I'm using a RaycastCast Node to detect the wall, and his position as it walk through every gridtile
but I can't figure it out a nested loop to find the neighbors points to connect
this is what I tried to do (obviously get_closest_point() is not working the way I wanted).
If I could get a point using only Vector3 Coordinates, I think I could make it work.
EXTRA: if you guys can show me a way to clean the code, especially on the "FORs" syntaxes, because I kind don't know what I'm doing
Any other clean code recommendations would be amazing and very much welcomed
At the end has a visual draw(image) of the logic of the idea.
onready var rc = $RayCast
onready var aS = AStar.new()
var floor_size = Vector3(12,0,12)
var origin = Vector3(-5.5, 0.5, -2.5)
var FRONT = Vector3(1,0,0)
var RIGHT = Vector3(0,0,1)
var BACK = Vector3(-1,0,0)
var LEFT = Vector3(-1,0,0)
func set_walkable():
var value = 0
var value2 = 0
var i = 0
for _length in range (origin.x, origin.x + floor_size.x + 1):
value += 1
value2 = 0
for _width in range(origin.z, origin.z + floor_size.z):
i += 1
value2 += 1
aS.add_point(i, Vector3(origin.x + value -1 , 0.5, origin.z + value2 -1) , 1.0)
value = 0
for _u in range(origin.x, origin.x + floor_size.x + 1):
value += 1
value2 = 0
for _v in range(origin.z, origin.z + floor_size.z):
value2 += 1
var from = aS.get_closest_point(Vector3(origin.x + value ,0.5, origin.z + value2) ) # Current
rc.translation = Vector3(origin.x + value -1 ,0.5, origin.z + value2 -1)
draw_points()
print(rc.translation)
rc.cast_to = FRONT
var to = aS.get_closest_point(rc.translation) # Front
if from != -1 and !rc.is_colliding():
aS.connect_points(from, to)
draw_connections(Vector3(rc.translation.x + 0.5,rc.translation.y,rc.translation.z))
rc.cast_to = BACK
to = aS.get_closest_point(rc.translation) # back
if from != -1 and !rc.is_colliding():
aS.connect_points(from, to)
draw_connections(Vector3(rc.translation.x + -0.5,rc.translation.y,rc.translation.z))
rc.cast_to = RIGHT
to = aS.get_closest_point(rc.translation) # right
if from != -1 and !rc.is_colliding():
aS.connect_points(from, to)
draw_connections(Vector3(rc.translation.x,rc.translation.y,rc.translation.z + 0.5))
rc.cast_to = LEFT
to = aS.get_closest_point(rc.translation) # left
if from != -1 and !rc.is_colliding():
aS.connect_points(from, to)
draw_connections(Vector3(rc.translation.x + 0.5,rc.translation.y,rc.translation.z + -0.5))
func draw_points(): # Make points visible
var cube = MeshInstance.new()
cube.mesh = CubeMesh.new()
cube.translation = rc.translation
cube.scale = Vector3(0.25,0.25,0.25)
add_child(cube)
print("Cubo adicionado")
func draw_connections(position): # Make connections visible
var line = MeshInstance.new()
line.mesh = PlaneMesh.new()
line.scale = Vector3(0.03,0.03,0.03)
line.translation = position
add_child(line)
print("Cubo adicionado")
Convert between Coordinates and Point ids
Let us establish a mapping between coordinates and point ids. Given that we have a floor_size, this is easy:
func vector_to_id(vector:Vector3, size:Vector3) -> int:
return int(int3(vector).dot(dimension_size(size)))
func id_to_vector(id:int, size:Vector3) -> Vector3:
var s:Vector3 = dimension_size(size)
var z:int = int(id / s.z)
var y:int = int((id % int(s.z)) / s.y)
var x:int = id % int(s.y)
return Vector3(x, y, z)
func int3(vector:Vector3) -> Vector3:
return Vector3(int(vector.x), int(vector.y), int(vector.z))
func dimension_size(size:Vector3) -> Vector3:
return Vector3(1, int(size.x + 1), int(size.x + 1) * int(size.y + 1))
Possible optimizations:
Store dimension_size(floor_size) and use that directly.
Skip calling int3 on the condition that the values you pass to vector_to_id are guaranteed to be integer.
We will need a function to get the total number of points:
func total_size(size:Vector3) -> int:
return int(size.x + 1) * int(size.y + 1) * int(size.z + 1)
Explanation
Let us start at 1D (one dimension). We will only have one coordinate. So we have an hypothetical Vector1 that has an x property. We are simply putting things in a line.
Then the mapping is trivial: to convert from the coordinates to the id, we take id = int(vector.x), and if we want the coordinate we simply do vector = Vector1(id).
Now, let us move to 2D. We have Vector2 with x and y. Thankfully we have a size (there are ways to do the mapping when the size is not known, but having a size is convenient).
Thus, we will be doing a 2D grid, with some width and height. The y coordinate tells us the row in which we are, and x tells us the position in the row.
Then if we have some id, we need to figure out how many rows we need to get there, and then in what position in that row we are. Figuring out the row is easy, we divide by the width of the grid. And the position in the row is the reminder. One caveat: We are measuring from 0 (so a width of 0 actually means 1 element per row).
We have:
func id_to_vector(id:int, size:Vector2) -> Vector2:
var y:int = int(id / (size.x + 1))
var x:int = id % int(size.x + 1)
return Vector2(x, y)
How about going the other way around? Well, we multiply y for the length of a row (the width), and add x:
func vector_to_id(vector:Vector2, size:Vector2) -> int:
return int(vector.x) + int(vector.y) * int(size.x + 1)
Notice:
We didn't need size.y.
We need size.x + 1 in both functions.
vector_to_id looks very similar to a dot product.
Thus, let us make a new function that returns the vector with which we would be making the dot product:
func dimension_size(size:Vector2) -> Vector2:
return Vector2(1, int(size.x + 1))
And use it:
func vector_to_id(vector:Vector2, size:Vector2) -> int:
return int(vector.dot(dimensional_size(size)))
func id_to_vector(id:int, size:Vector2) -> Vector2:
var s = dimensional_size(size)
var y:int = int(id / int(s.y))
var x:int = id % int(s.y)
return Vector2(x, y)
Note If there is no guarantee that vector only has integers in vector_to_id, the fractional part in the dot product make lead to a wrong result. Which is why I have a function to make it have only integer.
Time for 3D. We have Vector3 with x, y and z. We are making a 3D grid. Now the z will tell us the layer, and each layer is a 2D grid.
Let us review dimensional_size, We had:
func dimension_size(size:Vector2) -> Vector2:
return Vector2(1, int(size.x + 1))
That is the size of an element (1), the size of a row(size.x + 1), we need to add the size of a layer. That is, the size of the 2D grid, which is just width times height.
func dimension_size(size:Vector3) -> Vector3:
return Vector3(1, int(size.x + 1), int(size.x + 1) * int(size.y + 1))
And how do we get z from the id? We divide by the size of a grid (so we know on what grid we are). Then from the reminder of that division we can find y:
func vector_to_id(vector:Vector3, size:Vector3) -> int:
return int(vector.dot(dimensional_size(size)))
func id_to_vector(id:int, size:Vector3) -> Vector3:
var s = dimensional_size(size)
var z:int = int(id / int(s.z))
var y:int = int(int(id % int(s.z)) / int(s.y))
var x:int = id % int(s.y)
return Vector2(x, y, z)
In fact, technically, all these coordinates are computed on the same form:
func id_to_vector(id:int, size:Vector3) -> Vector3:
var s = dimensional_size(size)
var tot = total_size(size)
var z:int = int(int(id % int(tot)) / int(s.z))
var y:int = int(int(id % int(s.z)) / int(s.y))
var x:int = int(int(id % int(s.y)) / int(s.x))
return Vector2(x, y, z)
Except, there is no need to take the reminder with the total size because id should always be less than that. And there is no need to divide by s.x because the size of a single element is always 1. And I also removed some redundant int casts.
What is total_size? The next element of dimensional_size, of course:
func dimension_size(size:Vector3) -> Vector3:
return Vector3(1, int(size.x + 1), int(size.x + 1) * int(size.y + 1))
func total_size(size:Vector3) -> int:
return int(size.x + 1) * int(size.y + 1) * int(size.z + 1)
Checking connectivity
And a way to check connectivity:
func check_connected(start:Vector3, end:Vector3) -> bool:
rc.transform.origin = start
rc.cast_to = end
rc.force_update_transform()
rc.force_raycast_update()
return !raycast.is_colliding()
And you had the right idea with FRONT, RIGHT, BACK and LEFT but put them in an array:
var offsets = [Vector3(1,0,0), Vector3(0,0,1), Vector3(-1,0,0), Vector3(-1,0,0)]
Note I'm calling force_update_transform and force_raycast_update because are doing multiple raycast checks on the same frame.
Populating AStar
Alright, enough setup, we can now iterate:
for id in total_size(floor_size):
pass
On each iteration, we need to get the vector:
for id in total_size(floor_size):
var vector = id_to_vector(id, floor_size)
Posible optimization: Iterate over the vector coordinates directly to avoid calling id_to_vector.
We can add the vector to AStar:
for id in total_size(floor_size):
var vector = id_to_vector(id, floor_size)
aS.add_point(id, vector)
Next we need the adjacent vectors:
for id in total_size(floor_size):
var vector = id_to_vector(id, floor_size)
aS.add_point(id, vector)
for offset in offsets:
var adjacent = vector + offset
Let us add them to AStar too:
for id in total_size(floor_size):
var vector = id_to_vector(id, floor_size)
aS.add_point(id, vector)
for offset in offsets:
var adjacent = vector + offset
var adjacent_id = vector_to_id(adjacent, floor_size)
aS.add_point(adjacent_id, adjacent)
Possible optimizations:
Do not add if has_point returns true.
If the id of the adjacent vector is lower, do not process it.
Modify offsets so that you only check adjacent position that are yet to be added (and thus preventing the prior two cases).
Let us check connectivity:
for id in total_size(floor_size):
var vector = id_to_vector(id, floor_size)
aS.add_point(id, vector)
for offset in offsets:
var adjacent = vector + offset
var adjacent_id = vector_to_id(adjacent, floor_size)
aS.add_point(adjacent_id, adjacent)
if check_connected(vector, adjacent):
pass
And tell the AStar about the connectivity:
for id in total_size(floor_size):
var vector = id_to_vector(id, floor_size)
aS.add_point(id, vector)
for offset in offsets:
var adjacent = vector + offset
var adjacent_id = vector_to_id(adjacent, floor_size)
aS.add_point(adjacent_id, adjacent)
if check_connected(vector, adjacent):
connect_points(id, adjacent_id)

Add water between in a bar chart

Recently came across an interview question in glassdoor-like site and I can't find an optimized solution to solve this problem:
This is nothing like trapping water problem. Please read through the examples.
Given an input array whose each element represents the height of towers, the amount of water will be poured and the index number indicates the pouring water position.The width of every tower is 1. Print the graph after pouring water.
Notes:
Use * to indicate the tower, w to represent 1 amount water.
The pouring position will never at the peak position.No need to consider the divide water case.
(A Bonus point if you gave a solution for this case, you may assume that if Pouring N water at peak position, N/2 water goes to left, N/2 water goes to right.)
The definition for a peak: the height of peak position is greater than the both left and right index next to it.)
Assume there are 2 extreme high walls sits close to the histogram.
So if the water amount is over the capacity of the histogram,
you should indicate the capacity number and keep going. See Example 2.
Assume the water would go left first, see Example 1
Example 1:
int[] heights = {4,2,1,2,3,2,1,0,4,2,1}
It look like:
* *
* * **
** *** **
******* ***
+++++++++++ <- there'll always be a base layer
42123210431
Assume given this heights array, water amout 3, position 2:
Print:
* *
*ww * **
**w*** **
******* ***
+++++++++++
Example 2:
int[] heights = {4,2,1,2,3,2,1,0,4,2,1}, water amout 32, position 2
Print:
capacity:21
wwwwwwwwwww
*wwwwwww*ww
*www*www**w
**w***ww**w
*******w***
+++++++++++
At first I though it's like the trapping water problem but I was wrong. Does anyone have an algorithm to solve this problem?
An explanation or comments in the code would be welcomed.
Note:
The trapping water problem is asked for the capacity, but this question introduced two variables: water amount and the pouring index. Besides, the water has the flowing preference. So it not like trapping water problem.
I found a Python solution to this question. However, I'm not familiar with Python so I quote the code here. Hopefully, someone knows Python could help.
Code by #z026
def pour_water(terrains, location, water):
print 'location', location
print 'len terrains', len(terrains)
waters = [0] * len(terrains)
while water > 0:
left = location - 1
while left >= 0:
if terrains[left] + waters[left] > terrains[left + 1] + waters[left + 1]:
break
left -= 1
if terrains[left + 1] + waters[left + 1] < terrains[location] + waters[location]:
location_to_pour = left + 1
print 'set by left', location_to_pour
else:
right = location + 1
while right < len(terrains):
if terrains[right] + waters[right] > terrains[right - 1] + waters[right - 1]:
print 'break, right: {}, right - 1:{}'.format(right, right - 1)
break
right += 1
if terrains[right - 1] + waters[right - 1] < terrains[location] + waters[right - 1]:
location_to_pour = right - 1
print 'set by right', location_to_pour
else:
location_to_pour = location
print 'set to location', location_to_pour
waters[location_to_pour] += 1
print location_to_pour
water -= 1
max_height = max(terrains)
for height in xrange(max_height, -1, -1):
for i in xrange(len(terrains)):
if terrains + waters < height:
print ' ',
elif terrains < height <= terrains + waters:
print 'w',
else:
print '+',
print ''
Since you have to generate and print out the array anyway, I'd probably opt for a recursive approach keeping to the O(rows*columns) complexity. Note each cell can be "visited" at most twice.
On a high level: first recurse down, then left, then right, then fill the current cell.
However, this runs into a little problem: (assuming this is a problem)
*w * * *
**ww* * instead of **ww*w*
This can be fixed by updating the algorithm to go left and right first to fill cells below the current row, then to go both left and right again to fill the current row. Let's say state = v means we came from above, state = h1 means it's the first horizontal pass, state = h2 means it's the second horizontal pass.
You might be able to avoid this repeated visiting of cells by using a stack, but it's more complex.
Pseudo-code:
array[][] // populated with towers, as shown in the question
visited[][] // starts with all false
// call at the position you're inserting water (at the very top)
define fill(x, y, state):
if x or y out of bounds
or array[x][y] == '*'
or waterCount == 0
return
visited = true
// we came from above
if state == v
fill(x, y+1, v) // down
fill(x-1, y, h1) // left , 1st pass
fill(x+1, y, h1) // right, 1st pass
fill(x-1, y, h2) // left , 2nd pass
fill(x+1, y, h2) // right, 2nd pass
// this is a 1st horizontal pass
if state == h1
fill(x, y+1, v) // down
fill(x-1, y, h1) // left , 1st pass
fill(x+1, y, h1) // right, 1st pass
visited = false // need to revisit cell later
return // skip filling the current cell
// this is a 2nd horizontal pass
if state == h2
fill(x-1, y, h2) // left , 2nd pass
fill(x+1, y, h2) // right, 2nd pass
// fill current cell
if waterCount > 0
array[x][y] = 'w'
waterCount--
You have an array height with the height of the terrain in each column, so I would create a copy of this array (let's call it w for water) to indicate how high the water is in each column. Like this you also get rid of the problem not knowing how many rows to initialize when transforming into a grid and you can skip that step entirely.
The algorithm in Java code would look something like this:
public int[] getWaterHeight(int index, int drops, int[] heights) {
int[] w = Arrays.copyOf(heights);
for (; drops > 0; drops--) {
int idx = index;
// go left first
while (idx > 0 && w[idx - 1] <= w[idx])
idx--;
// go right
for (;;) {
int t = idx + 1;
while (t < w.length && w[t] == w[idx])
t++;
if (t >= w.length || w[t] >= w[idx]) {
w[idx]++;
break;
} else { // we can go down to the right side here
idx = t;
}
}
}
return w;
}
Even though there are many loops, the complexity is only O(drops * columns). If you expect huge amount of drops then it could be wise to count the number of empty spaces in regard to the highest terrain point O(columns), then if the number of drops exceeds the free spaces, the calculation of the column heights becomes trivial O(1), however setting them all still takes O(columns).
You can iterate over the 2D grid from bottom to top, create a node for every horizontal run of connected cells, and then string these nodes together into a linked list that represents the order in which the cells are filled.
After row one, you have one horizontal run, with a volume of 1:
1(1)
In row two, you find three runs, one of which is connected to node 1:
1(1)->2(1) 3(1) 4(1)
In row three, you find three runs, one of which connects runs 2 and 3; run 3 is closest to the column where the water is added, so it comes first:
3(1)->1(1)->2(1)->5(3) 6(1) 4(1)->7(1)
In row four you find two runs, one of which connects runs 6 and 7; run 6 is closest to the column where the water is added, so it comes first:
3(1)->1(1)->2(1)->5(3)->8(4) 6(1)->4(1)->7(1)->9(3)
In row five you find a run which connects runs 8 and 9; they are on opposite sides of the column where the water is added, so the run on the left goes first:
3(1)->1(1)->2(1)->5(3)->8(4)->6(1)->4(1)->7(1)->9(3)->A(8)
Run A combines all the columns, so it becomes the last node and is given infinite volume; any excess drops will simply be stacked up:
3(1)->1(1)->2(1)->5(3)->8(4)->6(1)->4(1)->7(1)->9(3)->A(infinite)
then we fill the runs in the order in which they are listed, until we run out of drops.
Thats my 20 minutes solution. Each drop is telling the client where it will stay, so the difficult task is done.(Copy-Paste in your IDE) Only the printing have to be done now, but the drops are taking their position. Take a look:
class Test2{
private static int[] heights = {3,4,4,4,3,2,1,0,4,2,1};
public static void main(String args[]){
int wAmount = 10;
int position = 2;
for(int i=0; i<wAmount; i++){
System.out.println(i+"#drop");
aDropLeft(position);
}
}
private static void aDropLeft(int position){
getHight(position);
int canFallTo = getFallPositionLeft(position);
if(canFallTo==-1){canFallTo = getFallPositionRight(position);}
if(canFallTo==-1){
stayThere(position);
return;
}
aDropLeft(canFallTo);
}
private static void stayThere(int position) {
System.out.print("Staying at: ");log(position);
heights[position]++;
}
//the position or -1 if it cant fall
private static int getFallPositionLeft(int position) {
int tempHeight = getHight(position);
int tempPosition = position;
//check left , if no, then check right
while(tempPosition>0){
if(tempHeight>getHight(tempPosition-1)){
return tempPosition-1;
}else tempPosition--;
}
return -1;
}
private static int getFallPositionRight(int position) {
int tempHeight = getHight(position);
int tempPosition = position;
while(tempPosition<heights.length-1){
if(tempHeight>getHight(tempPosition+1)){
return tempPosition+1;
}else if(tempHeight<getHight(tempPosition+1)){
return -1;
}else tempPosition++;
}
return -1;
}
private static int getHight(int position) {
return heights[position];
}
private static void log(int position) {
System.out.println("I am at position: " + position + " height: " + getHight(position));
}
}
Of course the code can be optimized, but thats my straightforward solution
l=[0,1,0,2,1,0,1,3,2,1,2,1]
def findwater(l):
w=0
for i in range(0,len(l)-1):
if i==0:
pass
else:
num = min(max(l[:i]),max(l[i:]))-l[i]
if num>0:
w+=num
return w
col_names=[1,2,3,4,5,6,7,8,9,10,11,12,13] #for visualization
bars=[4,0,2,0,1,0,4,0,5,0,3,0,1]
pd.DataFrame(dict(zip(col_names,bars)),index=range(1)).plot(kind='bar') # Plotting bars
def measure_water(l):
water=0
for i in range(len(l)-1): # iterate over bars (list)
if i==0: # case to avoid max(:i) situation in case no item on left
pass
else:
vol_at_curr_bar=min(max(l[:i]),max(l[i:]))-l[i] #select min of max heighted bar on both side and minus current height
if vol_at_curr_bar>0: # case to aviod any negative sum
water+=vol_at_curr_bar
return water
measure_water(bars)

How can I transform the code I wrote down below?

I am suppose to code the snake game in java with processing for IT classes and since I had no idea how to do it I searched for a YouTube tutorial. Now I did find one but he used the keys 'w','s','d','a' to move the snake around - I on the other hand want to use the arrow keys. Could someone explain to me how I transform this code:
if (keyPressed == true) {
int newdir = key=='s' ? 0 : (key=='w' ? 1 : (key=='d' ? 2 : (key=='a' ? 3 : -1)));
}
if(newdir != -1 && (x.size() <= 1 || !(x.get(1) ==x.get(0) + dx[newdir] && y.get (1) == y.get(0) + dy[newdir]))) dir = newdir;
}
into something like this:
void keyPressed () {
if (key == CODED) {
if (keyCode == UP) {}
else if (keyCode == RIGHT) {}
else if (keyCode == DOWN) {}
else if (keyCode == LEFT) {}
}
This is my entire coding so far:
ArrayList<Integer> x = new ArrayList<Integer> (), y = new ArrayList<Integer> ();
int w = 900, h = 900, bs = 20, dir = 1; // w = width ; h = height ; bs = blocksize ; dir = 2 --> so that the snake goes up when it starts
int[] dx = {0,0,1,-1} , dy = {1,-1,0,0};// down, up, right, left
void setup () {
size (900,900); // the 'playing field' is going to be 900x900px big
// the snake starts off on x = 5 and y = 30
x.add(5);
y.add(30);
}
void draw() {
//white background
background (255);
//
// grid
// vertical lines ; the lines are only drawn if they are smaller than 'w'
// the operator ++ increases the value 'l = 0' by 1
//
for(int l = 0 ; l < w; l++) line (l*bs, 0, l*bs, height);
//
// horizontal lines ; the lines are only drawn if they are smaller than 'h'
// the operator ++ increases the value 'l = 0' by 1
//
for(int l = 0 ; l < h; l++) line (0, l*bs, width, l*bs);
//
// snake
for (int l = 0 ; l < x.size() ; l++) {
fill (0,255,0); // the snake is going to be green
rect (x.get(l)*bs, y.get(l)*bs, bs, bs);
}
if(frameCount%5==0) { // will check it every 1/12 of a second -- will check it every 5 frames at a frameRate = 60
// adding points
x.add (0,x.get(0) + dx[dir]); // will add a new point x in the chosen direction
y.add (0,y.get(0) + dy[dir]); // will add a new point y in the chosen direction
// removing points
x.remove(x.size()-1); // will remove the previous point x
y.remove(y.size()-1); // will remove the previous point y
}
}
It's hard to answer general "how do I do this" type questions. Stack Overflow is designed for more specific "I tried X, expected Y, but got Z instead" type questions. That being said, I'll try to answer in a general sense:
You're going to have a very difficult time trying to take random code you find on the internet and trying to make it work in your sketch. That's not a very good way to proceed.
Instead, you need to take a step back and really think about what you want to happen. Instead of taking on your entire end goal at one time, try breaking your problem down into smaller steps and taking on those steps one at a time.
Step 1: Can you store the state of your game in variables? You might store things like the direction the snake is traveling the location of the snake, etc.
Step 2: Can you write code that just prints something to the console when you press the arrow keys? You might do this in a separate example sketch instead of trying to add it directly to your full sketch.
Step 3: Can you combine those two steps and change the state of your sketch when an arrow key is pressed? Maybe you change the direction the snake is traveling.
The point is that you need to try something instead of trying to copy-paste random code without really understanding it. Break your problem down into small steps, and then post an MCVE of that specific step if you get stuck. Good luck.
You should take a look into Java API KeyEvent VK_LEFT.
And as pczeus already told you, you need to implement a capturing of the keystrokes! This can be checked here (Link from this SO answer).

find a rectangle of 1s in 2d array of 1s and 0s

I have a 2d array of objects, if the object has the property of clicked set to true, then it should be considered as "1" otherwise "0". These are blocks that are selected. I need to check if the selected boxes form a single rectangle. What is the best way to go about this?
High-level:
Keep track of the outer-most 1s.
Count all the 1s.
If the count equals the area encased by the outer-most 1s, we have a rectangle.
Pseudo-code:
left = width + 1
right = 0
top = height + 1
bottom = 0
count = 0
for x = 1 to width
for y = 1 to height
if grid[x][y] == 1
left = min(left , x)
right = max(right , x)
top = min(top , y)
bottom = max(bottom, y)
count++
if count > 0 and count == (right-left+1)*(bottom-top+1)
print "We have a rectangle!"
else
print "We don't have a rectangle!"
You could solve it like that:
Search for the first element which is 1
walk horizontal to the right, then down, then left, then up
if you came back to the origin, you have a rectangle
then ensure that all the other elements are 0.
This algorithm is O(n^2) and works if you only allow one rectangle. If you have multiple rectangles it gets complicated..
I'd do something like this (pseudocode):
// your 2d-array / matrix (N is the number of lines, M the number of columns)
m[N][M] = ...
// x coord of top left object containing 1
baseM = -1
baseFound = false
// expected width of rectangle
width = 0
widthLocked = false
// this is set to true after we started recognizing a rectangle and encounter
// a row where the object expected to be 1 in order to extend the rectangle
// is 0.
heightExceeded = false
// loop over matrix
for i = 1 to N: // lines
// at the beginning of a line, if we already found a base, lock the width
// (it cannot be larger than the number of 1s in the row of the base)
if baseFound: widthLocked = true
for j = 1 to M: // columns
if m[i][j] == 1:
if not baseFound:
baseM = j, baseFound = true
width = 1
else:
if j < baseM:
// not in rectangle in negative x direction
return false
if heightExceeded:
// not in rectangle in y direction
return false
if widthLocked:
// not in rectangle in positive x direction
if j - baseM >= width: return false
else:
width = j - baseM
elseif baseFound:
if widthLocked:
// check if we left the rectangle and memorize it
if j == baseM: heightExceeded = true
if not heightExceeded:
// check if object in rectangle is 0
if j > baseM && j < baseM + width: return false
if baseFound:
return true
else:
// what is the expected result if no rectangle has been found?
return ?
Runs in O(n). Beware of bugs.
Note: Most programming languages have 0-based arrays, so you may need to loop i from 0 to N - 1, same for j.

Resources