Collecting all nodes within reach

  • joebert
  • Fart Bubbles
  • Genius
  • User avatar
  • Posts: 13502
  • Loc: Florida

Post 3+ Months Ago

I've got an array of interconnected nodes which looks like this.

Attachments:
node-connections.gif


The representation I have of these nodes in PHP looks like this. Where each node has a key in the array, which is associated with an array of connected node keys.

PHP Code: [ Select ]
$nodes = array(
   'a'   => array('b', 'c'),
   'b'   => array('a', 'c', 'd'),
   'c'   => array('a', 'b', 'd'),
   'd'   => array('b', 'c', 'e'),
   'e'   => array('d')
);
  1. $nodes = array(
  2.    'a'   => array('b', 'c'),
  3.    'b'   => array('a', 'c', 'd'),
  4.    'c'   => array('a', 'b', 'd'),
  5.    'd'   => array('b', 'c', 'e'),
  6.    'e'   => array('d')
  7. );


What I would like to do, is given a key K for a starting point SP, and a number N for the maximum "jumps", return an array of K which are within N jumps from SP.

Currently I'm using the following, which basically counts down from N and merges anything connected to the K already in the result array until N is zero.

PHP Code: [ Select ]
$maxJumps = 1;
$withinReach[] = 'a';
 
while($maxJumps)
{
   $_withinReach = $withinReach;
   foreach($_withinReach as $nodeID)
   {
      $withinReach = array_unique(array_merge($withinReach, $nodes[$nodeID]));
   }
   $maxJumps--;
}
  1. $maxJumps = 1;
  2. $withinReach[] = 'a';
  3.  
  4. while($maxJumps)
  5. {
  6.    $_withinReach = $withinReach;
  7.    foreach($_withinReach as $nodeID)
  8.    {
  9.       $withinReach = array_unique(array_merge($withinReach, $nodes[$nodeID]));
  10.    }
  11.    $maxJumps--;
  12. }


It returns results. For 1 jump it returns the expected nodes. However it's a tad daunting to verify whether it returns the correct results for more than 1 jump because the results grow pretty fast. Off the top of my head, I can also tell I should optimize this in some way so that each iteration of the while loop doesn't continually re-check past nodes.

Any and all [constructive] input is welcome. If you're wondering what this is for, the data set I'm using is the "mapSolarSystemJumps" table from Eve Online's database dump. :D
  • Anonymous
  • Bot
  • No Avatar
  • Posts: ?
  • Loc: Ozzuland
  • Status: Online

Post 3+ Months Ago

  • joebert
  • Fart Bubbles
  • Genius
  • User avatar
  • Posts: 13502
  • Loc: Florida

Post 3+ Months Ago

I switched to the following loops. The earlier code timed out after 30 seconds with $maxJumps set to 20, whereas this new code finds about 1200 nodes within reach of 20 jumps in 1 second tops. (including the time it takes to build the page and my browser to render it)

PHP Code: [ Select ]
$_withinReach = array('a' => new stdClass);
while($maxJumps--)
{
   foreach($_withinReach as $key => $val)
   {
      foreach($nodes[$key] as $_key)
      {
         $withinReach[$_key] = new stdClass;
      }
   }
   $_withinReach = array_diff_key($withinReach, $_withinReach);
}
unset($_withinReach);
  1. $_withinReach = array('a' => new stdClass);
  2. while($maxJumps--)
  3. {
  4.    foreach($_withinReach as $key => $val)
  5.    {
  6.       foreach($nodes[$key] as $_key)
  7.       {
  8.          $withinReach[$_key] = new stdClass;
  9.       }
  10.    }
  11.    $_withinReach = array_diff_key($withinReach, $_withinReach);
  12. }
  13. unset($_withinReach);
  • spork
  • Brewmaster
  • Silver Member
  • User avatar
  • Posts: 6252
  • Loc: Seattle, WA

Post 3+ Months Ago

Graph problems like this are a lot easier if you work within traditional graph theory, that is, labeling both vertices and edges. Then associating each vertex with its neighbors and finding paths, walks, and loops becomes much simpler.
  • joebert
  • Fart Bubbles
  • Genius
  • User avatar
  • Posts: 13502
  • Loc: Florida

Post 3+ Months Ago

