20 Sep 2020

feedPlanet Python

John Cook: Descartes and Toolz

I was looking recently at the Python module toolz, a collection of convenience functions. A lot of these functions don't do that much. They don't save you much code, but they do make your code more readable by making it more declarative. You may not realize need them until you see them.

For example, there is a function partitionby that breaks up a sequence at the points where a given function's value changes. I'm pretty sure that function would have improved some code I've written recently, making it more declarative than procedural, but I can't remember what that was.

Although I can't think of my previous example, I can think of a new one, and that is Descartes' rule of signs.

Given a polynomial p(x), read the non-zero coefficients in order and keep note of how many times they change sign, either from positive to negative or vice versa. Call that number n. Then the number of positive roots of p(x) either equals n or n minus a positive even number.

For example, suppose

p(x) = 4x4 + 3.1x3 - x2 - 2x + 6.

The coefficients are 4, 3.1, -1, -2, and 6. The list of coefficients changes signs twice: from positive to negative, and from negative to positive. Here's a first pass at how you might have Python split the coefficients to look sign changes.

    from toolz import partitionby

    coefficients = [4, 3.1, -1, -2, 6]
    parts = partitionby(lambda x: x > 0, coefficients)
    print([p for p in parts])

This prints

    [(4, 3.1), (-1, -2), (6,)]

The first argument to partitionby an anonymous function that tests whether its argument is positive. When this function changes value, we have a sign alteration. There are three groups of consecutive coefficients that have the same sign, so there are two times the signs change. So our polynomial either has two positive roots or no positive roots. (It turns out there are no positive roots.)

The code above isn't quite right though, because Descartes said to only look at non-zero coefficients. If we change our anonymous function to

    lambda x: x >= 0

that will work for zeros in the middle of positive coefficients, but it will give a false positive for zeros in the middle of negative coefficients. We can fix the code with a list comprehension. The following example works correctly.

    coefficients = [4, 0, 3.1, -1, 0, -2, 6]
    nonzero = [c for c in coefficients if c != 0]
    parts = partitionby(lambda x: x > 0, nonzero)
    print([p for p in parts])

If our coefficients were in a NumPy array rather than a list, we could remove the zeros more succinctly.

    from numpy import array

    c = array(coefficients)
    parts = partitionby(lambda x: x > 0, c[c != 0])

The function partitionby returns an iterator rather than a list. That's why we don't just print parts above. Instead we print [p for p in parts] which makes a list. In applications, it's often more efficient to have an iterator than a list, generating items if and when they are needed. If you don't need all the items, you don't have to generate them all. And even if you do need all the items, you could save memory by not keeping them all in memory at once. I'll ignore such efficiencies here.

We don't need the partitions per se, we just need to know how many there are. The example that escapes my mind would have been a better illustration if it needed to do more with each portion than just count it. We could count the number of sign alternations for Descartes rule as follows.

   len([p for p in parts]) - 1

Related posts

The post Descartes and Toolz first appeared on John D. Cook.

20 Sep 2020 3:22pm GMT

John Cook: Descartes and Toolz

I was looking recently at the Python module toolz, a collection of convenience functions. A lot of these functions don't do that much. They don't save you much code, but they do make your code more readable by making it more declarative. You may not realize need them until you see them.

For example, there is a function partitionby that breaks up a sequence at the points where a given function's value changes. I'm pretty sure that function would have improved some code I've written recently, making it more declarative than procedural, but I can't remember what that was.

Although I can't think of my previous example, I can think of a new one, and that is Descartes' rule of signs.

Given a polynomial p(x), read the non-zero coefficients in order and keep note of how many times they change sign, either from positive to negative or vice versa. Call that number n. Then the number of positive roots of p(x) either equals n or n minus a positive even number.

For example, suppose

p(x) = 4x4 + 3.1x3 - x2 - 2x + 6.

The coefficients are 4, 3.1, -1, -2, and 6. The list of coefficients changes signs twice: from positive to negative, and from negative to positive. Here's a first pass at how you might have Python split the coefficients to look sign changes.

    from toolz import partitionby

    coefficients = [4, 3.1, -1, -2, 6]
    parts = partitionby(lambda x: x > 0, coefficients)
    print([p for p in parts])

This prints

    [(4, 3.1), (-1, -2), (6,)]

The first argument to partitionby an anonymous function that tests whether its argument is positive. When this function changes value, we have a sign alteration. There are three groups of consecutive coefficients that have the same sign, so there are two times the signs change. So our polynomial either has two positive roots or no positive roots. (It turns out there are no positive roots.)

The code above isn't quite right though, because Descartes said to only look at non-zero coefficients. If we change our anonymous function to

    lambda x: x >= 0

that will work for zeros in the middle of positive coefficients, but it will give a false positive for zeros in the middle of negative coefficients. We can fix the code with a list comprehension. The following example works correctly.

    coefficients = [4, 0, 3.1, -1, 0, -2, 6]
    nonzero = [c for c in coefficients if c != 0]
    parts = partitionby(lambda x: x > 0, nonzero)
    print([p for p in parts])

If our coefficients were in a NumPy array rather than a list, we could remove the zeros more succinctly.

    from numpy import array

    c = array(coefficients)
    parts = partitionby(lambda x: x > 0, c[c != 0])

The function partitionby returns an iterator rather than a list. That's why we don't just print parts above. Instead we print [p for p in parts] which makes a list. In applications, it's often more efficient to have an iterator than a list, generating items if and when they are needed. If you don't need all the items, you don't have to generate them all. And even if you do need all the items, you could save memory by not keeping them all in memory at once. I'll ignore such efficiencies here.

We don't need the partitions per se, we just need to know how many there are. The example that escapes my mind would have been a better illustration if it needed to do more with each portion than just count it. We could count the number of sign alternations for Descartes rule as follows.

   len([p for p in parts]) - 1

Related posts

The post Descartes and Toolz first appeared on John D. Cook.

20 Sep 2020 3:22pm GMT

Kodnito: Tweet from Django application using Tweepy

In this tutorial, we will learn how to post a tweet from Django application using Tweepy.

20 Sep 2020 12:25pm GMT

Kodnito: Tweet from Django application using Tweepy

In this tutorial, we will learn how to post a tweet from Django application using Tweepy.

20 Sep 2020 12:25pm GMT

Evennia: Creating Evscaperoom, part 2


Jester smiling oh so sweetly
The Jester, your 'adversary'


This is part two of my post-mortem dev-blog about Evscaperoom, the multiplayer, text-based 'escape room' I wrote in Python and Evennia. You can read the first part of the dev blog here.

This was a game-jam entry I created in a month for the Mud Coder's guild's Game Jam. The theme was One Room. You can play the game for free in your browser or with a traditional MUD client. There are no spoilers in these blog posts.

Update: These days you can play the Evscaperoom by logging into the Evennia demo game at https://demo.evennia.com. It's just one of the exits you can get through when you enter.

The first part dealt with the overall game-design aspects. This second, final part will go into details of the code and the systems I built to quickly create all the content. The code referenced here is released under the BSD license and is available on github.

At the time of this post, players have played Evscaperoom for a little more than a week. At the end I'll share some observations and things I learned along the way.

Ease of building

Over the one-month game jam, I spent about four days making the game's 'engine' and toolset with Evennia. The rest of the time was spent using those tools to actually create game content (the story, puzzles etc).

An important thing was that I didn't want to do any traditional in-game 'building'. That is - no logging into the game and running various commands to build objects and rooms. This is partly because I wanted rooms to be buildable on-demand, but also because I didn't want my game to only exist in the database but in actual version-controllable python modules.

So all of the Evscaperoom is created in code (notably in the game states discussed below). This made it so that I could add unit tests to quickly find bugs and edge cases. It also made it easy to just clone the full game to an online server, init a database and run Evennia on it in a docker when time came to make it public.


Overall game structure

The main Evscaperoom menu, showing the option to create a new room or join one of two existing rooms.
Main menu

The game loop is simple: When you log in to the game, you get into a menu where you can create a new room to solve or join an existing one. Quitting a room brings you back to that menu. Quitting again leaves the game entirely. In between, you remain inside a single game location ('room').

To make it easier for people to agree to meet up in a room, i made a little 'fantasy name generator' to make unique random names of the rooms. It felt more thematic than showing room id's. The generator combines phonemes together with some very simple logic. Not all comes out easy-to-pronounce, but the result is at least identifiable, like the Sheru and Uyoha above.

I decided that I should not keep empty rooms around, so whenever a room has no more players in it, it's deleted from the database along with all its content. This means players can't really log off and come back to the same room unless a friend stays behind. I felt it was worth keeping things clean and avoid a growing backlog of empty, unsolved rooms. It is, unfortunately, quite common for players to log in, create a room and then immediately log off.

I distribute Evscaperoom as an Evennia 'game dir'. Once you've installed Evennia you can just clone the evscaperoom repo and start a new multiplayer server with it. While the game dir has some Evennia templates in it by default, Almost all the custom logic for this game is in the evscaperoom/ folder. The only other modification I did was to make sure Evennia rerouted new players into the Evscaperoom menu when they connect.


Room class

Since all of the gameplay happens in a single room, it made sense to center all of the data-storage around a new, custom Evennia Room class. This "EvscapeRoom" class holds all resources for this room. Evennia makes sure to persist it all to the database for you.

The Evennia API provides a lot of powerful but game-general functions. Since our use-case for this game is very strictly defined, I made a slew of helper functions to cut down on boiler plate and pre-set options I wanted to always use.

For example, I added helper methods both for creating and finding objects in the room. On creation, all objects are tagged with the room's unique hash, meaning that one can be sure to never have any cross-over between rooms (like accidentally finding the object in another room (that of course has the exact same name). Since I also decided to never have more than one object with a given name per room, I could make these methods very simple.

The room class also has helpers for finding all players in the room and for sending messages to them. It also catches players leaving so that eventual on-character variables can be cleaned.

Importantly, the very action of deleting the room will automatically clean all resources tied to it, keeping things tidy.


Commands and Objects

This shows a list of all commands useful in the room.
The help screen, show all top-level commands

As discussed in part one of this blog, the Evscaperoom, uses a 'focus' mode: The player must examine/focus on an object first in order to operate or use it.

The basic command syntax is:

> command [target]

The parsing I made actually allows for a more complex syntax, but in the end this was all that was really needed, since the currently 'focused' object does not need to be specified. This is the process of using one object with another:

> examine key

~~ key (examining) ~~
This is a brass key.

(To unlock something with it, use insert into <target>)

> insert into door

You unlock the door with the key!

(the into is optional). Here, we focus on the key. We get the key's description and a hint that you can insert it into things. We then insert it into the door, which is another object in the room. The insert command knows that we are focusing on the key already and that it should look into the room for an object door to use this with.

Technically, these on-object 'actions' (like insert above), are dynamically generated. Here is an example of the key object:

class Key(EvscaperoomObject):
def at_focus_insert(self, caller, **kwargs):
target = kwargs['args']
obj = caller.search(obj)
if not obj:
return
if obj.check_flag("can_use_key"):
obj.handle_insert(self)

Not shown here is that I made a wrapper for the "no-match" command of Evennia. This command fires when no other commands match. I made this instead analyze the currently 'focused' object to see if it had a method at_focus_<command_name> on it. If so, I inject the supplied arguments into that method as a keyword argument args.

So when you focus on the key and give the insert command, the at_focus_insert method on the key will be called with a target to insert the key into. We search for the target (the door in the example), check if it even accepts keys and then pass the key to that object to handle. It would then be up to the door to figure out if this particular key unlocks it.

I created a library of base objects that I can just use as mixins for the object I want to create. Here's an example:

from evscaperoom import objects

class Box(objects.Openable,
objects.CodeInput,
objects.Movable):
# ...

This class will offer actions to open, insert a code and move the object around. It will need some more configuration and addition of messages to show etc. But overall, this method-to-command solution ended up being very stable and extremely easy to use to make complex, interactive objects.


Room states

I think of the escape room as going through a series of states. A change of state could for example be that the user solved a puzzle to open a secret wall. That wall is now open, making new items and puzzles available. This means room description should change along with new objects being created or old ones deleted.

I chose to represent states as Python modules in a folder. To be a state, each module needs to have a global-level class State inheriting from my new BaseState class. This class has methods for initializing and cleaning up the state, as well as was for figuring out which state to go to next. As the system initializes the new state, it gets the current room as argument, so it can modify it.

This is a (simplified) example of a state module:

# module state_001_start.py

from evscaperoom.state import BaseState
from evscaperoom import objects


MUG_DESC = """
A blue mug filled with a swirling liquid.
On it is written "DRINK ME" with big letters.
"""

class Mug(objects.EvscapeRoomObject):
def at_focus_drink(self, caller, **kwargs):
caller.msg(f"You drink {self.key}.")
self.next_state() # trigger next state

class State(BaseState):

hints = ["You are feeling a little thirsty...",
"Drink from the mug, dummy."]

next_state = "state_002_big_puzzle"

def init(self):
mug = self.create_object(
Mug, key="wooden mug", aliases=["mug"])
mug.db.desc = MUG_DESC.strip()

In this simple state, a mug is created, and when you drink from it, the next state is triggered. The base object has a helper function to trigger the next state since I found that interactive with an object is almost always the reason for switching states.

The state-class has a lot of useful properties to set, such as which the next state should be (this can be overridden in case of branching paths). You can also store
a sequence of hints specific for that state.



Informing the room

I wrote the content in second-person perspective ("You open the door"). This is however a multiplayer game and I didn't intially appreciate how many texts must also exist in a third-party form for the rest of the room to see ("Griatch opens the door").

As the amount of text grew (the Evscaperoom has close to 10 000 lines of code, a lot of which is content strings), it became clear that it would not be feasible to manually supply third-persion version strings as well.

The solution was to add parsing and translation of pronouns and verbs (a concept I first saw on the game Armageddon).

I write the string like this:

OPEN_TEXT = "~You ~open the *door."

The ~ marks text that should be parsed for second/third-person use (I'll discuss the *door marking in the next section). This I then send to a helper method that either sends it only to you (which means it comes back pretty much the same, but without the special markers) or to you and to the room, in which it will look different depending on who receives it:

I see "You open the [door]."
Others see "Griatch opens the [door]."

English is luckily pretty easy to use for this kind of automatic translation - in general you can just add an "s" to the end of the verb. I made a simple mapping for the few irregular verbs I ended up using.

Overall, this made it quick to present multiple viewpoints with minimal extra text to write.

Shows the various accessibility options for showing items.
The option menu

The *door -style marking allowed me to generalize how target-able objects in the room were displayed. This meant that users can customize how objects are shown to them. The default is to mark them both with colors and square brackets (this makes it clear also for people with screen readers). But one can also use only colors or turn off the marking completely (hard mode).

Bringing it online

Evennia is both a mud framework and mudserver as well as a webserver based on Twisted. It runs the game's website (with the help of Django) and also provides its own HTML5 webclient. I tweaked the default website text and played a little with CSS but otherwise didn't spend too much time on this bit.

I got a $5/month DigitalOcean droplet with Ubuntu. I made a new, unprivileged "evennia" user on it and cloned the evscaperoom repo to it. I then started a tmux session and ran the Evennia docker image in there. Getting the game online took maybe thirty minutes, most of which was me figuring out where to open the droplet and DigitalOcean firewalls.

I then pointed http://experimental.evennia.com at the droplet's IP and that was it!

Updating the online server is now only a matter of pushing changes to my github repo, pulling it to the server and reloading Evennia; Before release, I used a private github repo for this, afterwards I simply made it public. Pretty straightforward.

Some lessons learned

I have gotten pretty positive reviews on Evscaperoom so far. In the first two days people stumbled on some edge-case bugs, but after that it has been very stable. Mostly I've had to make small typos and grammar corrections as I (or players) spot them.

There were nevertheless some things I learned, some of which led to more real improvements post-launch.

No amount of help is too much help

Shows focus on the 'bed', with an example of the header telling how to leave the 'focus' mode.
The header shows how to get out of focus mode

Firstly, the focus-system (examine, then do stuff) is a little un-orthodox and needs to be explained. I saw people logging in, examining exactly one thing and then logging out. Eventually I found out (because a user told me), that this was likely because they could not figure out how to leave the focus mode. They'd just flounder about, think the game was buggy and log off.

The answer (just run examine again) is found with the help command, but clearly this was not intuitive. The solution was to add an explicit help text to the top every time you examine something. After this, the confusion seems to have gone away.

Make it easy to connect for all tastes

Another example - a commenting user had pretty strong opinions about the fact that you used to have to supply a username and password to play the game. They suggested this was a 'huge hurdle'. Not sure if that's true. But unless you want to use a particular name, there is also no actual gameplay reason to formally authenticate for Evscaperoom.

This was easy to fix. Evennia has guest-player support out of the box so I just activated that and supplied some more fantasy-sounding names than the default "Guest 1", "Guest 2" etc. Since then, maybe 40% of players connecting have chosen to do so as an anonymous guest. I don't know if those would have left completely if the option was not available, but it's at least a convenient shortcut for getting into the game.

Everything takes longer than expected

I already knew this one, but still I fell into the trap of thinking that things were going well and that there would be plenty of time to finish before deadline.

Creating text content is a lot faster than creating graphical assets, but it's still a lot of work. Just the ending 'cinematics' took me almost two days to finish and clean up at the end.

For once I did pick a reasonable scale for this project though. So while the last few days of the Jam was more intense than I would have liked, I never truly felt like I would not be able to finish in time.


Building a MU* game in pure code is awesome

Evennia tries to not instil and specific game type, hence its tools are very general. Wrapping these general tools as a highly opinionated and game-specific toolbox enforced to me just how easy it is to do things when you don't need to cover the general case.

Using the tools and creating content purely in-code was great and ended up leading to a very fast content creation. Python works perfectly as a scripting language and I don't think there is a reason for using in-game building at all for your game, especially not when you are working on your own like this.

I made a few admin-only commands to jump between states and to set flags, but otherwise most bugs were caught by a generic unit test that just looped over all founds states and tried to initialize them, one after another.


Conclusions

For all my work on the Evennia library/server, I've not actually used it for games of my own very much. This was a great opportunity for doing so. It also gave me the opportunity to test the Python3-development branch of Evennia in a production setting.

I found a few edge-case library bugs which I fixed, but overall things worked very smoothly, also for this kind of game which is certainly far away from the normal MU*-mold that most use Evennia for. I am a bit biased, but overall I felt Evennia to be very mature for the use of making a game from scratch.

In the future I will most likely break out the 'engine' and tools of the Evscaperoom into an Evennia contrib so that others can make similar games with it easily.

Looking forward to future game jams now!

20 Sep 2020 10:39am GMT

Evennia: Creating Evscaperoom, part 2


Jester smiling oh so sweetly
The Jester, your 'adversary'


This is part two of my post-mortem dev-blog about Evscaperoom, the multiplayer, text-based 'escape room' I wrote in Python and Evennia. You can read the first part of the dev blog here.

This was a game-jam entry I created in a month for the Mud Coder's guild's Game Jam. The theme was One Room. You can play the game for free in your browser or with a traditional MUD client. There are no spoilers in these blog posts.

Update: These days you can play the Evscaperoom by logging into the Evennia demo game at https://demo.evennia.com. It's just one of the exits you can get through when you enter.

The first part dealt with the overall game-design aspects. This second, final part will go into details of the code and the systems I built to quickly create all the content. The code referenced here is released under the BSD license and is available on github.

At the time of this post, players have played Evscaperoom for a little more than a week. At the end I'll share some observations and things I learned along the way.

Ease of building

Over the one-month game jam, I spent about four days making the game's 'engine' and toolset with Evennia. The rest of the time was spent using those tools to actually create game content (the story, puzzles etc).

An important thing was that I didn't want to do any traditional in-game 'building'. That is - no logging into the game and running various commands to build objects and rooms. This is partly because I wanted rooms to be buildable on-demand, but also because I didn't want my game to only exist in the database but in actual version-controllable python modules.

So all of the Evscaperoom is created in code (notably in the game states discussed below). This made it so that I could add unit tests to quickly find bugs and edge cases. It also made it easy to just clone the full game to an online server, init a database and run Evennia on it in a docker when time came to make it public.


Overall game structure

The main Evscaperoom menu, showing the option to create a new room or join one of two existing rooms.
Main menu

The game loop is simple: When you log in to the game, you get into a menu where you can create a new room to solve or join an existing one. Quitting a room brings you back to that menu. Quitting again leaves the game entirely. In between, you remain inside a single game location ('room').

To make it easier for people to agree to meet up in a room, i made a little 'fantasy name generator' to make unique random names of the rooms. It felt more thematic than showing room id's. The generator combines phonemes together with some very simple logic. Not all comes out easy-to-pronounce, but the result is at least identifiable, like the Sheru and Uyoha above.

I decided that I should not keep empty rooms around, so whenever a room has no more players in it, it's deleted from the database along with all its content. This means players can't really log off and come back to the same room unless a friend stays behind. I felt it was worth keeping things clean and avoid a growing backlog of empty, unsolved rooms. It is, unfortunately, quite common for players to log in, create a room and then immediately log off.

I distribute Evscaperoom as an Evennia 'game dir'. Once you've installed Evennia you can just clone the evscaperoom repo and start a new multiplayer server with it. While the game dir has some Evennia templates in it by default, Almost all the custom logic for this game is in the evscaperoom/ folder. The only other modification I did was to make sure Evennia rerouted new players into the Evscaperoom menu when they connect.


Room class

Since all of the gameplay happens in a single room, it made sense to center all of the data-storage around a new, custom Evennia Room class. This "EvscapeRoom" class holds all resources for this room. Evennia makes sure to persist it all to the database for you.

The Evennia API provides a lot of powerful but game-general functions. Since our use-case for this game is very strictly defined, I made a slew of helper functions to cut down on boiler plate and pre-set options I wanted to always use.

For example, I added helper methods both for creating and finding objects in the room. On creation, all objects are tagged with the room's unique hash, meaning that one can be sure to never have any cross-over between rooms (like accidentally finding the object in another room (that of course has the exact same name). Since I also decided to never have more than one object with a given name per room, I could make these methods very simple.

The room class also has helpers for finding all players in the room and for sending messages to them. It also catches players leaving so that eventual on-character variables can be cleaned.

Importantly, the very action of deleting the room will automatically clean all resources tied to it, keeping things tidy.


Commands and Objects

This shows a list of all commands useful in the room.
The help screen, show all top-level commands

As discussed in part one of this blog, the Evscaperoom, uses a 'focus' mode: The player must examine/focus on an object first in order to operate or use it.

The basic command syntax is:

> command [target]

The parsing I made actually allows for a more complex syntax, but in the end this was all that was really needed, since the currently 'focused' object does not need to be specified. This is the process of using one object with another:

> examine key

~~ key (examining) ~~
This is a brass key.

(To unlock something with it, use insert into <target>)

> insert into door

You unlock the door with the key!

(the into is optional). Here, we focus on the key. We get the key's description and a hint that you can insert it into things. We then insert it into the door, which is another object in the room. The insert command knows that we are focusing on the key already and that it should look into the room for an object door to use this with.

Technically, these on-object 'actions' (like insert above), are dynamically generated. Here is an example of the key object:

class Key(EvscaperoomObject):
def at_focus_insert(self, caller, **kwargs):
target = kwargs['args']
obj = caller.search(obj)
if not obj:
return
if obj.check_flag("can_use_key"):
obj.handle_insert(self)

Not shown here is that I made a wrapper for the "no-match" command of Evennia. This command fires when no other commands match. I made this instead analyze the currently 'focused' object to see if it had a method at_focus_<command_name> on it. If so, I inject the supplied arguments into that method as a keyword argument args.

So when you focus on the key and give the insert command, the at_focus_insert method on the key will be called with a target to insert the key into. We search for the target (the door in the example), check if it even accepts keys and then pass the key to that object to handle. It would then be up to the door to figure out if this particular key unlocks it.

I created a library of base objects that I can just use as mixins for the object I want to create. Here's an example:

from evscaperoom import objects

class Box(objects.Openable,
objects.CodeInput,
objects.Movable):
# ...

This class will offer actions to open, insert a code and move the object around. It will need some more configuration and addition of messages to show etc. But overall, this method-to-command solution ended up being very stable and extremely easy to use to make complex, interactive objects.


Room states

I think of the escape room as going through a series of states. A change of state could for example be that the user solved a puzzle to open a secret wall. That wall is now open, making new items and puzzles available. This means room description should change along with new objects being created or old ones deleted.

I chose to represent states as Python modules in a folder. To be a state, each module needs to have a global-level class State inheriting from my new BaseState class. This class has methods for initializing and cleaning up the state, as well as was for figuring out which state to go to next. As the system initializes the new state, it gets the current room as argument, so it can modify it.

This is a (simplified) example of a state module:

# module state_001_start.py

from evscaperoom.state import BaseState
from evscaperoom import objects


MUG_DESC = """
A blue mug filled with a swirling liquid.
On it is written "DRINK ME" with big letters.
"""

class Mug(objects.EvscapeRoomObject):
def at_focus_drink(self, caller, **kwargs):
caller.msg(f"You drink {self.key}.")
self.next_state() # trigger next state

class State(BaseState):

hints = ["You are feeling a little thirsty...",
"Drink from the mug, dummy."]

next_state = "state_002_big_puzzle"

def init(self):
mug = self.create_object(
Mug, key="wooden mug", aliases=["mug"])
mug.db.desc = MUG_DESC.strip()

In this simple state, a mug is created, and when you drink from it, the next state is triggered. The base object has a helper function to trigger the next state since I found that interactive with an object is almost always the reason for switching states.

The state-class has a lot of useful properties to set, such as which the next state should be (this can be overridden in case of branching paths). You can also store
a sequence of hints specific for that state.



Informing the room

I wrote the content in second-person perspective ("You open the door"). This is however a multiplayer game and I didn't intially appreciate how many texts must also exist in a third-party form for the rest of the room to see ("Griatch opens the door").

As the amount of text grew (the Evscaperoom has close to 10 000 lines of code, a lot of which is content strings), it became clear that it would not be feasible to manually supply third-persion version strings as well.

The solution was to add parsing and translation of pronouns and verbs (a concept I first saw on the game Armageddon).

I write the string like this:

OPEN_TEXT = "~You ~open the *door."

The ~ marks text that should be parsed for second/third-person use (I'll discuss the *door marking in the next section). This I then send to a helper method that either sends it only to you (which means it comes back pretty much the same, but without the special markers) or to you and to the room, in which it will look different depending on who receives it:

I see "You open the [door]."
Others see "Griatch opens the [door]."

English is luckily pretty easy to use for this kind of automatic translation - in general you can just add an "s" to the end of the verb. I made a simple mapping for the few irregular verbs I ended up using.

Overall, this made it quick to present multiple viewpoints with minimal extra text to write.

Shows the various accessibility options for showing items.
The option menu

The *door -style marking allowed me to generalize how target-able objects in the room were displayed. This meant that users can customize how objects are shown to them. The default is to mark them both with colors and square brackets (this makes it clear also for people with screen readers). But one can also use only colors or turn off the marking completely (hard mode).

Bringing it online

Evennia is both a mud framework and mudserver as well as a webserver based on Twisted. It runs the game's website (with the help of Django) and also provides its own HTML5 webclient. I tweaked the default website text and played a little with CSS but otherwise didn't spend too much time on this bit.

I got a $5/month DigitalOcean droplet with Ubuntu. I made a new, unprivileged "evennia" user on it and cloned the evscaperoom repo to it. I then started a tmux session and ran the Evennia docker image in there. Getting the game online took maybe thirty minutes, most of which was me figuring out where to open the droplet and DigitalOcean firewalls.

I then pointed http://experimental.evennia.com at the droplet's IP and that was it!

Updating the online server is now only a matter of pushing changes to my github repo, pulling it to the server and reloading Evennia; Before release, I used a private github repo for this, afterwards I simply made it public. Pretty straightforward.

Some lessons learned

I have gotten pretty positive reviews on Evscaperoom so far. In the first two days people stumbled on some edge-case bugs, but after that it has been very stable. Mostly I've had to make small typos and grammar corrections as I (or players) spot them.

There were nevertheless some things I learned, some of which led to more real improvements post-launch.

No amount of help is too much help

Shows focus on the 'bed', with an example of the header telling how to leave the 'focus' mode.
The header shows how to get out of focus mode

Firstly, the focus-system (examine, then do stuff) is a little un-orthodox and needs to be explained. I saw people logging in, examining exactly one thing and then logging out. Eventually I found out (because a user told me), that this was likely because they could not figure out how to leave the focus mode. They'd just flounder about, think the game was buggy and log off.

The answer (just run examine again) is found with the help command, but clearly this was not intuitive. The solution was to add an explicit help text to the top every time you examine something. After this, the confusion seems to have gone away.

Make it easy to connect for all tastes

Another example - a commenting user had pretty strong opinions about the fact that you used to have to supply a username and password to play the game. They suggested this was a 'huge hurdle'. Not sure if that's true. But unless you want to use a particular name, there is also no actual gameplay reason to formally authenticate for Evscaperoom.

This was easy to fix. Evennia has guest-player support out of the box so I just activated that and supplied some more fantasy-sounding names than the default "Guest 1", "Guest 2" etc. Since then, maybe 40% of players connecting have chosen to do so as an anonymous guest. I don't know if those would have left completely if the option was not available, but it's at least a convenient shortcut for getting into the game.

Everything takes longer than expected

I already knew this one, but still I fell into the trap of thinking that things were going well and that there would be plenty of time to finish before deadline.

Creating text content is a lot faster than creating graphical assets, but it's still a lot of work. Just the ending 'cinematics' took me almost two days to finish and clean up at the end.

For once I did pick a reasonable scale for this project though. So while the last few days of the Jam was more intense than I would have liked, I never truly felt like I would not be able to finish in time.


Building a MU* game in pure code is awesome

Evennia tries to not instil and specific game type, hence its tools are very general. Wrapping these general tools as a highly opinionated and game-specific toolbox enforced to me just how easy it is to do things when you don't need to cover the general case.

Using the tools and creating content purely in-code was great and ended up leading to a very fast content creation. Python works perfectly as a scripting language and I don't think there is a reason for using in-game building at all for your game, especially not when you are working on your own like this.

I made a few admin-only commands to jump between states and to set flags, but otherwise most bugs were caught by a generic unit test that just looped over all founds states and tried to initialize them, one after another.


Conclusions

For all my work on the Evennia library/server, I've not actually used it for games of my own very much. This was a great opportunity for doing so. It also gave me the opportunity to test the Python3-development branch of Evennia in a production setting.

I found a few edge-case library bugs which I fixed, but overall things worked very smoothly, also for this kind of game which is certainly far away from the normal MU*-mold that most use Evennia for. I am a bit biased, but overall I felt Evennia to be very mature for the use of making a game from scratch.

In the future I will most likely break out the 'engine' and tools of the Evscaperoom into an Evennia contrib so that others can make similar games with it easily.

Looking forward to future game jams now!

20 Sep 2020 10:39am GMT

Evennia: Creating Evscaperoom, part 1

Over the last month (April-May 2019) I have taken part in the Mud Coder's Guild Game Jam "Enter the (Multi-User) Dungeon". This year the theme for the jam was One Room.

The result was Evscaperoom, an text-based multi-player "escape-room" written in Python using the Evennia MU* creation system. You can play it from that link in your browser or MU*-client of choice. If you are so inclined, you can also vote for it here in the jam (well, no more).

This little series of (likely two) dev-blog entries will try to recount the planning and technical aspects of the Evscaperoom. This is also for myself - I'd better write stuff down now while it's still fresh in my mind!

Update: The next part of this blog is here.

Update 2: The Evscaperoom can these days be played by connecting to the Evennia game demo at https://demo.evennia.com.


Inception

When I first heard about the upcoming game-jam's theme of One Room, an 'escape room' was the first thing that came to mind, not the least because I just recently got to solve my my own first real-world escape-room as a gift on my birthday.

If you are not familiar with escape-rooms, the premise is simple - you are locked into a room and have to figure out a way to get out of it by solving practical puzzles and finding hidden clues in the room.

While you could create such a thing in your own bedroom (and there are also some one-use board game variants), most escape-rooms are managed by companies selling this as an experience for small groups. You usually have one hour to escape and if you get stuck you can press a button (or similar) to get a hint.

I thought making a computer escape-room. Not only can you do things in the computer that you cannot do in the real world, restricting the game to a single room limits so that it's conceivable to actually finish the damned thing in a month.

A concern I had was that everyone else in the jam surely must have went for the same obvious idea. In the end that was not an issue at all though.


Basic premises

I was pretty confident that I would technically be able to create the game in time (not only is Python and Evennia perfect for this kind of fast experimentation and prototyping, I know the engine very well). But that's not enough; I had to first decide on how the thing should actually play. Here are the questions I had to consider:

Room State

An escape room can be seen as going through multiple states as puzzles are solved. For example, you may open a cabinet and that may open up new puzzles to solve. This is fine in a single-player game, but how to handle it in a multi-player environment?

My first thought was that each object may have multiple states and that players could co-exist in the same room, seeing different states at the same time. I really started planning for this. It would certainly be possible to implement.

But in the end I considered how a real-world escape-room works - people in the same room solves it together. For there to be any meaning with multi-player, they must share the room state.

So what I went with was a solution where players can create their own room or join an existing one. Each such room is generated on the fly (and filled with objects etc) and will change as players solve it. Once complete and/or everyone leaves, the room is deleted along with all objects in it. Clean and tidy.

So how to describe these states? I pictured that these would be described as normal Python modules with a start- and end function that initialized each state and cleaned it up when a new state was started. In the beginning I pictured these states as being pretty small (like one state to change one thing in the room). In the end though, the entire Evscaperoom fits in 12 state modules. I'll describe them in more detail in the second part of this post.

Accessibility and "pixel-hunting" in text

When I first started writing descriptions I didn't always note which objects where interactive. It's a very simple and tempting puzzle to add - mention an object as part of a larger description and let the player figure out that it's something they can interact with. This practice is sort-of equivalent to pixel-hunting in graphical games - sweeping with the mouse across the screen until you find that little spot on the screen that you can do something with.

Problem is, pixel-hunting's not really fun. You easily get stuck and when you eventually find out what was blocking you, you don't really feel clever but only frustrated. So I decided that I should clearly mark every object that people could interact with and focus puzzles on better things.


In fact, in the end I made it an option:

Option menu ('quit' to return) 1: ( ) No item markings (hard mode) 2: ( ) Items marked as item (with color) 3: (*) Items are marked as [item] (screenreader friendly) 4: ( ) Screenreader mode


As part of this I had to remind myself never to use colors only when marking important information: Visually impaired people with screen readers will simply miss that. Not to mention that some just disable colors in their clients.

So while I personally think option 2 above is the most visually pleasing, Evscaperoom defaults to the third option. It should should start everyone off on equal footing. Evennia has a screen-reader mode out of the box, but I moved it into the menu here for easy access.

Inventory and collaboration

In a puzzle-game, you often find objects and combine them with other things. Again, this is simple to do in a single-player game: Players just pick things up and use them later.

But in a multi-player game this offers a huge risk: players that pick up something important and then log off. The remaining players in that room would then be stuck in an unsolvable room - and it would be very hard for them to know this.

In principle you could try to 'clean' player inventories when they leave, but not only does it add complexity, there is another issue with players picking things up: It means that the person first to find/pick up the item is the only one that can use it and look at it. Others won't have access until the first player gives it up. Trusting that to anonymous players online is not a good idea.

So in the end I arrived at the following conclusions:

As a side-effect of this I also set a limit to the kind of puzzles I would allow:


Focusing on objects

So without inventory system, how do you interact with objects? A trademark of any puzzle is using one object with another and also to explore things closer to find clues. I turned to graphical adventure games for inspiration:

Hovering with mouse over lens object offers action
Secret of Monkey Island ©1990 LucasArts. Image from old-games.com


A common way to operate on an object in traditional adventure games is to hover the mouse over it and then select the action you want to apply to it. In later (3D) games you might even zoom in of the object and rotate it around with your mouse to see if there are some clues to be had.

While Evennia and modern UI clients may allow you to use the mouse to select objects, I wanted this to work the traditional MUD-way, by inserting commands. So I decided that you as a player would be in one of two states:

A small stone fireplace sits in the middle of the wall opposite the [door]. On the chimney hangs a small oil [painting] of a man. Hanging over the hearth is a black [cauldron]. The piles of [ashes] below are cold. (It looks like fireplace may be suitable to [climb].)


In the example above, the fireplace points out other objects you could also focus on, whereas the last parenthesis includes one or more "actions" that you can perform on the fireplace only when you have it focused.

This ends up pretty different from most traditional MUD-style inputs. When I first released this to the public, I found people logged off after their first examine. It turned out that they couldn't figure out how to leave the focus mode. So they just assumed the thing was buggy and quit instead. Of course it's mentioned if you care to write help, but this is clearly one step too many for such an important UI concept.

So I ended up adding the header above that always reminds you. And since then I've not seen any confusion over how the focus mode works.

For making it easy to focus on things, I also decided that each room would only ever have one object named a particular thing. So there is for example only one single object in the game named "key" that you can focus on.

Communication

I wanted players to co-exist in the same room so that they could collaborate on solving it. This meant communication must be possible. I pictured people would want to point things out and talk to each other.

In my first round of revisions I had a truckload of individual emotes; you could

point at target

for example. In the end I just limited it to

say/shout/whisper <message>

and

emote <whatever>

And seeing what people actually use, this is more than enough (say alone is probably 99% of what people need, really). I had a notion that the shout/whisper could be used in a puzzle later but in the end I decided that communication commands should be strictly between players and not have anything to do with the puzzles.

I removed all other interaction: There is no fighting and without an inventory or requirement to collaborate on puzzles, there is no need for other interactions than to communicate.

First version you didn't even see what the others did, but eventually I added so that you at least saw what other players were focusing on at the moment (and of course if some major thing was solved/found).

In the end I don't even list characters as objects in the room (you have to use the who command to see who's in there with you).

Listing of commands available in the Evscaperoom (output of the help-command in game)
The main help command output.

Story

It's very common for this type of game to have a dangerous or scary theme. Things like "get out before the bomb explodes", "save the space ship before the engines overheat", "flee the axe murderer before he comes back" etc). I'm no stranger to dark themes, but for this I wanted something friendlier and brighter, maybe with a some dark undercurrents here and there.

My Jester character is someone I've not only depicted in art, but she's also an old RP character and literary protagonist of mine. Who else would find it funny to lock someone into a room only to provide crazy puzzles and hints for them to get out again? So my flimsy 'premise' was this:


The village Jester wants to win the pie eating contest. You are one of her most dangerous opponents. She tricked you to her cabin and now you are locked in! If you don't get out in time, she'll get to eat all those pies on her own and surely win!


That's it - this became the premise from which the entire game flowed. I quickly decided that it to be a very "small-scale" story: no life-or-death situation, no saving of the world. The drama takes place in a small village with an "adversary" that doesn't really want to hurt you, but only to eat more pies than you.

From this, the way to offer hints came naturally - just eat a slice of "hintberry pie" the jester made (she even encourage you to eat it). It gives you a hint but is also very filling. So if you eat too much, how will you beat her in the contest later, even if you do get out?

To further the rustic and friendly tone I made sure the story took place on a warm summer day. Many descriptions describe sunshine, chirping birds and the smell of pie. I aimed at letting the text point out quirky and slightly comedic tone of the puzzles the Jester left behind. The player also sometimes gets teased by the game when doing things that does not make sense.

I won't go into the story further here - it's best if you experience it yourself. Let's just say that the village has some old secrets. And and the Jester has her own ways of doing things and of telling a story. The game has multiple endings and so far people have drawn very different conclusions in the end.

Scoring

Most often in escape rooms, final score is determined by the time and the number of hints used. I do keep the latter - for every pie you eat, you get a penalty on your final score.

As for time - this background story would fit very well with a time limit (get out in X time, after which the pie-eating contest will start!). But from experience with other online text-based games I decided against this. Not only should a player be able to take a break, they may also want to wait for a friend to leave and come back etc.

But more importantly, I want players to explore and read all my carefully crafted descriptions! So I'd much rather prefer they take their time and reward them for being thorough.

So in the end I give specific scores for actions throughout the game instead. Most points are for doing things that drive the story forward, such as using something or solving a puzzle. But a significant portion of the score comes from turning every stone and trying everything out. The nice side-effect of this is that even if you know exactly how to solve everything and rush through the game you will still not end up with a perfect score.

The final score, adjusted by hints is then used to determine if you make it in time to the contest and how you fare. This means that if you explore carefully you have a "buffer" of points so eating a few pies may still land you a good result in the end.


First sketch

I really entered the game 'building' aspect with no real notion of how the Jester's cabin should look nor which puzzles should be in it. I tried to write things down beforehand but it didn't really work for me.

So in the end I decided "let's just put a lot of interesting stuff in the room and then I'll figure out how they interact with each other". I'm sure this is different from game-maker to game-maker. But for me, this process worked perfectly.


Scribbles on my notebook, sketching up the room's main items
My first, very rough, sketch of the Jester's cabin


The above, first sketch ended up being what I used, although many of the objects mentioned never ended up in the final game and some things switched places. I did some other sketches too, but they'd be spoilers so I won't show them here ...


The actual game logic

The Evscaperoom principles outlined above deviate quite a bit from the traditional MU* style of game play.

While Evennia provides everything for database management, in-game objects, commands, networking and other resources, the specifics of your game is something you need to make yourself - and you have the full power of Python to do it!

So for the first three days of the jam I used Evennia to build the custom game logic needed to provide the evscaperoom style of game play. I also made the tools I needed to quickly create the game content (which then took me the rest of the jam to make).

In part 2 of this blog post I will cover the technical details of the Evscaperoom I built. I'll also go through some issues I ran into and conclusions I drew. I'll link to that from here when it's available!

Continue to part 2.

20 Sep 2020 10:39am GMT

Evennia: Creating Evscaperoom, part 1

Over the last month (April-May 2019) I have taken part in the Mud Coder's Guild Game Jam "Enter the (Multi-User) Dungeon". This year the theme for the jam was One Room.

The result was Evscaperoom, an text-based multi-player "escape-room" written in Python using the Evennia MU* creation system. You can play it from that link in your browser or MU*-client of choice. If you are so inclined, you can also vote for it here in the jam (well, no more).

This little series of (likely two) dev-blog entries will try to recount the planning and technical aspects of the Evscaperoom. This is also for myself - I'd better write stuff down now while it's still fresh in my mind!

Update: The next part of this blog is here.

Update 2: The Evscaperoom can these days be played by connecting to the Evennia game demo at https://demo.evennia.com.


Inception

When I first heard about the upcoming game-jam's theme of One Room, an 'escape room' was the first thing that came to mind, not the least because I just recently got to solve my my own first real-world escape-room as a gift on my birthday.

If you are not familiar with escape-rooms, the premise is simple - you are locked into a room and have to figure out a way to get out of it by solving practical puzzles and finding hidden clues in the room.

While you could create such a thing in your own bedroom (and there are also some one-use board game variants), most escape-rooms are managed by companies selling this as an experience for small groups. You usually have one hour to escape and if you get stuck you can press a button (or similar) to get a hint.

I thought making a computer escape-room. Not only can you do things in the computer that you cannot do in the real world, restricting the game to a single room limits so that it's conceivable to actually finish the damned thing in a month.

A concern I had was that everyone else in the jam surely must have went for the same obvious idea. In the end that was not an issue at all though.


Basic premises

I was pretty confident that I would technically be able to create the game in time (not only is Python and Evennia perfect for this kind of fast experimentation and prototyping, I know the engine very well). But that's not enough; I had to first decide on how the thing should actually play. Here are the questions I had to consider:

Room State

An escape room can be seen as going through multiple states as puzzles are solved. For example, you may open a cabinet and that may open up new puzzles to solve. This is fine in a single-player game, but how to handle it in a multi-player environment?

My first thought was that each object may have multiple states and that players could co-exist in the same room, seeing different states at the same time. I really started planning for this. It would certainly be possible to implement.

But in the end I considered how a real-world escape-room works - people in the same room solves it together. For there to be any meaning with multi-player, they must share the room state.

So what I went with was a solution where players can create their own room or join an existing one. Each such room is generated on the fly (and filled with objects etc) and will change as players solve it. Once complete and/or everyone leaves, the room is deleted along with all objects in it. Clean and tidy.

So how to describe these states? I pictured that these would be described as normal Python modules with a start- and end function that initialized each state and cleaned it up when a new state was started. In the beginning I pictured these states as being pretty small (like one state to change one thing in the room). In the end though, the entire Evscaperoom fits in 12 state modules. I'll describe them in more detail in the second part of this post.

Accessibility and "pixel-hunting" in text

When I first started writing descriptions I didn't always note which objects where interactive. It's a very simple and tempting puzzle to add - mention an object as part of a larger description and let the player figure out that it's something they can interact with. This practice is sort-of equivalent to pixel-hunting in graphical games - sweeping with the mouse across the screen until you find that little spot on the screen that you can do something with.

Problem is, pixel-hunting's not really fun. You easily get stuck and when you eventually find out what was blocking you, you don't really feel clever but only frustrated. So I decided that I should clearly mark every object that people could interact with and focus puzzles on better things.


In fact, in the end I made it an option:

Option menu ('quit' to return) 1: ( ) No item markings (hard mode) 2: ( ) Items marked as item (with color) 3: (*) Items are marked as [item] (screenreader friendly) 4: ( ) Screenreader mode


As part of this I had to remind myself never to use colors only when marking important information: Visually impaired people with screen readers will simply miss that. Not to mention that some just disable colors in their clients.

So while I personally think option 2 above is the most visually pleasing, Evscaperoom defaults to the third option. It should should start everyone off on equal footing. Evennia has a screen-reader mode out of the box, but I moved it into the menu here for easy access.

Inventory and collaboration

In a puzzle-game, you often find objects and combine them with other things. Again, this is simple to do in a single-player game: Players just pick things up and use them later.

But in a multi-player game this offers a huge risk: players that pick up something important and then log off. The remaining players in that room would then be stuck in an unsolvable room - and it would be very hard for them to know this.

In principle you could try to 'clean' player inventories when they leave, but not only does it add complexity, there is another issue with players picking things up: It means that the person first to find/pick up the item is the only one that can use it and look at it. Others won't have access until the first player gives it up. Trusting that to anonymous players online is not a good idea.

So in the end I arrived at the following conclusions:

As a side-effect of this I also set a limit to the kind of puzzles I would allow:


Focusing on objects

So without inventory system, how do you interact with objects? A trademark of any puzzle is using one object with another and also to explore things closer to find clues. I turned to graphical adventure games for inspiration:

Hovering with mouse over lens object offers action
Secret of Monkey Island ©1990 LucasArts. Image from old-games.com


A common way to operate on an object in traditional adventure games is to hover the mouse over it and then select the action you want to apply to it. In later (3D) games you might even zoom in of the object and rotate it around with your mouse to see if there are some clues to be had.

While Evennia and modern UI clients may allow you to use the mouse to select objects, I wanted this to work the traditional MUD-way, by inserting commands. So I decided that you as a player would be in one of two states:

A small stone fireplace sits in the middle of the wall opposite the [door]. On the chimney hangs a small oil [painting] of a man. Hanging over the hearth is a black [cauldron]. The piles of [ashes] below are cold. (It looks like fireplace may be suitable to [climb].)


In the example above, the fireplace points out other objects you could also focus on, whereas the last parenthesis includes one or more "actions" that you can perform on the fireplace only when you have it focused.

This ends up pretty different from most traditional MUD-style inputs. When I first released this to the public, I found people logged off after their first examine. It turned out that they couldn't figure out how to leave the focus mode. So they just assumed the thing was buggy and quit instead. Of course it's mentioned if you care to write help, but this is clearly one step too many for such an important UI concept.

So I ended up adding the header above that always reminds you. And since then I've not seen any confusion over how the focus mode works.

For making it easy to focus on things, I also decided that each room would only ever have one object named a particular thing. So there is for example only one single object in the game named "key" that you can focus on.

Communication

I wanted players to co-exist in the same room so that they could collaborate on solving it. This meant communication must be possible. I pictured people would want to point things out and talk to each other.

In my first round of revisions I had a truckload of individual emotes; you could

point at target

for example. In the end I just limited it to

say/shout/whisper <message>

and

emote <whatever>

And seeing what people actually use, this is more than enough (say alone is probably 99% of what people need, really). I had a notion that the shout/whisper could be used in a puzzle later but in the end I decided that communication commands should be strictly between players and not have anything to do with the puzzles.

I removed all other interaction: There is no fighting and without an inventory or requirement to collaborate on puzzles, there is no need for other interactions than to communicate.

First version you didn't even see what the others did, but eventually I added so that you at least saw what other players were focusing on at the moment (and of course if some major thing was solved/found).

In the end I don't even list characters as objects in the room (you have to use the who command to see who's in there with you).

Listing of commands available in the Evscaperoom (output of the help-command in game)
The main help command output.

Story

It's very common for this type of game to have a dangerous or scary theme. Things like "get out before the bomb explodes", "save the space ship before the engines overheat", "flee the axe murderer before he comes back" etc). I'm no stranger to dark themes, but for this I wanted something friendlier and brighter, maybe with a some dark undercurrents here and there.

My Jester character is someone I've not only depicted in art, but she's also an old RP character and literary protagonist of mine. Who else would find it funny to lock someone into a room only to provide crazy puzzles and hints for them to get out again? So my flimsy 'premise' was this:


The village Jester wants to win the pie eating contest. You are one of her most dangerous opponents. She tricked you to her cabin and now you are locked in! If you don't get out in time, she'll get to eat all those pies on her own and surely win!


That's it - this became the premise from which the entire game flowed. I quickly decided that it to be a very "small-scale" story: no life-or-death situation, no saving of the world. The drama takes place in a small village with an "adversary" that doesn't really want to hurt you, but only to eat more pies than you.

From this, the way to offer hints came naturally - just eat a slice of "hintberry pie" the jester made (she even encourage you to eat it). It gives you a hint but is also very filling. So if you eat too much, how will you beat her in the contest later, even if you do get out?

To further the rustic and friendly tone I made sure the story took place on a warm summer day. Many descriptions describe sunshine, chirping birds and the smell of pie. I aimed at letting the text point out quirky and slightly comedic tone of the puzzles the Jester left behind. The player also sometimes gets teased by the game when doing things that does not make sense.

