Latest Blogs

Priority Queue Using a Heap

Recently, I picked up Algorithms in C++, by Robert Sedgewick, again. I bought the book a few months ago, and started reading it then, but I never got anywhere. The first time around, I did nothing but look at the text and try to understand it. My current stab at it involves reading the book, marking it (that little "strategy" English teachers try to persuade students to use, but fail miserably), and now, because I understand the algorithms that much better, actually implementing them.

I tried to implement some algorithms far into the book, such as Huffman data compression, but after attempting that, I realized the need for lower-level data structures; those data structures introduced at the very beginning of the book. I restarted my perusal from the first few chapters, and I've now successfully implemented a Priority Queue using a Heap data structure. Code after the jump (I've always wanted to say that, but I've also always wanted to punch people in the face for saying that. I'm gonna have a hard time explaining this black eye to my friends.)

class HeapPriorityQueue
{
private:
/// Our heap/array.
int *m_pHeap;
/// Length of our array/heap.
unsigned int m_iMax;
/// The largest used index in the heap at the moment
unsigned int m_iN;

/**
* Uses the passed index to sort the item up the tree.
* @param k: index to the internal array
*/
void upheap(unsigned int k)
{
if(k > m_iN) return;

unsigned int j = k;
int val = m_pHeap[j];

while((k /= 2) > 0 && val > m_pHeap[k])
{
m_pHeap[j] = m_pHeap[k];
m_pHeap[k] = val;
j = k;
}
};

/**
* Uses the passed index to sort the item down the tree.
* @param k: index to the internal array
*/
void downheap(unsigned int k)
{
if(k > m_iN) return;

unsigned int j;
int val = m_pHeap[k];

unsigned int limit = m_iN / 2;

while(k < = limit)
{
j = k + k;

// Move to the right child if it is larger than the left child
if(j < m_iN && m_pHeap[j] < m_pHeap[j+1]) j++;

// If `val` is larger than both children of `k`, we're done.
if(val >= m_pHeap[j]) break;

m_pHeap[k] = m_pHeap[j];
k = j;
}

m_pHeap[k] = val;
};

public:
/**
* @param max: The amount of items to be stored in the queue.
*/
HeapPriorityQueue(unsigned int max) : m_iMax(max), m_iN(0)
{
m_pHeap = new int[m_iMax];
};

~HeapPriorityQueue()
{
delete [] m_pHeap;
};

/**
* Insert an item into the queue.
* @param val: Item to add.
*/
void insert(int val)
{
if(m_iN >= m_iMax-1) return;

m_pHeap[++m_iN] = val;
upheap(m_iN);
}

/**
* Removes the largest item from the queue and returns it.
* @return: Largest item from the queue.
*/
int remove()
{
if(m_iN < = 1) return -1;

int val = m_pHeap[1];
m_pHeap[1] = m_pHeap[m_iN--];
downheap(1);

return val;
}
};


Call of Duty 4 Update

Just recently Infinity Ward released an update to Call of Duty 4: version 1.20. I was ecstatic to find it, and couldn't wait to get on. When the downloading and installing finally finished, I trembled like a rabbit facing a 12-gauge as the game loaded. Upon entering multiplayer, I found that the game mode Oldcore is gone. AAAAHHHHH!

Oldcore is Hardcore (No HUD, less health, slower regeneration) Old School (No classes, higher jumping, pickups), and it was the absolute best game mode there. And they removed it! They killed Oldcore! YOU BASTARDS!

However, they did add a few things that I like. For example, you can now mute people in-game. So no more mic-spamming! I honestly don't understand why developers don't include this from the get-go. Anyways, they also optimized server selection, upped the bandwidth standard for 18-player games (No more lag :D), added chase (third-person) cam for spectators, and added better kill cams (For grenades, RPGs, M203 nades, etc).

ConVar Manager Update and more!

Last night and today I worked on finishing the ConVar manager, which I did actually complete! All convars created inside of a plug-in are added to the ConVar manager's internal database (A Trie) and the plug-in's convar list. Tomorrow I'll work on adding a "cvars" option to the Viper menu, which will be accessed with "sm py cvars". I've created a test plug-in to create many ConVars, which successfully created every single one, and was able to retrieve the value from each; each convar was declared as a different type of data (Float, int, string, etc.), and retrieved by each type, so as to test my error checking, also.

