Maze Recursion and shortest path - c#

I know this isn't perfect, and I know that it isn't near done. The board is a 19 by 19 array, where 1's represent empty squares. Right now, it will go straight down, then go west. If there is a wall to the left of it, then it will have a stack overflow. The reason why is when it trys to 'climb' up the wall, it ends up going back down over and over and crashes. Even if I fix this, though, it wont find the shortest path. The solutions I've found draw paths, not count how many squares it is away.
private static int turnsforshortestmove(Vector2 location, int[,] board, int endrow)
{
if (location.Y == endrow)
{
return 0;
}
if (board[(int)location.X, (int)location.Y - 1] == 1)
{
return 1 + turnsforshortestmove(new Vector2(location.X, location.Y - 2), board, endrow);
}
else if (board[(int)location.X - 1, (int)location.Y] == 1)
{
return 1 + turnsforshortestmove(new Vector2(location.X - 2, location.Y), board, endrow);
}
else if (board[(int)location.X, (int)location.Y + 1] == 1)
{
return 1 + turnsforshortestmove(new Vector2(location.X, location.Y + 2), board, endrow);
}
else if (board[(int)location.X + 1, (int)location.Y ] == 1)
{
return 1 + turnsforshortestmove(new Vector2(location.X + 2, location.Y), board, endrow);
}
return 0;
}

This is a path-finding problem. As SJuan76 has already suggested, Dijkstra's algorithm is the best starting point for this sort of problem.
Given a grid-style map of open/blocked squares where only orthogonal moves (up, down, left and right) are allowed and each move costs the same amount, finding a path from one grid cell to another involves a fairly simple but time-consuming iteration over possible moves.
The basic principle is to create a list of possible moves and process each one looking for the shortest path. In each step you check the possible moves from the current position, check if the target location has been moved to previously, and add the ones that haven't been checked already - or that can be moved to more quickly than the previous check - to the list to be processed. Keep processing the list until you find the location you're aiming for.
How you do this is the fun part.
There are a few things you need to get started on this:
A method for finding possible moves from an arbitrary point in the grid.
A way to track locations you've already visited, and what location they were visited from.
A fast way to figure out the best location to check next.
Given that you're working from a simple square grid, that you're only doing orthogonal moves (up, down, left, right) and that all moves will cost the same, you can gloss over some of the concepts that are not useful in your scenario. So...
Create two collections: one to store the list of locations to process, and one to store the list of visited locations.
Add your starting point to the process list.
While the process list is not empty
Get the next location from the process list
If current location is the target, return the list of previous locations that form the path.
Find available moves from that location, excluding any moves in the visited list
Push all un-visited possible moves into the process list
Eventually, one of two things will happen: either you'll run out of possible moves that haven't already been checked, or you will find your target point.
Here's a structure similar to what I used last time I did path-finding like this:
public struct SearchNode
{
public Vector2 position;
public SearchNode prior;
public int TotalCost;
}
The visited list can be done with a Dictionary:
var visited = new Dictionary<Vector2, SearchNode>();
The process list can be done with a bunch of collection types. The simplest form would be:
var process = new Queue<Vector2>();
Hopefully I've given you something to start with.

Related

Delete point in trail Renderer