I won't go into the story further here - it's best if you experience it yourself. Let's just say that the village has some old secrets. And and the Jester has her own ways of doing things and of telling a story. The game has multiple endings and so far people have drawn very different conclusions in the end.

Scoring

Most often in escape rooms, final score is determined by the time and the number of hints used. I do keep the latter - for every pie you eat, you get a penalty on your final score.

As for time - this background story would fit very well with a time limit (get out in X time, after which the pie-eating contest will start!). But from experience with other online text-based games I decided against this. Not only should a player be able to take a break, they may also want to wait for a friend to leave and come back etc.

But more importantly, I want players to explore and read all my carefully crafted descriptions! So I'd much rather prefer they take their time and reward them for being thorough.

So in the end I give specific scores for actions throughout the game instead. Most points are for doing things that drive the story forward, such as using something or solving a puzzle. But a significant portion of the score comes from turning every stone and trying everything out. The nice side-effect of this is that even if you know exactly how to solve everything and rush through the game you will still not end up with a perfect score.

The final score, adjusted by hints is then used to determine if you make it in time to the contest and how you fare. This means that if you explore carefully you have a "buffer" of points so eating a few pies may still land you a good result in the end.


First sketch

I really entered the game 'building' aspect with no real notion of how the Jester's cabin should look nor which puzzles should be in it. I tried to write things down beforehand but it didn't really work for me.

