Marketing and fuzzy distribution

I have mentioned fuzzy logic and random distribution before but I think that it is also being applied in some marketing strategies.

A supermarket chain in our country is giving away collectibles in the form of images of football players (soccer for the Americans). For every, Oh… I don’t know, € 5 , you spend you will get 5 random pictures.

At lunch my mother, who collects them, was going over a list of friends seeing if they have a picture she doesn’t have or the other way around and she noted that certain images nobody seems to have.

If you think about it from a marketing perspective it makes a lot sense why she doesn’t have certain images. The marketing strategy is all about making you willing to pay a certain amount or attract customers because you want those pictures. Once you have them, the marketing strategy will no longer have affect on you. It is in interest of the marketing company to try and keep you as long as possible under the effect of the marketing strategy.

One way of doing it by doing an imbalanced distribution: Certain pictures will not be distributed in certain locations. That way the customer under the effect of marketing will keep buying. Of course this won’t hold in the long run, so what you do is slowly slide the distribution.

Sliding random distribution:

A distribution whose content is randomized will only distribute a small subset which moves over the entire distribution so that in the end the entire content was equally distributed, however if a moment in time was used only a small subset would have been available.

If you have trouble understanding think of it as traveling from the north pole to the south pole visiting every restaurant you can find. At every stop you will select one random soup on the menu. Each place has different flavors and as you go more and more south you will encounter different flavors. However because your are “sliding” you will often encounter the same soup.

Anyway if that wasn’t clear here is it in code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <iostream>
#include <algorithm>
#include <iomanip>

#define MAX_AMOUNT 100
#define SLIDER_SIZE 5
/* Uncomment the next line to see the values in random order */
#define USE_RANDOM_ORDER

class SlidingDistribution{
    int m_Values[MAX_AMOUNT];
    int m_SliderBegin;
    int m_SubPos;
public:
    SlidingDistribution() : m_SliderBegin(0), m_SubPos(0) {
        for(int i =0; i < MAX_AMOUNT; ++i)
        {
            m_Values[i] = i;
        }
#ifdef USE_RANDOM_ORDER
        std::random_shuffle(m_Values, m_Values + MAX_AMOUNT);
#endif
    }

    int GetRandomNumber(){
        m_SubPos += 1;
        if(m_SubPos % SLIDER_SIZE == 0)
        {
            m_SliderBegin = (m_SliderBegin + 1) % MAX_AMOUNT;
            m_SubPos = 0;
        }
        return m_Values[(m_SliderBegin + (m_SubPos % SLIDER_SIZE))%MAX_AMOUNT];
    }
};


int main(int argc, const char** argv)
{
    SlidingDistribution distribution;
    int amounts = 0;
    do{    
        int alignCounter = 0;
        while(amounts)
        {
            std::cout << std::setfill(' ') << std::setw(3) << distribution.GetRandomNumber();
            alignCounter++;
            if(alignCounter >= 14)
            {
                std::cout << "\n";
                alignCounter = 0;
            }else
            {
                std::cout << " ";
            }
           
            amounts--;
        }
        std::cout << "\n" << "How many values do you wish to see? (type 0 to quit)\nLoops: ";
        std::cin >> amounts;
    } while(amounts);
    return 0;
}

Brick3 has become Brick4

Brick3, my graduation project, will be no longer developed and instead I will be working on Brick4.

The reason I abandon Brick3 is because the system has become too hard to maintain and there are too many pieces of legacy code around for me to quickly improve it. On top of that Brick3 was the first incarnation of the Brick project series in 3D with some advanced features, the new way of memory management (a 37 MB instead of 2 GB). So I had expected I would need to rewrite it, even though I wanted to avoid it.

Brick4 will have unlike its predecessor cleaner code a new way to some things (XML instead of custom file formats) and it will make heavy use of the command and strategy patterns. This will allow me to developer faster and safer in the long run, although I fear that rewriting the application will have an heavy cost and that any advantage I gain will be lost to that.

The good is that this will allow me to revisit some off the old features and make some notes and see if I can improve it.

If I’m lucky everything should be rewritten at the end of this week and with even some more luck I will also have implemented a new feature. Guess time will tell.