I was wondering if there would be a way to delete the last couple of positions/indexes of a trail renderer. I am trying to stop the trail render emission after a bullet collision, but the trail renderer always spawns a couple of indexes too much, and I was wondering if there was a way to delete those indexes.
I have tried setting the positions of newer indexes to equal older indexes, and that worked to some extent but not to the extent that I wanted.
tR = GetComponent<TrailRenderer>();
int positions = tR.positionCount;
for (int i = 0; i < vertsToDelete; i++) {
if (positions - 1 - i - (int)vertsToDelete > 0) {
tR.SetPosition(positions - 1 - i, tR.GetPosition(positions - 1 - i - (int)vertsToDelete));
}
}
This code works mostly except for certain instances when the positions screw up. Thats why i think being able to delete an index would make the process much easier.
It is more efficient to use one single GetPositions call, manipulate the array and write it back completely using one single AddPositions call.
In order to alternate the array you could go through a list which allows dynamically changing the amount of elements more easily.
Start by converting the array to a list using Linq IEnumerable.ToList()
var positions = new Vector3[tr.positionCount];
tr.GetPositions(positions);
var positionsList = positions.ToList();
then remove an element by index using List<T>.RemoveAt(int index)
positionsList.RemoveAt(indexToRemove);
or remove multiple sequential elements using List<T>.RemoveRange(int startIndex, int amount)
positionsList.RemoveRange(startIndex, amountToRemove);
And finally convert it back to the required arrays using List<T>.ToArray()
tR.Clear();
tR.AddPositions(positionsList.ToArray());
For anyone still searching for this.
I had an issue just like that, my Trail Renderer was drawing some artifact when I used the Floating Origin on it (even when I turned emission off, it was like it had a delay on turning off).
After 2 weeks trying many things and searching I solved this in the most ridiculous way:
//I have this at the beginning os my class:
//public TrailRenderer trailRenderer;
//and this declared at start:
//trailRenderer = trailRenderer.GetComponent<TrailRenderer>();
int trailSize = trailRenderer.positionCount;
float distance = Vector3.Distance(trailRenderer.GetPosition(trailSize - 1), (trailRenderer.GetPosition(trailSize - 2)));
Debug.Log("Distance: " + distance);
if (distance > 90f)
{
trailRenderer.SetPosition(trailSize - 1, trailRenderer.transform.position);
}
This verify the wrong Draw (in my case is just the last point) and get it back to my trail renderer transform, preventing any artifacts my floating origin may cause if it causes any. That's way better than use a for to verify every position since I only have an issue with the last one. Just adapt that to your needs :)

How to properly check the available path on a maze [duplicate]