So in the end I decided "let's just put a lot of interesting stuff in the room and then I'll figure out how they interact with each other". I'm sure this is different from game-maker to game-maker. But for me, this process worked perfectly.


Scribbles on my notebook, sketching up the room's main items
My first, very rough, sketch of the Jester's cabin


The above, first sketch ended up being what I used, although many of the objects mentioned never ended up in the final game and some things switched places. I did some other sketches too, but they'd be spoilers so I won't show them here ...


The actual game logic

The Evscaperoom principles outlined above deviate quite a bit from the traditional MU* style of game play.

While Evennia provides everything for database management, in-game objects, commands, networking and other resources, the specifics of your game is something you need to make yourself - and you have the full power of Python to do it!

So for the first three days of the jam I used Evennia to build the custom game logic needed to provide the evscaperoom style of game play. I also made the tools I needed to quickly create the game content (which then took me the rest of the jam to make).

In part 2 of this blog post I will cover the technical details of the Evscaperoom I built. I'll also go through some issues I ran into and conclusions I drew. I'll link to that from here when it's available!

Continue to part 2.

20 Sep 2020 10:39am GMT

"CodersLegacy": What are Dependencies in Programming

This article explains what Dependencies in Programming mean.

This article is going to be a very informative read no matter what kind of programmer you are. In fact, even if you aren't a programmer you will find this article useful. After all, dependencies is not just a programming concept. It's a general term that has meaning even outside of Computer Science.

Table of Contents:


What are Dependencies

Dependency is a broad software engineering term used to refer when a piece of software relies on another one. Simply put, if Program A requires Program B to be able to run, Program A is dependent on Program B. This makes Program B a dependency of Program A.

You may ask, why would Program A even need Program B, or any other program for that matter? This will be further elaborated in the "Why we use dependencies" section in this article, but a short version is that Program A requires a special service or feature which Program B has.

It doesn't really matter what it is, if your program needs to run correctly, it's a dependency. Common examples of dependencies are programming libraries, Online services, programming scripts etc.

If you're a Python programmer reading this, I recommend you check this article on Pyinstaller as well. It also has alot to do with Dependencies, converting python files to exe's and distributing software, a very informative article overall.


The Dangers of using Dependencies

Having dependencies for your code is generally frowned upon. As we explained earlier, it reduces the flexibility of your code and worse case scenario, it can completely ruin your program. Before we get into this though, we're going to categorize dependencies into the two follow categories.

  1. Dependencies that we control
  2. Dependencies that we do not control

Uptil now we've mostly been talking about the first category, dependencies which we have direct control over, such as a custom library that you may have wrote. Now we'll briefly discuss the second category, dependencies that we do not control.

Unlike dependencies that you have direct control over, (like a custom library) dependencies that you do not control have a much higher risk factor involved. What happens if one of the dependencies suddenly shuts down or goes through some kind of drastic change (breaking your program in the process), what will you do?

There have been cases where a company completely based their application around a dependency or external service and it was shut down suddenly, causing them major losses.

Of course, this doesn't mean you shouldn't be using dependencies. Most of the time you won't have a choice anyway. What you can do however is minimize the risk involved by choosing your dependencies smartly.


Why we use Dependencies

At this point you may be wondering, "why do we even use dependencies if there is so much risk?". That's a good question, and the answer is pretty simple and straightforward.

Applications are becoming more and more complex day by day. The average amount of code behind an application is also increasing day by day. If each one of us started from scratch each time, we would barely make any progress.

What we do is to carry forward what has already been tried and tested and then further build upon that. Basically, we save time by using pre-written and tested code, and then use the time we saved to create new and better things.

This is actually one of the major reason Python is so popular. There are so many Python libraries with pre-written code for various scenarios, that a new programmer can build complex and advanced applications within a few weeks using these libraries.

Reinventing the wheel

You may have heard of this expression, "reinventing the wheel". It refers to the act of creating your own version of something that has already been created. Trying to reinvent the wheel is generally a highly discouraged practice in programming (with few exceptions).

The reason for this is quite simple. If a widely tested and adopted service/library already exists, why waste the time and effort making your own version which is probably going to be subpar to the one that already exists.

To sum up, we use dependencies to avoid having to reinvent the wheel, to speed up our coding process, save time and increase efficiency. Let's say you have a software that requires location data for a certain part, are you going to create an entire service that provides location data? Of course not, you're going to use a pre-existing location service to provide you that data. It could be the difference between writing 10 and 10,000 lines of code.


Things to look for in a Dependency

A couple of important things to keep in mind while selecting a dependency.

  1. Portability: The last thing you want is a dependency that only works on certain systems and platforms. Unless you only plan to release your application on a certain platform, you should definitely research your dependency carefully and even pre-test it on the platforms you're aiming for.
  2. Version control: Be mindful of the version you pick for your dependency. You should already know this, but each new version brings in new features. If you're using the latest version of that dependency and your customers/clients have a slighter older version there might be issues. You also have to consider how you will be managing your update schedule.
  3. Regular Updates: This is both a security issue, and also an indication that this dependency could abandoned entirely in the future. If the dependency you're looking to use hasn't been updated in a year, it's best to avoid it.
  4. Adoption rate and usage: You'll usually find several different possible dependencies you can use for your program. You should aim for the one has been widely adopted in it's respective field and is actively being used. Not only does this show the dependency is reliable and trustworthy, it also indicates that the community for this Dependency will be large. Popular dependencies are thoroughly documented and discussed across the internet, making troubleshooting or asking for help easier.
  5. Compatibility: The last thing you want is to pick a dependency without properly researching it and later finding out that it wasn't compatible on all the platforms you were aiming for. This problem is more common than you may think. There are all kinds of issue that may be involved so be sure to do your research before hand. As another suggestion, while coding keep testing your code on different platforms and settings. You don't have to leave all the testing for once you're done.

Good Dependencies

An example of a good third party dependency would be Google Maps. If you build an application that requires locations services, you could use the Google Maps API to retrieve location data. I say this is a good dependency because:

  1. Google Maps is managed by Google, a large company.
  2. Google Maps as a service is used globally, hence you can expect it to be reliable and consistent. You don't have worry about this service vanishing over night or something.
  3. The Google Maps API is simple and easy to use. It has a free version with a limited number of requests and a premium (paid) version as well. For most cases the free version is perfectly fine.

If you've been coding for a while, you'll also have undoubtedly used many libraries too. About 95% of the time using these programming libraries as your dependencies is perfectly fine due to how widespread their use is. As a bonus, it's not too hard to bundle up these libraries into a compiled program either using something a file to exe converter like pyinstaller (for python programs).

You should however avoid libraries which are outdated and have very little support. Basically just keep an eye out for everything we mentioned in the previous section.

Be smart and pick wisely!


Other Resources

Dependencies in programming is a topic over which an entire book can be written. There's alot more to them than what was covered in this article, so if you're interested we've included some resources here for further reading.

If you interested in hearing more about dependencies and their dangers in programming, I suggest you read this article.


This marks the end of the "What are Dependencies in Programming" article. Any suggestions or contributions for CodersLegacy are more than welcome. Questions regarding the article content can be asked in the comments section below.

The post What are Dependencies in Programming appeared first on CodersLegacy.

20 Sep 2020 7:50am GMT

"CodersLegacy": What are Dependencies in Programming

This article explains what Dependencies in Programming mean.

This article is going to be a very informative read no matter what kind of programmer you are. In fact, even if you aren't a programmer you will find this article useful. After all, dependencies is not just a programming concept. It's a general term that has meaning even outside of Computer Science.

Table of Contents:


What are Dependencies

Dependency is a broad software engineering term used to refer when a piece of software relies on another one. Simply put, if Program A requires Program B to be able to run, Program A is dependent on Program B. This makes Program B a dependency of Program A.

You may ask, why would Program A even need Program B, or any other program for that matter? This will be further elaborated in the "Why we use dependencies" section in this article, but a short version is that Program A requires a special service or feature which Program B has.

It doesn't really matter what it is, if your program needs to run correctly, it's a dependency. Common examples of dependencies are programming libraries, Online services, programming scripts etc.

If you're a Python programmer reading this, I recommend you check this article on Pyinstaller as well. It also has alot to do with Dependencies, converting python files to exe's and distributing software, a very informative article overall.


The Dangers of using Dependencies

Having dependencies for your code is generally frowned upon. As we explained earlier, it reduces the flexibility of your code and worse case scenario, it can completely ruin your program. Before we get into this though, we're going to categorize dependencies into the two follow categories.

  1. Dependencies that we control
  2. Dependencies that we do not control

Uptil now we've mostly been talking about the first category, dependencies which we have direct control over, such as a custom library that you may have wrote. Now we'll briefly discuss the second category, dependencies that we do not control.

Unlike dependencies that you have direct control over, (like a custom library) dependencies that you do not control have a much higher risk factor involved. What happens if one of the dependencies suddenly shuts down or goes through some kind of drastic change (breaking your program in the process), what will you do?

There have been cases where a company completely based their application around a dependency or external service and it was shut down suddenly, causing them major losses.

Of course, this doesn't mean you shouldn't be using dependencies. Most of the time you won't have a choice anyway. What you can do however is minimize the risk involved by choosing your dependencies smartly.


Why we use Dependencies

At this point you may be wondering, "why do we even use dependencies if there is so much risk?". That's a good question, and the answer is pretty simple and straightforward.

Applications are becoming more and more complex day by day. The average amount of code behind an application is also increasing day by day. If each one of us started from scratch each time, we would barely make any progress.

What we do is to carry forward what has already been tried and tested and then further build upon that. Basically, we save time by using pre-written and tested code, and then use the time we saved to create new and better things.

This is actually one of the major reason Python is so popular. There are so many Python libraries with pre-written code for various scenarios, that a new programmer can build complex and advanced applications within a few weeks using these libraries.

Reinventing the wheel

You may have heard of this expression, "reinventing the wheel". It refers to the act of creating your own version of something that has already been created. Trying to reinvent the wheel is generally a highly discouraged practice in programming (with few exceptions).

The reason for this is quite simple. If a widely tested and adopted service/library already exists, why waste the time and effort making your own version which is probably going to be subpar to the one that already exists.

To sum up, we use dependencies to avoid having to reinvent the wheel, to speed up our coding process, save time and increase efficiency. Let's say you have a software that requires location data for a certain part, are you going to create an entire service that provides location data? Of course not, you're going to use a pre-existing location service to provide you that data. It could be the difference between writing 10 and 10,000 lines of code.


Things to look for in a Dependency

A couple of important things to keep in mind while selecting a dependency.

  1. Portability: The last thing you want is a dependency that only works on certain systems and platforms. Unless you only plan to release your application on a certain platform, you should definitely research your dependency carefully and even pre-test it on the platforms you're aiming for.
  2. Version control: Be mindful of the version you pick for your dependency. You should already know this, but each new version brings in new features. If you're using the latest version of that dependency and your customers/clients have a slighter older version there might be issues. You also have to consider how you will be managing your update schedule.
  3. Regular Updates: This is both a security issue, and also an indication that this dependency could abandoned entirely in the future. If the dependency you're looking to use hasn't been updated in a year, it's best to avoid it.
  4. Adoption rate and usage: You'll usually find several different possible dependencies you can use for your program. You should aim for the one has been widely adopted in it's respective field and is actively being used. Not only does this show the dependency is reliable and trustworthy, it also indicates that the community for this Dependency will be large. Popular dependencies are thoroughly documented and discussed across the internet, making troubleshooting or asking for help easier.
  5. Compatibility: The last thing you want is to pick a dependency without properly researching it and later finding out that it wasn't compatible on all the platforms you were aiming for. This problem is more common than you may think. There are all kinds of issue that may be involved so be sure to do your research before hand. As another suggestion, while coding keep testing your code on different platforms and settings. You don't have to leave all the testing for once you're done.

