Check for closed path in numerical heightmap - c#

I'm working on a game, and I have the necessity to check a closed path in a given numerical heightmap:
The server and the client use this heightmap to set the right coords to move etc...
Now, when an user walks on a "special" tile, it lights...
My problem is:
When an user, walking on these tiles creates a closed path with empty tiles in it, the server should automatically fill the tiles in this path...
It should do something like this:
http://www.youtube.com/watch?v=kAVUNE2NTUQ - 1:32
I'm sure I've to use some maths here or there, but I dunno how...
I could do a "for" cycle, but it would be too long, and the problem is that the server needs to do the cycle every time an user walks...
Thanks in advance for your answers, hope someone could help me.
PS: I'm using C#
EDIT: When an user walks on a tile, the server automatically replaces the heightmap[X, Y] with an integer that represents the color of the user

The problem can be divided into two parts:
Detecting when a path has closed. One way to do this is by making links between sequential tiles in the path: when you take a step, if one of your new neighbors has been visited before and you cannot trace your path back to it among your current neighbors then you have closed the path (you may have to establish additional links to deal with the case of going back alongside your path). This will also tell on which side of your path (left or right) the interior region lies. Play around with this on graph paper and it should become clear. This is O(1) with each step.
Filling in the enclosed region. Once you have found a single tile that is in the region, iterate over its neighbors, and then their neighbors, and so on. For a region of area n, this is O(n) in time and on average O(sqrt(n)) in memory, depending on geometry (O(n) at worst).

Let's assume you have rectangular field with upper left corner in (0, 0) and bottom right in (M, N). Then you can use the following pseudocode fill algorithm:
find the upper and bottom cells of the path (yTop, yBottom)
for (int y = yTop; y != yBottom; ++y)
{
find leftmost and rightmost path cells (xLeft, xRight) for that y
bool isInside = true;
for (int x = xLeft+1; x<xRight; ++x)
{
if ((x, y) is path cell)
isInside = !isInside;
if (isInside)
fill(x, y);
}
}

