comparison gamelib/lab.py @ 153:a644f6b64a6d

Implement just the tiny bit of networkx we actually need, so we can drop the extra dependency.
author Jeremy Thurgood <firxen@gmail.com>
date Fri, 11 May 2012 20:27:37 +0200
parents 372d886f9e70
children 4bbd4a1879f8
comparison
equal deleted inserted replaced
152:5b58e2150a4f 153:a644f6b64a6d
1 # -*- test-case-name: gamelib.tests.test_lab -*- 1 # -*- test-case-name: gamelib.tests.test_lab -*-
2 2
3 from random import random, choice, sample 3 from random import random, choice, sample
4
5 import networkx
6 4
7 from gamelib import research, schematics 5 from gamelib import research, schematics
8 from gamelib.game_base import get_subclasses 6 from gamelib.game_base import get_subclasses
9 7
10 8
11 class ScienceGraph(object): 9 class ScienceGraph(object):
12 def __init__(self, all_science, known_science): 10 def __init__(self, all_science, known_science):
13 self.graph = networkx.DiGraph() 11 self._graph = {}
12 self.node = {}
14 self.all_science = all_science 13 self.all_science = all_science
15 self.known_science = known_science 14 self.known_science = known_science
16 self.add_all_science() 15 self.add_all_science()
17 self.tag_known_science() 16 self.tag_known_science()
18 assert networkx.is_directed_acyclic_graph(self.graph)
19 17
20 def add_all_science(self): 18 def add_all_science(self):
21 # Add level 0 of everything to the graph. 19 # Add level 0 of everything to the graph.
22 for science in self.all_science: 20 for science in self.all_science:
23 self.graph.add_node((science, 0), known=False) 21 self.add_node((science, 0), known=False)
24 22
25 # Walk dependencies and fill in intermediate nodes. 23 # Walk dependencies and fill in intermediate nodes.
26 for science in self.all_science: 24 for science in self.all_science:
27 for dep in science.PREREQUISITES: 25 for dep in science.PREREQUISITES:
28 self.add_node_string(*dep) 26 self.add_node_string(*dep)
29 self.graph.add_edge(dep, (science, 0)) 27 self.add_edge(dep, (science, 0))
28
29 def add_node(self, node, **attrs):
30 self.node[node] = attrs
31 self._graph[node] = {}
32
33 def add_edge(self, a, b, **attrs):
34 if a not in self._graph:
35 self.add_node(a)
36 if b not in self._graph:
37 self.add_node(b)
38 self._graph[a][b] = attrs
39
40 def predecessors(self, node):
41 preds = []
42 for n, e in self._graph.iteritems():
43 if node in e:
44 preds.append(n)
45 return preds
30 46
31 def add_node_string(self, science, level): 47 def add_node_string(self, science, level):
32 node = (science, level) 48 node = (science, level)
33 if node in self.graph: 49 if node in self._graph:
34 return node 50 return node
35 51
36 # We prepopulate with level 0 of eveything. 52 # We prepopulate with level 0 of eveything.
37 assert level >= 0 53 assert level >= 0
38 54
39 self.graph.add_node(node, known=False) 55 self.add_node(node, known=False)
40 parent = self.add_node_string(science, level - 1) 56 parent = self.add_node_string(science, level - 1)
41 self.graph.add_edge(parent, node) 57 self.add_edge(parent, node)
42 return node 58 return node
43 59
44 def tag_known_science(self): 60 def tag_known_science(self):
45 for science in self.known_science: 61 for science in self.known_science:
46 # We may know more of this than the graph has. 62 # We may know more of this than the graph has.
47 self.add_node_string(type(science), science.points + 1) 63 self.add_node_string(type(science), science.points + 1)
48 for i in range(science.points + 1): 64 for i in range(science.points + 1):
49 self.graph.node[(type(science), i)]['known'] = True 65 self.node[(type(science), i)]['known'] = True
50 66
51 def is_known(self, node): 67 def is_known(self, node):
52 return self.graph.node[node]['known'] 68 return self.node[node]['known']
53 69
54 def distances_to_known(self, science): 70 def distances_to_known(self, science):
55 nodes = set() 71 nodes = set()
56 nodes_to_check = [(science, 0)] 72 nodes_to_check = [(science, 0)]
57 73
58 while nodes_to_check: 74 while nodes_to_check:
59 node = nodes_to_check.pop() 75 node = nodes_to_check.pop()
60 if self.is_known(node) or node in nodes: 76 if self.is_known(node) or node in nodes:
61 continue 77 continue
62 nodes.add(node) 78 nodes.add(node)
63 nodes_to_check.extend(self.graph.predecessors(node)) 79 nodes_to_check.extend(self.predecessors(node))
64 80
65 distances = {} 81 distances = {}
66 for node in nodes: 82 for node in nodes:
67 distances.setdefault(node[0], 0) 83 distances.setdefault(node[0], 0)
68 distances[node[0]] += 1 84 distances[node[0]] += 1