A-Star Search with 3D Universe
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
3
down vote
favorite
I am attempting to write up a program in Python that will find the shortest path between two nodes in 3D space. The actual domain is the EVE-Online Universe, which is composed of systems connected by stargates.
The input to my program is a list of systems, represented as Python dicts (JSON). I am trying to use the physical 3D distance as well as an incrementing step-cost as my two heuristics.
from math import sqrt
from Queue import PriorityQueue
class Universe(object):
def __init__(self, systems):
self._id_to_system = system["system_id"]: system for system in systems
self._name_to_system = system["name"]: system for system in systems
@property
def num_systems(self):
return len(self._id_to_system)
def __getitem__(self, key):
if key in self._id_to_system:
return self._id_to_system[key]
elif key in self._name_to_system:
return self._name_to_system[key]
else:
raise KeyError("No system with a name or id equal to ".format(key))
def distance(a, b):
""" Returns straight-line distance in AUs between two systems """
a_pos = a["position"]
b_pos = b["position"]
x_dist = b_pos["x"] - a_pos["x"]
y_dist = b_pos["y"] - b_pos["y"]
z_dist = b_pos["z"] - b_pos["z"]
distance = sqrt((x_dist)*(x_dist) + (y_dist)*(y_dist) + (z_dist)*(z_dist))
# Convert from meters to AUs before returning - helps keep this number reasonable
return distance / 1.496e+11
class SystemNode(object):
""" Used to represent a system inside the open and closed sets """
def __init__(self, system, parent, step_cost):
self.system = system
self.parent = parent
self.step_cost = step_cost
def find_stargate_route(universe, start_system, end_system, step_cost=10):
# Create open and closed sets
frontier_nodes = PriorityQueue(universe.num_systems)
closed_system_ids =
# Add starting system to frontier
start_node = SystemNode(start_system, None, 0)
frontier_nodes.put((0, start_node))
while not frontier_nodes.empty():
# Grab the node with the lowest cost
current_node = frontier_nodes.get(False)[1]
# Check if we have found our goal
if current_node.system == end_system:
print("Found Route to ".format(end_system["name"]))
break
# Calculate next node step cost
next_step_cost = current_node.step_cost + step_cost
# Add each output system if we haven't seen it yet
for system_id in (
stargate["destination"]["system_id"] for stargate in current_node.system["stargates"]
):
system = universe[system_id]
system_node = SystemNode(system, current_node, next_step_cost)
# Check if system is in our closed list
if system_id in closed_system_ids:
continue
# Add to our frontier with priority=step_cost + distance
total_cost = distance(system, end_system) + next_step_cost
frontier_nodes.put((total_cost, system_node))
# Add the current node to the closed set
closed_system_ids[current_node.system["system_id"]] = current_node
if current_node.system != end_system:
return None
else:
# Return a list of systems from start to end
route =
while current_node != None:
route.insert(0, current_node.system)
current_node = current_node.parent
return route
And then a little program to run it...
A jsonl.gz file with all of the systems is available in this gitlab snippet (see the attached file - "combined_systems.jsonl.gz")
import gzip
import json
with gzip.open("combined_systems.jsonl.gz", 'rb') as gzfp:
systems = [json.loads(line) for line in gzfp]
start_name = "Amarr"
end_name = "Jita"
universe = Universe(systems)
route = find_stargate_route(
universe, universe[start_name], universe[end_name]
)
print(len(route))
Any suggestions? This was meant more as a coding exercise to help me grasp the A-star algorithm, so any pointers are much appreciated :)
EDIT: Removed the dependency on PrioritySet
- it works the same with Queue.PriorityQueue
. Also added my Universe class (basically just getters for the different systems). Also added a link to the jsonl.gz
file containing all of the systems, see the gitlab link.
python python-2.7 graph search a-star
add a comment |Â
up vote
3
down vote
favorite
I am attempting to write up a program in Python that will find the shortest path between two nodes in 3D space. The actual domain is the EVE-Online Universe, which is composed of systems connected by stargates.
The input to my program is a list of systems, represented as Python dicts (JSON). I am trying to use the physical 3D distance as well as an incrementing step-cost as my two heuristics.
from math import sqrt
from Queue import PriorityQueue
class Universe(object):
def __init__(self, systems):
self._id_to_system = system["system_id"]: system for system in systems
self._name_to_system = system["name"]: system for system in systems
@property
def num_systems(self):
return len(self._id_to_system)
def __getitem__(self, key):
if key in self._id_to_system:
return self._id_to_system[key]
elif key in self._name_to_system:
return self._name_to_system[key]
else:
raise KeyError("No system with a name or id equal to ".format(key))
def distance(a, b):
""" Returns straight-line distance in AUs between two systems """
a_pos = a["position"]
b_pos = b["position"]
x_dist = b_pos["x"] - a_pos["x"]
y_dist = b_pos["y"] - b_pos["y"]
z_dist = b_pos["z"] - b_pos["z"]
distance = sqrt((x_dist)*(x_dist) + (y_dist)*(y_dist) + (z_dist)*(z_dist))
# Convert from meters to AUs before returning - helps keep this number reasonable
return distance / 1.496e+11
class SystemNode(object):
""" Used to represent a system inside the open and closed sets """
def __init__(self, system, parent, step_cost):
self.system = system
self.parent = parent
self.step_cost = step_cost
def find_stargate_route(universe, start_system, end_system, step_cost=10):
# Create open and closed sets
frontier_nodes = PriorityQueue(universe.num_systems)
closed_system_ids =
# Add starting system to frontier
start_node = SystemNode(start_system, None, 0)
frontier_nodes.put((0, start_node))
while not frontier_nodes.empty():
# Grab the node with the lowest cost
current_node = frontier_nodes.get(False)[1]
# Check if we have found our goal
if current_node.system == end_system:
print("Found Route to ".format(end_system["name"]))
break
# Calculate next node step cost
next_step_cost = current_node.step_cost + step_cost
# Add each output system if we haven't seen it yet
for system_id in (
stargate["destination"]["system_id"] for stargate in current_node.system["stargates"]
):
system = universe[system_id]
system_node = SystemNode(system, current_node, next_step_cost)
# Check if system is in our closed list
if system_id in closed_system_ids:
continue
# Add to our frontier with priority=step_cost + distance
total_cost = distance(system, end_system) + next_step_cost
frontier_nodes.put((total_cost, system_node))
# Add the current node to the closed set
closed_system_ids[current_node.system["system_id"]] = current_node
if current_node.system != end_system:
return None
else:
# Return a list of systems from start to end
route =
while current_node != None:
route.insert(0, current_node.system)
current_node = current_node.parent
return route
And then a little program to run it...
A jsonl.gz file with all of the systems is available in this gitlab snippet (see the attached file - "combined_systems.jsonl.gz")
import gzip
import json
with gzip.open("combined_systems.jsonl.gz", 'rb') as gzfp:
systems = [json.loads(line) for line in gzfp]
start_name = "Amarr"
end_name = "Jita"
universe = Universe(systems)
route = find_stargate_route(
universe, universe[start_name], universe[end_name]
)
print(len(route))
Any suggestions? This was meant more as a coding exercise to help me grasp the A-star algorithm, so any pointers are much appreciated :)
EDIT: Removed the dependency on PrioritySet
- it works the same with Queue.PriorityQueue
. Also added my Universe class (basically just getters for the different systems). Also added a link to the jsonl.gz
file containing all of the systems, see the gitlab link.
python python-2.7 graph search a-star
Welcome to Code Review! For what Python version did you write this and does it work correctly?
â Mast
Jul 14 at 8:09
2
To make it easier to reproduce, could you add your imports? CurrentlyPrioritySet
(andUniverse
) are undefined.
â Graipher
Jul 14 at 8:22
1
@Mast - It is in python2.7 and yes! It works correctly and finds routes, although I'm not too sure if they are the best routes out there
â wKavey
Jul 14 at 15:42
1
@Graipher - Added theUniverse
dependency, and removed my customPrioritySet
- it was basically just a PriorityQueue with some extra stuff thrown around. The above code should work now
â wKavey
Jul 14 at 15:43
add a comment |Â
up vote
3
down vote
favorite
up vote
3
down vote
favorite
I am attempting to write up a program in Python that will find the shortest path between two nodes in 3D space. The actual domain is the EVE-Online Universe, which is composed of systems connected by stargates.
The input to my program is a list of systems, represented as Python dicts (JSON). I am trying to use the physical 3D distance as well as an incrementing step-cost as my two heuristics.
from math import sqrt
from Queue import PriorityQueue
class Universe(object):
def __init__(self, systems):
self._id_to_system = system["system_id"]: system for system in systems
self._name_to_system = system["name"]: system for system in systems
@property
def num_systems(self):
return len(self._id_to_system)
def __getitem__(self, key):
if key in self._id_to_system:
return self._id_to_system[key]
elif key in self._name_to_system:
return self._name_to_system[key]
else:
raise KeyError("No system with a name or id equal to ".format(key))
def distance(a, b):
""" Returns straight-line distance in AUs between two systems """
a_pos = a["position"]
b_pos = b["position"]
x_dist = b_pos["x"] - a_pos["x"]
y_dist = b_pos["y"] - b_pos["y"]
z_dist = b_pos["z"] - b_pos["z"]
distance = sqrt((x_dist)*(x_dist) + (y_dist)*(y_dist) + (z_dist)*(z_dist))
# Convert from meters to AUs before returning - helps keep this number reasonable
return distance / 1.496e+11
class SystemNode(object):
""" Used to represent a system inside the open and closed sets """
def __init__(self, system, parent, step_cost):
self.system = system
self.parent = parent
self.step_cost = step_cost
def find_stargate_route(universe, start_system, end_system, step_cost=10):
# Create open and closed sets
frontier_nodes = PriorityQueue(universe.num_systems)
closed_system_ids =
# Add starting system to frontier
start_node = SystemNode(start_system, None, 0)
frontier_nodes.put((0, start_node))
while not frontier_nodes.empty():
# Grab the node with the lowest cost
current_node = frontier_nodes.get(False)[1]
# Check if we have found our goal
if current_node.system == end_system:
print("Found Route to ".format(end_system["name"]))
break
# Calculate next node step cost
next_step_cost = current_node.step_cost + step_cost
# Add each output system if we haven't seen it yet
for system_id in (
stargate["destination"]["system_id"] for stargate in current_node.system["stargates"]
):
system = universe[system_id]
system_node = SystemNode(system, current_node, next_step_cost)
# Check if system is in our closed list
if system_id in closed_system_ids:
continue
# Add to our frontier with priority=step_cost + distance
total_cost = distance(system, end_system) + next_step_cost
frontier_nodes.put((total_cost, system_node))
# Add the current node to the closed set
closed_system_ids[current_node.system["system_id"]] = current_node
if current_node.system != end_system:
return None
else:
# Return a list of systems from start to end
route =
while current_node != None:
route.insert(0, current_node.system)
current_node = current_node.parent
return route
And then a little program to run it...
A jsonl.gz file with all of the systems is available in this gitlab snippet (see the attached file - "combined_systems.jsonl.gz")
import gzip
import json
with gzip.open("combined_systems.jsonl.gz", 'rb') as gzfp:
systems = [json.loads(line) for line in gzfp]
start_name = "Amarr"
end_name = "Jita"
universe = Universe(systems)
route = find_stargate_route(
universe, universe[start_name], universe[end_name]
)
print(len(route))
Any suggestions? This was meant more as a coding exercise to help me grasp the A-star algorithm, so any pointers are much appreciated :)
EDIT: Removed the dependency on PrioritySet
- it works the same with Queue.PriorityQueue
. Also added my Universe class (basically just getters for the different systems). Also added a link to the jsonl.gz
file containing all of the systems, see the gitlab link.
python python-2.7 graph search a-star
I am attempting to write up a program in Python that will find the shortest path between two nodes in 3D space. The actual domain is the EVE-Online Universe, which is composed of systems connected by stargates.
The input to my program is a list of systems, represented as Python dicts (JSON). I am trying to use the physical 3D distance as well as an incrementing step-cost as my two heuristics.
from math import sqrt
from Queue import PriorityQueue
class Universe(object):
def __init__(self, systems):
self._id_to_system = system["system_id"]: system for system in systems
self._name_to_system = system["name"]: system for system in systems
@property
def num_systems(self):
return len(self._id_to_system)
def __getitem__(self, key):
if key in self._id_to_system:
return self._id_to_system[key]
elif key in self._name_to_system:
return self._name_to_system[key]
else:
raise KeyError("No system with a name or id equal to ".format(key))
def distance(a, b):
""" Returns straight-line distance in AUs between two systems """
a_pos = a["position"]
b_pos = b["position"]
x_dist = b_pos["x"] - a_pos["x"]
y_dist = b_pos["y"] - b_pos["y"]
z_dist = b_pos["z"] - b_pos["z"]
distance = sqrt((x_dist)*(x_dist) + (y_dist)*(y_dist) + (z_dist)*(z_dist))
# Convert from meters to AUs before returning - helps keep this number reasonable
return distance / 1.496e+11
class SystemNode(object):
""" Used to represent a system inside the open and closed sets """
def __init__(self, system, parent, step_cost):
self.system = system
self.parent = parent
self.step_cost = step_cost
def find_stargate_route(universe, start_system, end_system, step_cost=10):
# Create open and closed sets
frontier_nodes = PriorityQueue(universe.num_systems)
closed_system_ids =
# Add starting system to frontier
start_node = SystemNode(start_system, None, 0)
frontier_nodes.put((0, start_node))
while not frontier_nodes.empty():
# Grab the node with the lowest cost
current_node = frontier_nodes.get(False)[1]
# Check if we have found our goal
if current_node.system == end_system:
print("Found Route to ".format(end_system["name"]))
break
# Calculate next node step cost
next_step_cost = current_node.step_cost + step_cost
# Add each output system if we haven't seen it yet
for system_id in (
stargate["destination"]["system_id"] for stargate in current_node.system["stargates"]
):
system = universe[system_id]
system_node = SystemNode(system, current_node, next_step_cost)
# Check if system is in our closed list
if system_id in closed_system_ids:
continue
# Add to our frontier with priority=step_cost + distance
total_cost = distance(system, end_system) + next_step_cost
frontier_nodes.put((total_cost, system_node))
# Add the current node to the closed set
closed_system_ids[current_node.system["system_id"]] = current_node
if current_node.system != end_system:
return None
else:
# Return a list of systems from start to end
route =
while current_node != None:
route.insert(0, current_node.system)
current_node = current_node.parent
return route
And then a little program to run it...
A jsonl.gz file with all of the systems is available in this gitlab snippet (see the attached file - "combined_systems.jsonl.gz")
import gzip
import json
with gzip.open("combined_systems.jsonl.gz", 'rb') as gzfp:
systems = [json.loads(line) for line in gzfp]
start_name = "Amarr"
end_name = "Jita"
universe = Universe(systems)
route = find_stargate_route(
universe, universe[start_name], universe[end_name]
)
print(len(route))
Any suggestions? This was meant more as a coding exercise to help me grasp the A-star algorithm, so any pointers are much appreciated :)
EDIT: Removed the dependency on PrioritySet
- it works the same with Queue.PriorityQueue
. Also added my Universe class (basically just getters for the different systems). Also added a link to the jsonl.gz
file containing all of the systems, see the gitlab link.
python python-2.7 graph search a-star
edited Jul 14 at 15:46
asked Jul 14 at 6:06
wKavey
185
185
Welcome to Code Review! For what Python version did you write this and does it work correctly?
â Mast
Jul 14 at 8:09
2
To make it easier to reproduce, could you add your imports? CurrentlyPrioritySet
(andUniverse
) are undefined.
â Graipher
Jul 14 at 8:22
1
@Mast - It is in python2.7 and yes! It works correctly and finds routes, although I'm not too sure if they are the best routes out there
â wKavey
Jul 14 at 15:42
1
@Graipher - Added theUniverse
dependency, and removed my customPrioritySet
- it was basically just a PriorityQueue with some extra stuff thrown around. The above code should work now
â wKavey
Jul 14 at 15:43
add a comment |Â
Welcome to Code Review! For what Python version did you write this and does it work correctly?
â Mast
Jul 14 at 8:09
2
To make it easier to reproduce, could you add your imports? CurrentlyPrioritySet
(andUniverse
) are undefined.
â Graipher
Jul 14 at 8:22
1
@Mast - It is in python2.7 and yes! It works correctly and finds routes, although I'm not too sure if they are the best routes out there
â wKavey
Jul 14 at 15:42
1
@Graipher - Added theUniverse
dependency, and removed my customPrioritySet
- it was basically just a PriorityQueue with some extra stuff thrown around. The above code should work now
â wKavey
Jul 14 at 15:43
Welcome to Code Review! For what Python version did you write this and does it work correctly?
â Mast
Jul 14 at 8:09
Welcome to Code Review! For what Python version did you write this and does it work correctly?
â Mast
Jul 14 at 8:09
2
2
To make it easier to reproduce, could you add your imports? Currently
PrioritySet
(and Universe
) are undefined.â Graipher
Jul 14 at 8:22
To make it easier to reproduce, could you add your imports? Currently
PrioritySet
(and Universe
) are undefined.â Graipher
Jul 14 at 8:22
1
1
@Mast - It is in python2.7 and yes! It works correctly and finds routes, although I'm not too sure if they are the best routes out there
â wKavey
Jul 14 at 15:42
@Mast - It is in python2.7 and yes! It works correctly and finds routes, although I'm not too sure if they are the best routes out there
â wKavey
Jul 14 at 15:42
1
1
@Graipher - Added the
Universe
dependency, and removed my custom PrioritySet
- it was basically just a PriorityQueue with some extra stuff thrown around. The above code should work nowâ wKavey
Jul 14 at 15:43
@Graipher - Added the
Universe
dependency, and removed my custom PrioritySet
- it was basically just a PriorityQueue with some extra stuff thrown around. The above code should work nowâ wKavey
Jul 14 at 15:43
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
2
down vote
accepted
Let's start with the distance
function.
distance = sqrt((x_dist)*(x_dist) + (y_dist)*(y_dist) + (z_dist)*(z_dist))
is how you would probably write it in C++, in Python there exists a more readable way using the **
operator:
distance = sqrt(x_dist**2 + y_dist**2 + z_dist**2)
It is not even slower than doing the multiplication yourself:
In : %timeit 123456789123456789123456789**2
12.4 ns ñ 0.184 ns per loop (mean ñ std. dev. of 7 runs, 100000000 loops each)
In : %timeit 123456789123456789123456789*123456789123456789123456789
12.5 ns ñ 0.199 ns per loop (mean ñ std. dev. of 7 runs, 100000000 loops each)
You also have a bug in that function:
y_dist = b_pos["y"] - b_pos["y"]
z_dist = b_pos["z"] - b_pos["z"]
So your distance only takes into account the distance in x. In y and z it is always zero.
1.496e+11
is a magic number. You should save it as a constant on the module level: METER_PER_AU = 1.496e+11
.
In find_stargate_route
, at the end when you have found the target system, you create the route to it. You do that using this code:
route =
while current_node != None:
route.insert(0, current_node.system)
current_node = current_node.parent
return route
This has a bad runtime, because list.insert
has a worst case runtime of $mathcalO(n)$. Instead either use a data structure that supports appending on the left (like collections.deque
), or just build the path using list.append
and return list(reversed(route))
at the end.
You should also not compare to None
using ==
or !=
, instead use is
and is not
.
Thanks for the suggestions - can't believe I missed the distance function calculations (it explains why I was getting a sub-optimal route).
â wKavey
Jul 14 at 16:28
add a comment |Â
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
2
down vote
accepted
Let's start with the distance
function.
distance = sqrt((x_dist)*(x_dist) + (y_dist)*(y_dist) + (z_dist)*(z_dist))
is how you would probably write it in C++, in Python there exists a more readable way using the **
operator:
distance = sqrt(x_dist**2 + y_dist**2 + z_dist**2)
It is not even slower than doing the multiplication yourself:
In : %timeit 123456789123456789123456789**2
12.4 ns ñ 0.184 ns per loop (mean ñ std. dev. of 7 runs, 100000000 loops each)
In : %timeit 123456789123456789123456789*123456789123456789123456789
12.5 ns ñ 0.199 ns per loop (mean ñ std. dev. of 7 runs, 100000000 loops each)
You also have a bug in that function:
y_dist = b_pos["y"] - b_pos["y"]
z_dist = b_pos["z"] - b_pos["z"]
So your distance only takes into account the distance in x. In y and z it is always zero.
1.496e+11
is a magic number. You should save it as a constant on the module level: METER_PER_AU = 1.496e+11
.
In find_stargate_route
, at the end when you have found the target system, you create the route to it. You do that using this code:
route =
while current_node != None:
route.insert(0, current_node.system)
current_node = current_node.parent
return route
This has a bad runtime, because list.insert
has a worst case runtime of $mathcalO(n)$. Instead either use a data structure that supports appending on the left (like collections.deque
), or just build the path using list.append
and return list(reversed(route))
at the end.
You should also not compare to None
using ==
or !=
, instead use is
and is not
.
Thanks for the suggestions - can't believe I missed the distance function calculations (it explains why I was getting a sub-optimal route).
â wKavey
Jul 14 at 16:28
add a comment |Â
up vote
2
down vote
accepted
Let's start with the distance
function.
distance = sqrt((x_dist)*(x_dist) + (y_dist)*(y_dist) + (z_dist)*(z_dist))
is how you would probably write it in C++, in Python there exists a more readable way using the **
operator:
distance = sqrt(x_dist**2 + y_dist**2 + z_dist**2)
It is not even slower than doing the multiplication yourself:
In : %timeit 123456789123456789123456789**2
12.4 ns ñ 0.184 ns per loop (mean ñ std. dev. of 7 runs, 100000000 loops each)
In : %timeit 123456789123456789123456789*123456789123456789123456789
12.5 ns ñ 0.199 ns per loop (mean ñ std. dev. of 7 runs, 100000000 loops each)
You also have a bug in that function:
y_dist = b_pos["y"] - b_pos["y"]
z_dist = b_pos["z"] - b_pos["z"]
So your distance only takes into account the distance in x. In y and z it is always zero.
1.496e+11
is a magic number. You should save it as a constant on the module level: METER_PER_AU = 1.496e+11
.
In find_stargate_route
, at the end when you have found the target system, you create the route to it. You do that using this code:
route =
while current_node != None:
route.insert(0, current_node.system)
current_node = current_node.parent
return route
This has a bad runtime, because list.insert
has a worst case runtime of $mathcalO(n)$. Instead either use a data structure that supports appending on the left (like collections.deque
), or just build the path using list.append
and return list(reversed(route))
at the end.
You should also not compare to None
using ==
or !=
, instead use is
and is not
.
Thanks for the suggestions - can't believe I missed the distance function calculations (it explains why I was getting a sub-optimal route).
â wKavey
Jul 14 at 16:28
add a comment |Â
up vote
2
down vote
accepted
up vote
2
down vote
accepted
Let's start with the distance
function.
distance = sqrt((x_dist)*(x_dist) + (y_dist)*(y_dist) + (z_dist)*(z_dist))
is how you would probably write it in C++, in Python there exists a more readable way using the **
operator:
distance = sqrt(x_dist**2 + y_dist**2 + z_dist**2)
It is not even slower than doing the multiplication yourself:
In : %timeit 123456789123456789123456789**2
12.4 ns ñ 0.184 ns per loop (mean ñ std. dev. of 7 runs, 100000000 loops each)
In : %timeit 123456789123456789123456789*123456789123456789123456789
12.5 ns ñ 0.199 ns per loop (mean ñ std. dev. of 7 runs, 100000000 loops each)
You also have a bug in that function:
y_dist = b_pos["y"] - b_pos["y"]
z_dist = b_pos["z"] - b_pos["z"]
So your distance only takes into account the distance in x. In y and z it is always zero.
1.496e+11
is a magic number. You should save it as a constant on the module level: METER_PER_AU = 1.496e+11
.
In find_stargate_route
, at the end when you have found the target system, you create the route to it. You do that using this code:
route =
while current_node != None:
route.insert(0, current_node.system)
current_node = current_node.parent
return route
This has a bad runtime, because list.insert
has a worst case runtime of $mathcalO(n)$. Instead either use a data structure that supports appending on the left (like collections.deque
), or just build the path using list.append
and return list(reversed(route))
at the end.
You should also not compare to None
using ==
or !=
, instead use is
and is not
.
Let's start with the distance
function.
distance = sqrt((x_dist)*(x_dist) + (y_dist)*(y_dist) + (z_dist)*(z_dist))
is how you would probably write it in C++, in Python there exists a more readable way using the **
operator:
distance = sqrt(x_dist**2 + y_dist**2 + z_dist**2)
It is not even slower than doing the multiplication yourself:
In : %timeit 123456789123456789123456789**2
12.4 ns ñ 0.184 ns per loop (mean ñ std. dev. of 7 runs, 100000000 loops each)
In : %timeit 123456789123456789123456789*123456789123456789123456789
12.5 ns ñ 0.199 ns per loop (mean ñ std. dev. of 7 runs, 100000000 loops each)
You also have a bug in that function:
y_dist = b_pos["y"] - b_pos["y"]
z_dist = b_pos["z"] - b_pos["z"]
So your distance only takes into account the distance in x. In y and z it is always zero.
1.496e+11
is a magic number. You should save it as a constant on the module level: METER_PER_AU = 1.496e+11
.
In find_stargate_route
, at the end when you have found the target system, you create the route to it. You do that using this code:
route =
while current_node != None:
route.insert(0, current_node.system)
current_node = current_node.parent
return route
This has a bad runtime, because list.insert
has a worst case runtime of $mathcalO(n)$. Instead either use a data structure that supports appending on the left (like collections.deque
), or just build the path using list.append
and return list(reversed(route))
at the end.
You should also not compare to None
using ==
or !=
, instead use is
and is not
.
answered Jul 14 at 16:20
Graipher
20.4k42981
20.4k42981
Thanks for the suggestions - can't believe I missed the distance function calculations (it explains why I was getting a sub-optimal route).
â wKavey
Jul 14 at 16:28
add a comment |Â
Thanks for the suggestions - can't believe I missed the distance function calculations (it explains why I was getting a sub-optimal route).
â wKavey
Jul 14 at 16:28
Thanks for the suggestions - can't believe I missed the distance function calculations (it explains why I was getting a sub-optimal route).
â wKavey
Jul 14 at 16:28
Thanks for the suggestions - can't believe I missed the distance function calculations (it explains why I was getting a sub-optimal route).
â wKavey
Jul 14 at 16:28
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f198476%2fa-star-search-with-3d-universe%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Welcome to Code Review! For what Python version did you write this and does it work correctly?
â Mast
Jul 14 at 8:09
2
To make it easier to reproduce, could you add your imports? Currently
PrioritySet
(andUniverse
) are undefined.â Graipher
Jul 14 at 8:22
1
@Mast - It is in python2.7 and yes! It works correctly and finds routes, although I'm not too sure if they are the best routes out there
â wKavey
Jul 14 at 15:42
1
@Graipher - Added the
Universe
dependency, and removed my customPrioritySet
- it was basically just a PriorityQueue with some extra stuff thrown around. The above code should work nowâ wKavey
Jul 14 at 15:43