What are the possible ways to solve a maze?
Ive got two ideas, but I think they are not very elegant.
Base situation: We have a matrix, and the elements in this matrix are ordered in a way that it represents a maze, with one way in, and one out.
My first idea was to send a robot through the maze, following one side, until it's out of the maze. I think this is a very slow solution.
The second one passes through every successive item marked with 1, checks where it can go (up, right, down, left) chooses one way and it continues its path there. This is even slower than the first one.
Of course it's a bit faster if I make the two bots multi-threaded at every junction, but thats also not the best way.
There needs to be better solutions to send a bot through a maze.
EDIT
First: Thanks for the nice answers!
The second part of my question is: What to do in the case if we have a multi-dimensional graph? Are there special practices for that, or is the answer of Justin L. usable for that too?
I think it's not the best way for this case.
The third question:
Which of these maze solver algorithms is/are the fastest? (Purely hypothetically)
You can think of your maze as a tree.
A
/ \
/ \
B C
/ \ / \
D E F G
/ \ \
H I J
/ \
L M
/ \
** O
(which could possibly represent)
START
+ +---+---+
| A C G |
+---+ + + +
| D B | F | J |
+---+---+ +---+---+
| L H E I |
+---+ +---+---+
| M O |
+ +---+
FINISH
(ignoring left-right ordering on the tree)
Where each node is a junction of paths. D, I, J, L and O are dead ends, and ** is the goal.
Of course, in your actual tree, each node has a possibility of having as many as three children.
Your goal is now simply finding what nodes to traverse to to find the finish. Any ol' tree search algorithm will do.
Looking at the tree, it's pretty easy to see your correct solution by simply "tracing up" from the ** at the deepest part of the tree:
A B E H M **
Note that this approach becomes only slightly more complicated when you have "loops" in your maze (i.e., when it is possible, without backtracing, you re-enter a passage you've already traversed through). Check the comments for one nice solution.
Now, let's look at your first solution you mentioned, applied to this tree.
Your first solution is basically a Depth-First Search, which really isn't that bad. It's actually a pretty good recursive search. Basically, it says, "Always take the rightmost approach first. If nothing is there, backtrack until the first place you can go straight or left, and then repeat.
A depth-first search will search the above tree in this order:
A B D (backtrack) E H L (backtrack) M ** (backtrack) O (backtrack thrice) I
(backtrack thrice) C F (backtrack) G J
Note that you can stop as soon as you find the **.
However, when you actually code a depth-first search, using recursive programming makes makes everything much easier. Even iterative methods work too, and you never have to explicitly program how to backtrack. Check out the linked article for implementations.
Another way of searching a tree is the Breadth-First solution, which searches through trees by depth. It'd search through the above tree in this order:
A (next level) B C (next level) D E F G (next level)
H I J (next level) L M (next level) ** O
Note that, due to the nature of a maze, breadth-first has a much higher average amount of nodes it checks. Breadth-first is easily implementing by having a queue of paths to search, and each iteration popping a path out of a queue, "exploding it" by getting all of the paths that it can turn into after one step, and putting those new paths at the end of the queue. There are no explicit "next level" commands to code, and those were just there to aid in understanding.
In fact, there is a whole expansive list of ways to search a tree. I've just mentioned the two simplest, most straightforward way.
If your maze is very, very long and deep, and has loops and crazies, and is complicated, I suggest the A* algorithm, which is the industry standard pathfinding algorithm which combines a Breadth-First search with heuristics...sort of like an "intelligent breadth-first search".
It basically works like this:
Put one path in a queue (the path where you only walk one step straight into the maze). A path has a "weight" given by its current length + its straight-line distance from the end (which can be calculated mathematically)
Pop the path with the lowest weight from the queue.
"Explode" the path into every path that it could be after one step. (i.e., if your path is Right Left Left Right, then your exploded paths are R L L R R and R L L R L, not including illegal ones that go through walls)
If one of these paths has the goal, then Victory! Otherwise:
Calculate the weights of the exploded paths, and put all of them back into the queue (not including the original path)
Sort the queue by weight, lowest first. Then repeat from Step #2
And that's A*, which I present specially highlighted because it is more or less the industry standard pathfinding algorithm for all applications of pathfinding, including moving from one edge of the map to another while avoiding off-road paths or mountains, etc. It works so well because it uses a shortest possible distance heuristic, which gives it its "intelligence". A* is so versatile because, given any problem, if you have a shortest possible distance heuristic available (ours is easy -- the straight line), you can apply it.
BUT it is of great value to note that A* is not your only option.
In fact, the wikipedia category of tree traversal algorithms lists 97 alone! (the best will still be on this page linked earlier)
Sorry for the length =P (I tend to ramble)
Lots of maze-solving algorithms exist:
http://en.wikipedia.org/wiki/Maze_solving_algorithm
http://www.astrolog.org/labyrnth/algrithm.htm#solve
For a robot, Tremaux's algorithm looks promising.
An interesting approach, at least I found it interesting, is to use cellular automata. In short a "space" cell surrounded by 3 "wall" cells turns into a "wall" cell. At the end the only space cells left are the ones on route to the exit.
If you look at the tree Justin put in his answer then you can see that leaf nodes have 3 walls. Prune the tree until you have a path.
This is one of my favorite algorithms ever....
1) Move forward
2) Are you at a wall?
2a) If yes, turn left
3) Are you at the finish?
3a) If no, go to 1
3b) If yes, solved
How about building a graph out of your Matrix and using Breadth First Search, Depth First Search or Dijkstras Algorithm?
I had a similar problem in one of my University Comp. Sci. courses. The solution we came up with was to follow the left hand wall (right hand wall will work just as well). Here is some pseudocode
While Not At End
If Square To Left is open,
Rotate Left
Go Forward
Else
Rotate Right
End If
Wend
That's basically it. The complex part is keeping track of which direction your facing, and figuring out which grid position is on your left based on this direction. It worked for any test case I put up against it. Interesting enough the Professors solution was something along the lines of:
While Not At End
If Can Go North
Go North
ElseIf Can Go East
Go East
ElseIf Can Go South
Go South
ElseIf Can Go West
Go West
EndIf
Wend
Which will work well for most simple mazes, but fails on the a maze that looks like the following:
SXXXXXXXXXXXXX
X X
X X
X X
XXX X
X X X
X XXXXXXXXXXX XXXE
X X
XXXXXXXXXXXXXXXXXXX
With S and E being the start and end.
With anything that doesn't follow the wall, you end up having to keep a list of the places you have been, so that you can backtrack if necessary, when you fall into a dead end, and so that you don't get caught in a loop. If you follow the wall, there's no need to keep track of where you've been. Although you won't find the most optimal path through the maze, you will always get through it.
This is a very simple representation to simulate maze in C++ :)
#ifndef vAlgorithms_Interview_graph_maze_better_h
#define vAlgorithms_Interview_graph_maze_better_h
static const int kMaxRows = 100;
static const int kMaxColumns = 100;
class MazeSolver
{
private:
char m_matrix[kMaxRows][kMaxColumns]; //matrix representation of graph
int rows, cols; //actual rows and columns
bool m_exit_found;
int m_exit_row, m_exit_col;
int m_entrance_row, m_entrance_col;
struct square //abstraction for data stored in every verex
{
pair<int, int> m_coord; //x and y co-ordinates of the matrix
square* m_parent; //to trace the path backwards
square() : m_parent(0) {}
};
queue<square*> Q;
public:
MazeSolver(const char* filename)
: m_exit_found(false)
, m_exit_row(0)
, m_exit_col(0)
, m_entrance_row(0)
, m_entrance_col(0)
{
ifstream file;
file.open(filename);
if(!file)
{
cout << "could not open the file" << endl << flush;
// in real world, put this in second phase constructor
}
init_matrix(file);
}
~MazeSolver()
{
}
void solve_maze()
{
//we will basically use BFS: keep pushing squares on q, visit all 4 neighbors and see
//which way can we proceed depending on obstacle(wall)
square* s = new square();
s->m_coord = make_pair(m_entrance_row, m_entrance_col);
Q.push(s);
while(!m_exit_found && !Q.empty())
{
s = Q.front();
Q.pop();
int x = s->m_coord.first;
int y = s->m_coord.second;
//check if this square is an exit cell
if(x == m_exit_row && y == m_exit_col)
{
m_matrix[x][y] = '>'; // end of the path
m_exit_found = true;
//todo: try breaking? no= queue wont empty
}
else
{
//try walking all 4 neighbors and select best path
//NOTE: Since we check all 4 neighbors simultaneously,
// the path will be the shortest path
walk_path(x-1, y, s);
walk_path(x+1, y, s);
walk_path(x, y-1, s);
walk_path(x, y+1, s);
}
} /* end while */
clear_maze(); //unset all previously marked visited shit
//put the traversed path in maze for printing
while(s->m_parent)
{
m_matrix[s->m_coord.first][s->m_coord.second] = '-';
s = s->m_parent;
} /* end while */
}
void print()
{
for(int i=0; i<rows; i++)
{
for(int j=0; j<cols; j++)
cout << m_matrix[i][j];
cout << endl << flush;
}
}
private:
void init_matrix(ifstream& file)
{
//read the contents line-wise
string line;
int row=0;
while(!file.eof())
{
std::getline(file, line);
for(int i=0; i<line.size(); i++)
{
m_matrix[row][i] = line[i];
}
row++;
if(line.size() > 0)
{
cols = line.size();
}
} /* end while */
rows = row - 1;
find_exit_and_entry();
m_exit_found = false;
}
//find and mark ramp and exit points
void find_exit_and_entry()
{
for(int i=0; i<rows; i++)
{
if(m_matrix[i][cols-1] == ' ')
{
m_exit_row = i;
m_exit_col = cols - 1;
}
if(m_matrix[i][0] == ' ')
{
m_entrance_row = i;
m_entrance_col = 0;
}
} /* end for */
//mark entry and exit for testing
m_matrix[m_entrance_row][m_entrance_col] = 's';
m_matrix[m_exit_row][m_exit_col] = 'e';
}
void clear_maze()
{
for(int x=0; x<rows; x++)
for(int y=0; y<cols; y++)
if(m_matrix[x][y] == '-')
m_matrix[x][y] = ' ';
}
// Take a square, see if it's the exit. If not,
// push it onto the queue so its (possible) pathways
// are checked.
void walk_path(int x, int y, square* parent)
{
if(m_exit_found) return;
if(x==m_exit_row && y==m_exit_col)
{
m_matrix[x][y] = '>';
m_exit_found = true;
}
else
{
if(can_walk_at(x, y))
{
//tag this cell as visited
m_matrix[x][y] = '-';
cout << "can walk = " << x << ", " << y << endl << flush;
//add to queue
square* s = new square();
s->m_parent = parent;
s->m_coord = make_pair(x, y);
Q.push(s);
}
}
}
bool can_walk_at(int x, int y)
{
bool oob = is_out_of_bounds(x, y);
bool visited = m_matrix[x][y] == '-';
bool walled = m_matrix[x][y] == '#';
return ( !oob && !visited && !walled);
}
bool is_out_of_bounds(int x, int y)
{
if(x<0 || x > rows || y<0 || y>cols)
return true;
return false;
}
};
void run_test_graph_maze_better()
{
MazeSolver m("/Users/vshakya/Dropbox/private/graph/maze.txt");
m.print();
m.solve_maze();
m.print();
}
#endif
Just an idea. Why not throw some bots in there in the monte carlo fashion.
Let's call the first generation of bots gen0.
We only keep the bots from gen0 that have some continuous roads in this way:
-from the start to some point
or -from some point to the end
We run a new gen1 of bots in new random dots, then we try to connect the roads of the bots of gen1 with those of gen0 and see if we get a continous road from start to finish.
So for genn we try to connect with the bots form gen0, gen1, ..., genn-1.
Of course a generation lasts only a feasibil finit amount of time.
I don't know if the complexion of the algorithm will prove to be practical for small data sets.
Also the algorithm assumes we know start and finish points.
some good sites for ideas:
http://citeseerx.ist.psu.edu/
http://arxiv.org/
If the robot can keep track of its location, so it knows if it has been to a location before, then depth-first search is the obvious algorithm. You can show by an adversarial argument that it is not possible to get better worst-case performance than depth-first search.
If you have available to you techniques that cannot be implemented by robots, then breadth-first search may perform better for many mazes, as may Dijkstra's algorithm for finding the shortest path in a graph.
Same answer as all questions on stack-overflow ;)
Use vi!
http://www.texteditors.org/cgi-bin/wiki.pl?Vi-Maze
It's truly fascinating to see a text editor solve an ascii-maze, I'm sure the emacs guys have an equivalent ..
there are many algorithms, and many different settings that specify which algorithm is best.
this is just one idea about an interesting setting:
let's assume you have the following properties...
you move a robot and you want to minimize its movement, not its CPU usage.
that robot can either inspect only its neighbouring cells or look along corridors either seeing or not seeing cross-ways.
it has GPS.
it knows the coordinates of its destination.
then you can design an A.I. which...
draws a map – every time it receives new information about the maze.
calculates the minimal known path lengths between all unobserved positions (and itself and the destination).
can prioritize unobserved positions for inspection based upon surrounding structures. (if it is impossible to reach the destination from there anyway...)
can prioritize unobserved positions for inspection based upon direction and distance to destination.
can prioritize unobserved positions for inspection based upon experience about collecting information. (how far can it see on average and how far does it have to walk?)
can prioritize unobserved positions to find possible shortcuts. (experience: are there many loops?)
This azkaban algorithm might also help you,
http://journals.analysisofalgorithms.com/2011/08/efficient-maze-solving-approach-with.html
The best way to solve a maze is to use a connectivity algorithm such as union-find which is a quasi-linear time algorithm assuming path compression is done.
Union-Find is a data structure that tells you whether two elements in a set are transitively connected.
To use a union-find data structure to solve a maze, first the neighbor connectivity data is used to build the union-find data structure. Then the union find is compressed. To determine whether the maze is solvable the entrance and exit values are compared. If they have the same value, then they are connected and the maze is solvable. Finally, to find a solution, you start with the entrance and examine the root associated with each of its neighbors. As soon as you find a previously unvisited neighbor with the same root as the current cell, you visit that cell and repeat the process.
The main disadvantage of this approach is that it will not tell you the shortest route through the maze, if there is more than one path.
Not specifically for your case, but I've come across several programming contest questions where I found the Lee's algorithm quite handy to code up quickly. Its not the most efficient for all cases, but is easy to crank out. Here's one I hacked up for a contest.