Good Dependencies

An example of a good third party dependency would be Google Maps. If you build an application that requires locations services, you could use the Google Maps API to retrieve location data. I say this is a good dependency because:

  1. Google Maps is managed by Google, a large company.
  2. Google Maps as a service is used globally, hence you can expect it to be reliable and consistent. You don't have worry about this service vanishing over night or something.
  3. The Google Maps API is simple and easy to use. It has a free version with a limited number of requests and a premium (paid) version as well. For most cases the free version is perfectly fine.

If you've been coding for a while, you'll also have undoubtedly used many libraries too. About 95% of the time using these programming libraries as your dependencies is perfectly fine due to how widespread their use is. As a bonus, it's not too hard to bundle up these libraries into a compiled program either using something a file to exe converter like pyinstaller (for python programs).

You should however avoid libraries which are outdated and have very little support. Basically just keep an eye out for everything we mentioned in the previous section.

Be smart and pick wisely!


Other Resources

Dependencies in programming is a topic over which an entire book can be written. There's alot more to them than what was covered in this article, so if you're interested we've included some resources here for further reading.

If you interested in hearing more about dependencies and their dangers in programming, I suggest you read this article.


This marks the end of the "What are Dependencies in Programming" article. Any suggestions or contributions for CodersLegacy are more than welcome. Questions regarding the article content can be asked in the comments section below.

The post What are Dependencies in Programming appeared first on CodersLegacy.

20 Sep 2020 7:50am GMT

IslandT: Create the function which converts a given string into an md5 hash and return the value in the hexadecimal format

When you sign up for an account somewhere, some websites do not actually store your password in their databases. Instead, they will transform your password into something else using a cryptographic hashing algorithm.

After the password is transformed, it is then called a password hash. Whenever you try to login, the website will transform the password you tried using the same hashing algorithm and simply see if the password hashes are the same.

Create the python function that converts a given string into an md5 hash. The return value should be encoded in hexadecimal.


For Examples

the function will turn "password" into "5f4dcc3b5aa765d61d8327deb882cf99"

We will use the hashlib module to evoke the md5 function, but before we can turn any string into an md5 hash we need to make sure we have already encoded the string first. Finally, return the md5 hash in the hexadecimal format!

import hashlib

def pass_hash(str):

    m = hashlib.md5(str.encode())
    return m.hexdigest()

If you are using Python 3.x then you will need to use hashlib instead of the other python md5 hash's library.

20 Sep 2020 4:58am GMT

IslandT: Create the function which converts a given string into an md5 hash and return the value in the hexadecimal format

When you sign up for an account somewhere, some websites do not actually store your password in their databases. Instead, they will transform your password into something else using a cryptographic hashing algorithm.

After the password is transformed, it is then called a password hash. Whenever you try to login, the website will transform the password you tried using the same hashing algorithm and simply see if the password hashes are the same.

Create the python function that converts a given string into an md5 hash. The return value should be encoded in hexadecimal.


For Examples

the function will turn "password" into "5f4dcc3b5aa765d61d8327deb882cf99"

We will use the hashlib module to evoke the md5 function, but before we can turn any string into an md5 hash we need to make sure we have already encoded the string first. Finally, return the md5 hash in the hexadecimal format!

import hashlib

def pass_hash(str):

    m = hashlib.md5(str.encode())
    return m.hexdigest()

If you are using Python 3.x then you will need to use hashlib instead of the other python md5 hash's library.

20 Sep 2020 4:58am GMT

ListenData: How to rename columns in Pandas Dataframe

In this tutorial, we will cover various methods to rename columns in pandas dataframe in Python. Renaming or changing the names of columns is one of the most common data wrangling task. If you are not from programming background and worked only in Excel Spreadsheets in the past you might feel it not so easy doing this in Python as you can easily rename columns in MS Excel by just typing in the cell what you want to have. If you are from database background it is similar to ALIAS in SQL. In Python there is a popular data manipulation package called pandas which simplifies doing these kind of data operations.
rename columns in Pandas Dataframe
2 Methods to rename columns in Pandas
In Pandas there are two simple methods to rename name of columns.

First step is to install pandas package if it is not already installed. You can check if the package is installed on your machine by running !pip show pandas statement in Ipython console. If it is not installed, you can install it by using the command !pip install pandas.

Import Dataset for practice

To import dataset, we are using read_csv( ) function from pandas package.

import pandas as pd
df = df = pd.read_csv("https://raw.githubusercontent.com/JackyP/testing/master/datasets/nycflights.csv", usecols=range(1,17))
To see the names of columns in a data frame, write the command below :
df.columns
Index(['year', 'month', 'day', 'dep_time', 'dep_delay', 'arr_time',
'arr_delay', 'carrier', 'tailnum', 'flight', 'origin', 'dest',
'air_time', 'distance', 'hour', 'minute'],
dtype='object')
Method I : rename() function
Suppose you want to replace column name year with years. In the code below it will create a new dataframe named df2 having new column names and same values.
df2 = df.rename(columns={'year':'years'})
If you want to make changes in the same dataset df you can try this option inplace = True
df.rename(columns={'year':'years'}, inplace = True)
By default inplace = False is set, hence you need to specify this option and mark it True. If you want to rename names of multiple columns, you can specify other columns with comma separator.
df.rename(columns={'year':'years', 'month':'months' }, inplace = True)
Method II : dataframe.columns = [list]
You can also assign the list of new column names to df.columns. See the example below. We are renaming year and month columns here.
df.columns = ['years', 'months', 'day', 'dep_time', 'dep_delay', 'arr_time',
'arr_delay', 'carrier', 'tailnum', 'flight', 'origin', 'dest',
'air_time', 'distance', 'hour', 'minute']
Rename columns having pattern
Suppose you want to rename columns having underscore '_' in their names. You want to get rid of underscore
df.columns = df.columns.str.replace('_' , '')
New column names are as follows. You can observe no underscore in the column names.
  Index(['year', 'month', 'day', 'deptime', 'depdelay', 'arrtime', 'arrdelay',
'carrier', 'tailnum', 'flight', 'origin', 'dest', 'airtime', 'distance',
'hour', 'minute'],
dtype='object')
Add prefix / suffix in column names
In case you want to add some text before or after existing column names, you can do it by using add_prefix( ) and add_suffix( ) functions.
df = df.add_prefix('V_')
df = df.add_suffix('_V')
How to access columns having space in names
For demonstration purpose we can add space in some column names by using df.columns = df.columns.str.replace('_' , ' '). You can access the column using the syntax df["columnname"]
df["arr delay"]
How to change row names
With the use of index option, you can rename rows (or index). In the code below, we are altering row names 0 and 1 to 'First' and 'Second' in dataframe df. By creating dictionary and taking previous row names as keys and new row names as values.
df.rename(index={0:'First',1:'Second'}, inplace=True)

20 Sep 2020 1:46am GMT

ListenData: How to rename columns in Pandas Dataframe

In this tutorial, we will cover various methods to rename columns in pandas dataframe in Python. Renaming or changing the names of columns is one of the most common data wrangling task. If you are not from programming background and worked only in Excel Spreadsheets in the past you might feel it not so easy doing this in Python as you can easily rename columns in MS Excel by just typing in the cell what you want to have. If you are from database background it is similar to ALIAS in SQL. In Python there is a popular data manipulation package called pandas which simplifies doing these kind of data operations.
rename columns in Pandas Dataframe
2 Methods to rename columns in Pandas
In Pandas there are two simple methods to rename name of columns.

First step is to install pandas package if it is not already installed. You can check if the package is installed on your machine by running !pip show pandas statement in Ipython console. If it is not installed, you can install it by using the command !pip install pandas.

Import Dataset for practice

To import dataset, we are using read_csv( ) function from pandas package.

import pandas as pd
df = df = pd.read_csv("https://raw.githubusercontent.com/JackyP/testing/master/datasets/nycflights.csv", usecols=range(1,17))
To see the names of columns in a data frame, write the command below :
df.columns
Index(['year', 'month', 'day', 'dep_time', 'dep_delay', 'arr_time',
'arr_delay', 'carrier', 'tailnum', 'flight', 'origin', 'dest',
'air_time', 'distance', 'hour', 'minute'],
dtype='object')
Method I : rename() function
Suppose you want to replace column name year with years. In the code below it will create a new dataframe named df2 having new column names and same values.
df2 = df.rename(columns={'year':'years'})
If you want to make changes in the same dataset df you can try this option inplace = True
df.rename(columns={'year':'years'}, inplace = True)
By default inplace = False is set, hence you need to specify this option and mark it True. If you want to rename names of multiple columns, you can specify other columns with comma separator.
df.rename(columns={'year':'years', 'month':'months' }, inplace = True)
Method II : dataframe.columns = [list]
You can also assign the list of new column names to df.columns. See the example below. We are renaming year and month columns here.
df.columns = ['years', 'months', 'day', 'dep_time', 'dep_delay', 'arr_time',
'arr_delay', 'carrier', 'tailnum', 'flight', 'origin', 'dest',
'air_time', 'distance', 'hour', 'minute']
Rename columns having pattern
Suppose you want to rename columns having underscore '_' in their names. You want to get rid of underscore
df.columns = df.columns.str.replace('_' , '')
New column names are as follows. You can observe no underscore in the column names.
  Index(['year', 'month', 'day', 'deptime', 'depdelay', 'arrtime', 'arrdelay',
'carrier', 'tailnum', 'flight', 'origin', 'dest', 'airtime', 'distance',
'hour', 'minute'],
dtype='object')
Add prefix / suffix in column names
In case you want to add some text before or after existing column names, you can do it by using add_prefix( ) and add_suffix( ) functions.
df = df.add_prefix('V_')
df = df.add_suffix('_V')
How to access columns having space in names
For demonstration purpose we can add space in some column names by using df.columns = df.columns.str.replace('_' , ' '). You can access the column using the syntax df["columnname"]
df["arr delay"]
How to change row names
With the use of index option, you can rename rows (or index). In the code below, we are altering row names 0 and 1 to 'First' and 'Second' in dataframe df. By creating dictionary and taking previous row names as keys and new row names as values.
df.rename(index={0:'First',1:'Second'}, inplace=True)

20 Sep 2020 1:46am GMT

Brett Cannon: Unravelling unary arithmetic operators

In this entire blog series on Python's syntactic sugar, this might end up being the most boring post. 😄 We will cover the unary arithmetic operators: -, +, and ~ (inversion if you don't happen to be familiar with that last operator). Due to the fact that there is only a single object being involved, it's probably the most straightforward syntax to explain in Python.

The example we are going to use in this post is ~ a.

What the data model says

If you look at the data model, you will see the documentation says that for inversion the method name is __invert__ (and the other operators) and has following details:

Called to implement the unary arithmetic operations (-, +, abs()and ~).

That's it. That is literally all of the documentation for unary arithmetic operators in Python's data model. Now is that an over-simplification, or is it actually as simple as it sounds?

Looking at the bytecode

Let's look at what CPython executes for ~ a:

>>> def spam(): ~ a
... 
>>> import dis; dis.dis(spam)
  1           0 LOAD_GLOBAL              0 (a)
              2 UNARY_INVERT
              4 POP_TOP
              6 LOAD_CONST               0 (None)
              8 RETURN_VALUE

Disassembly of the bytecode for ~ a

It looks like UNARY_INVERT is the opcode we care about here.

Looking at the C code

The opcode

Diving into Python/ceval.c, you can see how UNARY_INVERT is implemented:

case TARGET(UNARY_INVERT): {
    PyObject *value = TOP();
    PyObject *res = PyNumber_Invert(value);
    Py_DECREF(value);
    SET_TOP(res);
    if (res == NULL)
        goto error;
    DISPATCH();
}

Implementation of the UNARY_INVERT opcode

The C API

The opcode implementaiton seems simple and PyNumber_Invert() is the key function here.

PyObject *
PyNumber_Invert(PyObject *o)
{
    PyNumberMethods *m;


    if (o == NULL) {
        return null_error();
    }


    m = o->ob_type->tp_as_number;
    if (m && m->nb_invert)
        return (*m->nb_invert)(o);


    return type_error("bad operand type for unary ~: '%.200s'", o);
}

Implementation of PyNumber_Invert()

What this code does is:

  1. Gets the __invert__ method off of the object's type (which is typical for Python's data model; this is for performance as it bypasses descriptors and other dynamic attribute mechanisms)
  2. If the method is there then call it and return its value
  3. Otherwise raise a TypeError

Implementing in Python

In Python this all looks like:

import desugar.builtins as debuiltins