You went right over my head with that answer. Can you show me a quick example of what you mean by labeling vertices and edges ? :D
  • spork
  • Brewmaster
  • Silver Member
  • User avatar
  • Posts: 6252
  • Loc: Seattle, WA

Post 3+ Months Ago

Sure:

A vertex (plural: vertices) is a point in a graph. The lines connecting them are called edges. If you were to give a unique identifier to all vertices (i.e. v1, v2, etc.) and to all edges (i.e. e1, e2, etc.), then you can model the graph as a collection of vertices, each containing a collection of edges.

Attachments:
graph.png


In the example above, we have a graph containing 5 vertices and 5 edges. We can give each vertex a collection of edges. We use the notation E(vi) to say "the collection of edges having "vi" as an endpoint:

Code: [ Select ]
E(v1) = [e1, e2]
E(v2) = [e2, e3]
E(v3) = [e1, e4]
E(v4) = [e3, e4, e5]
E(v5) = [e5]
  1. E(v1) = [e1, e2]
  2. E(v2) = [e2, e3]
  3. E(v3) = [e1, e4]
  4. E(v4) = [e3, e4, e5]
  5. E(v5) = [e5]


Now, to find all nodes that are a certain number of jumps away, we just take the starting node, iterate through it's list of edges to grab the neighbors of the vertex, and repeat until we're far enough out.

The real benefit of this can be seen if you program this in an object-oriented fashion, where vertices and edges are all objects.
  • spork
  • Brewmaster
  • Silver Member
  • User avatar
  • Posts: 6252
  • Loc: Seattle, WA

Post 3+ Months Ago

Of course, if you're into matrix algebra, you can run even crazier algorithms on the adjacency matrix of the graph to obtain even more information.

Attachments:
adjacency_matrix.png
  • joebert
  • Fart Bubbles
  • Genius
  • User avatar
  • Posts: 13502
  • Loc: Florida

Post 3+ Months Ago

At the moment the only two results I need from this data are the set I'm working on now, being the set which tells me the systems which are within N jumps of any given system, and the shortest path between two systems, which I already have working.

Here are the tables I have to work with. The table I work with primarily is the mapSolarSystemJumps table, which has 14,334 rows.

