class implementation

markotaht at gmail.com markotaht at gmail.com
Thu Oct 10 14:34:53 EDT 2013


kolmapäev, 9. oktoober 2013 2:55.28 UTC+3 kirjutas Cameron Simpson:
> On 08Oct2013 01:20,  wrote:
> 
> > I cant just subclassing doesent work. It seem the init method of the source class also calls out another class. And the problem is, i can subclass the other class to with the required function but the end result is that it doesent work, since the source class cant accsess the subclass functions. 
> 
> > 
> 
> > The source code is pykkar. 
> 
> > 
> 
> > https://courses.cs.ut.ee/all/MTAT.03.100/2012_fall/uploads/opik/_downloads/pykkar.py
> 
> > 
> 
> > I want to add it a new ability called left(). I cant manipulate the source class, cause then my comp will be the only one where the program runs.
> 
> > 
> 
> > class pykkar_l(Pykkar):
> 
> >     def left(self):
> 
> >         self._world.execute("left")
> 
> [...]
> 
> 
> 
> You normally need to call the superclasses' __init__ method as well.
> 
> Example:
> 
> 
> 
>     def __init__(self):
> 
>         Pykkar.__init__(self)
> 
>         ... any of your own init stuff ...
> 
> 
> 
> Likewise for your world_l class.
> 
> 
> 
> BTW, it is conventional to start class names with an upper case letters. Just
> 
> style, but it helps other people when reading your code.
> 
> 
> 
> Cheers,
> 
> --  
> 
> 
> It looks like you've got Mister Bus Error installed.    - tjc

OK so I did a took time of and read the pykkar code through. abd I found that there is a third class i have to implement. 

This Is the pykkar sourcecode
# coding=UTF-8
"""
Intro and usage
===================
Pykkar is a virtual robot living in a virtual world. It can step, turn 90 degrees right,
paint floor tiles, take and put down traffic cones and push boxes. It can detect
whether there is a wall or other obstacle ahead or whether it's standing on a painted
tile. It can be commanded by Python code (either procedural or OOP style)

Pykkar's world can be created by a call to ``create_world`` (when using procedural style)
or by instantiating class ``World`` (OOP style). Both take single argument, which is
a string representation of the world. Lines in the string represent the rows in the world
map. Each character represents one tile. Meaning of characters:

#                    wall
<space>              plain floor
.                    painted floor
b                    box on plain floor
B                    box on painted floor
^ > v <              pykkar on plain floor without cone 
                     (caret, greater-than, lowercase v, less-than)
N E S W              pykkar on painted floor without cone
1 2 3 4 5 6 7 8 9    cone stack on plain floor
C                    single cone on painted floor

Sample:

    create_world('''
    ####
    #> #
    # 3#
    ####
    ''')

this creates a world where 2x2 floor are is padded with walls. Pykkar is in north-west
corner of the floor, looking east and in south-east corner there is a stack of 3 traffic
cones.

In procedural style, Pykkar can be commanded by calling global functions defined in this 
module (eg. ``step()``, ``right()``, etc). There are also functions for querying the 
world (``is_wall()``, ``is_box()``, etc). New compound commands can be defined by defining 
new functions in client module.

In OOP style, Pykkar is represented by a separate object of class ``Pykkar``. In the
start of the program, client code is supposed to create new world (eg. ``w = World(layout)``)
and a Pykkar living in that world (eg ``p = Pykkar(w)``). Commands are given by calling 
the methods of Pykkar object. New commands should be defined by subclassing ``Pykkar``. 
"""

"""
Technical stuff
================
In order to reserve the main thread for executing commands (this way respective function calls
can be written in client module's toplevel), tkinter window must run in a different thread. 
Unfortunately, tkinter runs reliably only in the main thread of the process. 
For this reason the execution is divided into 2 processes: the "main" process, 
which is just a shallow command proxy and the child process, which runs actual program 
logic and presents the world state in a tkinter window.

Main process (ie. user module) normally begins by creating the world (with either 
``create_world(...)`` or ``World(...)``). This spawns a child process which creates
tkinter window representing the world. Main process then continues by executing
user-provided function/method calls, which amounts to writing respective command strings
to child process' stdin and reading results back from child process' stdout.

Main player in child process is an object of class ``_WorldProper``. It keeps the 
data structures about world layout, responds to commands that alter the world state and runs 
a tkinter window. It reads periodically next command from stdin, acts upon it and writes 
result (may be None) to stdout.

NB! as stdout from tkinter process is parsed, you can't just print out debug information
to sys.stdout. Use sys.stderr instead!

Reading from stdin blocks, as usual. This would make window temporariliy unresponsive 
when commands are given interactively (including stepping in a debugger). One case, where
this can be annoying is when pykkar is run in a debugger and user wants to move the window.
For this reason, the child process is divided into 2 threads. Main thread runs tkinter
mainloop, and secondary thread takes care of stding and stdout. They communicate via
two Queues (see _WorldProper.execute and _WordProper._process_commands).


Creating new bitmaps
========================
TODO
    * embed base gif-s as base64 strings
        * http://effbot.org/tkinterbook/photoimage.htm
        * http://effbot.org/librarybook/base64.htm
        * http://www.tcl.tk/man/tcl8.4/TkCmd/photo.htm#M17
    * load user provided gif-s, when present

"""

import sys
import subprocess
import os.path
import traceback
from threading import Thread

try: 
    import tkinter as tk # works in Python 3
except ImportError:
    import Tkinter as tk # works in Python 2

try: 
    from queue import Queue  # works in Python 3
except ImportError:
    from Queue import Queue # works in Python 2


N = (0,-1)
W = (-1,0)
E = (1,0)
S = (0,1)