Broke the installation already

When I yesterday said that I don’t give Linux the 99.999% expectation to work I was not kidding. Just this morning I decided to use synergy and because I don’t want to run the command everytime I decided to add to the startup scripts, after some looking around I finally found how to do it and it was easy to understand, so I decided to give it a go. Once all the configurations were done I decided to reboot.

And then I noticed that something must have gone wrong somewhere. I simply get the console login instead of the graphical interface which I was expecting. Controlling Ubuntu from my laptop was of course also no longer possible (it was before, I have tested it). :(

So what went wrong?

Well, first of all I have been messing around with files I thought to understand (as a matter of fact I do understand them) however had I not done that the system would still have worked. Although the rule here is “If you don’t use it, it won’t break” is being applied, it is something a rule that remains true. In this case I did touch it and it did break.

Anyway I did a few more things I didn’t like so now I’m installing another Linux distribution just to see if I prefer this one.

Within a month I will get a netbook (a small laptop, that is actually too small to use) and then I intend to put some of my work on my current laptop on that. With a bit of luck I might actually set the laptops up in such a way that synergy uses thee laptops (oh and I get one monitor which I can use to increase the amount of screens to four).

Posted in Linux. Tags: , , , . No Comments »

Installing Ubuntu on my old laptop

After cleaning up my room. I found one of my old laptops (which have been passed to my mother and back again) and wondered what I should do with it. It was my first laptop and although I don’t intend to use it, I don’t want to throw away a good laptop (well, there is a line of pixels who always have red on but that is besides the point).

Before I decided to install Ubuntu I wanted to take one last look at what my old laptop had stored on the computer. A wise thing since I came across a few old applications and some documents that all had some kind of emotional value. But more important I found my old music collection. :D

Copying my music collection from one computer to another wouldn’t be such a big problem except that the library was/is around 10 GB. To give you an idea my current library is 27 GB which means I can let the music being played for almost 12 days before I encounter the first song in the playlist again. Anyway, copying from one system could be done in a few ways. One would be using an USB stick (which means I would to do it many times before everything would have been copied). The second method would be using the windows file shares to copy things over the network. Besides the fact that both devices are on wireless, the way windows copies a lot of files is not really fast.

In the end I decided to try something new: Bittorrent. Ok, I admit I have used bittorrent before but never to copy files from one device to another. Simply create a decentralized torrent, copy that to the receiving computer and run it. Besides that it worked (I tried it once before) it was rather fast. Of course once I decided to give the seeder a wire it was a whole lot faster (2.5 Mb per second instead of 500 Mb per second)

Once I copied a few of the other files using dropbox I decided to install Ubuntu. First downloading the live cd and put it on an usb using UNetbootin. The live version worked nice, so all that is left is installing.

The reason I decided for Ubuntu is because Windows XP is rather old and I have missed around with it a bit too much (somethings have been broken) and since I don’t want to pay money for something I’m rarely going to use I decided to put ubuntu on it.

Although the live version run perfectly, once I tried the installed version I got a flickering screen and couldn’t do anything anymore. Thank god, I’m not a complete Linux noob so after half an hour I finally fixed usplash problem (reinstall the graphics driver did the trick), but it at least demonstrates one the reason why I prefer Windows over ubuntu. When I install Windows I expect it to work 99.999% of the time. Linux on the other hand doesn’t get that amount of trust from me.

Long story short. Ubuntu has been installed and I’m thinking of using it as my backup and for word processing. My good laptop is slowly becoming an software development only laptop and the occasional game laptop. However on both occasion I see it as work and there are times I simply one play around. And for that reason I use my old laptop.

Posted in Uncategorized. Tags: , , . No Comments »

Custom exceptions

Besides finishing my study I’m currently also working as a software developer. And yesterday I came across a problem which thought me how a lesson.

The project I was working is basically a custom import tool for a financial software. We get an CSV or an XML file and that is imported using the SDK of the financial software. Nothing hard except that the SDK is unfinished and various features are yet to be implemented. The majority does work, but it is like walking through a mine field and every time you move forward the application might blow up in your face :twisted:

The application is written in Visual Basic .NET (not my choice, but it does the job) and the SDK uses exceptions to notify that a certain feature is not working or when a certain object doesn’t meet certain requirements when you ask it to be saved.

Because of the huge amount of data, I used reflection so that I don’t have to type as much. My system also uses exceptions, and I won’t be surprised if you already where this is going, but while I was debugging I came across multiple exceptions of the SDK which meant that I either had to write a workaround for it or remove the feature until the SDK does support it. When I finally fixed the majority of the errors I suddenly got hit in the face by the following exception:

1
Unable to complete save

Now the SDK did provide cryptic error messages but this one was completely new and I was doing a bare bone test. I called a coworker over to see if he knew what it meant but he also didn’t know what the message meant. A few minutes later he came back to me and said that the part of the SDK did work on his side and that the error must be somewhere in my code.

To cut a long story short. The exception that I got was my own and I hadn’t noticed because I had already encountered so many exceptions of the SDK that I just presumed that it was again the SDK that was throwing a fit. :oops:

Once I realized that it didn’t take long to solve it (I returned a true instead of false somewhere), however I was more worried about how to prevent it in the future. After some thought that also was simple.

If any of the application code would throw a fit it would throw not the standard exception which would have been:

1
throw new Exception("Unable to complete save")

but a custom type and a search and replace later we got:

1
throw new UtilityException("Unable to complete save")

so that error message would contain a special prefix by which it would be clear that it was our own code that decided to throw an exception.

1
2
3
4
5
6
7
8
9
10
11
12
Public Class UtilityException
    Inherits System.Exception
    Public Sub New(ByVal str As String)
        MyBase.new(str)
    End Sub

    Public Overrides ReadOnly Property Message() As String
        Get
            Return "UtilityException: " & MyBase.Message
        End Get
    End Property
End Class

In the future we will know when it was our own mine to blew up. A simple solution but it would have saved us a lot of time if we had done this from the start.

Information about Brick3

Brick3 is the third iteration of the grand project I decided to call “Brick” and I think I have mentioned it quite a few times before, but never gone in to detail, which is the reason for this post.

I’m from the IT sector and one of the things I thought myself early is that the computer should work for me and not the other way around. In the Netherlands IT used to be called “Automation” but I’m not certain if many people still know that or try to write programs by that principle.

In the game industry we have something called procedural generation (also known as procedural content generation) which is letting the computer generate the content in game. This can be music which changes depending on the amount of danger the play can be in (adding rhythmic drumming) or textures which are generated by the computer instead of an artist. Those are all examples of generating content by the computer instead of by human.

Any process can be fully converted to logic and any logic can be programmed. A computer can be used to execute any process as long as I’m able to convert the process to logic and program that logic.
– Wouter Lindenhof

The above quote is mine. And what I’m saying is that in time a computer should be able to replace any human, although I don’t that to happen in my lifetime (and I’m young).

However the above quote is what brick3 is all about. The earlier examples were all based on the fact the design was done ahead of the actual content generation. After all the music was composed and the texture that was generated was most likely done based on an algorithm. An example for the last one but then for a mesh can be found in this blog post Donuts! (Procedural Torus in C++).

Brick3 is a bit different as it wants to let the computer do the design instead of you. It tries to generate a flat and based on requirements (you don’t want a toilet in your living room) it will place the location of rooms and places the objects (lamps, light switches, paintings, trashcans et cetera). If you would use that in game like for example Grand Theft Auto you would be able to enter every house and assuming everything works correct you would have a fully designed interior while as a programmer (or artists) you hardly have to do a thing.

Anyway since a picture sometimes says more take a look the following screenshots.

This screenshot shows the minimal graphical quality I want to have. Graphics are important as they play part in deciding whether or not to buy a game. Besides that it also says a lot about the level of finish and the dedication put in the product. Although walls appear to have depth, they are flat, but using some smart programming code an illusion is created and when you look at the next screenshot I think everyone will agree that high graphical quality is a requirement for this application.

This screenshot shows the current state of the application. You will see that everything has a dummy texture and you will notice that not all walls are attached (this is because that a door is not generated and once it is does it will show a nice door frame). Both rooms have the same function and the big room that is directly in front of the camera is a test room (it is 27 by 27 by 27 meters big).

Besides the obvious issues the application is reaching its completion. There are some minor issues with placement and I need to improve the performance at some points but after that I only need to add some new models (the furniture is not procedural generated) and I will give some extra requirements and the application should design a room according to my specification.
Although I have to admit it doesn’t look like much at this point, I think many people will be surprised once the end result is ready. Not only will it be able to generate fully random interiors of flats, buildings and rooms but it will do so as if it was designed by a human and only I have to do is hit one key to generate a complete new result.

Posted in Project. Tags: , , . No Comments »

[DONE] Taking my time updating the website

Updating the site will take some time as I need to convert small parts of multiple posts to get it look correct. If you are using an RSS feed to keep track of the website, I’m sorry for any inconvenience it might cause.

If you find something missing or if your own links to my site, please send me a mail (or comment on this item) and I will try to fix it as soon as I can.

The good news is that wordpress is faster and easier to use than what I had before. The downside however is that all links need to be updated and some downloads won’t be directly available until later.

UPDATE 2010-03-03 21:49: A quarter has now been done. It’s going slower than expected as I need to correct quite a few pages and some of the links have changed so much that I lose at least a good 15 minutes to try and fix all of those. The good news is that I like wordpress, the interface is easy, although I miss the mugshot that I had on my old site ;)

