in textworld/render/render.py [0:0]
def load_state(world: World,
game_infos: Optional[Dict[str, EntityInfo]] = None,
action: Optional[Action] = None,
format: str = 'png',
limit_player_view: bool = False) -> dict:
"""
Generates serialization of game state.
:param world: The current state of the world to visualize.
:param game_infos: The mapping needed to get objects names.
:param action: If provided, highlight the world changes made by that action.
:param format: The graph output format (gv, svg, png...)
:param limit_player_view: Whether to limit the player's view (defaults to false)
:return: The graph generated from this World
"""
if world.player_room is None:
room = world.rooms[0]
else:
room = world.player_room
edges = []
pos = {room.name: (0, 0)}
def used_pos():
pos_along_edges = []
for e in edges:
A, B = pos[e[0]], pos[e[1]]
if A[0] == B[0]: # Y-axis edge.
for i in range(A[1], B[1], np.sign(B[1] - A[1])):
pos_along_edges.append((A[0], i))
else: # X-axis edge.
for i in range(A[0], B[0], np.sign(B[0] - A[0])):
pos_along_edges.append((i, A[1]))
return list(pos.values()) + pos_along_edges
openset = [room]
closedset = set()
# temp_viz(nodes, edges, pos, color=[world.player_room.name])
while len(openset) > 0:
room = openset.pop(0)
closedset.add(room)
for exit, target in room.exits.items():
if target in openset or target in closedset:
edges.append((room.name, target.name, room.doors.get(exit)))
continue
openset.append(target)
src_pos = np.array(pos[room.name])
if exit == "north":
target_pos = tuple(src_pos + (0, 1))
if target_pos in used_pos():
for n, p in pos.items():
if p[1] <= src_pos[1]:
pos[n] = (p[0], p[1] - 1)
pos[target.name] = (pos[room.name][0], pos[room.name][1] + 1)
elif exit == "south":
target_pos = tuple(src_pos + (0, -1))
if target_pos in used_pos():
for n, p in pos.items():
if p[1] >= src_pos[1]:
pos[n] = (p[0], p[1] + 1)
pos[target.name] = (pos[room.name][0], pos[room.name][1] - 1)
elif exit == "east":
target_pos = tuple(src_pos + (1, 0))
if target_pos in used_pos():
for n, p in pos.items():
if p[0] <= src_pos[0]:
pos[n] = (p[0] - 1, p[1])
pos[target.name] = (pos[room.name][0] + 1, pos[room.name][1])
elif exit == "west":
target_pos = tuple(src_pos + (-1, 0))
if target_pos in used_pos():
for n, p in pos.items():
if p[0] >= src_pos[0]:
pos[n] = (p[0] + 1, p[1])
pos[target.name] = (pos[room.name][0] - 1, pos[room.name][1])
edges.append((room.name, target.name, room.doors.get(exit)))
# temp_viz(nodes, edges, pos, color=[world.player_room.name])
rooms = {}
if game_infos is None:
new_game = Game(world)
game_infos = new_game.infos
for k, v in game_infos.items():
if v.name is None:
v.name = k
pos = {game_infos[k].name: v for k, v in pos.items()}
for room in world.rooms:
rooms[room.id] = GraphRoom(game_infos[room.id].name, room)
result = {}
# Objective
if "objective" in game_infos:
result["objective"] = game_infos["objective"]
del game_infos["objective"] # TODO: objective should not be part of game_infos in the first place.
# Objects
all_items = {}
inventory_items = []
objects = world.objects
# if limit_player_view:
# objects = world.get_visible_objects_in(world.player_room)
# objects += world.get_objects_in_inventory()
# add all items first, in case properties are "out of order"
for obj in objects:
cur_item = GraphItem(obj.type, game_infos[obj.id].name)
cur_item.portable = KnowledgeBase.default().types.is_descendant_of(cur_item.type, "o")
all_items[obj.id] = cur_item
for obj in sorted(objects, key=lambda obj: obj.name):
cur_item = all_items[obj.id]
for attribute in obj.get_attributes():
if action and attribute in action.added:
cur_item.highlight = True
if attribute.name == 'in':
# add object to inventory
if attribute.arguments[-1].type == 'I':
inventory_items.append(cur_item)
elif attribute.arguments[0].name == obj.id:
# add object to containers if same object
all_items[attribute.arguments[1].name].add_content(cur_item)
else:
print('DEBUG: Skipping attribute %s for object %s' % (attribute, obj.id))
elif attribute.name == 'at':
# add object to room
if attribute.arguments[-1].type == 'r':
rooms[attribute.arguments[1].name].add_item(cur_item)
elif attribute.name == 'on':
# add object to supporters
all_items[attribute.arguments[1].name].add_content(cur_item)
elif attribute.name == 'open':
cur_item.set_open_closed_locked('open')
elif attribute.name == 'closed':
cur_item.set_open_closed_locked('closed')
elif attribute.name == 'locked':
cur_item.set_open_closed_locked('locked')
if not limit_player_view:
cur_item.infos = " (locked)"
elif attribute.name == 'match':
if not limit_player_view:
cur_item.infos = " (for {})".format(game_infos[attribute.arguments[-1].name].name)
else:
cur_item.add_unknown_predicate(attribute)
for room in rooms.values():
room.position = pos[room.name]
result["rooms"] = []
for room in rooms.values():
room.items = [item.to_dict() for item in room.items]
temp = room.base_room.serialize()
temp["attributes"] = [a.serialize() for a in room.base_room.get_attributes()]
room.base_room = temp
result["rooms"].append(room.__dict__)
def _get_door(door):
if door is None:
return None
return all_items[door.name].__dict__
def _get_name(entity):
return game_infos[entity].name
result["connections"] = [{"src": _get_name(e[0]), "dest": _get_name(e[1]), "door": _get_door(e[2])}
for e in edges]
result["inventory"] = [inv.__dict__ for inv in inventory_items]
return result