Source code for aima.ipyviews

from IPython.display import HTML, display, clear_output
from collections import defaultdict
from aima.agents import PolygonObstacle
import os
import time
import json
import copy
import __main__

# repo root (the directory containing the `aima` package), so the bundled js/
# files load regardless of the current working directory
_AIMA_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# ______________________________________________________________________________
# Continuous environment


_CONTINUOUS_WORLD_HTML = '''
<div>
    <canvas class="main-robo-world" width="{0}" height="{1}" style="background:rgba(158, 167, 184, 0.2);" data-world_name="{2}"  onclick="getPosition(this,event)"/>
</div>

<script type="text/javascript">
var all_polygons = {3};
{4}
</script>
'''  # noqa

with open(os.path.join(_AIMA_ROOT, 'js/continuousworld.js'), 'r') as js_file:
    _JS_CONTINUOUS_WORLD = js_file.read()


[docs] class ContinuousWorldView: """ View for continuousworld Implementation in agents.py """ def __init__(self, world, fill="#AAA"): self.time = time.time() self.world = world self.width = world.width self.height = world.height
[docs] def object_name(self): """Return the variable name this view is bound to in the main namespace, matched by its creation timestamp, so the JavaScript canvas can address it.""" globals_in_main = {x: getattr(__main__, x) for x in dir(__main__)} for x in globals_in_main: if isinstance(globals_in_main[x], type(self)): if globals_in_main[x].time == self.time: return x
[docs] def handle_add_obstacle(self, vertices): """ Vertices must be a nestedtuple. This method is called from kernel.execute on completion of a polygon. """ self.world.add_obstacle(vertices) self.show()
[docs] def handle_remove_obstacle(self): """Hook for removing an obstacle from the world; not yet implemented.""" raise NotImplementedError
[docs] def get_polygon_obstacles_coordinates(self): """Return the vertex coordinates of every polygon obstacle in the world.""" obstacle_coordiantes = [] for thing in self.world.things: if isinstance(thing, PolygonObstacle): obstacle_coordiantes.append(thing.coordinates) return obstacle_coordiantes
[docs] def show(self): """Render the continuous world (its dimensions and obstacles) as an HTML canvas and display it in the notebook output.""" clear_output() total_html = _CONTINUOUS_WORLD_HTML.format(self.width, self.height, self.object_name(), str(self.get_polygon_obstacles_coordinates()), _JS_CONTINUOUS_WORLD) display(HTML(total_html))
# ______________________________________________________________________________ # Grid environment _GRID_WORLD_HTML = ''' <div class="map-grid-world" > <canvas data-world_name="{0}"></canvas> <div style="min-height:20px;"> <span></span> </div> </div> <script type="text/javascript"> var gridArray = {1} , size = {2} , elements = {3}; {4} </script> ''' with open(os.path.join(_AIMA_ROOT, 'js/gridworld.js'), 'r') as js_file: _JS_GRID_WORLD = js_file.read()
[docs] class GridWorldView: """ View for grid world. Uses XYEnviornment in agents.py as model. world: an instance of XYEnviornment. block_size: size of individual blocks in pixels. default_fill: color of blocks. A hex value or name should be passed. """ def __init__(self, world, block_size=30, default_fill="white"): self.time = time.time() self.world = world self.labels = defaultdict(str) # locations as keys self.representation = {"default": {"type": "color", "source": default_fill}} self.block_size = block_size
[docs] def object_name(self): """Return the variable name this view is bound to in the main namespace, matched by its creation timestamp, so the JavaScript canvas can address it.""" globals_in_main = {x: getattr(__main__, x) for x in dir(__main__)} for x in globals_in_main: if isinstance(globals_in_main[x], type(self)): if globals_in_main[x].time == self.time: return x
[docs] def set_label(self, coordinates, label): """ Add labels to a particular block of grid. coordinates: a tuple of (row, column). rows and columns are 0 indexed. """ self.labels[coordinates] = label
[docs] def set_representation(self, thing, repr_type, source): """ Set the representation of different things in the environment. thing: a thing object. repr_type : type of representation can be either "color" or "img" source: Hex value in case of color. Image path in case of image. """ thing_class_name = thing.__class__.__name__ if repr_type not in ("img", "color"): raise ValueError('Invalid repr_type passed. Possible types are img/color') self.representation[thing_class_name] = {"type": repr_type, "source": source}
[docs] def handle_click(self, coordinates): """ This method needs to be overridden. Make sure to include a self.show() call at the end. """ self.show()
[docs] def map_to_render(self): """Build the grid's render model and return it as a JSON string: a 2D array of cells annotated with each thing's class name and any per-location tooltip label.""" default_representation = {"val": "default", "tooltip": ""} world_map = [[copy.deepcopy(default_representation) for _ in range(self.world.width)] for _ in range(self.world.height)] for thing in self.world.things: row, column = thing.location thing_class_name = thing.__class__.__name__ if thing_class_name not in self.representation: raise KeyError('Representation not found for {}'.format(thing_class_name)) world_map[row][column]["val"] = thing.__class__.__name__ for location, label in self.labels.items(): row, column = location world_map[row][column]["tooltip"] = label return json.dumps(world_map)
[docs] def show(self): """Render the grid world (its cells, sizes, and representations) as an HTML canvas and display it in the notebook output.""" clear_output() total_html = _GRID_WORLD_HTML.format( self.object_name(), self.map_to_render(), self.block_size, json.dumps(self.representation), _JS_GRID_WORLD) display(HTML(total_html))