UPDATE 2010-03-06 12:47: Most of the important post have been transfered and I have decided to skip the rest. From this point on no new “old posts” will be added unless I notice that someone is going to an old link. If you do need a certain article you can use the contact form to send me a notice.

Posted in Website. Tags: . No Comments »

Wavefront Obj Mesh Loader

UPDATED 2010-03-02 11:07: There was a minor bug in the code which caused to tokens recognition to file. You won’t encounter it in an obj file, but I fixed it for the good order.

I can remember the first time I wrote my Obj Mesh loader. It took hours. Today I needed also an obj mesh loader and this time it took mere minutes (under 15 minutes at least), so I have decided to share it. Keep in mind you should most likely separate it in header and source files.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/**
 * The MIT License
 *
 * Copyright (c) 2010 Wouter Lindenhof (http://limegarden.net)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include <string>
#include <vector>
#include <sstream>
#include <fstream>

#define TOKEN_VERTEX_POS "v"
#define TOKEN_VERTEX_NOR "vn"
#define TOKEN_VERTEX_TEX "vt"
#define TOKEN_FACE "f"

struct Vector2f{
    float x, y;
};
struct Vector3f{
    float x, y, z;
};

struct ObjMeshVertex{
    Vector3f pos;
    Vector2f texcoord;
    Vector3f normal;
};

/* This is a triangle, that we can render */
struct ObjMeshFace{
    ObjMeshVertex vertices[3];
};