There is one problem, though: If you create a convar from the console by using the Python interpreter command I've created, "py", it does not work. The Python convar object is created, so you can call functions on it and the such, but the Source ConVar class instantiated through "new ConVar(name, defaultVal, ...)" equates to NULL when accessed. The chain of command is this:


  1. On the Python side, the user creates a convar object
    convar = console.CreateConVar("a_name", "a_value")


  2. CreateConVar does some simple error checking (Making sure the name isn't blank, etc) and calls New_ConVarObject, then Init_ConVarObject. I'm going to showoff here and present the code of this:
    static PyObject * Console_CreateConVar(PyObject* self, PyObject* args, PyObject *keywds)
    {
    char const *pName, *pDefaultValue, *pHelpString = NULL;
    int flags = FCVAR_PLUGIN;
    float fMin = NULL, fMax = NULL;

    static char* kwds[] = {"name", "value", "desc", "flags", "max", "min", NULL};

    if(!PyArg_ParseTupleAndKeywords(args, keywds, "ss|siff", kwds, &pName;, &pDefaultValue;, &pHelpString;, &flags;, &fMin;, &fMax;))
    return NULL;

    if(pName[0] == '0')
    Py_RETURN_NONE;

    Py_XINCREF((PyObject*) &console;_ConVarType);
    PyObject* ConVarObj = (PyObject*) console_ConVarType->tp_new((_typeobject*)console_ConVarType, args, (PyObject*)NULL);
    ConVarObj->ob_type->tp_init(ConVarObj, args, (PyObject*)NULL);
    return ConVarObj;
    }


  3. New_ConVarObject just sets the values of the object. Nothing to see here.

  4. Init_ConVarObject does all the real work for the Python side: error rechecks (Just in case :D), creates the ConVar (Through the ConVar manager), and does some work after the ConVar object is created.

  5. The ConVar manager does all the real work on the C++ side:
    static int console_ConVar_Get(console_ConVarObject *self, PyObject *args, PyObject *keywds)
    {
    char const *pName, *pDefaultValue, *pHelpString = NULL;
    int iFlags = 0;
    float fMin = NULL, fMax = NULL;

    static char* kwds[] = {"name", "value", "desc", "flags", "max", "min", NULL};

    if(!PyArg_ParseTupleAndKeywords(args, keywds, "ss|siff", kwds, &pName;, &pDefaultValue;, &pHelpString;, &iFlags;, &fMin;, &fMax;))
    return -1;

    // Make sure the ConVar has a name. teame06 would be dumb enough to make a ConVar with no name, which is why I add this check in!
    if(pName[0] == '0')
    {
    PyErr_SetString(PyExc_ValueError, "cannot have a blank ConVar name.");
    return -1;
    }

    CPlugin* pPlugin = g_VPlugins.GetPluginByPath(GetCurrentPath());

    if(pPlugin == NULL)
    {
    PyErr_SetString(PyExc_StandardError, "error in accessing the plugin.");
    return -1;
    }

    self->info = g_VVars.CreateConVar(pPlugin, pName, pDefaultValue, pHelpString,
    iFlags, (fMin != NULL), fMin, (fMax != NULL), fMax);

    if(!self->info || !self->info->pCvar)
    {
    PyErr_SetString(PyExc_StandardError, "error in creating ConVar.");
    return -1;
    }

    self->info->handle = self;
    self->convar = self->info->pCvar;

    printf("Convar '%s': '%s'n", self->convar->GetName(), self->convar->GetString());

    return 0;
    }



Anyways, I'm getting way too technical now. Nobody understands me. I'll go cry in a corner.

The "and more!" is that I added ClientCommand and FakeClientCommand to the Client object. I'll work on the Client object tomorrow, too; it needs Kick and Ban. Now, off to workout and bed for me!

ConCmd/Var Manager Deadline

Today, I set a deadline for the console command and variable managers. I was to finish the pair in around 3 hours, beginning at 3pm EST. It worked very well for around an hour, until I had an urge to play Team Fortress 2, for which I paused development, played for an hour, and pushed the deadline ahead another hour. The time I spent developing Viper was extremely productive, compared to my regular barely-work-lots-of-play schedule, which wreaks havoc on my development and school work :P

The results of it were, well, okay, at best. However, the so-so results were caused by fixing compiler errors, not from lack of work. I had much trouble with the py_console files. For example, recent compiling brought forth new errors to py_console.cpp; first off, there was this:
'console_ConVarType' : redefinition; different types of indirection

Then, this sprung up:
C:codinghl2sdkpublictier1/utlmemory.h(102) : error C2129: static function 'int console_ConVar_Get(PyObject *,PyObject *,PyObject *)' declared but not defined

It made absolutely no sense, for many reasons:


  1. utlmemory.h is not directly included from the file I suspected was causing the error (py_console.cpp)

  2. utlmemory.h is part of the HL2SDK, and should have nothing to do with my Python files

  3. Sawce loves Rukia!

I'll be working on it tonight, and hopefully it'll be committed working by the time I hit the showers.

Ubuntu and more!

Recently, I had to compile and package my SourceMod extension, Viper, on Linux. I've had Ubuntu on my other hard drive since the first day I used it, so I just booted into it. I never really appreciated Ubuntu, mostly because my stays in it were short. I wanted my games, and my games were on Windows, kicking it on Steam, running natively with great FPS (if you didn't catch that, I'm saying I get bad FPS under wine). Plus, it takes six hours to boot Vista, so if I switched over to Ubuntu for a day, it meant I'd have to wait for Vista to load up later.

For about 6-8 hours, I worked on Viper. I was having the same trouble as I was on Windows with it: getting my Python library to load. After 7 hours and 58 minutes of searching Google for some answers or documentation, I tried a few things to get it working. Failed miserably. At least it compiles :)

When the extension wouldn't load, I just slacked off. I downloaded Shrek and watched it. After that, I was aching for some music. Google and the Ubuntu forums being my advisor, I picked up Amarok. It's a great player, but something was terribly wrong with it: it was slow as hell. Opening up a context menu took 5-10 seconds. I looked around Amarok's menus and settings, and I found the Script Manager. A music player with a scripting interface? That's awesome!

That reminded me XChat (an IRC client; my favorite on Linux, but the Windows version is horrible) had plugins, too. Google found me the documentation for xchat-python (http://labix.org/xchat-python), and I set forth to make a Steam ID to Community ID converter. Good fellow CShadowRun had created a similar script for mIRC, but it was lacking something I really wanted: the ability to find user names, too. With his script, you could only exchange "STEAM_0:1:337" or "http://steamcommunity.com/profiles/762827591735028491" with each other. It was great for what it did, but a lot of the time, one only knows a person's user ID.

Luckily, one can find a person's user ID through this URL: http://steamcommunity.com/id/USER/. Bada-bing, bada-boom, I had a working script. With some more tweaks, it was almost perfect, save that if I use the command ("!steam user"), it replies with the answer before it sends my original message, so I get an output like this:
<theY4Kman> theY4Kman -> STEAM_0:1:10553940
<theY4Kman> !steam theY4Kman

Next, I wanted to see what scripts there were for Amarok. With their snazzy script manager, I found a neat script called "Playlog" that uploaded song information and play times to a MySQL database. Wow! Unfortunately, it was written in Perl, which I have no experience in, but my general programming experience allowed me to edit it quite easily (without errors, too. It was quite the phenomenon.) I setup the MySQL database and got the script running. All that I needed was a web page to display it all.

I love Python (AND YOU WILL USE IT), so I picked up mod_python (which I hear is inferior to mod_wsgi) for the Apache2 webserver. A few tests and bizarre errors later, I had it all working. With my handy KDevelop, I started working on the page to display it all. An hour or so later, the page displayed the time a song was played, its title, artist (if one was set), album (if one was set), and cover art. The cover art was a bitch to write, but it worked well enough to display everything correctly. Plus, I stole the default cover art from Amarok :P

Admiring my work, I noticed that I'd been on Ubuntu for days now, and I hadn't played one single game. I never thought that was possible. There was so much to do on Linux that I hadn't even cared to play a game.

« Previous 2 3 4 5 6 Next »