"the problem is that the server needs to do the cycle every time an user walks"...
You can eliminate the cycling over walked tiles by assigning each tile in the game a unique integer, having an array with the number of tiles, and then for each step mark this tile in the array. Of course, also check whether the tile has been walked before (i.e. whether it's marked in the array), and if it has, you have a loop (maybe of zero area). This approach has no cycling over walked tiles, etc, but just a single look-up for each step.

Related

Determine when a polygon is closed by a new side

My program has a List<Vector3> of unique points (A, B, C, ...) which are created each time a user draws a unique line (1, 2, 3, ...). Lines are stored in a List<int> where every two ints are the indices of each point to form a single line. No two lines can have the same two points, no points can occupy the same position, and stray lines are allowed.
Diagram
Points: {A, B, C, D, E} //Each letter represents a 2d or 3d position
Sides: {0,1,1,2,1,3,3,4,4,2} //(Each int is an index in Points, every pair is a side)
I am trying to find an efficient way of determining when a new line (Green, 5) closes a polygon with any number of sides. I have a way of doing this: iterating through each line connected to each side of the new line(and all subsequent lines) until they share a point (D).
Completed Polygon
My only problem here is that the more sides a polygon has, I need to do exponentially more checks (Every two additional sides on the polygon causes me to check one layer deeper on all attached sides).
Is there a way to reduce the number of checks I need to do in order to close the polygon?
Not exactly the same as Cycles in an Undirected Graph. This knows that at least one cycle is present and connected to a given side, and is looking for only the smallest cycle possible connected to that side. Other sides are irrelevant and it should avoid them.
It all depends on the level of optimization you need. For simple pictures (some what like < 10 - 100k lines) you can get away with running a BFS every time.
High level algorithm:
First you need something to store the graph using one of the Graph representation. Then whenever the user draws a line you take either of the two points and do a BFS on that point.
If you can reach the same point with your BFS and the path length is > 2 then you have a polygon.
The catch would be that since the graph is bidirectional you need to be careful when walking thru it. Do not re-visit nodes that you have already visited.

How to randomly place objects as player move around in an infinity map without overlap?

I trying to make a game where player only move forward in an infinity map, and the path (just thing of them like points, the path is only the visual) is procedurally generated. I want those path to have different length (something like the tree of life, but only branches of the selected path are generated).
This is how I generate branches without overlap:
List<Vector3> everyPos; //predetermined position
public void Spawn(int amount)
{
List<Vector3> possiblePos = new List<Vector3>(everyPos);
for (int i = 0; i < amount; i++)
{
int index = Random(0, possiblePos.Count); //Find a random position
SpawnObjectAt(currentPosition+possiblePos[index]));//Create a point there
possiblePos.RemoveAt(index); //Remove that position from the list
}
}
The problem is , look at this image(I can't embed image yet):
Red is where player start, green is possible spawn position in the first move.
If there are 2 point spawned at 1 and 2, player choose point1, then the possible position in the second time will be a point in the black zone, which include point2, so if I keep continue there will eventually overlap.
How can I avoid this? I'm making a mobile game so I don't want to cache every single point. Any help would be really appreciated! Thanks!
This is a small web game that have somewhat similar mechanic to what I trying to achieve: newgrounds.com/portal/view/592325/
This is an attempt here to answer, but honestly, you need to provide more information.
Depending on the language you are writing in, you can handle this differently. You may need dynamic allocation, but for now lets assume, since your idea is quite small, that you can just do one large array predefined before compile time.
I assume you know how to make an array, so create one with say, 500 length to start. If you want to 'generate' a link like they did in that game, you simply need a random function, (there is a built in library in pretty much every language I think) and you need to do a little math.
Whatever language you use will surely have a built in graphics library, or you can use a popular easy to use one. I'll just draw a picture to make this clear.
There are a number of ways you can do this mathematically as shown in the image, using angles for example, the simplest way, however, is just to follow the boxes.
If you have worked with graphics before, you know what a vector is, if not, you will need to learn. The 9 vectors presented in this image (0,1) (1,0) (1,1) etc. can be created as vector objects, or even stored as individual ints.
To make your nodes 'move' into another path, you can simply do a rand 1-9 and then correlated the result to one of 9 possible vectors, and then add them to your position vector. It is easiest to do this in array and just use the rand int as the index. In most c derived languages you do that like this:
positionVector += changeVectorArray[rand(1,9)];
You then increment your position vector by one of the 9 vectors as shown above.
The simplest way of making the 'path' is to copy the position before you add the change vector, and then store all of the changes sequentially in another 'path' array.
To show the path on screen, simply draw a line between the first and second, second and third, third and forth elements of your path array. This formula (of joining lines) is discrete mathematics if I'm not mistaken, and you can do much more complicated path shapes if you want, but you get the gist.
That should at least start you off. Without more info I can't really help you.
I could go off on a tangent describe a bunch of different ways you can make this happen differently but its probably easier if you just ask for specifics.
EDIT>>>
Continuing with this answer, yes, looking at it now, the nodes can definitely overlap. To solve this problem you could use collision detection, every time you generate a new 'position', before adding it and drawing the line you have to loop through your array like this:
boolean copy = true;
for(int i = 0; i < getLength(pathArray); i++){
if( newVector == pathArray[i]){
copy=false;
}
}
Then of course, if copy still is true, copy the new position int the pathArray. NOTE: this whole solution is sloppy as hell, and as your array gets larger, your program is going to take longer and longer to search through that loop. This may not also guarantee that the path goes in one direction, but it is likely. And note that the lines will still be able to overlap each other, even though the position vectors can't be on top of one another.
All this considered, I think it will work, the optimization is up to you. I would suggest that there is probably a much more efficient solution using a discrete formula. You can also use such a formula to make the path go in particular directions and do other more complicated things.
You could also quite easily apply constraints on your random rolls if you want to make the path go in a particular direction. But there are so many ways of doing this I can't begin to explain. You could google path-finding algorithms for that.
Good luck.

Game level read from file in XNA

I've been working on a tile based map engine for my game project in Xna C#. The system, like most others, uses a digit corresponding to a tile in a tileset mapped to a specific position on screen. This works fine, but requires every cell on screen to have a number manually entered. Instead, I've decided to have level layouts read from a .txt containing the number of each tile in the position it would be ingame, like so:
1111
0110
1001
1100
Where 1 is grass and 0 is dirt. Again, I'm aware this is a common technique. The code I have written can read each line and set the next position in the first column to the corresponding tile graphic. This is fine, but it does not help with the rest of the map. I've been searching and cannot find how you would split each number in a row into a separate number, so that the first line would read (0,0) = 1, (0,1) = 1, etc, so I can then match the coordinates to the x and y position on the map, and the value to the type of tile.
So what I need is the ability to assign a 2d array corresponding to the current position (how many characters left in the file, how many lines down in the .txt file), so I can just run two branched for loops (x and y) for every tile in the level ie:
for (x=0; x<levelwidth; x++)
{
for (y=0; y<levelheight; y++)
{
Row[x].Column[y].Tile = Convert.ToInt32(filepos[x,y]);
}
}
You don't want to use 2D arrays because of heavy performance issues.
Also, you probably want to use a separator between tile numbers, like this
1,1,1,1
1,0,1,1
for two reasons; 1 you can use more than 10 different tiles, and 2 you can then use String.Split() and Int.Parse() in order to get your tile IDs and build your map.
In order to use a 1D array, instead of doing myMap[x][y], you do myMap[y*mapWidth+x].
I switched to using XML so that I could more easily edit and read the file. That also gave me a great way of indicating the end of a row of tiles in my map as well as an easy way of identifying up front just how many columns/rows my map had prior to the reader loading it in the game.
The sample for the code can be found on my site in the "Looks Level to Me" sample and it may be that it will help get some ideas for how to change your current approach.
While the commas are the best approach you can also use .substring to take it apart if things are of fixed length.

How to find a random point in a quadrangle?

I have to be able to set a random location for a waypoint for a flight sim. The maths challenge is straightforward:
"To find a single random location within a quadrangle, where there's an equal chance of the point being at any location."
Visually like this:
An example ABCD quadrangle is:
A:[21417.78 37105.97]
B:[38197.32 24009.74]
C:[1364.19 2455.54]
D:[1227.77 37378.81]
Thanks in advance for any help you can provide. :-)
EDIT
Thanks all for your replies. I'll be taking a look at this at the weekend and will award the accepted answer then. BTW I should have mentioned that the quadrangle can be CONVEX OR CONCAVE. Sry 'bout dat.
Split your quadrangle into two triangles and then use this excellent SO answer to quickly find a random point in one of them.
Update:
Borrowing this great link from Akusete on picking a random point in a triangle.
(from MathWorld - A Wolfram Web Resource: wolfram.com)
Given a triangle with one vertex at
the origin and the others at positions v1
and v2, pick
(from MathWorld - A Wolfram Web Resource: wolfram.com)
where A1
and A2 are uniform
variates in the interval [0,1] , which gives
points uniformly distributed in a
quadrilateral (left figure). The
points not in the triangle interior
can then either be discarded, or
transformed into the corresponding
point inside the triangle (right
figure).
I believe there are two suitable ways to solve this problem.
The first mentioned by other posters is to find the smallest bounding box that encloses the rectangle, then generate points in that box until you find a point which lies inside the rectangle.
Find Bounding box (x,y,width, height)
Pick Random Point x1,y1 with ranges [x to x+width] and [y to y+height]
while (x1 or y1 is no inside the quadrangle){
Select new x1,y1
}
Assuming your quadrangle area is Q and the bounding box is A, the probability that you would need to generate N pairs of points is 1-(Q/A)^N, which approaches 0 inverse exponentially.
I would reccommend the above approach, espesially in two dimensions. It is very fast to generate the points and test.
If you wanted a gaurentee of termination, then you can create an algorithm to only generate points within the quadrangle (easy) but you must ensure the probablity distribution of the points are even thoughout the quadrangle.
http://mathworld.wolfram.com/TrianglePointPicking.html
Gives a very good explination
The "brute force" approach is simply to loop through until you have a valid coordinate. In pseudocode:
left = min(pa.x, pb.x, pc.x, pd.x)
right = max(pa.x, pb.x, pc.x, pd.x)
bottom = min(pa.y, pb.y, pc.y, pd.y)
top = max(pa.y, pb.y, pc.y, pd.y)
do {
x = left + fmod(rand, right-left)
y = bottom + fmod(rand, top-bottom)
} while (!isin(x, y, pa, pb, pc, pd));
You can use a stock function pulled from the net for "isin". I realize that this isn't the fastest-executing thing in the world, but I think it'll work.
So, this time tackling how to figure out if a point is within the quad:
The four edges can be expressed as lines in y = mx + b form. Check if the point is above or below each of the four lines, and taken together you can figure out if it's inside or outside.
Are you allowed to just repeatedly try anywhere within the rectangle which bounds the quadrangle, until you get something within the quad? Might this even be faster than some fancy algorithm to ensure that you pick something within the quad?
Incidentally, in that problem statement, I think the use of the word "find" is confusing. You can't really find a random value that satisfies a condition; the randomizer just gives it to you. What you're trying to do is set parameters on the randomizer to give you values matching certain criteria.
I would divide your quadrangle into multiple figures, where each figure is a regular polygon with one side (or both sides) parallel to one of the axes. For eg, for the figure above, I would first find the maximum rectangle that fits inside the quadrangle, the rectangle has to be parallel to the X/Y axes. Then in the remaining area, I would fit triangles, such triangles will be adjacent to each side of the rectangle.
then it is simple to write a function:
1) get a figure at random.
2) find a random point in the figure.
If the figure chosen in #1 is a rectangle, it should be pretty easy to find a random point in it. The tricky part is to write a routine which can find a random point inside the triangle
You may randomly create points in a bound-in-box only stopping after you find one that it's inside your polygon.
So:
Find the box that contains all the points of your polygon.
Create a random point inside the bounds of the previously box found. Use random functions to generate x and y values.
Check if that point is inside the polygon (See how here or here)
If that point is inside the polygon stop, you're done, if not go to step 2
So, it depends on how you want your distribution.
If you want the points randomly sampled in your 2d view space, then Jacob's answer is great. If you want the points to be sort of like a perspective view (in your example image, more density in top right than bottom left), then you can use bilinear interpolation.
Bilinear interpolation is pretty easy. Generate two random numbers s and t in the range [0..1]. Then if your input points are p0,p1,p2,p3 the bilinear interpolation is:
bilerp(s,t) = t*(s*p3+(1-s)*p2) + (1-t)*(s*p1+(1-s)*p0)
The main difference is whether you want your distribution to be uniform in your 2d space (Jacob's method) or uniform in parameter space.
This is an interesting problem and there's probably as really interesting answer, but in case you just want it to work, let me offer you something simple.
Here's the algorithm:
Pick a random point that is within the rectangle that bounds the quadrangle.
If it is not within the quadrangle (or whatever shape), repeat.
Profit!
edit
I updated the first step to mention the bounding box, per Bart K.'s suggestion.

Finding a Position on a 2D Map that meets several criteria

as my personal project i develop a game to which users can join at any time.
I have a tiled worldmap that is created from a simple Bitmap which has resources at random positions all over the map except for oceans.
When a player joins i want to create his starting position at a place that has at least 1 tile of each of the 4 resources in range (circle with a still to decide diameter, i think about 3-4 tiles) but no ocean tiles (Tile.Type != "ocean") and not conflicting with a field belonging to another player (Tile.Owner == null).
The map size can vary, currently it's 600x450 and it's implemented as a simple Array: Tile[][] with Tile.Resource being either null or having Tile.Resource.Type as a string of the resource name (as it's configurable by plaintext files to fit any scenery i want to put it in, so no built-in enums possible).
I currently have a loop that simple goes through every possible position, checks every field in range and counts the number of each resource field and discards it if there are none for one of them or if one of them belongs to a player or is an ocean field.
I would prefer if it finds a random position but thats not a requirement, mono-compatibility however is a requirement.
What would be the best way to implement an algorithm for that in C#?
Edit
The Area of players can and will increase/change and resources can be used up and may even appear randomly (=> "Your prospectors found a new goldmine") so pre-calculated positions will propably not work.
Instead of looping through all your positions, why don't you loop through all your resources? Your resources are likely to be more scant. Then pick one of the sets of resources that meet your clustering criterion.
You might consider simulated annealing ... it's not very complex to implement. You have a set of criteria with certain weight, and randomly "shake" the position at a certain "temperature" (the higher the temp, the greater the radius the position may randomly move within, from it's previous position), then when it "cools" you measure the value of the position based on the total weights and subtract negative things, like spawning too close to where they died, or next to other players, etc..., if the value is not within a certain range, you decrease the temperature, but "shake" the positions again, cool down, check weights and overall value, repeat until you get an acceptable solution.
Simulated annealing is used in map making, to label cities and features with maximum clarity, while staying within range and minimizing overlap. Since it's a heuristic approach there is no guarantee that there will be an optimal solution, so you keep "lowering the temp" and eventually just choose the best result.
Let's suppose that once your map is created you don't have to create a new one often.
Just add the following to each Tile and calculate them once after your map was generated:
-int NrOceanTiles
-int NrResourceA
-int ...
Now when you want to get a tile you can do it quite a bit faster:
IEnumerable<Tiles> goodTiles = tiles.Where(tile => tile.NrResourceA >= 1 && tile.NrResourceB >= 2);
Tile goodTile = goodTiles.ElementAt(randomI);
Predefined data would still be the best way forward.
As modifying the map size, and adding/losing resources would not happen as often, just update this data table when they do happen. Perhaps you could do the map/resource changes once per day, and have everything done in a daily database update.
In this way, finding a valid location would be far faster than any algorithm you implement to search all the tiles around it.
If the game isn't going to be designed for a huge number of players, most games implement "start spots" on the map. You'd hand-pick them and record the positions in your map somehow, probably similar to how you're implementing the map resources (i.e., on that spot, there exists an item you can pick up, but on top of the tile map).
Since the resources spawn at random, you could either not spawn resources on the start spots (which could be visible or not), or simply not spawn a player at a start spot on which there is a resource (or look within a 9-cell box to find a close alternate location).
Certainly you would want to hold the set of possible starting locations and update it as resources are created and consumed.
It seems like your best bet is to calculate open locations at map generation. Have your start location calculation function optionally take grid location and size or rectangle corners.
Have a list for Free locations and Occupied locations. Player occupies territory? Move resources in range to the Occupied list. Player gets crushed mercilessly? Move resources in range to the Free list. Resource eliminated? Delete any locations that used it in your Open/Occupied lists. Resource added? Recalculate using your effect radius to determine effected area. When your map area expands, just run the initial calculations on the new section of your grid + effect radius and add the new locations.
Then you just have to set the events up and pick a random Free value when someone joins.

Categories

Resources