Intermission: wiring things for behave

After reflecting the status of the building pieces for spell casting, I realised that I can wire things a bit further on behave side.

I started by fixing a step definition for behave:

@when('{caster_name} casts {spell_and_target}')
def impl(context, caster_name, spell_and_target):
    # Simon casts magic missile on Uglak
    # Simon casts healing wind
    
    caster = get_character(context, caster_name)
    spell = spell_and_target

    make(caster, cast_spell(spell_name = spell))

Since healing wind spell will heal only the caster, I make some assumptions here (like not caring about who I’m casting the spell at). I used cutesy here too, just like in the melee combat, in order to keep the step definition short and decoupled from the actual implementation details.

Implementation for cast_spell – function is as follows:

class CastSpell():
    """
    Class representing casting a spell
    """
    def __init__(self, spell_name):
        """
        Default constructor
        
        :param spell_name: name of the spell to cast
        :type spell_name: string
        """
        super(CastSpell, self).__init__()
        self.spell_name = spell_name
    
    def __call__(self, caster):
        """
        Performs the casting
        
        :param caster: character doing the casting
        :type caster: Character
        """
        caster.old_values = {}
        caster.old_values['hit points'] = caster.hit_points

        action_factory = (ActionFactoryBuilder()
                                    .with_move_factory()
                                    .with_attack_factory()
                                    .with_drink_factory()
                                    .with_inventory_factory()
                                    .with_dying_rules()
                                    .with_spellcasting_factory()
                                    .build())

        caster.cast(direction = 1,
                    spell_name = self.spell_name, 
                    action_factory = action_factory)

def cast_spell(spell_name):
    """
    Cast a spell

    :param spell_name: name of the spell to cast
    """
    action = CastSpell(spell_name)
    return action

This hopefully decouples behave steps enough from actual implementation, in case they change later. CastSpell class is used to cast spells and it is callable (__call__ method has been implemented). This allows me to store context about the action in the object’s attributes and still call it like it would be a function. Another option would of course be to create a function and handle context parameters with closures.

cast_spell – function is just a convenient way of constructing CastSpell object with given parameters.

I’m keeping track of casters hit points, because further down the line I want to verify that they change after the spell has been cast. Later on I should add other attributes like mana points for tracking.

I’m also creating a new instance of ActionFactory. That is an object that is used to create actions, like moving, fighting and casting spells. Having a builder object makes it easy to construct the ActionFactory.

Final step was to implement one more behave step:

@then('{character_name} should be in full health')
def impl(context, character_name):
    character = get_character(context, character_name)

    assert_that(character.hit_points, equal_to(character.max_hp))

The step is short and it verifies that the character in question is in full health.

After running the behave I got following output:

  @wip
  Scenario: Healing                       # features\magic.feature:29
    Given Simon is Wizard                 # features\helpers\events.py:35
    And Uglak is Goblin                   # features\helpers\events.py:35
    And Uglak is almost dead              # features\helpers\events.py:35
    And Uglak is standing in room         # features\helpers\context.py:35
    And Simon is standing away from Uglak # <string>:50
    Given Simon is almost dead            # features\helpers\events.py:35
    When Simon casts healing wind         # <string>:24
    Then Simon should be in full health   # <string>:109
      Assertion Failed: 
      Expected: <5>
           but: was <1>

So Uglak and Simon, both in weak condition, are standing in a room. Simon casts healing wind, but does not have full health. Every step should have been implemented at this point, meaning I can keep coding and running the test to see when the code satisfies it.

Code for this change can be found from commit 3a32c172c65f19e7fcee9360eda4c301994ad8e8.

Instant SymPy Starter

I got a review copy of Instant SymPy Starter from Packt Publishing.

Since the book is from Instant series, it is not a thick one, only around 50 pages and it does not aim to teach each and every feature of the SymPy to the reader. Instead of that, 5 common features were chosen to be covered in the book. These features are: creating and manipulating expressions, numerical evaluation, calculus and solving equations. In addition to that there are instructions for installing SymPy and various other tools that could be useful and a quick example on curve sketching.

