generated from mwc/lab_retro
When I run the game, it works for a bit but then when the first asteroid
gets to the bottom I get this:
Traceback (most recent call last):
File "/root/making_with_code/mwc1/unit3/lab_retro/nav_game.py", line 14, in <module>
game.play()
File "/root/making_with_code/mwc1/unit3/lab_retro/retro/game.py", line 80, in play
agent.play_turn(self)
File "/root/making_with_code/mwc1/unit3/lab_retro/asteroid.py", line 16, in play_turn
game.remove_agent_by_name(self.name)
AttributeError: 'Asteroid' object has no attribute 'name'
This commit is contained in:
162
retro/graph.py
Normal file
162
retro/graph.py
Normal file
@@ -0,0 +1,162 @@
|
||||
from retro.errors import GraphError
|
||||
|
||||
class Graph:
|
||||
def __init__(self, vertices=None, edges=None):
|
||||
self.vertices = vertices or []
|
||||
self.edges = edges or []
|
||||
|
||||
def __str__(self):
|
||||
return '\n'.join(str(e) for e in self.edges)
|
||||
|
||||
def get_or_create_vertex(self, x, y):
|
||||
for v in self.vertices:
|
||||
if x == v.x and y == v.y:
|
||||
return v
|
||||
for e in self.edges:
|
||||
if e.crosses(x, y):
|
||||
return self.split_edge(e, x, y)
|
||||
v = Vertex(x, y)
|
||||
self.vertices.append(v)
|
||||
return v
|
||||
|
||||
def get_or_create_edge(self, x0, y0, x1, y1):
|
||||
v0 = self.get_or_create_vertex(x0, y0)
|
||||
v1 = self.get_or_create_vertex(x1, y1)
|
||||
new_edge = Edge(v0, v1)
|
||||
for e in self.edges:
|
||||
if e == new_edge:
|
||||
new_edge.remove()
|
||||
return e
|
||||
return new_edge
|
||||
|
||||
def split_edge(self, edge, x, y):
|
||||
"""
|
||||
Splits an edge by inserting a new vertex along the edge.
|
||||
"""
|
||||
if not edge.crosses(x, y):
|
||||
raise GraphError(f"Can't split edge {edge} at ({x}, {y})")
|
||||
self.remove_edge(edge)
|
||||
v = Vertex(x, y)
|
||||
self.vertices.append(v)
|
||||
self.edges.append(Edge(edge.begin, v))
|
||||
self.edges.append(Edge(v, edge.end))
|
||||
|
||||
def remove_edge(self, edge):
|
||||
if edge not in self.edges:
|
||||
raise GraphError(f"Edge {edge} is not in the graph")
|
||||
self.edges.remove(edge)
|
||||
edge.begin.edges.remove(edge)
|
||||
edge.end.edges.remove(edge)
|
||||
|
||||
def render(self, terminal):
|
||||
for v in self.vertices:
|
||||
v.render(terminal)
|
||||
for e in self.edges:
|
||||
e.render(terminal)
|
||||
|
||||
class Vertex:
|
||||
CHARACTERS = {
|
||||
"0000": " ",
|
||||
"0001": "═",
|
||||
"0010": "║",
|
||||
"0011": "╗",
|
||||
"0100": "═",
|
||||
"0101": "═",
|
||||
"0110": "╔",
|
||||
"0111": "╦",
|
||||
"1000": "║",
|
||||
"1001": "╝",
|
||||
"1010": "║",
|
||||
"1011": "╣",
|
||||
"1100": "╚",
|
||||
"1101": "╩",
|
||||
"1110": "╠",
|
||||
"1111": "╬",
|
||||
}
|
||||
def __init__(self, x, y):
|
||||
self.x = x
|
||||
self.y = y
|
||||
self.edges = []
|
||||
|
||||
def __str__(self):
|
||||
return f"({self.x}, {self.y})"
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.x == other.x and self.y == other.y
|
||||
|
||||
def neighbors(self):
|
||||
vertices = []
|
||||
for edge in self.edges:
|
||||
if self == edge.begin:
|
||||
vertices.append(edge.end)
|
||||
else:
|
||||
vertices.append(edge.begin)
|
||||
return vertices
|
||||
|
||||
def render(self, terminal):
|
||||
print(terminal.move_xy(self.x, self.y) + self.get_character())
|
||||
|
||||
def get_character(self):
|
||||
u = self.has_up_edge()
|
||||
r = self.has_right_edge()
|
||||
d = self.has_down_edge()
|
||||
l = self.has_left_edge()
|
||||
code = ''.join([str(int(direction)) for direction in [u, r, d, l]])
|
||||
return self.CHARACTERS[code]
|
||||
|
||||
def has_up_edge(self):
|
||||
return any([v.x == self.x and v.y < self.y for v in self.neighbors()])
|
||||
|
||||
def has_right_edge(self):
|
||||
return any([v.y == self.y and self.x < v.x for v in self.neighbors()])
|
||||
|
||||
def has_down_edge(self):
|
||||
return any([v.x == self.x and self.y < v.y for v in self.neighbors()])
|
||||
|
||||
def has_left_edge(self):
|
||||
return any([v.y == self.y and v.x < self.x for v in self.neighbors()])
|
||||
|
||||
class Edge:
|
||||
def __init__(self, begin, end):
|
||||
if not isinstance(begin, Vertex) or not isinstance(end, Vertex):
|
||||
raise ValueError("Tried to initialize an Edge with a non-vertex")
|
||||
if begin.x < end.x or begin.y < end.y:
|
||||
self.begin = begin
|
||||
self.end = end
|
||||
else:
|
||||
self.begin = end
|
||||
self.end = begin
|
||||
if not (self.is_horizontal() or self.is_vertical()):
|
||||
raise ValueError("Edges must be horizontal or vertical.")
|
||||
if self.is_horizontal() and self.is_vertical():
|
||||
raise ValueError("Self-edges are not allowed.")
|
||||
self.begin.edges.append(self)
|
||||
self.end.edges.append(self)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.begin} -> {self.end}"
|
||||
|
||||
def render(self, terminal):
|
||||
if self.is_horizontal():
|
||||
with terminal.location(self.begin.x + 1, self.begin.y):
|
||||
line = "═" * (self.end.x - self.begin.x - 1)
|
||||
print(line)
|
||||
else:
|
||||
for y in range(self.begin.y + 1, self.end.y):
|
||||
print(terminal.move_xy(self.begin.x, y) + "║")
|
||||
|
||||
def is_horizontal(self):
|
||||
return self.begin.y == self.end.y
|
||||
|
||||
def is_vertical(self):
|
||||
return self.begin.x == self.end.x
|
||||
|
||||
def crosses(self, x, y):
|
||||
if self.is_horizontal():
|
||||
return self.begin.y == y and self.begin.x < x and x < self.end.x
|
||||
else:
|
||||
return self.begin.x == x and self.begin.y < y and y < self.end.y
|
||||
|
||||
def remove(self):
|
||||
self.begin.edges.remove(self)
|
||||
self.end.edges.remove(self)
|
||||
Reference in New Issue
Block a user