Thursday, October 22, 2015

Cryptic Reeborg

Like many people, one of the main reasons I like Python so much is that Python programs are usually very readable ... at least for people that can read and understand English.   This post is definitely not about making Python programs readable in the usual sense.

I like to think of Reeborg's World as a learning environment not only for beginners, but also as a fun and visual place to experiment with various Python features.  For example, is it possible to give a different and interesting introduction to Python's "magic" methods within Reeborg's World?  By this, I mean to replace the usual English names for methods by symbols.  Here's one such quick attempt that may find its way into my Python tutorial.

Reeborg likes to collect objects.  He can add (+) an object found in his world to his collection, or leave an object behind, by removing an object from his collection (-).

Reeborg's favourite objects are (smilie face) tokens: These can be represented in a program by ":-)"  [I would have like to be able to use the unicode character but it is not a valid Python identifier.]

Reeborg can move forward (>) a set number of steps (> n); he can turn perpendicular to his direction of motion (^)  either to his left (^ left) or to his right (^ right).  Reeborg can also "invert" his position and turn around (~reeborg).

Reeborg can detect if there is a wall (|) immediately in front of him (| front) or to his right (| right); he can also build a wall if needed (| build).

Reeborg can detect if he has reached a goal (>> goal) or if he has reached a point where there is a wall in front of him (>> wall) or where there is an object [for instance, a token: >> ":-)"].    Here I would have preferred to use the __matmul__ symbol @ [as in @ goal], but it is not (yet) supported by Brython.  When @ becomes supported, I may use >> as a "fast forward" indicator to vary the speed of the display update [thus >> 100  could be equivalent to think(100)].

Here's a quick implementation of the above, followed by two animated gifs illustrating the result in action.

RUR.world.__remove_default_robot()

build = "build"
front = "front"
right = "right"
left = "left"
token = ":-)"
wall = "wall"
goal = "goal"


class Cryptic(UsedRobot):
    
    def __add__(self, obj):
        if obj == token:
            self.take("token")
        else:
            self.take(obj)    
            
    def __sub__(self, obj):
        if obj == token:
            self.put("token")
        else:
            self.put(obj)
    
    def __gt__(self, n):
        for _ in range(n):
            self.move()
    
    def __or__(self, wall):
        if wall == front:
            return self.wall_in_front()
        elif wall == right:
            return self.wall_on_right()
        elif wall == build:
            self.build_wall()
        else:
            raise ReeborgError("Unknown wall action")
            
    def __rshift__(self, obj):
        while self.front_is_clear():
            self.move()
            
    def __xor__(self, direction):
        if direction == left:
            self.turn_left()
        elif direction == right:
            for _ in range(3):
                self.turn_left()
                
    def __rshift__(self, obj):
        if obj == token:
            return self.object_here()
        if obj == goal:
            return self.at_goal()
    def __invert__(self):
        self.turn_left()
        self.turn_left()

reeborg = Cryptic(1, 1)




 [Note that turn_right() and turn_around() shown as comments on the image below must be defined by the student since Reeborg only knows turn_left().]




No comments: