Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #55055 > unrolled thread

class implementation

Started bymarkotaht@gmail.com
First post2013-09-30 01:43 -0700
Last post2013-10-09 00:41 +0100
Articles 15 on this page of 35 — 15 participants

Back to article view | Back to comp.lang.python


Contents

  class implementation markotaht@gmail.com - 2013-09-30 01:43 -0700
    Re: class implementation Peter Otten <__peter__@web.de> - 2013-09-30 11:03 +0200
    Re: class implementation markotaht@gmail.com - 2013-09-30 02:10 -0700
      Re: class implementation Peter Otten <__peter__@web.de> - 2013-09-30 11:27 +0200
    Re: class implementation markotaht@gmail.com - 2013-09-30 05:41 -0700
      Re: class implementation Peter Otten <__peter__@web.de> - 2013-09-30 15:02 +0200
      Re: class implementation Joel Goldstick <joel.goldstick@gmail.com> - 2013-09-30 09:21 -0400
      Re: class implementation Piet van Oostrum <piet@vanoostrum.org> - 2013-09-30 13:32 -0400
      Re: class implementation Dave Angel <davea@davea.name> - 2013-09-30 19:34 +0000
        Re: class implementation 88888 Dihedral <dihedral88888@gmail.com> - 2013-10-01 00:01 -0700
      Re: class implementation Ned Batchelder <ned@nedbatchelder.com> - 2013-09-30 17:28 -0400
        Re: class implementation Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-09-30 23:45 +0000
          Re: class implementation Ethan Furman <ethan@stoneleaf.us> - 2013-09-30 17:31 -0700
      Re: class implementation random832@fastmail.us - 2013-09-30 17:49 -0400
      Python variables?  [was Re: class implementation] Ethan Furman <ethan@stoneleaf.us> - 2013-09-30 15:02 -0700
      Re: Python variables? Ben Finney <ben+python@benfinney.id.au> - 2013-10-01 08:37 +1000
      Re: Python variables?  [was Re: class implementation] Ned Batchelder <ned@nedbatchelder.com> - 2013-09-30 19:45 -0400
        Re: Python variables?  [was Re: class implementation] "Rhodri James" <rhodri@wildebst.demon.co.uk> - 2013-10-01 01:29 +0100
      Re: Python variables? Ned Batchelder <ned@nedbatchelder.com> - 2013-09-30 19:47 -0400
        Re: Python variables? Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-10-01 01:03 +0000
          Re: Python variables? Ned Batchelder <ned@nedbatchelder.com> - 2013-09-30 21:28 -0400
      Re: class implementation Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-10-01 00:19 +0000
    Re: class implementation markotaht@gmail.com - 2013-10-06 06:15 -0700
      Re: class implementation Terry Reedy <tjreedy@udel.edu> - 2013-10-06 15:52 -0400
      Re: class implementation Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2013-10-07 01:24 +0000
    Re: class implementation markotaht@gmail.com - 2013-10-08 01:20 -0700
      Re: class implementation Mark Lawrence <breamoreboy@yahoo.co.uk> - 2013-10-08 09:41 +0100
      Re: class implementation Dave Angel <davea@davea.name> - 2013-10-08 10:31 +0000
      Re: class implementation Cameron Simpson <cs@zip.com.au> - 2013-10-09 10:55 +1100
        Re: class implementation markotaht@gmail.com - 2013-10-10 11:34 -0700
          Re: class implementation Cameron Simpson <cs@zip.com.au> - 2013-10-11 09:07 +1100
          Re: class implementation Piet van Oostrum <piet@vanoostrum.org> - 2013-10-10 19:29 -0400
            Re: class implementation Ben Finney <ben+python@benfinney.id.au> - 2013-10-11 10:51 +1100
    Re: class implementation markotaht@gmail.com - 2013-10-08 07:05 -0700
      Re: class implementation "Rhodri James" <rhodri@wildebst.demon.co.uk> - 2013-10-09 00:41 +0100

Page 2 of 2 — ← Prev page 1 [2]


#55156 — Re: Python variables?

FromNed Batchelder <ned@nedbatchelder.com>
Date2013-09-30 21:28 -0400
SubjectRe: Python variables?
Message-ID<mailman.528.1380591267.18130.python-list@python.org>
In reply to#55152
On 9/30/13 9:03 PM, Steven D'Aprano wrote:
> On Mon, 30 Sep 2013 19:47:49 -0400, Ned Batchelder wrote:
>
>> On 9/30/13 6:37 PM, Ben Finney wrote:
>>> Ethan Furman <ethan@stoneleaf.us> writes:
>>>
>>>>   From [Ned Batchelder]'s blog:
>>>>> Names are Python's variables: they refer to values, and
>>>>>    those values can change (vary) over the course of your program.
>>>> This is partially incorrect.  If the value referred to by the name is
>>>> immutable, then it cannot change; perhaps you meant to say that which
>>>> object the name points to can vary over time?
>>> I agree. Names are not Python's variables.
>>>
>>> If anything in Python is a “variable” as generally understood, it is
>>> not a name. It is a *binding*, from a reference (a name, or some other
>>> reference like a list item) to a value.
>>>
>>> It is the binding which can change over the course of the program, so
>>> that is the variable.
>>>
>>>
>> True, but no one calls the binding the variable.  Here is a program:
>>
>>       x = 4
>>
>> Every one of us is perfectly comfortable talking about the variable x.
>> Don't get hung up on implementation pedantry.  The name x here refers to
>> 4.  Later it could refer to "four".  The value associated with the name
>> x changed.  x is a variable.
> Your statement is ambiguous -- do you mean the *association* between
> value (object) and name changed, or the value which is associated with
> the name changed?

Yes, my statement was ambiguous.  The value of x at time t1 can be 
different than the value of x at time t2, and there are two different 
ways it can differ.  None of that changes the fact that the value 
associated with the name varies over the course of a program, giving 
rise to "variables."

I prefer to say that Python has variables, and they work by a mechanism 
of names referring to values.  I don't find that beginners get it by 
being told that Python has no variables.  It seems to be something that 
experts sometimes find helpful, though.

--Ned.
>
> In the first case, "the value associated with the name x changed" is no
> different from saying "the name binding changed", only longer and more
> ambiguous.
>
> In the second case, if you mean that the association remains the same,
> but the value itself changed, that's demonstrably untrue since 4 is
> immutable. But you know that :-)
>
> I straddle the fence on this dispute... I'll often refer to Python
> variables when, in my option, it doesn't confuse the issue or introduce
> ambiguity, but I feel guilty doing so :-) And I always look for the
> opportunity to introduce the concept of name binding into the discussion.
> I'm just not religious about it.
>
>

[toc] | [prev] | [next] | [standalone]


#55148

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-10-01 00:19 +0000
Message-ID<524a1512$0$29974$c3e8da3$5496439d@news.astraweb.com>
In reply to#55066
On Mon, 30 Sep 2013 05:41:16 -0700, markotaht wrote:

> under variables, i mean, the int's and lists and strings and floats that
> the parent class uses. IF in parent class there is variable called
> location, then can i use the same variable in my sub class.

Firstly, in Python circles we prefer to call them "attributes" rather 
than variables.

Since this is Python, it is trivially easy to test this for yourself. 
Start an interactive Python interpreter, and then in under a dozen lines 
you can test it:

py> class Test:
...     attr = "Hello World!"  # Shared class attribute.
...
py> class MyTest(Test):
...     pass
...
py> x = MyTest()
py> x.attr
'Hello World!'


Works perfectly! (It would be a funny programming language where it 
didn't, since this is one of the most fundamental parts of inheritance. A 
language that didn't do something equivalent to this couldn't really 
claim to be object-oriented.)



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#56253

Frommarkotaht@gmail.com
Date2013-10-06 06:15 -0700
Message-ID<052c735c-0d79-4a1b-91d9-b0676acf9ba8@googlegroups.com>
In reply to#55055
There is this class file, it has its functions and variables. Now im greating my program, that uses the funcions from the class. BUt there are some functions missing from the class. So i want to add some extra funtions to the class, whidout altering the original source code, but by extending it in my code. But for that i need to use some variables that exsist in the original class. Is there a way i can acccsess them?

[toc] | [prev] | [next] | [standalone]


#56281

FromTerry Reedy <tjreedy@udel.edu>
Date2013-10-06 15:52 -0400
Message-ID<mailman.795.1381089306.18130.python-list@python.org>
In reply to#56253
On 10/6/2013 9:15 AM, markotaht@gmail.com wrote:
> There is this class file, it has its functions and variables. Now im greating my program, that uses the funcions from the class. BUt there are some functions missing from the class. So i want to add some extra funtions to the class, whidout altering the original source code, but by extending it in my code. But for that i need to use some variables that exsist in the original class. Is there a way i can acccsess them?

I though you already got an answer: subclass the class.


-- 
Terry Jan Reedy

[toc] | [prev] | [next] | [standalone]


#56296

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2013-10-07 01:24 +0000
Message-ID<52520d5c$0$29984$c3e8da3$5496439d@news.astraweb.com>
In reply to#56253
On Sun, 06 Oct 2013 06:15:51 -0700, markotaht wrote:

> There is this class file, it has its functions and variables. 

What's a class file?

Do you mean a file containing only a single class? 


> Now im
> greating my program, that uses the funcions from the class.

They are called "methods".


> BUt there
> are some functions missing from the class. So i want to add some extra
> funtions to the class, whidout altering the original source code, but by
> extending it in my code. But for that i need to use some variables that
> exsist in the original class. Is there a way i can acccsess them?

When you say "variables", we prefer to say "attributes".

A string variable is a variable that holds a string.
An int variable is a variable that holds an int.
A list variable is a variable that holds a list.
A float variable is a variable that holds a float.

So... 

...a class variable is a variable that holds a class, and an instance 
variable is a variable that holds an instance.


When extending classes, you access attributes exactly the same way you 
would access them if you were writing the class in the first place.

class Test(object):
    def __init__(self, arg):
        self.arg = arg  # Store the arg as an instance attribute.
    def method(self):
        print("arg is", self.arg)


class NewTest(Test):  # subclass to add new methods
    def add_one(self):
        return self.arg+1


For experts only: sometimes you need to extend the class itself. You can 
do that by adding methods to the class:

def minus_one(self):
    return self.arg-1

NewTest.minus_one = minus_one



-- 
Steven

[toc] | [prev] | [next] | [standalone]


#56367

Frommarkotaht@gmail.com
Date2013-10-08 01:20 -0700
Message-ID<99e763bd-9757-4d44-ad8d-10fd8a2dc3bd@googlegroups.com>
In reply to#55055
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")

    def _cmd_left(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)

class world_l(World):
    def left(self):
        self._world.execute("left")

These are my subclasses. For it to work. Class World, must obtain the method from subclass world_l

[toc] | [prev] | [next] | [standalone]


#56370

FromMark Lawrence <breamoreboy@yahoo.co.uk>
Date2013-10-08 09:41 +0100
Message-ID<mailman.839.1381221721.18130.python-list@python.org>
In reply to#56367
On 08/10/2013 09:20, markotaht@gmail.com wrote:

To whom and to what are you replying?

-- 
Roses are red,
Violets are blue,
Most poems rhyme,
But this one doesn't.

Mark Lawrence

[toc] | [prev] | [next] | [standalone]


#56383

FromDave Angel <davea@davea.name>
Date2013-10-08 10:31 +0000
Message-ID<mailman.847.1381228302.18130.python-list@python.org>
In reply to#56367
On 8/10/2013 04:20, markotaht@gmail.com wrote:

> I cant just subclassing doesent work.

I can't parse that "sentence."

> 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. 

What's a "source class"?  If you mean parent class, then say so.
Otherwise, if you give it a name, we might be able to follow.   But
"source" and "other" don't narrow the field very much.

A parent class can certainly access the child class (subclass) 
methods (not functions).  But only if the instance (self) is an instance
of the child class. That's the whole point of subclassing.

>
> 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")
>
>     def _cmd_left(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)
>
> class world_l(World):
>     def left(self):
>         self._world.execute("left")
>
> These are my subclasses. For it to work. Class World, must obtain the method from subclass world_l

Then it sounds like you should make sure that the global value "world"
in that module is an instance of your world_l class, rather than an
instance or World.  And that the proxy is an instance of pykkar_l rather
than of Pykkar.

import pykkar

layout = "fdlkjdsljdslfkjsdljfdsf"
pykkar.world = world_I(layout)
??? = pykkar_l(pykkar.world)

You don't show your own top-level code, so I can't integrate it in.

By the way, it's conventional to use uppercase for class names, and
lowercase for instances of those classes.

I'm astounded that your class is using eval and multiprocessing before
understanding classes and subclasses.


-- 
DaveA

[toc] | [prev] | [next] | [standalone]


#56456

FromCameron Simpson <cs@zip.com.au>
Date2013-10-09 10:55 +1100
Message-ID<mailman.882.1381278450.18130.python-list@python.org>
In reply to#56367
On 08Oct2013 01:20, markotaht@gmail.com <markotaht@gmail.com> 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,
-- 
Cameron Simpson <cs@zip.com.au>