class World():
    """ Object, which creates GUI and mediates commands and results
        between Pykkar and GUI"""
        
    # This is actually a proxy for the actual world (_WorldProper, 
    # which lives in another process)
    
    def __init__(self, layout_str):
        """ """
        self.proc = subprocess.Popen (
            (sys.executable, '-u', '-m', 'pykkar',  repr(layout_str)),
            stdin=subprocess.PIPE,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            bufsize=0
        )

        # Check initialization result
        result_str = self.proc.stdout.readline().decode()
        if result_str.strip() != "OK":
            raise RuntimeError("World creation failed: " + eval(result_str))

    def execute(self, command_str):
        if self.proc.poll() != None:
            return
        
        self.proc.stdin.write((command_str + "\n").encode())
        self.proc.stdin.flush()
        result_str = self.proc.stdout.readline().decode()
        if result_str == "":
            return
        
        result = eval(result_str)
        
        if isinstance(result, Exception):
            raise result
        else:
            return result

def create_world(layout_str):
    global world
    world = World(layout_str)

def step():
    world.execute("step")

def right():
    world.execute("right")
    
def take():
    world.execute("take")
    
def put():
    world.execute("put")
    
def push():
    world.execute("push")
    
def paint():
    world.execute("paint")
    
def get_heading():
    return world.execute("get_heading")
    
def get_direction():
    return world.execute("get_direction")
    
def get_speed():
    return world.execute("get_speed")
    
def set_speed(value):
    world.execute("set_speed " + str(value))
    
def is_wall():
    return world.execute("is_wall")        
        
def is_box():
    return world.execute("is_box")        
        
def is_cone():
    return world.execute("is_cone")        

def is_painted():
    return world.execute("is_painted")        


class Pykkar:
    """ Just a handle to the world, it passes all commands to its world """
    def __init__(self, world):
        self._world = world

    def step(self):
        self._world.execute("step")
    
    def right(self):
        self._world.execute("right")
        
    def take(self):
        self._world.execute("take")
        
    def put(self):
        self._world.execute("put")
        
    def push(self):
        self._world.execute("push")
        
    def paint(self):
        self._world.execute("paint")
        
    def get_heading(self):
        return self._world.execute("get_heading")
        
    def get_direction(self):
        return self._world.execute("get_direction")
        
    def get_speed(self):
        return self._world.execute("get_speed")
        
    def set_speed(self, value):
        self._world.execute("set_speed " + str(value))
        
    def is_wall(self):
        return self._world.execute("is_wall")        
            
    def is_box(self):
        return self._world.execute("is_box")        
            
    def is_cone(self):
        return self._world.execute("is_cone")       
    
    def is_painted(self):
        return self._world.execute("is_painted") 
            
    