/* This contains a list of triangles */
struct ObjMesh{
    std::vector<ObjMeshFace> faces;
};

/* Internal structure */
struct _ObjMeshFaceIndex{
    int pos_index[3];
    int tex_index[3];
    int nor_index[3];
};

/* Call this function to load a model, only loads trianglized meshes */
ObjMesh LoadObjMesh(std::string filename){
    ObjMesh myMesh;

    std::vector<Vector3f>           positions;
    std::vector<Vector2f>           texcoords;
    std::vector<Vector3f>           normals;
    std::vector<_ObjMeshFaceIndex>  faces;
    /**
     * Load file, parse it
     * Lines beginning with:
     * '#'  are comments can be ignored
     * 'v'  are vertices positions (3 floats that can be positive or negative)
     * 'vt' are vertices texcoords (2 floats that can be positive or negative)
     * 'vn' are vertices normals   (3 floats that can be positive or negative)
     * 'f'  are faces, 3 values that contain 3 values which are separated by / and <space>
     */


    char char_buffer[256];
    std::ifstream filestream;
    filestream.open(filename.c_str());
    while(filestream.eof() == false &amp;amp;amp;&amp;amp;amp; filestream.bad() == false){
        memset(char_buffer, 0, 256);
        filestream.getline(char_buffer, 256);
        /* FIXED:
         * Where strlen stood was first 256, however this would cause a problem
         * when you only have a token
         */

        std::stringstream str_stream(std::string(char_buffer, strlen(char_buffer)));
        std::string type_str;
        str_stream >> type_str;
        if(type_str == TOKEN_VERTEX_POS){
            Vector3f pos;
            str_stream >> pos.x >> pos.y >> pos.z;
            positions.push_back(pos);
        }else if(type_str == TOKEN_VERTEX_TEX){
            Vector2f tex;
            str_stream >> tex.x >> tex.y;
            texcoords.push_back(tex);
        }else if(type_str == TOKEN_VERTEX_NOR){
            Vector3f nor;
            str_stream >> nor.x >> nor.y >> nor.z;
            normals.push_back(nor);
        }else if(type_str == TOKEN_FACE){
            _ObjMeshFaceIndex face_index;
            char interupt;
            for(int i = 0; i < 3; ++i){
                str_stream >>  face_index.pos_index[i] >> interupt
                           >> face_index.tex_index[i]  >> interupt
                           >> face_index.nor_index[i];
            }
            faces.push_back(face_index);
        }
    }
    filestream.close();

    for(size_t i = 0; i < faces.size(); ++i){
        ObjMeshFace face;
        for(size_t j = 0; j < 3; ++j){
            face.vertices[j].pos        = positions[faces[i].pos_index[j] - 1];
            face.vertices[j].texcoord   = texcoords[faces[i].tex_index[j] - 1];
            face.vertices[j].normal     = normals[faces[i].nor_index[j] - 1];
        }
        myMesh.faces.push_back(face);
    }

    return myMesh;
}

