Ok I am trying to make a dynamic pathing system so the player can move from point A to point B without having predefined paths. Note this game is all text based no graphics. The player can move in 10 directions: up, down, n, e, s, w, sw, se, nw and ne.
The map of the entire world is in a database, each row of the database contains a room or a node, each room/node has directions it's capable of going. The room may not be sequential persay. An Example:
Map Number, Room Number, Direction_N, Direction_S, Direction_E, Direction_W, etc.
1 1 1/3 1/100 1/1381 1/101
The Direction_N indicates it goes to Map 1 Room 3, Direction_S Map 1 Room 100, etc...
Ok, I reworked the code with suggestions (thank you guys by the way!) here is revised code. It seems to find the rooms now, even vast distances! But now the issue is finding the shortest path to the destination, I tried traversing the collection but the path is not coming out right...
In the image link below, I have start point in red square in center and stop point at red square at upper left. This returns visitedStartRooms = 103 and visitedStopRooms = 86, when it's only about 16 rooms.
Quess my missing piece of the puzzle is I am not sure how to sort out the rooms in those collection to gain the true shortest route.
Example of map
Here is the new code
public void findRoute(ROOM_INFO startRoom, ROOM_INFO destinationRoom)
{
Dictionary<ROOM_INFO, bool> visitedStartRooms = new Dictionary<ROOM_INFO, bool>();
Dictionary<ROOM_INFO, bool> visitedStopRooms = new Dictionary<ROOM_INFO, bool>();
List<string> directions = new List<string>();
startQueue.Enqueue(startRoom); // Queue up the initial room
destinationQueue.Enqueue(destinationRoom);
visitedStartRooms.Add(startRoom, true);// say we have been there, done that
visitedStopRooms.Add(destinationRoom, true);
string direction = "";
bool foundRoom = false;
while (startQueue.Count != 0 || destinationQueue.Count != 0)
{
ROOM_INFO currentStartRoom = startQueue.Dequeue(); // remove room from queue to check out.
ROOM_INFO currentDestinationRoom = destinationQueue.Dequeue();
ROOM_INFO startNextRoom = new ROOM_INFO();
ROOM_INFO stopNextRoom = new ROOM_INFO();
if (currentStartRoom.Equals(destinationRoom))
{
break;
}
else
{
// Start from destination and work to Start Point.
foreach (string exit in currentDestinationRoom.exitData)
{
stopNextRoom = extractMapRoom(exit); // get adjacent room
if (stopNextRoom.Equals(startRoom))
{
visitedStopRooms.Add(stopNextRoom, true);
foundRoom = true;
break;
}
if (stopNextRoom.mapNumber != 0 && stopNextRoom.roomNumber != 0)
{
if (!visitedStopRooms.ContainsKey(stopNextRoom))
{
if (visitedStartRooms.ContainsKey(stopNextRoom))
{
foundRoom = true;
}
else
{
destinationQueue.Enqueue(stopNextRoom);
visitedStopRooms.Add(stopNextRoom, true);
}
}
}
}
if (foundRoom)
{
break;
}
}
// start from the start and work way to destination point
foreach (string exit in currentStartRoom.exitData)
{
startNextRoom = extractMapRoom(exit); // get adjacent room
if (startNextRoom.Equals(destinationRoom))
{
visitedStartRooms.Add(startNextRoom, true);
foundRoom = true;
break;
}
if (startNextRoom.mapNumber != 0 && startNextRoom.roomNumber != 0)
{
if (!visitedStartRooms.ContainsKey(startNextRoom))
{
if (visitedStopRooms.ContainsKey(startNextRoom))
{
foundRoom = true;
break;
}
else
{
startQueue.Enqueue(startNextRoom);
visitedStartRooms.Add(startNextRoom, true);
}
}
}
}
if (foundRoom)
{
break;
}
}
}
You have a good start. There are a few basic improvements that will help. First, to be able to reconstruct your path, you should create a new data structure to store visited rooms. But for each entry, you want to store the room, plus the previous room in the path back to the starting point. A good data structure for this would be a dictionary where the key is the room identifier, and the value is the previous room identifier. To know if you've visited a room, you look to see if it exists in that data structure, not your openList queue. With this new structure, you can properly check if you've visited a room, and you can reconstruct the path back by repeatedly looking up the previous room in the same structure until you get to the origination.
The second improvement will increase the performance quite a bit. Instead of just doing a breadth-first search from the start point until you bump into the destination, as you currently do, instead create matching data structures like you have for the start room search, but have them be for the destination room. After you've looked one room away from the start, look one room away from the destination. Repeat this...two rooms away from start, then two rooms away from destination.. etc., working your way out, until you discover a room that has been visited by both your search from start and your search from destination. Build the path from this room back to the start, and back to the destination, and that will be your shortest path.
The problem you are trying to solve is the shortest path problem with unweighted edges or where the weights of all edges are equal. The weight of an edge is the time/cost to move from one room to another. If the cost to move from one room to another varies depending on which pair of rooms you're talking about, then the problem is more complicated, and the algorithm you started with and for which I've suggested modifications, will not work as it is. Here are some links about it:
Shortest path (fewest nodes) for unweighted graph
http://en.wikipedia.org/wiki/Shortest_path_problem
You may also be interested in the A* algorithm which uses a different approach. It uses a hueristic approach to concentrate the search in a subset of the solution space more likely to contain the shortest path. http://en.wikipedia.org/wiki/A%2a_search_algorithm
But A* is probably overkill in your case since the weight of all edges is the same between all rooms.
Related
I don't have any code to share at this point, but I'm trying to figure out how to solve my issue.. I was hoping some of you might have some advice.
I'm building an app where I get the user's lat/long from geolocation and if they are in an predetermined area with a radius they can post data to the server, but not if they aren't in an area that I specified is allowed.. Here is an image for example:
So in this example, the user could post if they are in the radius of one of the circles but not if they aren't.
I would also have to fetch the data based off of which circle they are in..
What I'm wondering is, how would I specify where these radius' exist and does this scale easily? If I needed to add 10-30 new locations would that be easy to do?
You have the user location from the device and as you have the circles; you have the circle centre with their radius. At time of posting, you check the distance from the user location to the circle centre and enumerate thought the circle locations. if the distance is within the radius, they can post if not, not.
var radius = 100 //example
let canPostLocations = [
CLLocation1,
CLLocation2
]
func isInRange() -> Bool {
for canPost in canPostLocations {
let locationDistance = location.distance(from: canPost)
if (locationDistance < radius) {
return true
}
}
return false
}
use as:
var mayPost = false
var userLocation: CLLocation! = nil
if userLocation != nil {
mayPost = InRange(location: userLocation).isInRange()
}
I've a network graph
Now I've some connected nodes and as you can see most of the nodes only have one connected node that is their degree is 1. Now I'd like to remove such nodes to clear the clutter. Unable to find how to since last 2 days. No such helper functions available in visjs documentation. Would appreciate help.
I believe the algorithm suggested by the 1st answer -by macramole- (before updates) would actually hide the non-connected nodes (degree 0), instead of the ones with degree 1.
I would probably just iterate over all the edges in the network while keeping 'degree' counters for each node that is an endpoint in the edge you are visiting (you can obtain these nodes by grabbing the edge.from and edge.to values, as shown above). You would increment the degree counter for a node, whenever the node is 'hit' in this search through the edges.
Eventually you'll end up with the degree value for each node in the network, at which point you can decide which ones to hide.
Updating this answer now to include my suggested code (note: nodes and edges are vis DataSet instances):
Example code:
var nodeToDegrees = {}; // keeps a map of node ids to degrees
var nodeFrom, nodeTo;
for (edge in edges) {
nodeFrom = edge.from;
nodeTo = edge.to;
nodeToDegrees[nodeFrom] = nodeToDegrees[nodeFrom] ? nodeToDegrees[nodeFrom] + 1 : 0;
nodeToDegrees[nodeTo] = nodeToDegrees[nodeTo] ? nodeToDegrees[nodeTo] + 1 : 0;
}
for (node in nodes) {
if (nodeToDegrees[node.id] = 1) nodes.update([{node.id, hidden: true}]);
}
This might work:
var DEGREES_HIDDEN = 1;
for ( var node of nodes ) {
node.cantLinks = 0;
for ( var link of links ) {
if ( link.from == node.id || link.to == node.id ) {
node.cantLinks++;
}
}
}
for ( var node of nodes ) {
if ( node.cantLinks <= DEGREES_HIDDEN ) {
node.hidden = true;
}
}
Nodes and links are arrays not vis.DataSet, I create the latter after doing that.
Doesn't look very nice perfomance wise but it does get the job done. Hope you find it useful.
I've a graph in OrientDB with vertexes Area & Place with edges visited. Your average path goes Area > visited > Place > visited > Place > visited > Place > visited > Place and so on. It tracks which places user visited after the previous one. visited contains YYYYmmDD datestamp.
I'm trying to find out all Area vertexes based on arbitrary Place vertexes for certain day - i.e. I want to know from which areas users came to a certain place after visiting certain place first.
Traversing from any single Place in the path would be easy but I need to to follow the path for only for a specific datestamp. What I did was that I created index for datestamp to get day's visited edges quickly and then finds the one that has in to the first Place. However now I can't figure out how to create a fast query that finds all Area vertexes based on the first Place while also making sure that the path contains second Place as well. I can get path between first and second Place via shortestPath() but I still have the same problem with extending the path to include Area vertexes.
I found some theory on the subject but if somebody could point me to the right direction how to use OrientDB to do this instead of pure graph theory I would really appreciate it - I've been working on this for the past week now. Originally this was done via bruteforce by traversing everything and then selecting but as the database grows it's not obviously sustainable.
I created the three Vertices 'Area', 'Place' and 'User' and the two Edges 'visited' and 'placed' where datestamp is a property on the edge 'visited.
In this way you don't have to insert everytime the User as a property on the edge.
Edit
Try this JavaScript function that has three parameters(places,date,propertyPlace)
var g=orient.getGraph();
var myPlaces=places.substring(1,places.length-1).split(",");
var b=g.command("sql","select from Area");
var result=[];
if(checkPlaces){
for(i=0;i<b.length;i++){
var listPlaces=[];
for(ind=0;ind<myPlaces.length;ind++){
listPlaces.push(myPlaces[ind]);
}
if(search(b[i],listPlaces)){
result.push(b[i]);
}
}
}
return result;
function checkPlaces() {
for(index=0;index<myPlaces.length;index++){
var place=g.command("sql","select from Place where "+ propertyPlace + "='"+myPlaces[index]+"'");
if(place.length==0){
return false;
}
}
return true;
}
function checkDate(edge){
var datestamp=edge.getRecord().field("datestamp");
var year=datestamp.getYear()+1900;
var month=datestamp.getMonth()+1;
var day=datestamp.getDate();
var app=date.split("-");
var myYear=parseInt(app[0]);
var myMonth=parseInt(app[1]);
var myDay=parseInt(app[2]);
if(year==myYear && month==myMonth && day==myDay){
return true;
}
return false;
}
function search(v,places){
var edge=v.getRecord().field("out_visited");
if(edge!=null){
var edgeIterator=edge.iterator();
while(edgeIterator.hasNext()){
var edge = edgeIterator.next();
if (checkDate(edge)) {
var v1 = edge.field("in");
if(v1!=null){
var name = v1.field(propertyPlace);
for(j=0;j<places.length;j++){
if(name==(places[j])) {
places.splice(j, 1);
break;
}
}
if(places.length==0){
return true;
}
else if(search(v1,places)){
return true;
}
}
}
}
}
return false;
}
Using the following command
select expand(result) from (select myFunction("[place1,place2]","2015-12-03","name") as result)
Let me know if it works
This is not a solution to this exact problem but instead a workaround I came up with. Inspired by Orientdb get last vertex from each path when Traversing by edge property
I changed to structure so that Area is now created per visitation instead of being static and it includes yyyymmdd timestamp also. Now I can use Area to start the query and use visited edges to get Place vertices only for a certain date.
Here's the query:
SELECT $path, $depth FROM (
TRAVERSE * FROM (
SELECT outE('visited') FROM (
SELECT EXPAND(rid) FROM INDEX:area.dt WHERE key = 20151205
)
) WHILE (#class = 'visited' AND dt = 20151205) OR #class = 'place')
WHERE #class = 'place' AND NOT (outE() contains (dt=20151205))
This returns correct paths with vertices and edges so you can verify it's only for a certain day. However note that Area is not contained in the path and I still need to figure out how to do that but if you want, you can just traverse the first visited edge backwards in the path and get it that way.
I have coded a table driven LR(1) parser and it is working very well however I am having a bit of a disconnect on the stage of turing a parse into a syntax tree/abstract syntax tree. This is a project that I m very passionate about but I have really just hit a dead end here. Thank you for your help in advance.
Edit: Also my parser just uses a 2d array and an action object that tells it where to go next or if its a reduction where to go and how many items to pop. I noticed that many people use the visitor pattern. Im not sure how they know what type of node to make.
Here is the pushdown automata for context
while (lexer.hasNext() || parseStack.size() > 0) {
Action topOfStack = parseStack.peek();
token = parseStack.size() > 0 ? lexer.nextToken() : new Token(TokenType.EOF, "EOF");
topOfStack.setToken(token);
int row = topOfStack.getTransitionIndex();
int column = getTerminalIndex(token.getLexeme());
column = token.getType() == TokenType.IDENTIFIER
&& !terminalsContain(token.getLexeme()) ? 0 : column;
Action action = actionTable[row][column];
if (action instanceof Accept) {
System.out.println("valid parse!!!!!!");
} else if (action instanceof Reduction) {
Reduction reduction = (Reduction) action;
popStack(parseStack, reduction.getNumberOfItemsToPop());
column = reduction.getTransitionIndex();
row = parseStack.peek().getTransitionIndex();
parseStack.push(new Action(gotoTable[row][column]));
lexer.backupTokenStream();
} else if (action != null) {
parseStack.push(actionTable[row][column]);
} else {
System.out.println("Parse error");
System.out.println("On token: " + token.getLexeme());
break;
}
Each reduction in the LR parsing process corresponds to an internal node in the parse tree. The rule being reduced is the internal AST node, and the items popped off the stack correspond to the children of that internal node. The item pushed for the goto corresponds to the internal node, while those pushed by shift actions correspond to leaves (tokens) of the AST.
Putting all that together, you can easily build an AST by createing a new internal node every time you do a reduction and wiring everything together appropriately.
I have a 2D array structure to represent a grid of tiles that is a part of the game I am making. One aspect of the game is that the grid is filled in in a somewhat random fashion, based on analysis of a text file. Right from the outset though, I already realised that just leaving it be pretty much randomly done like this without sticking in some kind of validity checks or prevention mechanism, to stop really badly configured grid from forming, would not work out. The main problem I want to avoid is too many tiles that would be untraversable being close together, potentially severing chunks of the grid from the rest.
The idea I came up with to try avoid some really bad grids is to check when assigning a tile value to each "grid square" during generation with logic like this
if (tileBeingInserted.isTraversable()) {
//all is well
return true;
} else {
//we may have a problem, are there too many untraversables nearby?
//Proceed to check all squares "around" the current one.
}
To be clear, checking around the current square means checking the square immediately adjacent in each of the 8 cardinal directions. Now, my problem is that I am trying to reason out how to code this so that it will certainly not give a RangeErrorat any point or at least catch it and recover if it must. As an example, you could clearly take one of the corner squares to be the worst scenario in the sense that only 2 of the squares the algorithm would want to check are within the array's bounds. Naturally, if a RangeErrorhappens for this reason I just want the program to progress onward without issue so the structure
try {
//check1
//check2...8
} catch (RangeError e) {
}
is unacceptable because as soon as a single out of range square is tested the code falls out of the check block. An alternative I thought of, but do not like because of its messiness, would be to individually wrap each check in a try-catch and yes that would work I guess but that's some horrid looking code...so can anyone help me out here? Is there perhaps a different angle from which to come at this problem of avoiding the RangeErrors that I am not seeing?
So my code for testing whether another untraversable tile should be placed has shaped up like this:
bool _tileFitsWell(int tileTypeInt, int row, int col)
{
//...initialise some things, set stuff up
...
if (tile.traversable == true) {
//In this case a new traversable tile is being put in, so no problems.
return true;
} else {
//begin testing what tiles are around the current tile
//Test NW adjacent
if (row > 0 && col > 0) {
temp = tileAt(row - 1, col - 1);
if (!temp.traversable) {
strikeCount++;
}
}
//Test N adjacent
if (row > 0) {
temp = tileAt(row - 1, col - 1);
if (!temp.traversable) {
strikeCount++;
}
}
//Test NE adjacent
if (row > 0 && col < _grid[0].length - 2) {
temp = tileAt(row - 1, col 1);
if (!temp.traversable) {
strikeCount++;
}
}
//Test W adjacent
if (col > 0) {
temp = tileAt(row, col - 1);
if (!temp.traversable) {
strikeCount++;
}
}
}
return strikeCount < 2;
}
The code inside each "initial" if-statement (the ones that check row and col) is a bit pseudocode-ish for simplicity's sake. As I explained in a previous comment, the reason why I don't need to check tiles in the other 4 cardinal directions is since these checks are done while filling the map, tiles in those positions will always be either uninitialised or just out of bounds, depending on what tile the function is called to check at a given time.