lørdag den 16. juni 2012

Playing with Prometheus

Filling out the blanks are usually the best thing about recent scifi movies. Prometheus is no different if you want to play that game.

So let's make up the story....

The Engineers are an advanced humanoid race that travels across galaxies like you have breakfast. They are physically and mentally superior to human beings. They have been at war with themselves for tens of thousands of years. As they developed more and more advanced conventional weapons they discovered that they could manipulate their own creation process, by genetic engineering, to create super nasty clones of themselves. With an infinite amount of nasty creatures possible. Some count acid for blood, armor skin, super reflexes and ability to produce huge amounts of saliva... all at 100% berserker mode and with the ability to reproduce faster than chlamydia at a highschool pool party.

Basically the Aliens are a bomb that Engineers can unleash at each other either at genetic level, facehugger level or adult Alien level. If the enemy shows the least weakness in their defenses an Alien can always be introduced to them and trigger a cataclysm.

Since the Engineers create the Aliens from their own dna then having large caches of both ready-to-go dna and construction material is very useful if you planning a long war. The Engineers seeded thousands of planets with a, direct-to-video, physically and mentally diminished version of themselves, optimized for being very fast catalysts of Alien incubation. Let's call those creatures "Humans".

The Humans can then eventually rise and multiply as the dominant lifeform on whatever planet they are introduced to. Smart enough to win over anything else, but still supermarket meat stock. Once they have increased sufficiently in numbers they can either be infected at the genetic level for "birthing" Aliens or have facebuggers introduced to them directly. In either case the caterpillars will be turned into their respective butterflies. Once the Engineers have a planet with 100 million Aliens it's a simple matter of luring them on automated ships, hundred thousands at the time, freezing them on the journey to distant star systems where they wake up and destroy anything with the Engineer dna, including Humans, for the rest of their precious lives.

So from the Engineers perspective the Humans is a completely inferior lifeform - except for the fact that when they are infected they offspring into the unstoppable killing machines that the Engineers themselves plan to destroy their follow enemy Engineers with.

There... the backstory for Prometheus. Sounds like you can make some good action sequences out of it.

fredag den 28. januar 2011

simple event system

Hey all

I'm sick and what a time for updating some code. I've updatd my generic event handler to be completely self-contained. This means that we can deliver a specific payload from a specific function to any amount of listeners - without doing external type registration. I also found this nice tool for escaping text for use in html environments here.

I found this super simple Type2Int function that runtime maps types to ints. With that tool it's pretty simply (compile errors aside) to rewrite my old enum-based manager.

The code still has the limitation of not supporting member function listeners, but supporting that should be as simple as either converting to your favorite function wrapper or overloading these methods with member pointer syntax.

The example at the bottom should get my point across.


#include <iostream>
#include <vector>
#include <assert.h>
#include <map>


// ---------------------------------------------------------------------------
// Framework

inline size_t NextUnique()
{
static size_t id = 0;
size_t result = id;
++id;
return result;
}

/** Returns a small value which identifies the type.
Multiple calls with the same type return the same value. */
template <typename T>
size_t Type2Int()
{
const static size_t id = NextUnique();
return id;
}

// Manager class never needs to be updated.
class ZManager
{
public:
template<typename T>
void RegisterListener( void(*fpListener)(const T*) )
{
const size_t nType = Type2Int<T>();
// convert callback to void* for storage.
void(*fpStorage)(void*)  = (void(*)(void*))fpListener;
m_Listeners[nType].push_back( fpStorage );
}

template<typename T>
void RecieveEvent( const T* Args ) const
{
const size_t nType = Type2Int<T>();
TypeCallbackMap::const_iterator itCallbackList = m_Listeners.find( nType );
if( itCallbackList == m_Listeners.end() )
{
// unregistered argument type
return;
}
const CallbackList& aListeners = itCallbackList->second;
for( size_t i = 0; i < aListeners.size(); ++i )
{
// convert callback argument type from void* to T*;
void(*fpListener)(const T*) = (void(*)(const T*)) aListeners[i];
fpListener( Args );
}
}

private:
// array of listeners
//typedef void (*CBType)(void*); // void* arguments to casted at registration.
typedef std::vector<void(*)(void*)> CallbackList;
typedef std::map<size_t, CallbackList> TypeCallbackMap;
TypeCallbackMap m_Listeners;
};


// ---------------------------------------------------------------------------
// Example

struct  ZFruitEventArgs
{
// real args go here
float m_fTastines;
int m_nHowManyMore;
};

void TastyPrinter( const ZFruitEventArgs* Args )
{
std::cout << "mmm, tasty: " << Args->m_fTastines << std::endl;
}

void ManyPrinter( const ZFruitEventArgs* Args )
{
std::cout << "more: " << Args->m_nHowManyMore << std::endl;
}

struct A{};