Removing objects from SortedSet

I've been looking at this for far too long, hopefully someone can help.
The general jist is;
I have a SortedSet of player objects (sorted by Y position), each player contains a sortedset of 'Polygon' objects which in turn contain a list of three point objects, obviously forming a triangle.
This polygon set is sorted by area of said polygon, smallest to largest.
What I want to do is iterate through the set of players and;
I. Assign the point at index[1] (the 'peak' of the triangle) from the first object in the polygon SortedSet to another variable inside the player.
II. Once the point at index[1] has been assigned to a player, I need to iterate through every player and remove any instance of a polygon that contains the current point at ElementAt(1) so no subsequent players in the 'parent' iteration can be assigned a polygon that contains that Point.
It's probably important to note that the point at polygonPoints[1] is based on the enemy position so they're consistent across all players, this is why I'm trying to use it as my 'reference' point to remove any polygon objects that contain said point.
It's a convoluted explanation but hopefully you've been able to follow.
Right now I've got the first part working, but the second part is proving to be a serious pain - I've tried remove and removewhere (using criteria that should remove everything) and the set stubbornly stays the same length no matter what I do.
For reference here's the latest iteration of code that I'm wrangling with.
List<PointF> duplicates = new List<PointF>();
foreach (Player p in playerSet)
{
//Assign lowest cost polygon to current player, then remove all polygons containing the point at p.triangleSet.ElementAt(0).polygonPoints[1] from every other player so it can't be assigned to any subsequent player.
p.currentAttackingPoint = p.triangleSet.ElementAt(0).polygonPoints[1];
//I use this method to keep track of which 'attacking points' have been assigned.
add(p.currentAttackingPoint);
//Then, in theory, I use this method to remove all polygons that contain any point in the duplicates list from every other player. Obviously this is proving to be the troublesome aspect.
remove(duplicates);
}
...
private void add(PointF i)
{
duplicates.Add(i);
}
private void remove(List<PointF> dupes)
{
foreach(PointF p in dupes)
{
foreach (Player l in playerSet)
{
//Outputs 100
textBox3.AppendText(l.triangleSet.Count.ToString() + "\r\n");
l.triangleSet.RemoveWhere(e => e.polygonPoints[1] == p);
//l.pressingTriangleSet.RemoveWhere(e => e.polygonPoints[1].X > 0); --Doesn't work either, despite it being true of every point in the set.
//Still 100
textBox3.AppendText(l.triangleSet.Count.ToString() + "\r\n");
}
}
}
Please bear in mind that the set of polygons inside each player, whilst the same length all have largely different content, they're based on the position of the player the position of the enemy and another arbitrary fact about the game state - so I can't just remove the first polygon from each player's set.
I'm thinking about converting each set to a list once they've been created because this is bizarre, it's got to be some order of operations issue that I'm overlooking.
Purely for my own sanity I knocked this out http://pastie.org/private/ikq5lhhacxxvfaoervauw and it works exactly as you'd expect it to.
EDIT - For anyone who finds this looking for a solution to a similar problem, don't waste your time using sortedsets to sort a collection of objects, you can use OrderBy to achieve the same thing with lists.
This is a longshot but sometimes comparing floats and double is a bit tricky because of precision. For example a point 1.0 might be represented as 1.0000001 because of rounding errors. It is possible that your points are not compared correctly
Try something like
e.polygonPoints[1].X - p.X < 0.00001
&& p.X - e.polygonPoints[1].X < 0.00001
&& e.polygonPoints[1].Y - p.Y < 0.00001
&& p.Y - e.polygonPoints[1].Y < 0.00001
I would have assumed that PointF equality operator would take care of that but it may not