Each section contains clear examples that teach how to for example simplify symbolic expressions or calculate limits. The mathematical reasons behind examples are not explained, but it assumed that the reader is proficient with mathematics. I liked the decision since it kept the book short and compact and there are plenty of resources for mathematics elsewhere.

In the end of the book there is some resources for further study, like articles, tutorials, mailing lists and blogs.

The book is good purchase for a person who has not used SymPy before and wants to quickly get started with the basics. The same information can be found from internet of course, but in the book it has been laid out in a nice format and explained in such a way that the reader does not get sidetracked with unnecessary details.

The book is available from Packt Publishing at: http://www.packtpub.com/sympy-python-starter/book

Targetting spells

My next goal was to start working with actual spell objects. I sketched my ideas on a paper and decided that there would be a single Spell class that could be parametrized to handle various spells. And the first step to creating that class would be targeting characters with spells.

I started writing following test:

    def test_target_single(self):
        """
        Targeting a single character should be possible
        """
        level = LevelBuilder().build()
        
        character = (CharacterBuilder()
                        .with_level(level)
                        .with_location((5, 5))
                        .build())

        spell_generator = SpellGeneratorBuilder().build()

        spell = spell_generator.create_spell(spell_name = 'healing wind', 
                                             target = character)

        assert_that(character, is_in(spell.target))

Nothing too complicated. My focus will be on healing wind spell and after I get it working, I can start from the beginning and see what needs to be changed to get magic missile working. You may notice that target attribute is a list of some sort, instead of just a single entity. I’m jumping forward a bit here, but I know already that I want spells that can target multiple characters and felt that it makes sense to write the system to support that from the beginning.

The code needed to make the test pass is simple:

class Spell():
    """
    Class to represent spells
    
    .. versionadded:: 0.9
    """
    
    def __init__(self):
        """
        Default constructor
        """
        self.target = []

class SpellGenerator():
    """
    Factory for creating spells
    
    .. versionadded:: 0.9
    """
    @logged
    def __init__(self):
        """
        Default constructor
        """
        pass
     
    @logged
    def create_spell(self, spell_name, target):
        """
        Create a spell
         
        :param spell_name: name of the spell
        :type spell_name: string
        :param target: target of the spell
        :type target: Character
        :returns: ready to use spell
        :rtype: Spell
        """
        new_spell = Spell()
        new_spell.target.append(target)
 
        return new_spell

SpellGenerator will be the most used interface for the spell subsystem. It can be used to create all the different spells.

Code for this can be found from commit 112e9a77654490e0c8875c23572aa561bf35462d

Testing screencast

As part of YIIP1400 course I created a short screencast about how testing is done in pyherc/Herculeum. It is available at YouTube. Making it was rather interesting even when the end result is quite rough and unpolished. I probably will make more of these later.

When the magic system has something substantial to show I’m going to make a short demo where I play the game and talk about the new features.

Getting closer to the source of magic

The current plan is to have spell casting use effects sub-system and make Spell object a composite that has a list of effects. In order to make construction of Spells easy, I’m planning on using a factory and call it while creating the action. Following code captures this in the form of a test:

def test_spell_is_created_with_a_factory(self):
    """
    When creating a spell casting action, spell should be created
    """
    spell_factory = SpellFactoryBuilder().build()
    when(spell_factory).create_spell('healing wind').thenReturn(mock())
    spellcasting_factory = (SpellCastingFactoryBuilder()
                                        .with_spell_factory(spell_factory)
                                        .build())
    
    spellcasting_factory.get_action(
                              SpellCastingParameters(self,
                                                     direction = 1, 
                                                     spell_name = 'healing wind'))
    
    verify(spell_factory).create_spell('healing wind')