class _WorldProper:
    _block_size = 32

    def __init__(self, layout_str):
        self._command_queue = Queue(maxsize=1)
        self._result_queue = Queue(maxsize=1)

        self._setup_layout(layout_str)
        self._setup_ui()
        self._speed = 5
        self.closed = False
        
        
    def run(self):
        try:
            self.root.after_idle(self._process_commands)
            self.root.mainloop()
        finally:
            # give a result in case there's a pending command from client
            self.closed = True
            if not self._command_queue.empty():
                self._result_queue.put(Exception("World has ended"), block=False)
    
        
    def execute(self, command_str):
        """ meant for calling by outsiders (from another thread) """
        
        if self.closed:
            # ignore command and return constant answer
            result = Exception("Window is closed")
        else:
            # put won't normally block, because commands are given and processed synchronously
            self._command_queue.put(command_str, block=False)
            # get blocks until mainloop handles the command
            result = self._result_queue.get()
        
        return result

    def _setup_layout(self, layout_str):
        self.layout = []
        self.px = None
        self.py = None
        lines = layout_str.strip("\r\n").split("\n")
        longest_row_width = 0
        
        for y in range(len(lines)):
            line = list(lines[y].strip("\r"))
            row = []
            for x in range(len(line)):
                code = line[x]
                tile = _Tile.create_from_code(code)
                
                if tile.pykkar_heading != None:
                    if self.px != None:
                        raise RuntimeError("Only one pykkar is allowed")
                    self.px = x
                    self.py = y
                
                row.append(tile)
                
            self.layout.append(row)
                
            longest_row_width = max(longest_row_width, len(row))
        
        if self.px == None:
            raise Exception("Pykkar is missing")
        
        # pad the layout
        for line in self.layout:
            # extend with floor in the right
            line.extend(list((longest_row_width - len(line)) * [_Tile('plain_floor')]))
        
             
        self.width = len(self.layout[0])
        self.height = len(self.layout)
        
    def _setup_ui(self):
        self.root = tk.Tk()
        self.root.title("Pykkar")
        self.px_width = self.width * _WorldProper._block_size
        self.px_height = self.height * _WorldProper._block_size
        self.root.geometry("%dx%d" % (self.px_width, self.px_height))
        self.root.resizable(0,0)
        self.canvas = tk.Canvas(self.root, 
                                width=self.px_width, 
                                height=self.px_height,
                                highlightthickness=0)
        self.canvas.grid()
        
        # load images
        self.images = {}
        for name in ('wall', 'box', 'cone', 'plain_floor', 'painted_floor',
                     'pykkar_n', 'pykkar_e', 'pykkar_s', 'pykkar_w',
                     'pykkar_n_cone', 'pykkar_e_cone', 'pykkar_s_cone', 'pykkar_w_cone'):
            self.images[name] = self._load_image(name)
        
        # draw tiles
        for y in range(len(self.layout)):
            row = self.layout[y]
            for x in range(len(row)):
                tile = row[x]
                
                # base image
                tile.base_image_id = self.canvas.create_image (
                    x * _WorldProper._block_size,
                    y * _WorldProper._block_size,
                    image=self.images[tile.base_kind], 
                    anchor=tk.NW
                )

                # item image
                if tile.item_kind != None and tile.pykkar_heading == None:
                    tile.item_image_id = self.canvas.create_image (
                        x * _WorldProper._block_size,
                        y * _WorldProper._block_size,
                        image=self.images[tile.item_kind], 
                        anchor=tk.NW
                    )
                    self._update_item_image(tile)
                
                # pykkar
                if tile.pykkar_heading != None:
                    self.pykkar_id = self.canvas.create_image (
                        self.px * _WorldProper._block_size,
                        self.py * _WorldProper._block_size,
                        image=self._get_pykkar_img(tile.pykkar_heading, tile.item_kind),
                        anchor=tk.NW
                    )
            # done with row
        # done with all rows            
                
        self.canvas.tag_raise(self.pykkar_id)
    
    def _load_image(self, name):
        filename = "./" + name + ".gif"
        if os.path.exists(filename):
            return tk.PhotoImage(file=filename)
        else:
            return tk.PhotoImage(data=_image_data[name])
    
    def _process_commands(self):
        """ is called periodically be WorldProper itself """
        delay = _WorldProper._delays[self._speed-1]
        
        if not self._command_queue.empty():
            try:
                command_str = self._command_queue.get()
                parts = command_str.strip().split()
                cmd = parts[0]
                args = tuple(parts[1:]) 
                # look up corresponding method
                f = getattr(self, "_cmd_" + cmd)
                result = f(*args)
                #self._result_queue.put(result, block=False)
                self._result_queue.put(result)
                
                # reduce delay for some commands
                if cmd in ['set_speed', 'get_speed']:
                    delay = 10 
                
            except BaseException as e:
                traceback.print_exc(file=sys.stderr)
                # no command may stay without result, otherwise client remains blocked
                self._result_queue.put(e)
        
        # schedule next processing
        self.root.after(delay, self._process_commands)
    
    def _cmd_get_x(self):
        return self.px
    
    def _cmd_get_y(self):
        return self.py
    
    def _cmd_is_wall(self):
        (next_x, next_y) = self._get_next_pos()
        # wall means either actuall wall block or outside of window
        return not self._is_valid_pos(next_x, next_y) \
            or self.layout[next_y][next_x].base_kind == 'wall' 
    
    def _cmd_is_box(self):
        return self._is_item("box")
    
    def _cmd_is_cone(self):
        return self._is_item("cone")
    
    def _cmd_is_painted(self):
        return self._get_current_tile().base_kind == 'painted_floor'
    
    def _is_item(self, item_kind):
        (next_x, next_y) = self._get_next_pos()
        return self._is_valid_pos(next_x, next_y) \
            and self.layout[next_y][next_x].item_kind == item_kind
    
    def _cmd_step(self):
        (next_x, next_y) = self._get_next_pos()
        next_tile = self.layout[next_y][next_x]
        if not self._is_valid_pos(next_x, next_y) \
                or next_tile.base_kind not in ('plain_floor', 'painted_floor') \
                or next_tile.item_kind != None:
            raise Exception("Can't go to (%d,%d)" % (next_x, next_y))
        
        current_tile = self._get_current_tile()
        next_tile.pykkar_heading = current_tile.pykkar_heading
        next_tile.item_kind = current_tile.item_kind
        next_tile.item_count = current_tile.item_count
        
        current_tile.pykkar_heading = None
        current_tile.item_kind = None
        current_tile.item_count = None
        
        # move pykkar image
        self.canvas.coords(self.pykkar_id, 
                           next_x * _WorldProper._block_size,
                           next_y * _WorldProper._block_size)
        
        # update current position
        self.px = next_x
        self.py = next_y
        
    def _cmd_right(self):
        headings = (N,E,S,W)
        cur_tile = self._get_current_tile() 
        
        cur_heading_index = headings.index(cur_tile.pykkar_heading)
        new_heading_index = (cur_heading_index + 1) % 4
        cur_tile.pykkar_heading = headings[new_heading_index]
        
        self._update_pykkar_image(cur_tile)
    
    def _cmd_with_cone(self):
        tile = self._get_current_tile()
        return tile.item_kind == 'cone'
    
    def _cmd_take(self):
        cur_tile  = self._get_current_tile()
        next_tile = self._get_next_tile()
        
        if cur_tile.item_kind != None:
            raise Exception("Pykkar already carries something")
        
        if next_tile.item_kind != 'cone':
            raise Exception("Pykkar can take only cones")
        
        cur_tile.item_kind = next_tile.item_kind
        cur_tile.item_count = 1
        next_tile.item_count -= 1
        if next_tile.item_count == 0:
            next_tile.item_kind = None
            next_tile.item_count = None
        
        self._update_pykkar_image(cur_tile)
        self._update_item_image(next_tile)
    
    def _cmd_put(self):
        cur_tile  = self._get_current_tile()
        next_tile = self._get_next_tile()
        
        if cur_tile.item_kind == None:
            raise Exception("Not carrying anything")
        
        if next_tile.base_kind not in ['plain_floor', 'painted_floor'] \
            or (next_tile.item_kind != cur_tile.item_kind \
                and next_tile.item_kind != None):
            raise Exception("Can't put it there")
        
        if cur_tile.item_kind != 'cone' and next_tile.item_kind != None:
            raise Exception("There is one already")
            
        if cur_tile.item_kind == 'cone' and next_tile.item_count == 9:
            raise Exception("Can't stack more than 9 cones")
            
        
        next_tile.item_kind = cur_tile.item_kind
        next_tile.item_count = 1 if next_tile.item_count == None else next_tile.item_count + 1
        
        cur_tile.item_kind = None
        cur_tile.item_count = None
        
        self._update_pykkar_image(cur_tile)
        self._update_item_image(next_tile)
    
    def _cmd_push(self):
        if self._cmd_with_cone():
            raise Exception("Can't push when carrying something")
        
        (next_x, next_y) = self._get_next_pos()
        if not self._is_valid_pos(next_x, next_y):
            raise Exception("Nothing to push")
        
        cur_tile  = self._get_current_tile()
        next_tile = self._get_next_tile()
        
        if next_tile.item_kind == None:
            raise Exception("Nothing to push")
            
        
        next_next_x = self.px + (cur_tile.pykkar_heading[0]*2)
        next_next_y = self.py + (cur_tile.pykkar_heading[1]*2)
        if not self._is_valid_pos(next_next_x, next_next_y):
            raise Exception("Nowhere to push")
        
        next_next_tile = self.layout[next_next_y][next_next_x]
        
        if next_next_tile.base_kind not in ['plain_floor', 'painted_floor']:
            raise Exception("Nowhere to push")
            
        if next_next_tile.item_kind != None:
            raise Exception("No room to push")
        
        # move item
        next_next_tile.item_kind = next_tile.item_kind
        next_next_tile.item_count = next_tile.item_count
        next_tile.item_kind = None
        next_tile.item_count = None
        
        self._update_item_image(next_tile)
        self._update_item_image(next_next_tile)
        
        # move pykkar
        self._cmd_step()
        
    def _cmd_paint(self):
        tile = self._get_current_tile()
        if tile.item_kind != None:
            raise Exception("Can't paint when carrying something")
        
        self.canvas.itemconfig(tile.base_image_id, image=self.images['painted_floor'])
        tile.base_kind = 'painted_floor'
    
    def _cmd_get_heading(self):
        return self._get_current_tile().pykkar_heading
    
    def _cmd_get_direction(self):
        heading = self._cmd_get_heading()
        if heading == N:
            return "N"
        elif heading == E:
            return "E"
        elif heading == S:
            return "S"
        else:
            assert heading == W
            return "W"
    
    def _cmd_set_speed(self, value):
        self._speed = int(value)

    def _cmd_get_speed(self):
        return self._speed

    def _get_current_tile(self):
        return self.layout[self.py][self.px]
    
    def _get_next_tile(self):
        (next_x, next_y) = self._get_next_pos()
        if not self._is_valid_pos(next_x, next_y):
            raise Exception("Not valid position")
        
        return self.layout[next_y][next_x]
    
    def _get_next_pos(self):
        tile = self._get_current_tile() 
        next_x = self.px + tile.pykkar_heading[0]
        next_y = self.py + tile.pykkar_heading[1]
        return (next_x, next_y)
    
    def _is_valid_pos(self, x, y):
        return  x >= 0 and x < self.width \
            and y >= 0 and y < self.height
    
    
    def _update_pykkar_image(self, tile):
        new_image = self._get_pykkar_img(tile.pykkar_heading,
                                         tile.item_kind)
        
        self.canvas.itemconfig(self.pykkar_id, image=new_image)
    
    def _get_tile_pos(self, tile):
        for y in range(self.height):
            for x in range(self.width):
                if self.layout[y][x] is tile:
                    return (x, y)
    
    def _update_item_image(self, tile):
        (x, y) = self._get_tile_pos(tile)
        
        # update image
        if tile.item_kind == None:
            #if tile.item_image_id != None:
                self.canvas.delete(tile.item_image_id)
        else:
            img = self.images[tile.item_kind]
            if tile.item_image_id == None:
                tile.item_image_id = self.canvas.create_image(
                    x * _WorldProper._block_size,
                    y * _WorldProper._block_size,
                    image=img,
                    anchor=tk.NW
                )
            else:
                self.canvas.itemconfig(tile.item_image_id, image=img)
        
        # update count text
        if tile.item_count == None or tile.item_count <= 1:
            if tile.text_id != None:   
                self.canvas.delete(tile.text_id)
        else:
            if tile.text_id == None:
                tile.text_id = self.canvas.create_text (
                    x * _WorldProper._block_size+3,
                    y * _WorldProper._block_size+1,
                    text=str(tile.item_count),
                    anchor=tk.NW
                )
            else:
                self.canvas.itemconfig(tile.text_id, text=str(tile.item_count))
            
    
    def _get_pykkar_img(self, heading, item_kind):
        img_name = "pykkar"
        if   heading == N: img_name += '_n'
        elif heading == E: img_name += '_e'
        elif heading == S: img_name += '_s'
        else:              img_name += '_w'
        
        if item_kind != None:
            img_name += '_' + item_kind
        
        return self.images[img_name]
    
    _delays = (500, 300, 200, 150, 100, 75, 50, 30, 25, 20) 
    