def __invert__(object_: Any, /) -> Any:
        """Implement the unary operator `~`."""
        type_ = type(object_)
        try:
            unary_method = debuiltins._mro_getattr(type_, "__invert__")
        except AttributeError:
            raise TypeError(f"bad operand type for unary ~: {type_!r}")
        else:
            return unary_method(object_)

This can be generalized to create a closure for an arbitrary unary operation like so:

import desugar.builtins as debuiltins

def _create_unary_op(name: str, operator: str) -> Callable[[Any], Any]:
    """Create a unary arithmetic operation function."""
    method_name = f"__{name}__"

    def unary_op(object_: Any, /) -> Any:
        """A closure implementing a unary arithmetic operation."""
        type_ = type(object_)
        try:
            unary_method = debuiltins._mro_getattr(type_, method_name)
        except AttributeError:
            raise TypeError(f"bad operand type for unary {operator}: {type_!r}")
        else:
            return unary_method(object_)

    unary_op.__name__ = unary_op.__qualname__ = method_name
    unary_op.__doc__ = f"Implement the unary operation `{operator} a`."
    return unary_op


neg = __neg__ = _create_unary_op("neg", "-")
pos = __pos__ = _create_unary_op("pos", "+")
inv = __inv__ = invert = __invert__ = _create_unary_op("invert", "~")

Generalization of the creation of unary arithmetic operator functions

And that's it! As always, the code in this post can be found in my desugar project.

Aside: a bit of method name history

You may have noticed that for inversion there are four function names in the operator module:

  1. inv
  2. __inv__
  3. invert
  4. __invert__

It turns out that in Python 2.0, the special/magic method for inversion was renamed from the first two to the last two (I assume to be more self-explanatory). For backwards-compatibility the older names were left in the operator module.

20 Sep 2020 12:51am GMT

Brett Cannon: Unravelling unary arithmetic operators

In this entire blog series on Python's syntactic sugar, this might end up being the most boring post. 😄 We will cover the unary arithmetic operators: -, +, and ~ (inversion if you don't happen to be familiar with that last operator). Due to the fact that there is only a single object being involved, it's probably the most straightforward syntax to explain in Python.

The example we are going to use in this post is ~ a.

What the data model says

If you look at the data model, you will see the documentation says that for inversion the method name is __invert__ (and the other operators) and has following details:

Called to implement the unary arithmetic operations (-, +, abs()and ~).

That's it. That is literally all of the documentation for unary arithmetic operators in Python's data model. Now is that an over-simplification, or is it actually as simple as it sounds?

Looking at the bytecode

Let's look at what CPython executes for ~ a:

>>> def spam(): ~ a
... 
>>> import dis; dis.dis(spam)
  1           0 LOAD_GLOBAL              0 (a)
              2 UNARY_INVERT
              4 POP_TOP
              6 LOAD_CONST               0 (None)
              8 RETURN_VALUE

Disassembly of the bytecode for ~ a

It looks like UNARY_INVERT is the opcode we care about here.

Looking at the C code

The opcode

Diving into Python/ceval.c, you can see how UNARY_INVERT is implemented:

case TARGET(UNARY_INVERT): {
    PyObject *value = TOP();
    PyObject *res = PyNumber_Invert(value);
    Py_DECREF(value);
    SET_TOP(res);
    if (res == NULL)
        goto error;
    DISPATCH();
}

Implementation of the UNARY_INVERT opcode

The C API

The opcode implementaiton seems simple and PyNumber_Invert() is the key function here.

PyObject *
PyNumber_Invert(PyObject *o)
{
    PyNumberMethods *m;


    if (o == NULL) {
        return null_error();
    }


    m = o->ob_type->tp_as_number;
    if (m && m->nb_invert)
        return (*m->nb_invert)(o);


    return type_error("bad operand type for unary ~: '%.200s'", o);
}

Implementation of PyNumber_Invert()

What this code does is:

  1. Gets the __invert__ method off of the object's type (which is typical for Python's data model; this is for performance as it bypasses descriptors and other dynamic attribute mechanisms)
  2. If the method is there then call it and return its value
  3. Otherwise raise a TypeError

Implementing in Python

In Python this all looks like:

import desugar.builtins as debuiltins

def __invert__(object_: Any, /) -> Any:
        """Implement the unary operator `~`."""
        type_ = type(object_)
        try:
            unary_method = debuiltins._mro_getattr(type_, "__invert__")
        except AttributeError:
            raise TypeError(f"bad operand type for unary ~: {type_!r}")
        else:
            return unary_method(object_)

This can be generalized to create a closure for an arbitrary unary operation like so:

import desugar.builtins as debuiltins

def _create_unary_op(name: str, operator: str) -> Callable[[Any], Any]:
    """Create a unary arithmetic operation function."""
    method_name = f"__{name}__"

    def unary_op(object_: Any, /) -> Any:
        """A closure implementing a unary arithmetic operation."""
        type_ = type(object_)
        try:
            unary_method = debuiltins._mro_getattr(type_, method_name)
        except AttributeError:
            raise TypeError(f"bad operand type for unary {operator}: {type_!r}")
        else:
            return unary_method(object_)

    unary_op.__name__ = unary_op.__qualname__ = method_name
    unary_op.__doc__ = f"Implement the unary operation `{operator} a`."
    return unary_op


neg = __neg__ = _create_unary_op("neg", "-")
pos = __pos__ = _create_unary_op("pos", "+")
inv = __inv__ = invert = __invert__ = _create_unary_op("invert", "~")

Generalization of the creation of unary arithmetic operator functions

And that's it! As always, the code in this post can be found in my desugar project.

Aside: a bit of method name history

You may have noticed that for inversion there are four function names in the operator module:

  1. inv
  2. __inv__
  3. invert
  4. __invert__

It turns out that in Python 2.0, the special/magic method for inversion was renamed from the first two to the last two (I assume to be more self-explanatory). For backwards-compatibility the older names were left in the operator module.

20 Sep 2020 12:51am GMT

19 Sep 2020

feedPlanet Python

Doug Hellmann: sphinxcontrib.datatemplates 0.7.0

sphinxcontrib.datatemplates is an extension for Sphinx to render parts of reStructuredText pages from data files in formats like JSON, YAML, XML, and CSV. What's new in 0.7.0? add release history to documentation add sphinx builder environment to template context (contributions by Eric Holscher) add a 'dump' subcommand to the command line interface cli: create 'render' …

Continue reading "sphinxcontrib.datatemplates 0.7.0"

19 Sep 2020 1:19pm GMT

Doug Hellmann: sphinxcontrib.datatemplates 0.7.0

sphinxcontrib.datatemplates is an extension for Sphinx to render parts of reStructuredText pages from data files in formats like JSON, YAML, XML, and CSV. What's new in 0.7.0? add release history to documentation add sphinx builder environment to template context (contributions by Eric Holscher) add a 'dump' subcommand to the command line interface cli: create 'render' …

Continue reading "sphinxcontrib.datatemplates 0.7.0"

19 Sep 2020 1:19pm GMT

ListenData: Python : 10 Ways to Filter Pandas DataFrame

In this article, we will cover various methods to filter pandas dataframe in Python. Data Filtering is one of the most frequent data manipulation operation. It is similar to WHERE clause in SQL or you must have used filter in MS Excel for selecting specific rows based on some conditions. In terms of speed, python has an efficient way to perform filtering and aggregation. It has an excellent package called pandas for data wrangling tasks. Pandas has been built on top of numpy package which was written in C language which is a low level language. Hence data manipulation using pandas package is fast and smart way to handle big sized datasets.
Examples of Data Filtering
It is one of the most initial step of data preparation for predictive modeling or any reporting project. It is also called 'Subsetting Data'. See some of the examples of data filtering below.
  • Select all the active customers whose accounts were opened after 1st January 2019
  • Extract details of all the customers who made more than 3 transactions in the last 6 months
  • Fetch information of employees who spent more than 3 years in the organization and received highest rating in the past 2 years
  • Analyze complaints data and identify customers who filed more than 5 complaints in the last 1 year
  • Extract details of metro cities where per capita income is greater than 40K dollars
filter pandas dataframe
Import Data
Make sure pandas package is already installed before submitting the following code. You can check it by running !pip show pandas statement in Ipython console. If it is not installed, you can install it by using the command !pip install pandas.

We are going to use dataset containing details of flights departing from NYC in 2013. This dataset has 336776 rows and 16 columns. See column names below. To import dataset, we are using read_csv( ) function from pandas package.

['year', 'month', 'day', 'dep_time', 'dep_delay', 'arr_time',
'arr_delay', 'carrier', 'tailnum', 'flight', 'origin', 'dest',
'air_time', 'distance', 'hour', 'minute']
import pandas as pd
df = df = pd.read_csv("https://raw.githubusercontent.com/JackyP/testing/master/datasets/nycflights.csv", usecols=range(1,17))

Filter pandas dataframe by column value

Select flights details of JetBlue Airways that has 2 letters carrier code B6 with origin from JFK airport

READ MORE »

19 Sep 2020 9:13am GMT

ListenData: Python : 10 Ways to Filter Pandas DataFrame

In this article, we will cover various methods to filter pandas dataframe in Python. Data Filtering is one of the most frequent data manipulation operation. It is similar to WHERE clause in SQL or you must have used filter in MS Excel for selecting specific rows based on some conditions. In terms of speed, python has an efficient way to perform filtering and aggregation. It has an excellent package called pandas for data wrangling tasks. Pandas has been built on top of numpy package which was written in C language which is a low level language. Hence data manipulation using pandas package is fast and smart way to handle big sized datasets.
Examples of Data Filtering
It is one of the most initial step of data preparation for predictive modeling or any reporting project. It is also called 'Subsetting Data'. See some of the examples of data filtering below.
  • Select all the active customers whose accounts were opened after 1st January 2019
  • Extract details of all the customers who made more than 3 transactions in the last 6 months
  • Fetch information of employees who spent more than 3 years in the organization and received highest rating in the past 2 years
  • Analyze complaints data and identify customers who filed more than 5 complaints in the last 1 year
  • Extract details of metro cities where per capita income is greater than 40K dollars
filter pandas dataframe
Import Data
Make sure pandas package is already installed before submitting the following code. You can check it by running !pip show pandas statement in Ipython console. If it is not installed, you can install it by using the command !pip install pandas.

We are going to use dataset containing details of flights departing from NYC in 2013. This dataset has 336776 rows and 16 columns. See column names below. To import dataset, we are using read_csv( ) function from pandas package.

['year', 'month', 'day', 'dep_time', 'dep_delay', 'arr_time',
'arr_delay', 'carrier', 'tailnum', 'flight', 'origin', 'dest',
'air_time', 'distance', 'hour', 'minute']
import pandas as pd
df = df = pd.read_csv("https://raw.githubusercontent.com/JackyP/testing/master/datasets/nycflights.csv", usecols=range(1,17))

Filter pandas dataframe by column value

Select flights details of JetBlue Airways that has 2 letters carrier code B6 with origin from JFK airport

READ MORE »

19 Sep 2020 9:13am GMT

Catalin George Festila: Python 3.8.5 : Linked List - part 001.

In computer science, a linked list is a linear collection of data elements whose order is not given by their physical placement in memory. see wikipedia.org.In this tutorial I will show you how these linked list works and how can build with python programming language.Let's start with some basic elements:Linked List is a linear data structure;Linked List are not array;Linked List are not stored

19 Sep 2020 2:52am GMT

Catalin George Festila: Python 3.8.5 : Linked List - part 001.

In computer science, a linked list is a linear collection of data elements whose order is not given by their physical placement in memory. see wikipedia.org.In this tutorial I will show you how these linked list works and how can build with python programming language.Let's start with some basic elements:Linked List is a linear data structure;Linked List are not array;Linked List are not stored

19 Sep 2020 2:52am GMT

Catalin George Festila: Python 3.8.5 : Testing with openpyxl - part 002 .

Today I will show you how can use Levenshtein ratio and distance between two strings, see wikipedia. I used three files created with LibreOffice and save it like xlsx file type. All of these files come with the column A fill with strings of characters, in this case, numbers. The script will read all of these files from the folder named xlsx_files and will calculate Levenshtein ratio and distance

19 Sep 2020 1:46am GMT

Catalin George Festila: Python 3.8.5 : Testing with openpyxl - part 002 .

Today I will show you how can use Levenshtein ratio and distance between two strings, see wikipedia. I used three files created with LibreOffice and save it like xlsx file type. All of these files come with the column A fill with strings of characters, in this case, numbers. The script will read all of these files from the folder named xlsx_files and will calculate Levenshtein ratio and distance

19 Sep 2020 1:46am GMT

Catalin George Festila: Python 3.8.5 : Testing with openpyxl - part 001 .