Essentially, when SpellCastingFactory is used to create a spell called “healing wind”, the SpellFactory should receive a call to make a spell called “healing wind”. I’m creating spell_factory with SpellFactoryBuilder (so I have a real instance and not just a mock object), but then I’m using mockito to tell it to return mock when create_spell – method is called. I would like to use mock, but for some reason I couldn’t get it working with the code in SpellCastingFactoryBuilder:

def with_spell_factory(self, spell_factory):
    """
    Configure spell factory to use
    """
    if spell_factory == None:
        self.use_real_spell_factory = True
    else:
        if hasattr(spell_factory, 'build'):
            self.spell_factory = spell_factory.build()
        else:
            self.spell_factory = spell_factory
    return self

When creating a SpellCastingFactory with the builder, I can supply it with a spell_factory to use. I the spell_factory has method “build”, it will be called and the result is used as a factory, otherwise the supplied object is used. For mock object, hasattr will always return True, so this approach does not work.

Following modification to code makes the test to pass:

@logged
def get_action(self, parameters):
    """
    Create a spell casting action

    :param parameters: parameters used to control creation
    :type parameters: SpellCastingParameters
    """
    spell = self.spell_factory.create_spell(parameters.spell_name)
    
    return SpellCastingAction(caster = parameters.caster, 
                                       direction = parameters.direction,
                                       spell = spell)

Again, really small step forward, but the progression is steady and the direction looks good. I’m going to leave details about finding who the spell hits and how much the mana is subtracted later (both probably ending up in the SpellCastingAction) and concentrate on getting the spell part done.

Code for the changes can be found in the following commit.

Small steps

I managed to figure out why the style sheets were not working on Herculeum. While Python 2.x was treating them as ASCII, Python 3.x is treating them as Unicode by default. And since the actual file is in ASCII, there was a mismatch that caused errors in serialization and in turn prevented them from loading.

Switch to Python 3.2 has caused other problems too and I have been slowly patching things back in order. Behave does not currently seem to generate xUnit reports without throwing an exception, so I had to exclude it from the test reporting. I’m probably either going to use regular text output or figure a workaround for the error. As far as I understand, the problems is related to Unicode vs. ASCII again.

But the important thing is that I’m making some progress again and fixing little bugs that are lurking in the code. Eventually I want to finish the curses interface and release 0.9 and then start working on the magic system. That probably means a new player class that relies mostly on the magic.

My thesis is nearing completion. If everything goes as planned, I’ll return it in two weeks. The review process takes around a month after that. I’m really looking forward seeing it in print too.

Status update

The past month has been extremely busy and I have not had time to take care of the blog properly. I am on the final stretch of my thesis and hopefully after finishing it I will have time to code again.

I managed to write some clojure code and get the very elemental ray tracer up and running. It does not do shadows or reflections yet, but those are just some details that I can add later.

I also converted pyherc and satin-python to 3.x version of Python and things are mostly working. For some reason style sheets fail to load, which is really bad problem. I have to find the reason behind this behaviour before adding more content.

Decorators – redux

Recently I blogged about how decorators are best thing since sliced bread and how to create them. I had example code like this:

def logged(fn):
    """
    Decorator to perform logging
    """
    logger_name = str(fn)
    logger = logging.getLogger(logger_name)

    def log(*args, **kwargs):
        """
        Log function call
        """
        call_message = ' '.join([logger_name,
                                 'call',
                                 ':',
                                 str(args),
                                 str(kwargs)])

        logger.debug(call_message)

        result = fn(*args, **kwargs)

        result_message = ' '.join([logger_name,
                                   'return',
                                   ':',
                                   str(result)])

        logger.debug(result_message)

        return result

    return log

It works just fine and gets the job done, but it also has at least two major issues. First one is that the decorator is masking signature of the function it is used to decorate. This in turn causes trouble when generating API-documentation with Sphinx. Instead of correct parameters, you end up with not-so-useful function_name(*args, **kwargs). Same thing applies with docstring, which in turn makes help-function useless in interactive mode. Also, in case of multiple decorators, there is some repeating code that I could live without.