class _CmdBroker(Thread):
    """ Mediates between stdin/stdout/stderr and World""" 
    def __init__(self, world_proper):
        Thread.__init__(self)
        self.world_proper = world_proper
    
    def run(self):
        while True:
            command_str = sys.stdin.readline()
            if command_str == "": # client finished
                break
            
            result = self.world_proper.execute(command_str.strip())
            print(repr(result))

class _Tile:
    
    @staticmethod
    def create_from_code(code):
        proto = _content_codes[code]
        return _Tile(proto.base_kind, proto.pykkar_heading, proto.item_kind, proto.item_count)
        
    
    def __init__(self, base_kind, pykkar_heading=None, item_kind=None, item_count=None):
        self.base_kind = base_kind
        self.pykkar_heading = pykkar_heading
        self.item_kind = item_kind
        self.item_count = item_count
        self.base_image_id = None
        self.item_image_id = None
        self.text_id = None
    
    def __eq__(self, other):
        return  self.base_kind == other.base_kind \
            and self.pykkar_heading == other.pykkar_heading \
            and self.item_kind == other.item_kind \
            and self.item_count == other.item_count
            
    def __ne__(self, other):
        return not self.__eq__(other)
    
    def __str__(self):
        return self.get_content_code()
                
    def get_content_code(self):
        for key in _content_codes:
            if _content_codes[key] == self:
                return key
            
        raise LookupError("No code found")
        