It looks like you've got Mister Bus Error installed.    - tjc

[toc] | [prev] | [next] | [standalone]


#56596

Frommarkotaht@gmail.com
Date2013-10-10 11:34 -0700
Message-ID<706f150c-add5-492b-833e-f8813ce6a96c@googlegroups.com>
In reply to#56456
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

[toc] | [prev] | [next] | [standalone]


#56610

FromCameron Simpson <cs@zip.com.au>
Date2013-10-11 09:07 +1100
Message-ID<mailman.962.1381442885.18130.python-list@python.org>
In reply to#56596
On 10Oct2013 11:34, markotaht@gmail.com <markotaht@gmail.com> wrote:
> 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
[... lots and lots of docstring and code ...]
[... and finally a little more messgae ...]
> 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

As a matter of readability, if I really need to include a huge body
of text I append it below the end of my message, and say something
like this (pretending I were writing your message):

  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.

  I've appended the relevant pykkar source below this message.

  So I have come up with this code: [...]

That way your message does not get hidden by the (overly long IMO)
included material and readers can get on with looking at your stuff,
knowing that if necessary they can wade through the other stuff.

Cheers,
-- 
Cameron Simpson <cs@zip.com.au>

Any profit should go to Arnie's `get the daemon carved on Mount Rushmore' fund.
        - Marty Albini, DOD0550, martya@sdd.hp.com

[toc] | [prev] | [next] | [standalone]


#56615

FromPiet van Oostrum <piet@vanoostrum.org>
Date2013-10-10 19:29 -0400
Message-ID<m2siw8wvr3.fsf@cochabamba.vanoostrum.org>
In reply to#56596
markotaht@gmail.com writes:

>
> 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. 

[...]

> 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):

Should that not be _cmd_left?

>         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

from import * doesn't import names that start with underscore (_). So therefore _WorldProper is not defined.

from import * is considered bad practice anyway. It is better just to import the things you need.

from pykkar import World, Pykkar, _WorldProper

I have looked a bit in this pykkar.py and I think it is badly structured for extension. The three classes are too strongly connected and it is difficult to get three subclasses connected in the proper way without duplicating code. But anyway you will have to do that when you create your world.

-- 
Piet van Oostrum <piet@vanoostrum.org>
WWW: http://pietvanoostrum.com/
PGP key: [8DAE142BE17999C4]

[toc] | [prev] | [next] | [standalone]


#56620

FromBen Finney <ben+python@benfinney.id.au>
Date2013-10-11 10:51 +1100
Message-ID<mailman.969.1381449079.18130.python-list@python.org>
In reply to#56615
Piet van Oostrum <piet@vanoostrum.org> writes:

> from import * is considered bad practice anyway. It is better just to import the things you need.
>
> from pykkar import World, Pykkar, _WorldProper

Or, even better, be explicit:

    import pykkar

    …

    foo = pykkar.World()

-- 
 \          “Computer perspective on Moore's Law: Human effort becomes |
  `\           twice as expensive roughly every two years.” —anonymous |
_o__)                                                                  |
Ben Finney

[toc] | [prev] | [next] | [standalone]


#56398

Frommarkotaht@gmail.com
Date2013-10-08 07:05 -0700
Message-ID<ab5d690a-7112-4f93-b9e4-a9011d64eb63@googlegroups.com>
In reply to#55055
Parent class is at the link. 

[toc] | [prev] | [next] | [standalone]


#56454

From"Rhodri James" <rhodri@wildebst.demon.co.uk>
Date2013-10-09 00:41 +0100
Message-ID<op.w4ntfjcsa8ncjz@gnudebeest>
In reply to#56398
On Tue, 08 Oct 2013 15:05:26 +0100, <markotaht@gmail.com> wrote:

> Parent class is at the link.

Please quote some context when you reply.  What link?

Then again, I'm not about to click on some random link someone posts to a  
newsgroup.  Apart from being one of the classic ways to get a virus onto  
my computer, it's rather selfish of you.  While your newsgroup posting  
will stay around essentially forever, the link will eventually rot.  At  
some point in the future, no one will be able to follow that link, so no  
one will be able to learn from what you have done.

Please show your working, it makes it so much easier for the rest of us to  
understand what you meant when you use terms so loosely!

-- 
Rhodri James *-* Wildebeest Herder to the Masses

[toc] | [prev] | [standalone]


Page 2 of 2 — ← Prev page 1 [2]

Back to top | Article view | comp.lang.python


csiph-web