Path-finding with Depth Limited Search (Unity/C#~)

I am making a grid based game where characters can move their units turn by turn. Each character has a move amount (for example 4 - where they can move 4 tiles).
I've implemented a DLS (which is limited to their move amount). Using this, all available tiles that the player can move to are highlighted.
This works fine. However, I would like modify the algorithm (or implement a specific one) to work out the route. For example, the player wants to G3 - what route should the character take (forward 1, left 1 etc).
Bearing in mind that each tile can have different properties (such as some may be blocked).
Code
private void DLS(int x, int z, int depth, float jump, float previousHeight)
{
int resistance=1;
if (depth >=0)
{
tiles[x,z].GetComponentInChildren<CheckIfClicked>().Selected();
if (x+1 < 25)
{
CheckTile(x+1, z, depth, jump, previousHeight);
}
if (x-1 >= 0)
{
CheckTile(x-1, z, depth, jump, previousHeight);
}
if (z+1 <25)
{
CheckTile(x, z+1, depth, jump, previousHeight);
}
if (z-1 >=0)
{
CheckTile(x, z-1, depth,jump, previousHeight);
}
}
}
private void CheckTile(int x, int z, int depth, float jump, float previousHeight)
{
float tileHeight = tiles[x, z].GetComponent<TileDimensions>().height;
float difference = tileHeight - previousHeight;
if (difference<0) difference*=-1;
if (!tiles[x, z].GetComponentInChildren<CheckIfClicked>().occupied && difference<jump)
{
int resistance = tiles[x, z].GetComponent<TileDimensions>().getResistance();
if (resistance<0) resistance=1;
DLS(x, z, depth-resistance, jump, tileHeight);
}
}
My code takes advantage of the different tile properties (such as the tiles resistance (some tiles limit the movement) and height (you can only climb so far up)).
If you wish to use a more efficient algorithm there are two suggested implementations:
A star. A star is best used when you know the destination you want to travel to but you need to find the way of getting there. e.g if you clicked in tile G3, and were in G1, you know where you need to go. A star takes advantage of a heuristic which tries to "guess" how much further you have to go. This means that when searching for potential routes, A star will attempt to take what should be the shortest route before attempting to look at other routes. There's a fantastic tutorial here: Link
Djikstra's algorithm. This is better used when you don't know where you're going but you want to find the nearest node that contains a certain "thing", i.e. you might want your A.I to search for the nearest health pack in an FPS. I've not implemented Djikstra's algorithm before but there are plenty of tutorials available online.
With both you can add properties such as resistance on certain tiles and whatever else.
Since your algorithm is working, I would like to give you a few suggestions to enhance your code, both involve using list/dictionary.
Perform path searching once
If you can highlight every movable tiles, that means you are able to traverse paths originating from a source tile to different destination tiles, which implies you are validating the tiles one by one until the character cannot make additional moves. Therefore, you can store the results into a dictionary of "destination tile - lists" pairs. Whenever you need to retrieve a path going to a particular tile, just get the previously stored path.
Perform path searching twice
As the aforementioned approach may take up a lot of memory usage, you can run your path-searching algorithm once more when the player makes a move. Time spent for the second execution should be less than the first one, as the player has specified certain tile to be the destination of the path. During the second search, keep updating a list/dictionary while recursively executing the path-searching functions. Have every valid intermediate tile saved to the list/dictionary, then you can get the path after the search.
If you are developing games on mobile platforms, even a little bit of memory usage does matter. I would then suggest to perform path searching twice as long as the time spent for searching is acceptable to players.
Of course, it is always a good practice to monitor the performance via the Unity Profiler to check which approach suits your needs in a better manner.

Check for closed path in numerical heightmap

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.

Categories

Resources