_content_codes = {
    '#' : _Tile('wall'),
    ' ' : _Tile('plain_floor'),
    '.' : _Tile('painted_floor'),
    
    'b' : _Tile('plain_floor', None, 'box', 1),
    'B' : _Tile('painted_floor', None, 'box', 1),
    
    '^' : _Tile('plain_floor', N),
    '>' : _Tile('plain_floor', E),
    'v' : _Tile('plain_floor', S),
    '<' : _Tile('plain_floor', W),
    
    'N' : _Tile('painted_floor', N),
    'E' : _Tile('painted_floor', E),
    'S' : _Tile('painted_floor', S),
    'W' : _Tile('painted_floor', W),
    
    
    '1' : _Tile('plain_floor', None, 'cone', 1),
    '2' : _Tile('plain_floor', None, 'cone', 2),
    '3' : _Tile('plain_floor', None, 'cone', 3),
    '4' : _Tile('plain_floor', None, 'cone', 4),
    '5' : _Tile('plain_floor', None, 'cone', 5),
    '6' : _Tile('plain_floor', None, 'cone', 6),
    '7' : _Tile('plain_floor', None, 'cone', 7),
    '8' : _Tile('plain_floor', None, 'cone', 8),
    '9' : _Tile('plain_floor', None, 'cone', 9),
    
    'C' : _Tile('painted_floor', None, 'cone', 1),
} 