STL algorithms

UPDATE@2010-Feb-23 22:11: Thanks to Arseny Kapoulkine (his blog is : http://zeuxcg.blogspot.com/ ) I discovered that there was a bug in the code I showed. I have fixed this bug

I’m not a huge fan of the STL library (you know std::vectorand it’s relatives) as I don’t like the syntax and the naming of some functions and yes, I’m well aware those are mood points but then again I’m always looking for perfection. But there is one part of the STL library I really love which is STL algorithms.

For example, let’s say we have the following code


#include <vector>
/* ...
 * Somewhere in the code
 * ...
 */
std::vector<int> numbers;
numbers.push_back(1);
numbers.push_back(2);
numbers.push_back(3);

And we want to remove the number "2" from the vector, sadly std::vector is lacking a remove function. It does have an erase function but that would require an iterator. We could switch to std::list who does have a remove function. Without STL algorithms we would write something like this:


/* Written for readability
 * And it only removes the first one it finds.
 */
template <typename T>
void RemoveFromVector(const T val, std::vector<T> vec)
{
    for(std::vector<T>::iterator begin = vec.begin(); begin != vec.end(); ++begin)
    {
        if(*begin == val)
        {
            vec.erase(begin);
            return;
        }
    }
}
/* ... And here we call it */
RemoveFromVector<int>(2, numbers);

The only thing I can say about it is that it looks ugly. Now let’s use stl algorithms and see how that looks like.


/**
 * Previously the code was:
 * std::remove(numbers.begin(), numbers.end(), 2);
 * But that only removes the number, but keeps the same size. std::remove instead
 * returns an iterator which holds the end. (numbers.size() would give the same
 * result before and after the above code.
 * Thanks to  Arseny Kapoulkine this has been corrected and the good version is
 * now here available.
 */
numbers.erase( std::find(numbers.begin(), numbers.end(), 2) );

One line of code and that’s all. Well, it’s still one line of code, but two rather simple functions. The erase function takes an iterator as input (which std::find returns for you). However keep in mind that if std::find can’t find a result (for example "2" was already missing, your application will crash.
One thing I always hate was when I stored pointers in an object that needed destruction


#include <vector>
#define SAFE_DELETE(p) if(p) delete(p); (p)=0;
class StorageObject1;
class StorageObject2;
class StorageContainer
{
    std::vector<StorageObject1*> m_Objects1;
    std::vector<StorageObject2*> m_Objects2;
public:
    ~StorageContainer()
    {
        for(size_t i = 0; i < m_Objects1.size(); ++i)
        {
            SAFE_DELETE(m_Objects1[i]);
        }
        for(size_t i = 0; i < m_Objects2.size(); ++i)
        {
            SAFE_DELETE(m_Objects2[i]);
        }
    }
};

The above example is rather tame but if you have a lot of different objects it quickly becomes ugly to look at. However with a bit of ingenuity you can become a lazier programmer. Here is the same example but then easier to read


#include <algorithm>
#include <vector>
#define SAFE_DELETE(p) if(p) delete(p); (p)=0;
template <typename T> void SAFE_DELETE_FUNC(T* object) { SAFE_DELETE(object); }
class StorageObject1;
class StorageObject2;
class StorageContainer
{
    std::vector<StorageObject1*> m_Objects1;
    std::vector<StorageObject2*> m_Objects2;
public:
    ~StorageContainer()
    {
        std::for_each(m_Objects1.begin(), m_Objects1.end(), SAFE_DELETE_FUNC<StorageObject1>);
        std::for_each(m_Objects2.begin(), m_Objects2.end(), SAFE_DELETE_FUNC<StorageObject2>);
    }
}

Of course you can make the function even a bit smarter so that you don’t have to write the start and end iterators, but I prefer it like this.
Here you can find the other versions of STL algorithm: http://www.cplusplus.com/reference/algorithm/

Procedural story

A little while ago I was meeting a good friend of mine and we had a lot of things to talk about. For one he had just returned from Kenya and he had a lot to show and tell and the things he told me where amazing. But as the day went one, we almost always seem to come back to one subject: Games and developing of games. Funny enough the two of us have almost had the same kind of ideas.
Both of us are developing games in our free time and both have the idea of trying to make as much as possible procedural generated. One of the things we are both interested in is creating the story. While I look for an infinite solution (where the player can play forever and has an interesting storyline) he has a more pragmatic approach.
As we discussed procedural generated stories he pointed out that a story teller needs to tell his audience what happens where and when (not to be confused with why). This triggered a thinking path I had not yet explored. Until then I had simply assumed events happen in a certain order. When a user is playing a computer game he will grow a certain emotional attachment to the player. Emotions in a story are important. For example Romeo and Juliet is a story about hate between families, love between two person and has a lot of betray. Romeo and Juliet is considered one of the classic romantic stories and by some it is considered one of the most romantic stories ever written.
So after the talk and some thinking a procedural story generator could be written as a system that tries to move from emotion to another emotion both for individuals as a culture. To give yet another example: The player gets betrayed by a general and while he was betrayed the general does end the war (and the country he fought for sees him as a hero), while at the other side (the defeating side) wants to see the general death. You now have four elements: The player, the general, the winning country and the losing country. The player is angry as he is betrayed. The general is content and pleased as he is being seen as hero. The winning country feels superior to the losing country and the losing country feels disgust towards all other elements. See the diagram.

At this point the computer needs to “write” the next part of the story. The computer could now plot a new scheme by just adding or removing some story elements. The player could for example become the leader of the rebellion or he could join the general as one of his right-hand leaving his feelings of betray or he could kill the general and become the new general. In this case I want to add another character say the princess of the winning country and make the player the leader of the rebellion. The princess finds out that the generals betray and for some reasons she encounters the player and they fall in love with each other. Yet they can’t be with each other as one country hates the other ruler. The general at this point hates the player. The graph might be clearer.

Moving forward we arrive at a point in the story where the player and the princess are married and they rule both countries. The general is now hated by all. And here is another graph.

For the story generator the only thing is how the possible futures of all elements could be. Once he knows the possible futures all it has to do is create “story chapters” which move the story toward the possible features. If needed a chapter could have a branch which excludes one of the possible features, for example the player kills the general before the princess was able to find out about the betray of the player so she never finds out the wrong he did and therefore never encounters the player.
Of course a lot more thought needs to go in this, but it solved for the procedural “writers-block”.