SQL Code: [ Select ]
CREATE TABLE `mapSolarSystems` (
  `regionID` int(11) DEFAULT NULL,
  `constellationID` int(11) DEFAULT NULL,
  `solarSystemID` int(11) NOT NULL,
  `solarSystemName` varchar(100) DEFAULT NULL,
  `x` double DEFAULT NULL,
  `y` double DEFAULT NULL,
  `z` double DEFAULT NULL,
  `xMin` double DEFAULT NULL,
  `xMax` double DEFAULT NULL,
  `yMin` double DEFAULT NULL,
  `yMax` double DEFAULT NULL,
  `zMin` double DEFAULT NULL,
  `zMax` double DEFAULT NULL,
  `luminosity` double DEFAULT NULL,
  `border` tinyint(1) DEFAULT NULL,
  `fringe` tinyint(1) DEFAULT NULL,
  `corridor` tinyint(1) DEFAULT NULL,
  `hub` tinyint(1) DEFAULT NULL,
  `international` tinyint(1) DEFAULT NULL,
  `regional` tinyint(1) DEFAULT NULL,
  `constellation` tinyint(1) DEFAULT NULL,
  `security` double DEFAULT NULL,
  `factionID` int(11) DEFAULT NULL,
  `radius` double DEFAULT NULL,
  `sunTypeID` smallint(6) DEFAULT NULL,
  `securityClass` varchar(2) DEFAULT NULL,
  PRIMARY KEY  (`solarSystemID`),
  UNIQUE KEY `solarSystemID` (`solarSystemID`,`constellationID`,`regionID`),
  KEY `mapSolarSystems_IX_constellation` (`constellationID`),
  KEY `mapSolarSystems_IX_region` (`regionID`),
  KEY `mapSolarSystems_IX_security` (`security`),
  KEY `factionID` (`factionID`),
  KEY `sunTypeID` (`sunTypeID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
  1. CREATE TABLE `mapSolarSystems` (
  2.   `regionID` int(11) DEFAULT NULL,
  3.   `constellationID` int(11) DEFAULT NULL,
  4.   `solarSystemID` int(11) NOT NULL,
  5.   `solarSystemName` varchar(100) DEFAULT NULL,
  6.   `x` double DEFAULT NULL,
  7.   `y` double DEFAULT NULL,
  8.   `z` double DEFAULT NULL,
  9.   `xMin` double DEFAULT NULL,
  10.   `xMax` double DEFAULT NULL,
  11.   `yMin` double DEFAULT NULL,
  12.   `yMax` double DEFAULT NULL,
  13.   `zMin` double DEFAULT NULL,
  14.   `zMax` double DEFAULT NULL,
  15.   `luminosity` double DEFAULT NULL,
  16.   `border` tinyint(1) DEFAULT NULL,
  17.   `fringe` tinyint(1) DEFAULT NULL,
  18.   `corridor` tinyint(1) DEFAULT NULL,
  19.   `hub` tinyint(1) DEFAULT NULL,
  20.   `international` tinyint(1) DEFAULT NULL,
  21.   `regional` tinyint(1) DEFAULT NULL,
  22.   `constellation` tinyint(1) DEFAULT NULL,
  23.   `security` double DEFAULT NULL,
  24.   `factionID` int(11) DEFAULT NULL,
  25.   `radius` double DEFAULT NULL,
  26.   `sunTypeID` smallint(6) DEFAULT NULL,
  27.   `securityClass` varchar(2) DEFAULT NULL,
  28.   PRIMARY KEY  (`solarSystemID`),
  29.   UNIQUE KEY `solarSystemID` (`solarSystemID`,`constellationID`,`regionID`),
  30.   KEY `mapSolarSystems_IX_constellation` (`constellationID`),
  31.   KEY `mapSolarSystems_IX_region` (`regionID`),
  32.   KEY `mapSolarSystems_IX_security` (`security`),
  33.   KEY `factionID` (`factionID`),
  34.   KEY `sunTypeID` (`sunTypeID`)
  35. ) ENGINE=MyISAM DEFAULT CHARSET=utf8;


SQL Code: [ Select ]
CREATE TABLE `mapSolarSystemJumps` (
  `fromRegionID` int(11) DEFAULT NULL,
  `fromConstellationID` int(11) DEFAULT NULL,
  `fromSolarSystemID` int(11) NOT NULL,
  `toSolarSystemID` int(11) NOT NULL,
  `toConstellationID` int(11) DEFAULT NULL,
  `toRegionID` int(11) DEFAULT NULL,
  PRIMARY KEY  (`fromSolarSystemID`,`toSolarSystemID`),
  KEY `mapSolarSystemJumps_IX_fromConstellation` (`fromConstellationID`),
  KEY `mapSolarSystemJumps_IX_fromRegion` (`fromRegionID`),
  KEY `fromSolarSystemID` (`fromSolarSystemID`,`fromConstellationID`,`fromRegionID`),
  KEY `toSolarSystemID` (`toSolarSystemID`,`toConstellationID`,`toRegionID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
  1. CREATE TABLE `mapSolarSystemJumps` (
  2.   `fromRegionID` int(11) DEFAULT NULL,
  3.   `fromConstellationID` int(11) DEFAULT NULL,
  4.   `fromSolarSystemID` int(11) NOT NULL,
  5.   `toSolarSystemID` int(11) NOT NULL,
  6.   `toConstellationID` int(11) DEFAULT NULL,
  7.   `toRegionID` int(11) DEFAULT NULL,
  8.   PRIMARY KEY  (`fromSolarSystemID`,`toSolarSystemID`),
  9.   KEY `mapSolarSystemJumps_IX_fromConstellation` (`fromConstellationID`),
  10.   KEY `mapSolarSystemJumps_IX_fromRegion` (`fromRegionID`),
  11.   KEY `fromSolarSystemID` (`fromSolarSystemID`,`fromConstellationID`,`fromRegionID`),
  12.   KEY `toSolarSystemID` (`toSolarSystemID`,`toConstellationID`,`toRegionID`)
  13. ) ENGINE=MyISAM DEFAULT CHARSET=utf8;


SQL Code: [ Select ]
CREATE TABLE `mapRegions` (
  `regionID` int(11) NOT NULL,
  `regionName` varchar(100) DEFAULT NULL,
  `x` double DEFAULT NULL,
  `y` double DEFAULT NULL,
  `z` double DEFAULT NULL,
  `xMin` double DEFAULT NULL,
  `xMax` double DEFAULT NULL,
  `yMin` double DEFAULT NULL,
  `yMax` double DEFAULT NULL,
  `zMin` double DEFAULT NULL,
  `zMax` double DEFAULT NULL,
  `factionID` int(11) DEFAULT NULL,
  `radius` double DEFAULT NULL,
  PRIMARY KEY  (`regionID`),
  KEY `factionID` (`factionID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
  1. CREATE TABLE `mapRegions` (
  2.   `regionID` int(11) NOT NULL,
  3.   `regionName` varchar(100) DEFAULT NULL,
  4.   `x` double DEFAULT NULL,
  5.   `y` double DEFAULT NULL,
  6.   `z` double DEFAULT NULL,
  7.   `xMin` double DEFAULT NULL,
  8.   `xMax` double DEFAULT NULL,
  9.   `yMin` double DEFAULT NULL,
  10.   `yMax` double DEFAULT NULL,
  11.   `zMin` double DEFAULT NULL,
  12.   `zMax` double DEFAULT NULL,
  13.   `factionID` int(11) DEFAULT NULL,
  14.   `radius` double DEFAULT NULL,
  15.   PRIMARY KEY  (`regionID`),
  16.   KEY `factionID` (`factionID`)
  17. ) ENGINE=MyISAM DEFAULT CHARSET=utf8;


SQL Code: [ Select ]
CREATE TABLE `mapRegionJumps` (
  `fromRegionID` int(11) NOT NULL,
  `toRegionID` int(11) NOT NULL,
  PRIMARY KEY  (`fromRegionID`,`toRegionID`),
  KEY `toRegionID` (`toRegionID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
  1. CREATE TABLE `mapRegionJumps` (
  2.   `fromRegionID` int(11) NOT NULL,
  3.   `toRegionID` int(11) NOT NULL,
  4.   PRIMARY KEY  (`fromRegionID`,`toRegionID`),
  5.   KEY `toRegionID` (`toRegionID`)
  6. ) ENGINE=MyISAM DEFAULT CHARSET=utf8;


SQL Code: [ Select ]
CREATE TABLE `mapConstellations` (
  `regionID` int(11) DEFAULT NULL,
  `constellationID` int(11) NOT NULL,
  `constellationName` varchar(100) DEFAULT NULL,
  `x` double DEFAULT NULL,
  `y` double DEFAULT NULL,
  `z` double DEFAULT NULL,
  `xMin` double DEFAULT NULL,
  `xMax` double DEFAULT NULL,
  `yMin` double DEFAULT NULL,
  `yMax` double DEFAULT NULL,
  `zMin` double DEFAULT NULL,
  `zMax` double DEFAULT NULL,
  `factionID` int(11) DEFAULT NULL,
  `radius` double DEFAULT NULL,
  PRIMARY KEY  (`constellationID`),
  UNIQUE KEY `constellationID` (`constellationID`,`regionID`),
  KEY `mapConstellations_IX_region` (`regionID`),
  KEY `factionID` (`factionID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
 
  1. CREATE TABLE `mapConstellations` (
  2.   `regionID` int(11) DEFAULT NULL,
  3.   `constellationID` int(11) NOT NULL,
  4.   `constellationName` varchar(100) DEFAULT NULL,
  5.   `x` double DEFAULT NULL,
  6.   `y` double DEFAULT NULL,
  7.   `z` double DEFAULT NULL,
  8.   `xMin` double DEFAULT NULL,
  9.   `xMax` double DEFAULT NULL,
  10.   `yMin` double DEFAULT NULL,
  11.   `yMax` double DEFAULT NULL,
  12.   `zMin` double DEFAULT NULL,
  13.   `zMax` double DEFAULT NULL,
  14.   `factionID` int(11) DEFAULT NULL,
  15.   `radius` double DEFAULT NULL,
  16.   PRIMARY KEY  (`constellationID`),
  17.   UNIQUE KEY `constellationID` (`constellationID`,`regionID`),
  18.   KEY `mapConstellations_IX_region` (`regionID`),
  19.   KEY `factionID` (`factionID`)
  20. ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
  21.  


SQL Code: [ Select ]
CREATE TABLE `mapConstellationJumps` (
  `fromRegionID` int(11) DEFAULT NULL,
  `fromConstellationID` int(11) NOT NULL,
  `toConstellationID` int(11) NOT NULL,
  `toRegionID` int(11) DEFAULT NULL,
  PRIMARY KEY  (`fromConstellationID`,`toConstellationID`),
  KEY `mapConstellationJumps_IX_fromRegion` (`fromRegionID`),
  KEY `toConstellationID` (`toConstellationID`,`toRegionID`),
  KEY `fromConstellationID` (`fromConstellationID`,`fromRegionID`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
  1. CREATE TABLE `mapConstellationJumps` (
  2.   `fromRegionID` int(11) DEFAULT NULL,
  3.   `fromConstellationID` int(11) NOT NULL,
  4.   `toConstellationID` int(11) NOT NULL,
  5.   `toRegionID` int(11) DEFAULT NULL,
  6.   PRIMARY KEY  (`fromConstellationID`,`toConstellationID`),
  7.   KEY `mapConstellationJumps_IX_fromRegion` (`fromRegionID`),
  8.   KEY `toConstellationID` (`toConstellationID`,`toRegionID`),
  9.   KEY `fromConstellationID` (`fromConstellationID`,`fromRegionID`)
  10. ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
  • PolishHurricane
  • Mastermind
  • Mastermind
  • User avatar
  • Posts: 1585

Post 3+ Months Ago

EVE, nice, I'm trying to quit, quite an addiction. Are you aware of this? http://www.eve-icsc.com/jumptools/jumpplanner.php Or are you trying to make something like it?
  • joebert
  • Fart Bubbles
  • Genius
  • User avatar
  • Posts: 13502
  • Loc: Florida

Post 3+ Months Ago

I'm not in anything that uses jump drives, I have to play connect the dots with jump gates.

I do a bit of trading. I like to buy stuff in other regions through contracts so sometimes I need to know the shortest route from a solar system to any one of that regions entry point systems in order to bid on the contract. So I pull all of the entrypoint systems in that region and calculate the shortest path to all of them before returning the shortest path.

I plan on using the thing I started this thread for to find systems close to high priced buy orders. I'm constantly buying minerals priced below market value in systems out in the middle of nowhere for cheap because some miner doesn't want to haul them to a market hub and waiting for someone to want them at a premium either in that system, or a system within N jumps some time later. ;)
  • PolishHurricane
  • Mastermind
  • Mastermind
  • User avatar
  • Posts: 1585

Post 3+ Months Ago

Yeah I've actually done that a lot. It looks like this guy tried to accomplish something similar, but it looks like a failure... http://games.chruker.dk/eve_online/shor ... region.php (BTW, the rest of his site is an amazing resource)

I hope you don't waste too much time on this man, because there are a lot of resources out there that you can make due with. Once you get to know the game more, you'll start just knowing which routes are shortest and get to know places. There's only so many high sec routes in and out of regions, especially the further out they are. Those are usually the best isk makers too for that kind of trading. Check this map out, I love it: http://www.ombeve.co.uk/

Damn this doesn't help me, I'm still trying to quit.
  • joebert
  • Fart Bubbles
  • Genius
  • User avatar
  • Posts: 13502
  • Loc: Florida

Post 3+ Months Ago

Yeah I've seen that first link. I believe it works if you're ingame and give the site trust so it receives HTTP request headers with your current location.

I'm a bit paranoid about using tools that can give away my planned location or tip off the author to my activities.

My "shortest path to region" is two textboxes and a submit button. The first textbox is autofilled with my current system, the second is pretty good about interpreting what I mean if I type in "sink liazon" it will use SOUNDEX() to figure out I meant "Sinq Liason". It utilizes the IGB javascript API to set destinations. Tells me how many jump gates are in each system in the route so I know to keep a lookout for gatecamps in corridors. I add other information as needed, for instance I'll probably add a station count sooner or later.

Post Information

  • Total Posts in this topic: 11 posts
  • Users browsing this forum: No registered users and 140 guests
  • You cannot post new topics in this forum
  • You cannot reply to topics in this forum
  • You cannot edit your posts in this forum
  • You cannot delete your posts in this forum
  • You cannot post attachments in this forum
 
 

© 1998-2014. Ozzu® is a registered trademark of Unmelted, LLC.