_image_data = {
    'box' : """
        R0lGODlhIAAgALMAAAAAAMxVAMyAAP+AAP+qM/+qZv/VM//VZv/Vmf/VzP//mf//zP////
        ///////////yH5BAEAAA8ALAAAAAAgACAAAwT/8MlJq70V6M27/5oEIEhClqdJquiaEoCY
        GAVx1LdNFMfeFzRgQSiIPUa1JG2H2zGXylpRZhMIBtZrFmvlagXMgRFJKILOmsVuekTcxF
        aAl0svxt3lMUIqLyAAX1laSGJ7BWwAM4eAO38CSU4FAGqLCjViInt5jz0JgENBZGZ7B4iK
        Yp+NAD8winaienxFAz8KADywWEiLIpaLugE/f4k0dot4mG1AdlepB39rfXkJ0VS/j8Y1ns
        Y0hcWxm2A1gEsL0nwJfDLdcgI9BxrBqjjH7JmyAUMjszh/SUWGELm5BsOXsR22vuERKKsI
        tUUH/dxyWO2IKzkjvg3Y8enGH28FWZLBSjTE2DtGPGCQzJPpDaM8A6BwfBQNwbd7m3QJ6h
        LnC6x1i9Cc8SVSUwEFJlQoTeECxbJYrIRIDbLkR1SGPiLJlOrkRxBEh3byFORl7JYxQtN6
        wMC2rYUIADs=""",
    'cone' : """
        R0lGODlhIAAgALMAAOyVC/n5+f////T09AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAACH5BAEAAAIALAAAAAAgACAAAwRTUMhJq7046827/2AoTgAwbqV5Xqm6Vu1r
        ta5M128Z7KUsAbsgbnRL2YpDENJ4AgafPaLzKUxylrEQlqbUUb9WjPdLjV63yAx6Hfa53/
        C4fE6fRwAAOw==""",
    'painted_floor' : """
        R0lGODlhIAAgAPcAAAAAAAAABgAAHQAATAAAlgAA/wAEAAAEBgAEHQAETAAElgAE/wATAA
        ATBgATHQATTAATlgAT/wAxAAAxBgAxHQAxTAAxlgAx/wBhAABhBgBhHQBhTABhlgBh/wCm
        AACmBgCmHQCmTACmlgCm/wD/AAD/BgD/HQD/TAD/lgD//wYAAAYABgYAHQYATAYAlgYA/w
        YEAAYEBgYEHQYETAYElgYE/wYTAAYTBgYTHQYTTAYTlgYT/wYxAAYxBgYxHQYxTAYxlgYx
        /wZhAAZhBgZhHQZhTAZhlgZh/wamAAamBgamHQamTAamlgam/wb/AAb/Bgb/HQb/TAb/lg
        b//x0AAB0ABh0AHR0ATB0Alh0A/x0EAB0EBh0EHR0ETB0Elh0E/x0TAB0TBh0THR0TTB0T
        lh0T/x0xAB0xBh0xHR0xTB0xlh0x/x1hAB1hBh1hHR1hTB1hlh1h/x2mAB2mBh2mHR2mTB
        2mlh2m/x3/AB3/Bh3/HR3/TB3/lh3//0wAAEwABkwAHUwATEwAlkwA/0wEAEwEBkwEHUwE
        TEwElkwE/0wTAEwTBkwTHUwTTEwTlkwT/0wxAEwxBkwxHUwxTEwxlkwx/0xhAExhBkxhHU
        xhTExhlkxh/0ymAEymBkymHUymTEymlkym/0z/AEz/Bkz/HUz/TEz/lkz//5YAAJYABpYA
        HZYATJYAlpYA/5YEAJYEBpYEHZYETJYElpYE/5YTAJYTBpYTHZYTTJYTlpYT/5YxAJYxBp
        YxHZYxTJYxlpYx/5ZhAJZhBpZhHZZhTJZhlpZh/5amAJamBpamHZamTJamlpam/5b/AJb/
        Bpb/HZb/TJb/lpb///8AAP8ABv8AHf8ATP8Alv8A//8EAP8EBv8EHf8ETP8Elv8E//8TAP
        8TBv8THf8TTP8Tlv8T//8xAP8xBv8xHf8xTP8xlv8x//9hAP9hBv9hHf9hTP9hlv9h//+m
        AP+mBv+mHf+mTP+mlv///////////////////////////////////////////yH5BAAAAA
        AALAAAAAAgACAABwj/AAEoS0aPYLJkwxAWVDaP4cCCBRFKhAggWcODBjFaTDZwXsaMDA8+
        5OhxYcOGJjkmHHbxJMeCJUmGdLjSoMeBDg3OvHiwZsSbN0lm/NlxZNCIJh0CVSkx50WcHi
        UK7WnR6MGlDE+OtLm1qMyRTr1qlWkwZUiiG5OK9NiSY9qqVT3WtEk1YU6IOumtxOk24kiz
        WON2pIsXr9CQEhOSbdk1qNaLEWVGVXuxJmSMO0NeHirUpE+4C93OdXo4KMaUMMe6bOryLO
        eBOjeCXSp59mDAO0vDzj3QLmjdOiuzLh23LmnNGZfC5Iv4qmSSl++uzfrXKFRliJEeXO72
        8tPiifuGRh+mOWzdzTDJducbk+v2q7PfM274mSfS7GS5R4UqPmLCm6MFJZ12UuWEHFftrU
        SPasQd5dVW2nlFID0ArKYdVkBJ+B4AAQEAOw==""",
    'plain_floor' : """
        R0lGODlhIAAgAOf1AAAAAAAAMwAAZgAAmQAAzAAA/wArAAArMwArZgArmQArzAAr/wBVAA
        BVMwBVZgBVmQBVzABV/wCAAACAMwCAZgCAmQCAzACA/wCqAACqMwCqZgCqmQCqzACq/wDV
        AADVMwDVZgDVmQDVzADV/wD/AAD/MwD/ZgD/mQD/zAD//zMAADMAMzMAZjMAmTMAzDMA/z
        MrADMrMzMrZjMrmTMrzDMr/zNVADNVMzNVZjNVmTNVzDNV/zOAADOAMzOAZjOAmTOAzDOA
        /zOqADOqMzOqZjOqmTOqzDOq/zPVADPVMzPVZjPVmTPVzDPV/zP/ADP/MzP/ZjP/mTP/zD
        P//2YAAGYAM2YAZmYAmWYAzGYA/2YrAGYrM2YrZmYrmWYrzGYr/2ZVAGZVM2ZVZmZVmWZV
        zGZV/2aAAGaAM2aAZmaAmWaAzGaA/2aqAGaqM2aqZmaqmWaqzGaq/2bVAGbVM2bVZmbVmW
        bVzGbV/2b/AGb/M2b/Zmb/mWb/zGb//5kAAJkAM5kAZpkAmZkAzJkA/5krAJkrM5krZpkr
        mZkrzJkr/5lVAJlVM5lVZplVmZlVzJlV/5mAAJmAM5mAZpmAmZmAzJmA/5mqAJmqM5mqZp
        mqmZmqzJmq/5nVAJnVM5nVZpnVmZnVzJnV/5n/AJn/M5n/Zpn/mZn/zJn//8wAAMwAM8wA
        ZswAmcwAzMwA/8wrAMwrM8wrZswrmcwrzMwr/8xVAMxVM8xVZsxVmcxVzMxV/8yAAMyAM8
        yAZsyAmcyAzMyA/8yqAMyqM8yqZsyqmcyqzMyq/8zVAMzVM8zVZszVmczVzMzV/8z/AMz/
        M8z/Zsz/mcz/zMz///8AAP8AM/8AZv8Amf8AzP8A//8rAP8rM/8rZv8rmf8rzP8r//9VAP
        9VM/9VZv9Vmf9VzP9V//+AAP+AM/+AZv+Amf+AzP+A//+qAP+qM/+qZv+qmf+qzP+q///V
        AP/VM//VZv/Vmf/VzP///////////////////////////////////////////yH+EUNyZW
        F0ZWQgd2l0aCBHSU1QACwAAAAAIAAgAAAI/gABKEtGj2CyZMMQFlQ2j+HAggURSoQIIFnD
        gwYxWkw2cF7GjAwPPuTocWHDhiY5Jhx28STHgiVJhnS40qDHgQ4Nzrx4sGbEmzdJZvzZcW
        TQiCYdAlUpMedFnB4lCu1p0ejBpQxPjrS5tajMkU69apVpMGVIohuTivTYkmPaqlU91rRJ
        NWFOiDrprcTpNuJIs1jjdqSLF6/QkBITkm3ZNajWixFlRlV7sSZkjDtDXh4q1KRPuAvdzn
        V6OCjGlDDHumzq8izngTo3gl0qefZgwDtLw8490C5o3Torsy4dty5pzRmXwuSL+Kpkkpfv
        rs361yhUZYiRHlzu9vLT4on7R4Yfpjls3c0wyXbnG5Pr9quz3zNu+Jkn0uxkuUeFKj5iwp
        ujBSWddlLlhBxX7a1Ej2rEHeXVVtp5RSA9AKymHVZASfgeAAEBADs=""",
    'pykkar_e' : """
        R0lGODlhIAAgALMAAAAAAJ83G8febf///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAACH5BAEAAAMALAAAAAAgACAAAwSMcMhJq7046827/6AWjKRXXmRaAagqAXCc
        sVY6DrGgCzIFiyTAbriL/X4bGHFJm/QsyqW0mRRKr1SMFWsscrY8Y5TnTV7JRWv2Aia21d
        8zOLqGytNlTXu47ddXezpdeU5sOWeESDNjWDhPFTYvgWEsipCRkkyAGJiSMS5Ofxw2AZsh
        pCGpqqusra6vFREAOw==""",
    'pykkar_e_cone' : """
        R0lGODlhIAAgALMAAAAAAJ83Gw2VC8l/CeyVC8febfT09PT09AAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAACH5BAEAAAIALAAAAAAgACAAAwS2UMhJq7046827H14oDaQVnKiHDkQ5oXAF
        XDDbDkCeZ7NZE0BSYaiT9TArIMFAGgyJutluY1sym8+jpHjJVQ0GpZDoyRW+YeDVWdBiAE
        +0EnzDceBDuTrdBGnwZ3NpVnt1PHGCiVZNf4iFj2Auh3mKhEuSk4GPliRuXXh6i06engI6
        oWNtFFMZcqlkUUhJaq9QUqUCMAFVtaqruD83UQAxv1QtPsUTrBeYEroBIiPS1NXW19jZGh
        EAOw==""",
    'pykkar_n' : """
        R0lGODlhIAAgALMAAAAAAJ83G8febf///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAACH5BAEAAAMALAAAAAAgACAAAwSecMhJq724grxp59N3fYCIbWU2pKkammPr
        SnA8a3PtdmXfh7dAgLYSGI8CX2eYEdIAyOhxI2RenEVkTwqoNofQaSkZRnoxznJSqxacr4
        HxlKvFotvt9XRgPUXlc3s5XEpqOhp0UkYyKoCLimQ3NH+QhyOUXJIeZXlJmnxCnWJvX2mQ
        nqRoXo5aoH2qWJ0pqaqbhRK0aJqvn72+v8DBwBEAOw==""",
    'pykkar_n_cone' : """
        R0lGODlhIAAgALMAAAAAAJ83Gw2VC8l/CeyVC8febfT09PT09AAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAACH5BAEAAAIALAAAAAAgACAAAwS5UMhJq724grxp59N3fYCIbWUmpKkamoNV
        mio9xB7tivftuSNJaUDokYCCQEC4KtwM0Nuss8wohYCCcwCNagsbZfVybW4J6PTgCxBbl1
        ktMa3+FtyYa/zZ7a+1eGQBJVt9hn9gZXl7dI1of2E7Z450kEhZN5SNazoyfIagUkifoKE4
        KpmamqcYqaqrqK+yrBQ9tre4uW96dr1hirtwcb1gScB5eMN2KYEqwFNTEs3OSNLV19jZ2t
        vc2REAOw==""",
    'pykkar_s' : """
        R0lGODlhIAAgALMAAAAAAJ83G8febf///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAACH5BAEAAAMALAAAAAAgACAAAwSZcMhJq7046827/2DwiV1gSkCqptTJmWIq
        zLQASDCpwQNQ16zc6+T70W7CDUxmPPI+xV+UBeo1o7MbtGmTQrFAqXbDvBrHGuxKde6oxd
        6d9XiW6i6mtxQIcOFNcHRHA34WMGc+bIOFFUuIYFqMLURcfDh3higrVz2XbhNrKihVnWRV
        VKYeomRoaTeoFyytsWOzFLWpoBm2pCARADs=""",
    'pykkar_s_cone' : """
        R0lGODlhIAAgALMAAAAAAJ83Gw2VC8l/CeyVC8febfT09PT09AAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAACH5BAEAAAIALAAAAAAgACAAAwS8UMhJq7046827/2DwiV1gSkCqptTJmWJa
        zHQBSDCpwQJQ16zc6+T70W5CzGDJbDqfTSVhSq1arwPN4MrFZrXd8JKzNJjP6PSYAyin34
        bljV3YhqdLW6doFw/0Oz0zfV1/NjoXJkV1cGZ5KS6JJjQDjXl6kRYwNYRUhpiIFTCLnQSX
        c5miRJRop6ihoigqbnF/N697E21Lpiw9ICgUUbrAvhNrFHN7xscVzBosz863bMrKF9Yb17
        8Y28DfAhEAOw==""",
    'pykkar_w' : """
        R0lGODlhIAAgALMAAAAAAJ83G8febf///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAACH5BAEAAAMALAAAAAAgACAAAwSJcMhJq7046827/2AIBmQpAkBVmuKAqiUq
        U2uAvRQg7Dw+1LbLS8YrCnC120xnNM40PldzKktZrLlidXrEZlC9MNd76zGP3COHCRZT17
        tzPE0WxuVyJ3x+r+L3XUR0gGladWWFZkpkeU1RSi5bdCtQjG19P0lXX34TmhVkQEEWLBxA
        LaipqqusIREAOw==""",
    'pykkar_w_cone' : """
        R0lGODlhIAAgALMAAAAAAJ83Gw2VC8l/CeyVC8febfT09PT09AAAAAAAAAAAAAAAAAAAAA
        AAAAAAAAAAACH5BAEAAAIALAAAAAAgACAAAwS4UMhJq7046827/6A3hEJgntYwZgBQnWg1
        ECvrUnCrqwQNY60KoEAs8noDWADo0hWNA0PPF7Poms8CzyBFboKTIfFI4E4HusuNMlSZe2
        8aEawBHOPxQXGdccO7ZYB6cxtuXXiCexoqUYeAeYoYjIF/U5CEi5OUlUiRdZOIZ54sY36c
        cnRfUJaCqWyuYlqMeRxBV7GyUWdVanwCTqW7P1Y2OzNUJmovSksTPEnJHcwpKiQdNdbZ2t
        vZEQA7""",
    'wall' : """
        R0lGODlhIAAgAIQAAAAAAGpsN2tVRWBgYHNzcwFhuCiX/owtALplDZlvQNl8ALqOV6quYv
        +1Us/RbYSEhJaWlrmoktWWhsa9lN+uot7Wrf/aqOvnkv//hMDAwMbGxtjY2AAAAAAAAAAA
        AAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQAZAAAACwAAAAAIAAgAIcAAAAAADMAAGYAAJ
        kAAMwAAP8AKwAAKzMAK2YAK5kAK8wAK/8AVQAAVTMAVWYAVZkAVcwAVf8AgAAAgDMAgGYA
        gJkAgMwAgP8AqgAAqjMAqmYAqpkAqswAqv8A1QAA1TMA1WYA1ZkA1cwA1f8A/wAA/zMA/2
        YA/5kA/8wA//8zAAAzADMzAGYzAJkzAMwzAP8zKwAzKzMzK2YzK5kzK8wzK/8zVQAzVTMz
        VWYzVZkzVcwzVf8zgAAzgDMzgGYzgJkzgMwzgP8zqgAzqjMzqmYzqpkzqswzqv8z1QAz1T
        Mz1WYz1Zkz1cwz1f8z/wAz/zMz/2Yz/5kz/8wz//9mAABmADNmAGZmAJlmAMxmAP9mKwBm
        KzNmK2ZmK5lmK8xmK/9mVQBmVTNmVWZmVZlmVcxmVf9mgABmgDNmgGZmgJlmgMxmgP9mqg
        BmqjNmqmZmqplmqsxmqv9m1QBm1TNm1WZm1Zlm1cxm1f9m/wBm/zNm/2Zm/5lm/8xm//+Z
        AACZADOZAGaZAJmZAMyZAP+ZKwCZKzOZK2aZK5mZK8yZK/+ZVQCZVTOZVWaZVZmZVcyZVf
        +ZgACZgDOZgGaZgJmZgMyZgP+ZqgCZqjOZqmaZqpmZqsyZqv+Z1QCZ1TOZ1WaZ1ZmZ1cyZ
        1f+Z/wCZ/zOZ/2aZ/5mZ/8yZ///MAADMADPMAGbMAJnMAMzMAP/MKwDMKzPMK2bMK5nMK8
        zMK//MVQDMVTPMVWbMVZnMVczMVf/MgADMgDPMgGbMgJnMgMzMgP/MqgDMqjPMqmbMqpnM
        qszMqv/M1QDM1TPM1WbM1ZnM1czM1f/M/wDM/zPM/2bM/5nM/8zM////AAD/ADP/AGb/AJ
        n/AMz/AP//KwD/KzP/K2b/K5n/K8z/K///VQD/VTP/VWb/VZn/Vcz/Vf//gAD/gDP/gGb/
        gJn/gMz/gP//qgD/qjP/qmb/qpn/qsz/qv//1QD/1TP/1Wb/1Zn/1cz/1f///wD//zP//2
        b//5n//8z///8AAAAAAAAAAAAAAAAI/wABAECjbBKaSWIATFJ28GDCgQUdKmRoEOHEimgS
        EsSYcCFHiB8pNuxY0WBCkSYVlsy48CBCMQnFjOxI8WXMmQoPZrrxUGBGmR1d9ug5EGZGAD
        DF8ASQSRlDgVCRwlza9GlUgTB9Eiup0SlSNFq5TvTK1GnDSUsjKhO4EGXas18xGpwIV6Zc
        sBvrTgrpsiHSvW5SRsQoNTCaTCf3ws14NrHLSW5iwnw5sGImiUkR4l1JeeDSv2cjPxQzFK
        tcmTmhXkZ6eW/W1WzBirmcFGTXvVKV3r49KTfYlhZbHsT6myJNNMOhEjwYGaLL5s4h8w5M
        U3HwwUc9Vjy+HUBEh0G3n5lsrJGjGOAIS593WHzk0fWaB+KEajRrQ8RE60sGWtZq1KSvmX
        WVTw+hsZVOXa111EAHToLYWGuNdVZaBkXY1oTjVRRXY3RpaBeHeXlo2VE1+QUfbd7dVZR1
        iclVFIeDKRbTUPGdBZlFQDFWWV/4YfUZfPPVBpp4TIEVG2suoTbXkbP9tNtEgeW2FEEPUt
        lbUu1ZFCKBHR6XXEAAOw==""",
}