int main()
{
ZManager TheMan;
TheMan.RegisterListener<ZFruitEventArgs>( TastyPrinter );
TheMan.RegisterListener<ZFruitEventArgs>( ManyPrinter );
//TheMan.RegisterListener<A>( ManyPrinter ); // Does not compile due to mismatching signatures :)

ZFruitEventArgs Fruity;
Fruity.m_fTastines = 1.2f;
Fruity.m_nHowManyMore = 6;

TheMan.RecieveEvent( &Fruity );

A a;
TheMan.RecieveEvent( &a ); // Does not do anything since A is not registered to a reciever.
}

søndag den 12. december 2010

Smaller arrays

With arrays sizes 1 to 10000:



and with the ratios truncated

How to do housecleaning

[i'll upload the code later]

Housecleaning I say! Time to get rid of those array elements that have been laying around since last winter (1 ms ago).

Deleting elements from an array requires a bit of delicacy if we want to do it in reasonable speed. I found two (new to me) methods of cleaning the arrays. The PopBack and the Defrag methods.

PopBack overwrites the element-to-be-deleted with the last element and then decrement the number of elements (or move 'end' pointer). PopBack destroys the order in the array, but can otherwise be used at any point in time. PopBack here accesses elements in random order.

With Defrag the goal is to partition the array into 'live' and 'die' elements. The 'live' elements are put in the beginning of the array. The element count is then decremented (or 'end' moved). This is done by accumulating a list of elements to die (aka death-row). We then re-assign the original array to itself while skipping elements in the death-row. The elements in death-row needs to be in linear order, so the method is only practically valuable if death-row does not need sorting.

I've made an experiment with the two methods, with Defrag working with a sorted death-row. Test parameters are array size and percentage of the array to be deleted. The deleted elements are picked at random. Results for my 3.73 GHz Xeon cpu:



In the bottom left dark blue region PopBack is faster than Defrag. For smallest arrays (~1000 elements) it's only after deleting more than 40% of the elements that Defrag becomes faster than PopBack.

Whenever we want to delete a high percentage, or have a large array, then Defrag becomes faster. This is very likely due to Defrag accesses two blocks of memory in linear order, while PopBack needs random access.

I'll redo the experiment of smaller array, in higher detail, soon :)

tirsdag den 7. december 2010

refactoring refactoring refactoring

and ending up with your descriptor class doesn't need to include anything. And everything* is sane and readable. Oh joy!

*) i wrote.

lørdag den 27. november 2010

touchy feely

When plowing through other peoples source i often find myself yelling and screaming that things are a complete chaos and mostly meaningless. While this is obviously partially true, it's definitely not true for the person that wrote the code originally as he/she have it all mapped out in their heads.

[goes to refill his drink]

One particular case where my minds says "change this" is mappings embedded in control logic. Case:

/* function was defined 100 lines above */
if( Type == Banana )
{
/* do Banana stuff */
}
else if( Type == Orange )
{
/* do Orange stuff */
}
else if( Type == Potato )
{
/* do Potato stuff */
}
else
{
/* issue "unsupported type" error and bail */
}


While the purpose might be perfectly understandable with real-world code, the reader has the problem that execution isn't directly stopped when the right type is found. This leads to two things: Execution of (minor) irrelevant code, and possible ambiguity in which if/else statements have been executed. (the branches might not be mutually exclusive).

Anyways, my strategy is to resolution in a separate function and keep execution in the control logic completely linear:

/* function was defined 100 lines above */
bool bOk = HandleVegetable( Type );
if( !bOk )
{
/* return error code */
}

with

bool HandleVegetable( VegetableType Type )
{
if( Type == Banana )
{
/* do Banana stuff */
return true;
}
if( Type == Orange )
{
/* do Orange stuff */
return true;
}
if( Type == Potato )
{
/* do Potato stuff */
return true;
}
return false;
}

in this way we're guaranteed type vs. execution uniqueness and as a consequence, a lot less headache in finding out which execution paths have been touched.

or i'm a newb.

torsdag den 25. november 2010

Internal protection

Yos all

I got a idea yesterday on how to guarantee that no member functions writes (or reads) to a given member variable.

Some c++ class end up being silly long (4000+ line) and no-one really have any idea of what's going on. Especially if the given class also derives from another class, is inherited by a third and used an aggregate in a fourth class. A big mess basically.

In such scenarios, you could easily be given the task of extending the class with a new type of subsystem X. I guess that any excuse could also be used.

Idea:

class BigClass
{
public:
// lotsa stuff
private:
bool m_StateOfX;
};

if we want to guarantee that the member function OnlyForX() is the only function that writes to m_StateOfX, when we can do the following (and accept some overhead):


class BigClass
{ /* bla */
private:
struct StrictX
{
public:
bool Get();
private:
bool m_StateOfX;
friend void BigClass::OnlyForX();
} m_StateOfX;
void OnlyForX();
}

if we further want to punish ourselves with templates we can also do that:

template
class Strict
{
public:
const T& Get() const { return m_Val; }
protected:
T m_Val;
};

class BigClass
{
class StrictX : public Strict { friend BigClass::OnlyForX(); };
void OnlyForX();
};

there you go! it might even compile..