generated from mwc/lab_retro
128 lines
4.8 KiB
Python
128 lines
4.8 KiB
Python
from retro.graph import Vertex, Edge, Graph
|
|
from retro.errors import TerminalTooSmall
|
|
|
|
class View:
|
|
BORDER_X = 2
|
|
BORDER_Y = 3
|
|
STATE_HEIGHT = 5
|
|
DEBUG_WIDTH = 60
|
|
|
|
def __init__(self, terminal, color='white_on_black'):
|
|
self.terminal = terminal
|
|
self.color = color
|
|
|
|
def render(self, game):
|
|
self.render_layout(game)
|
|
ox, oy = self.get_board_origin_coords(game)
|
|
self.render_state(game)
|
|
if game.debug:
|
|
self.render_debug_log(game)
|
|
for agent in sorted(game.agents, key=lambda a: getattr(a, 'z', 0)):
|
|
if getattr(agent, 'display', True):
|
|
ax, ay = agent.position
|
|
if hasattr(agent, 'color'):
|
|
color = self.get_color(agent.color)
|
|
print(self.terminal.move_xy(ox + ax, oy + ay) + color(agent.character))
|
|
else:
|
|
print(self.terminal.move_xy(ox + ax, oy + ay) + agent.character)
|
|
|
|
def render_layout(self, game):
|
|
bw, bh = game.board_size
|
|
self.check_terminal_size(game)
|
|
self.clear_screen()
|
|
layout_graph = self.get_layout_graph(game)
|
|
layout_graph.render(self.terminal)
|
|
|
|
def clear_screen(self):
|
|
print(self.terminal.home + self.get_color(self.color) + self.terminal.clear)
|
|
|
|
def get_color(self, color_string):
|
|
if not hasattr(self.terminal, color_string):
|
|
msg = (
|
|
f"{color_string} is not a supported color."
|
|
"See https://blessed.readthedocs.io/en/latest/colors.html"
|
|
)
|
|
raise ValueError(msg)
|
|
return getattr(self.terminal, color_string)
|
|
|
|
def render_state(self, game):
|
|
bw, bh = game.board_size
|
|
ox, oy = self.get_state_origin_coords(game)
|
|
for i, key in enumerate(sorted(game.state.keys())):
|
|
msg = f"{key}: {game.state[key]}"[:bw]
|
|
print(self.terminal.move_xy(ox, oy + i) + msg)
|
|
|
|
def render_debug_log(self, game):
|
|
bw, bh = game.board_size
|
|
debug_height = bh + self.STATE_HEIGHT
|
|
ox, oy = self.get_debug_origin_coords(game)
|
|
for i, (turn_number, message) in enumerate(game.log_messages[-debug_height:]):
|
|
msg = f"{turn_number}. {message}"[:self.DEBUG_WIDTH]
|
|
print(self.terminal.move_xy(ox, oy + i) + msg)
|
|
|
|
def get_layout_graph(self, game):
|
|
bw, bh = game.board_size
|
|
sh = self.STATE_HEIGHT
|
|
ox, oy = self.get_board_origin_coords(game)
|
|
|
|
vertices = [
|
|
Vertex(ox - 1, oy - 1),
|
|
Vertex(ox + bw, oy - 1),
|
|
Vertex(ox + bw, oy + bh),
|
|
Vertex(ox + bw, oy + bh + sh),
|
|
Vertex(ox - 1, oy + bh + sh),
|
|
Vertex(ox - 1, oy + bh)
|
|
]
|
|
edges = [
|
|
Edge(vertices[0], vertices[1]),
|
|
Edge(vertices[1], vertices[2]),
|
|
Edge(vertices[2], vertices[3]),
|
|
Edge(vertices[3], vertices[4]),
|
|
Edge(vertices[4], vertices[5]),
|
|
Edge(vertices[5], vertices[0]),
|
|
Edge(vertices[5], vertices[2]),
|
|
]
|
|
graph = Graph(vertices, edges)
|
|
if game.debug:
|
|
dw = self.DEBUG_WIDTH
|
|
graph.vertices.append(Vertex(ox + bw + dw, oy - 1))
|
|
graph.vertices.append(Vertex(ox + bw + dw, oy + bh + sh))
|
|
graph.edges.append(Edge(graph.vertices[1], graph.vertices[6]))
|
|
graph.edges.append(Edge(graph.vertices[6], graph.vertices[7]))
|
|
graph.edges.append(Edge(graph.vertices[3], graph.vertices[7]))
|
|
return graph
|
|
|
|
def check_terminal_size(self, game):
|
|
bw, bh = game.board_size
|
|
width_needed = bw + self.BORDER_X
|
|
height_needed = bh + self.BORDER_Y + self.STATE_HEIGHT
|
|
if self.terminal.width < width_needed:
|
|
raise TerminalTooSmall(width=self.terminal.width, width_needed=width_needed)
|
|
elif self.terminal.height < height_needed:
|
|
raise TerminalTooSmall(height=self.terminal.height, height_needed=height_needed)
|
|
|
|
def board_origin(self, game):
|
|
x, y = self.get_board_origin_coords(game)
|
|
return self.terminal.move_xy(x, y)
|
|
|
|
def get_board_origin_coords(self, game):
|
|
bw, bh = game.board_size
|
|
margin_top = (self.terminal.height - bh - self.BORDER_Y) // 2
|
|
if game.debug:
|
|
margin_left = (self.terminal.width - bw - self.DEBUG_WIDTH - self.BORDER_X) // 2
|
|
else:
|
|
margin_left = (self.terminal.width - bw - self.BORDER_X) // 2
|
|
return margin_left, margin_top
|
|
|
|
def get_state_origin_coords(self, game):
|
|
bw, bh = game.board_size
|
|
ox, oy = self.get_board_origin_coords(game)
|
|
return ox, oy + bh + 1
|
|
|
|
def get_debug_origin_coords(self, game):
|
|
bw, bh = game.board_size
|
|
ox, oy = self.get_board_origin_coords(game)
|
|
return ox + bw + 1, oy
|
|
|
|
|