Nice solution to all these is decorator library. It adds a decorator, that can turn any function into a decorator, while preserving signature and docstring. When using decorator library, the previous example turns into:

@decorator
def logged(wrapped_function, *args, **kwargs):
    """
    Decorator to perform logging
    """
    logger_name = str(wrapped_function)
    logger = logging.getLogger(logger_name)

    call_message = ' '.join([logger_name,
                             'call',
                             ':',
                             str(args),
                             str(kwargs)])

    logger.debug(call_message)

    result = wrapped_function(*args, **kwargs)

    result_message = ' '.join([logger_name,
                                   'return',
                                   ':',
                                   str(result)])

    logger.debug(result_message)

    return result

Pretty nice and clean I think. A drawback is that lose some flexibility since there is no way (as far as I know) to write logic that happens before decorator is applied. All the logic shown in the logged-function is logic that gets executed when the wrapped function is called. In this example, logger_name is taken from calling function each and every time the function is called. In the previous example, the name is resolved only once (when the decorator is created).

NumPy Cookbook

Recently I got a copy of NumPy Cookbook to read and review from Packt Publishing and I must say that I was positively surprised. Focus is of course NumPy, but the book touches SciPy too.

The book is laid out nicely and is generally easy to read and digest. I really loved how instead of doing examples as Python programs or even interpreter commands, they chose to use IPython, which is like regular Python shell, but in steroids (as my colleague eloquently put it). IPython makes experimenting and sharing the experiments with others fun and easy.

My only experience with NumPy before was from time when I was writing a simple ray tracer with Python. I knew that the library had lot to offer besides simple things I was doing, but did not really have good way to dig in into it. This book has over 70 different ways of using NumPy, SciPy, PIL among other libraries that can be used to analyze and manipulate data. It also briefly touches subject of quality assurance, which of course is very close to my heart.

Focus is all the time in showing how to do things with brief examples. This suited very well for me, since I’m more about learning by doing than learning by reading type of person. While the book is relatively thin (around 200 pages + index), it has quite lot in it. For seasoned NumPy / SciPy user it probably does not offer that much new, but for a person not familiar with the libraries it offers a fast way getting started.

Travis CI environment

I recently set up a build in Travis CI environment. It is really cool hosted continuous integration service for the open source community and well integrated with GitHub to boot. Every time I push code into my public repository in GitHub, Travis is notified and will run 3 test builds for me. Each build is done with different version of Python, so I can now easily cover 2.6, 2.7 and 3.2. Especially 3.2 is very good, since I don’t have that set up on my system. If everything goes fine, I don’t even notice the whole process. Only when build breaks, I get an email stating the problem and I can start hunting the error.

Setting up Travis was really easy. I just had to enable hook for it in GitHub and write a simple configuration file:

language: python
python:
  - "2.6"
  - "2.7"
  - "3.2"
# command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors
install: 
 - "easy_install -U mockito"
 - "easy_install -U pyhamcrest"
 - "easy_install -U decorator"
# command to run tests, e.g. python setup.py test
script: nosetests -w ./src/pyherc

The configuration is for running for three versions of Python (2.6, 2.7 and 3.2). At the start of the build, the system will install three libraries (mockito, pyhamcrest and decorator). Builds are always done in a clean environment and all changes are rolled back after finishing the build.

After that the system was more or less working and the only thing I had to do was to fix the codebase to work with Python 3.2.

The system has been set up to run only unit tests from pyherc project (more or less the engine of my game). UI tests I can not run without PyQt being installed and currently that is not provided as a easy install package. CPU time and bandwidth are considerations too, since I don’t want to take too much resources from a free service.

For a single developer working on a hobby project, this is probably a little bit overkill. But I like to tinker with things and try out them in a small software project, where it is easier than on a huge one.