The Python executes the code line by line because is an interpreter language. This allows users to solve issues in the programming area, fast and easy. I use python versiono 3.8.5 build on Aug 12 2020 at 00:00:00, see the result of interactive mode: [mythcat@desk ~]$ python Python 3.8.5 (default, Aug 12 2020, 00:00:00) [GCC 10.2.1 20200723 (Red Hat 10.2.1-1)] on linux Type "help", "copyright", "

19 Sep 2020 1:46am GMT

Catalin George Festila: Python 3.8.5 : Testing with openpyxl - part 001 .

The Python executes the code line by line because is an interpreter language. This allows users to solve issues in the programming area, fast and easy. I use python versiono 3.8.5 build on Aug 12 2020 at 00:00:00, see the result of interactive mode: [mythcat@desk ~]$ python Python 3.8.5 (default, Aug 12 2020, 00:00:00) [GCC 10.2.1 20200723 (Red Hat 10.2.1-1)] on linux Type "help", "copyright", "

19 Sep 2020 1:46am GMT

Catalin George Festila: Python 3.8.5 : Testing the pyre tool - part 001.

The Pyre is a static analysis tool to detect and prevent security issues in Python code that can be found on the official website. The Pyre tool supports the Language Server Protocol and has an extension for VSCode. The team development comes at August 7, 2020, with this intro: Pyre is a performant type checker for Python. Statically typing what are essentially fully dynamic languages has a long

19 Sep 2020 1:46am GMT

Catalin George Festila: Python 3.8.5 : Testing the pyre tool - part 001.

The Pyre is a static analysis tool to detect and prevent security issues in Python code that can be found on the official website. The Pyre tool supports the Language Server Protocol and has an extension for VSCode. The team development comes at August 7, 2020, with this intro: Pyre is a performant type checker for Python. Statically typing what are essentially fully dynamic languages has a long

19 Sep 2020 1:46am GMT

Catalin George Festila: Python 3.8.5 : The hashlib python package - part 001.

The tutorial for today is about hashlib python module. The official webpage comes for this python package has this intro: This module implements a common interface to many different secure hash and message digest algorithms. Included are the FIPS secure hash algorithms SHA1, SHA224, SHA256, SHA384, and SHA512 (defined in FIPS 180-2) as well as RSA's MD5 algorithm (defined in Internet RFC 1321).

19 Sep 2020 1:46am GMT

Catalin George Festila: Python 3.8.5 : The hashlib python package - part 001.

The tutorial for today is about hashlib python module. The official webpage comes for this python package has this intro: This module implements a common interface to many different secure hash and message digest algorithms. Included are the FIPS secure hash algorithms SHA1, SHA224, SHA256, SHA384, and SHA512 (defined in FIPS 180-2) as well as RSA's MD5 algorithm (defined in Internet RFC 1321).

19 Sep 2020 1:46am GMT

Catalin George Festila: Python 3.6.9 : My colab tutorials - part 008.

Today I deal with these two python packages named selenium and chromium-chromedriver. I used selenium to get pieces of information from webpages. These examples can be found at my GitHub project colab on the notebook named catafest_008.

19 Sep 2020 1:46am GMT

Catalin George Festila: Python 3.6.9 : My colab tutorials - part 008.

Today I deal with these two python packages named selenium and chromium-chromedriver. I used selenium to get pieces of information from webpages. These examples can be found at my GitHub project colab on the notebook named catafest_008.

19 Sep 2020 1:46am GMT

10 Nov 2011

feedPython Software Foundation | GSoC'11 Students

Benedict Stein: King Willams Town Bahnhof

Gestern musste ich morgens zur Station nach KWT um unsere Rerservierten Bustickets für die Weihnachtsferien in Capetown abzuholen. Der Bahnhof selber ist seit Dezember aus kostengründen ohne Zugverbindung - aber Translux und co - die langdistanzbusse haben dort ihre Büros.


Größere Kartenansicht




© benste CC NC SA

10 Nov 2011 10:57am GMT

09 Nov 2011

feedPython Software Foundation | GSoC'11 Students

Benedict Stein

Niemand ist besorgt um so was - mit dem Auto fährt man einfach durch, und in der City - nahe Gnobie- "ne das ist erst gefährlich wenn die Feuerwehr da ist" - 30min später auf dem Rückweg war die Feuerwehr da.




© benste CC NC SA

09 Nov 2011 8:25pm GMT

08 Nov 2011

feedPython Software Foundation | GSoC'11 Students

Benedict Stein: Brai Party

Brai = Grillabend o.ä.

Die möchte gern Techniker beim Flicken ihrer SpeakOn / Klinke Stecker Verzweigungen...

Die Damen "Mamas" der Siedlung bei der offiziellen Eröffnungsrede

Auch wenn weniger Leute da waren als erwartet, Laute Musik und viele Leute ...

Und natürlich ein Feuer mit echtem Holz zum Grillen.

© benste CC NC SA

08 Nov 2011 2:30pm GMT

07 Nov 2011

feedPython Software Foundation | GSoC'11 Students

Benedict Stein: Lumanyano Primary

One of our missions was bringing Katja's Linux Server back to her room. While doing that we saw her new decoration.

Björn, Simphiwe carried the PC to Katja's school


© benste CC NC SA

07 Nov 2011 2:00pm GMT

06 Nov 2011

feedPython Software Foundation | GSoC'11 Students

Benedict Stein: Nelisa Haircut

Today I went with Björn to Needs Camp to Visit Katja's guest family for a special Party. First of all we visited some friends of Nelisa - yeah the one I'm working with in Quigney - Katja's guest fathers sister - who did her a haircut.

African Women usually get their hair done by arranging extensions and not like Europeans just cutting some hair.

In between she looked like this...

And then she was done - looks amazing considering the amount of hair she had last week - doesn't it ?

© benste CC NC SA

06 Nov 2011 7:45pm GMT

05 Nov 2011

feedPython Software Foundation | GSoC'11 Students

Benedict Stein: Mein Samstag

Irgendwie viel mir heute auf das ich meine Blogposts mal ein bischen umstrukturieren muss - wenn ich immer nur von neuen Plätzen berichte, dann müsste ich ja eine Rundreise machen. Hier also mal ein paar Sachen aus meinem heutigen Alltag.

Erst einmal vorweg, Samstag zählt zumindest für uns Voluntäre zu den freien Tagen.

Dieses Wochenende sind nur Rommel und ich auf der Farm - Katja und Björn sind ja mittlerweile in ihren Einsatzstellen, und meine Mitbewohner Kyle und Jonathan sind zu Hause in Grahamstown - sowie auch Sipho der in Dimbaza wohnt.
Robin, die Frau von Rommel ist in Woodie Cape - schon seit Donnerstag um da ein paar Sachen zur erledigen.
Naja wie dem auch sei heute morgen haben wir uns erstmal ein gemeinsames Weetbix/Müsli Frühstück gegönnt und haben uns dann auf den Weg nach East London gemacht. 2 Sachen waren auf der Checkliste Vodacom, Ethienne (Imobilienmakler) außerdem auf dem Rückweg die fehlenden Dinge nach NeedsCamp bringen.

Nachdem wir gerade auf der Dirtroad losgefahren sind mussten wir feststellen das wir die Sachen für Needscamp und Ethienne nicht eingepackt hatten aber die Pumpe für die Wasserversorgung im Auto hatten.

Also sind wir in EastLondon ersteinmal nach Farmerama - nein nicht das onlinespiel farmville - sondern einen Laden mit ganz vielen Sachen für eine Farm - in Berea einem nördlichen Stadteil gefahren.

In Farmerama haben wir uns dann beraten lassen für einen Schnellverschluss der uns das leben mit der Pumpe leichter machen soll und außerdem eine leichtere Pumpe zur Reperatur gebracht, damit es nicht immer so ein großer Aufwand ist, wenn mal wieder das Wasser ausgegangen ist.

Fego Caffé ist in der Hemmingways Mall, dort mussten wir und PIN und PUK einer unserer Datensimcards geben lassen, da bei der PIN Abfrage leider ein zahlendreher unterlaufen ist. Naja auf jeden Fall speichern die Shops in Südafrika so sensible Daten wie eine PUK - die im Prinzip zugang zu einem gesperrten Phone verschafft.

Im Cafe hat Rommel dann ein paar online Transaktionen mit dem 3G Modem durchgeführt, welches ja jetzt wieder funktionierte - und übrigens mittlerweile in Ubuntu meinem Linuxsystem perfekt klappt.

Nebenbei bin ich nach 8ta gegangen um dort etwas über deren neue Deals zu erfahren, da wir in einigen von Hilltops Centern Internet anbieten wollen. Das Bild zeigt die Abdeckung UMTS in NeedsCamp Katjas Ort. 8ta ist ein neuer Telefonanbieter von Telkom, nachdem Vodafone sich Telkoms anteile an Vodacom gekauft hat müssen die komplett neu aufbauen.
Wir haben uns dazu entschieden mal eine kostenlose Prepaidkarte zu testen zu organisieren, denn wer weis wie genau die Karte oben ist ... Bevor man einen noch so billigen Deal für 24 Monate signed sollte man wissen obs geht.

Danach gings nach Checkers in Vincent, gesucht wurden zwei Hotplates für WoodyCape - R 129.00 eine - also ca. 12€ für eine zweigeteilte Kochplatte.
Wie man sieht im Hintergrund gibts schon Weihnachtsdeko - Anfang November und das in Südafrika bei sonnig warmen min- 25°C

Mittagessen haben wir uns bei einem Pakistanischen Curry Imbiss gegönnt - sehr empfehlenswert !
Naja und nachdem wir dann vor ner Stunde oder so zurück gekommen sind habe ich noch den Kühlschrank geputzt den ich heute morgen zum defrosten einfach nach draußen gestellt hatte. Jetzt ist der auch mal wieder sauber und ohne 3m dicke Eisschicht...

Morgen ... ja darüber werde ich gesondert berichten ... aber vermutlich erst am Montag, denn dann bin ich nochmal wieder in Quigney(East London) und habe kostenloses Internet.

© benste CC NC SA

05 Nov 2011 4:33pm GMT

31 Oct 2011

feedPython Software Foundation | GSoC'11 Students

Benedict Stein: Sterkspruit Computer Center

Sterkspruit is one of Hilltops Computer Centres in the far north of Eastern Cape. On the trip to J'burg we've used the opportunity to take a look at the centre.

Pupils in the big classroom


The Trainer


School in Countryside


Adult Class in the Afternoon


"Town"


© benste CC NC SA

31 Oct 2011 4:58pm GMT

Benedict Stein: Technical Issues

What are you doing in an internet cafe if your ADSL and Faxline has been discontinued before months end. Well my idea was sitting outside and eating some ice cream.
At least it's sunny and not as rainy as on the weekend.


© benste CC NC SA

31 Oct 2011 3:11pm GMT

30 Oct 2011

feedPython Software Foundation | GSoC'11 Students

Benedict Stein: Nellis Restaurant

For those who are traveling through Zastron - there is a very nice Restaurant which is serving delicious food at reasanable prices.
In addition they're selling home made juices jams and honey.




interior


home made specialities - the shop in the shop


the Bar


© benste CC NC SA

30 Oct 2011 4:47pm GMT

29 Oct 2011

feedPython Software Foundation | GSoC'11 Students

Benedict Stein: The way back from J'burg

Having the 10 - 12h trip from J'burg back to ELS I was able to take a lot of pcitures including these different roadsides

Plain Street


Orange River in its beginngings (near Lesotho)


Zastron Anglican Church


The Bridge in Between "Free State" and Eastern Cape next to Zastron


my new Background ;)


If you listen to GoogleMaps you'll end up traveling 50km of gravel road - as it was just renewed we didn't have that many problems and saved 1h compared to going the official way with all it's constructions sites




Freeway


getting dark


© benste CC NC SA

29 Oct 2011 4:23pm GMT

28 Oct 2011

feedPython Software Foundation | GSoC'11 Students

Benedict Stein: Wie funktioniert eigentlich eine Baustelle ?

Klar einiges mag anders sein, vieles aber gleich - aber ein in Deutschland täglich übliches Bild einer Straßenbaustelle - wie läuft das eigentlich in Südafrika ?

Ersteinmal vorweg - NEIN keine Ureinwohner die mit den Händen graben - auch wenn hier mehr Manpower genutzt wird - sind sie fleißig mit Technologie am arbeiten.

Eine ganz normale "Bundesstraße"


und wie sie erweitert wird


gaaaanz viele LKWs


denn hier wird eine Seite über einen langen Abschnitt komplett gesperrt, so das eine Ampelschaltung mit hier 45 Minuten Wartezeit entsteht


Aber wenigstens scheinen die ihren Spaß zu haben ;) - Wie auch wir denn gücklicher Weise mussten wir nie länger als 10 min. warten.

© benste CC NC SA

28 Oct 2011 4:20pm GMT