Effects of spells

The next step with spell casting takes me to effects. There is already a effect subsystem in place that is being used for healing potions and spider poisonings for example. Effects can be one off or they can have a duration (finite or even infinite). So it seemed like a good idea to reuse those effects for spells. It gives the possibility to have immediate spell effects (like magic missiles and fire balls) or longer lasting ones (blessings and curses).

First step is to create some effects, so I will start with a test:

def test_creating_effect(self):
    """
    Casting a spell should create effects it has
    """
    effects_factory = mock(EffectsFactory)
    effect = mock(Effect)
    dying_rules = mock(Dying)
    when(effects_factory).create_effect(key = 'healing wind',
                                        target = self.character).thenReturn(effect)

    effect_handle = EffectHandle(trigger = 'on spell hit',
                                 effect = 'healing wind',
                                 parameters = {},
                                 charges = 1)

    spell = (SpellBuilder()
                .with_effect_handle(effect_handle)
                .with_target(self.character)
                .build())

    spell.cast(effects_factory, 
               dying_rules)

    verify(effects_factory).create_effect(key = 'healing wind',
                                          target = self.character)

Essential parts are where we tell the effect_factory to return a mocked effect when it is being called with correct parameters. EffectHandles are sort of specifications that tell when to create what kind of effect. In this case, when ‘on spell hit’ event happens, we want to create a healing wind. EffectFactory on the other hand can be used to create effect by name, which in this case is ‘healing wind’.

I’m using a SpellBuilder to create instance of Spell object. The reason for this is to decouple tests and the code they are testing to a degree. Obviously there has to be some sort of connectivity, but I try to limit it a bit. If internal representation of spells change, it is enough to change the builder and all the tests are hopefully up and running again (at least if the verification part of the test works).

Executing tests at this point gives an error:

Traceback (most recent call last):
  File "C:\Python32\lib\site-packages\nose\case.py", line 198, in runTest
    self.test(*self.arg)
  File "C:\programming\pyHack\src\pyherc\test\unit\test_spells.py", line 85, in test_triggering_effect
    target = self.character)
  File "C:\Python32\lib\site-packages\mockito\invocation.py", line 98, in __call__
    verification.verify(self, len(matched_invocations))
  File "C:\Python32\lib\site-packages\mockito\verification.py", line 51, in verify
    raise VerificationError("\nWanted but not invoked: %s" % (invocation))
mockito.verification.VerificationError:
Wanted but not invoked: create_effect()

One noteworthy thing about how mockito-python verifies interactions between objects. If I have a verification like:

verify(effects_factory).create_effect(key = 'healing wind',
                                      target = character)

It does not match to a call like this:

effects_factory.create_effect('healing wind',
                              character)

If the verification is specified with keyword arguments, then the call must be made with keyword arguments:

effects_factory.create_effect(key = 'healing wind',
                              target = character)

This is a limitation in mockito-python and so far I have not found a workaround for it. It is something that needs to be remembered when working with keyword arguments.

Another advantage of reusing effects subsystem is that I already have an EffectsCollection class ready that is used to store and query Effects and EffectHandles. Instead of writing all that logic again, I can just reuse it in Spell class:

@logged
def get_effect_handles(self, trigger = None):
    """
    Get effect handles

    :param trigger: optional trigger type
    :type trigger: string

    :returns: effect handles
    :rtype: [EffectHandle]
    """
    return self.effects.get_effect_handles(trigger)

In order to make the test pass, I made following modifications to Spell class:

@logged
def cast(self, effects_factory):
    """
    Cast the spell

    :param effects_factory: factory for creating effects
    :type effects_factory: EffectsFactory
    """
    handles = self.effects.get_effect_handles('on spell hit')
    effects = []

    for target in self.target:
        for handle in handles:
            effects.append(effects_factory.create_effect(
                                            key = handle.effect,
                                            target = target))

At this point the test passes. The test verifies only that the EffectsFactory was called with parameters that it should be called with. It does not verify what is being done with the results of the call. That is left for the next step, when I want to write the code to actually trigger the created effects.

Code for this change (including the SpellBuilder) can be found in commit 62512fb694a93e81e792ec2cf41c1d10901f4c32.

Does it make sense to take this tiny steps? Couldn’t I have just written a test that checks that the effects being created are being triggered and hit two birds with a single stone? I could have done that and I think that would have been as valid approach as dividing it to two separate tests. I prefer to work with very small steps and small tests. While they help me to pinpoint the exact spot where the system is misbehaving, the drawback is the amount of code I have to write.

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

NumPy Beginner’s Guide – Second Edition

I got a review copy of NumPy Beginner’s Guide – Second Edition from Packt Publishing. The book is relatively thick, a bit over 300 pages and packed with content.

As usual with Packt books, it starts by introducing the tools and giving detailed instructions on installing them, before diving into actual subject. The book starts easy, teaching how to create arrays and manipulate vectors. Soon more concepts are introduced starting from slicing and ending to SciPy. There is even a chapter about testing, which I found especially interesting to read.

I liked how there are pop quizes to help the reader to check if he understood what he just read. They aren’t really hard, but still quite fun. Layout of the book is clear and makes the books easy to read. There are plenty of examples and graphs in the book that help to explain the concepts.

The book is very suited for a person who is not familiar with NumPy and wants to learn it. It covers lot of ground in sufficient detail. I felt that reading this book was good investment of time and enjoyed it.

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.

Learning something new

Learning new things can be useful and can often be helpful to see new aspects of old things. I have been working with Python code for 2 years or so now and wanted to try out something new: Clojure. I have known the language for a while already and even tried to dabble with it previously (with not that great success). Today I installed Leiningen and Light Table and decided to give it another try. I’m going to try and write a simple ray tracer with it. If I can get it to write png-files on hard drive with some shaded spheres and planes, I’m quite happy. I did something like that before with Python, so the problem domain is not new to me. Code is already available at GitHub of course, but it does not do much yet.

But the language and concept is totally new. I don’t know enough of basics to be productive with the language and even the simplest things take long time (first trying, then googling and then trying again). Light table helps lot though, since I see quickly what is happening and if all my tests are still passing.

I’m not going to abandon Herculeum. The project is in a spot that requires some mulling over design of the game and figuring out what kind of mechanics I would prefer the game to have.

Satin and Qt event loop

Qt comes with a really good testing library called QTest. It can be used to simulate keyboard and mouse input when testing the system. PyQt naturally includes the same library, but using it can be a bit tricky sometimes. Mouse input works quite fine, but keyboard input does not work well without event loop running in the background. It is possible to get around this, by instantiating QApplication and calling exec_ – method on it. At this point QApplication takes charge of things and execution leaves the test method.

There are several ways around this. One is to construct two threads, using one to send keyboard and mouse events to the system under test. One should note though, that the QApplication should be running in the main thread (it will helpfully notify you if this is not the case). Another thing is shared resources. Constructing QPixmap objects outside of the thread running QApplication is not advisable (you’ll be notified about this too).

Second option is to construct a QTimer, that will start execution of your test code. In this model you do not need to worry about multiple threads or shared resources.

Doing either one  can get tedious, especially if the amount of tests is more than two. Satin now has a class decorator satin_suite, that will take care of the basic steps, leaving the developer free to write more expressive tests. Essentially, the decorator will perform following steps:

  1. Replace setup-function with a version that creates instance of QApplication and calls the original setup-function.
  2. Replace teardown-function with a version that deallocates QApplication and calls the original teardown-function.
  3. Replace each test_* function with a version that will install a QTimer, start QApplication, execute test code and exit QApplication

Details are still rough and the system has some faults (like any exception or failure halting the execution of tests).

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