#def _create_rotated_image(source, source_height, source_width):
# Does not work ... but idea is good :)
#    """ returns new tk.PhotoImage with source pixels rotated 90deg clockwise.
#        Assuming source image has square dimensions
#    """
#    #source_height = int(source['height'])
#    #source_width = int(source['width'])
#    #print(source['height'], source['height'], file=sys.stderr)
#    dest = tk.PhotoImage(width=source_height, height=source_width)
#    for x in range(source_width):
#        for y in range(source_height):
#            px = source.get(x, y)
#            print("pixel: ", px, file=sys.stderr)
#            dest.put(px, to=(source_height-y, x))
#    
#    return dest

        
if __name__ == '__main__':
    if len(sys.argv) < 2:
        layout_str = "####\n#> #\n#  #\n####"
    else:
        layout_str = eval(sys.argv[1])

    try:
        wp = _WorldProper(layout_str)
        cb = _CmdBroker(wp)
        cb.start()
        print("OK")
    except:
        print(repr(traceback.format_exc()))
    # run mainloop
    wp.run()
    


So I have come up with this code
from pykkar import *

create_world("""
########
#      #
#     v#
#      #
#      #
#      #
########
""")

class world_täiend(World):
    def left(self):
        world.excecute("left")
        
class pykkar_täiend(Pykkar):
    def left(self):
        self._world.excecute("left")

class _WorldProper_täiend(_WorldProper):
    def _cmd_right(self):
        headings = (N,E,S,W)
        cur_tile = self._get_current_tile() 
        
        cur_heading_index = headings.index(cur_tile.pykkar_heading)
        new_heading_index = (cur_heading_index - 1) % 4
        cur_tile.pykkar_heading = headings[new_heading_index]
        
        self._update_pykkar_image(cur_tile)


left()

When I run my code I get this error.
Traceback (most recent call last):
  File "C:\Users\MarkoPC\Desktop\python\pykkar_test.py", line 21, in <module>
    class _WorldProper_täiend(_WorldProper):
NameError: name '_WorldProper' is not defined

I did not wan to but the source in here because it is just so god damn long. But some of you wanted it, so here it is :D



More information about the Python-list mailing list