Target Strings

I haven't posted substantially in a while. I got a bit busy with school and house stuff and messing around with the Ruby bugs I ran into before. Oh yeah, and I did some random bugfixes and cleanup. I don't have a lot to report, but I did make some updates to target string processing.

Target strings are a way of identifying a thing in the MUD world. You need to do this all the time. To look at someone, pick up an object, put an object in some container, attack someone all use target strings to identify the thing in question. I've somewhat copied the style of target strings that I'm familiar with from ROM.

A [key]word about keywords

I've talked about keywords before, but it's been a while, and this post involves them a lot, so I'll say a bit more.

Each thing in the game world has a set of keywords that are used to identify it. The player never sees these words, but the implicit contract is that at least some of the keywords can be gleaned from the short description or long description.

KeywordsShort DescriptionLong Description
sandwich ham cheesea ham and cheese sandwichA ham and cheese sandwich sits here, tempting you.
businessman man suita well dressed, important looking fellowA man wearing an expensive suit and wielding a briefcase stands here looking important.
amethysta beautiful purple crystalGlinting in the light, a light-purple gem is lying here.

Notice that there is no requirement that the keywords are easily guessed given the short and long description. Sometimes level builders like to play these kinds of games, though as often as not it can be seen as bad form. As an aside, keywords are unordered; in fact, internally they are stored as a Set.

So why all this nonsense about keywords? Well, for fun, but also for notation. In the following section I will represent a set of keywords as {keyword1, keyword2, ...}.

Target Strings

As I mentioned before, target strings are a way of identifying something when you enter a command. Target strings operate on keywords only, never long or short description. When I say "matches" below, I mean "prefix matches." So "man" matches {man} but also {manticore}.


a thing in this room where one of its keywords matches "man"
the second thing in this room with a keyword matching "man". If there is only one such thing in this room, then this is not found.
'man guy'
the first thing in this room that has a keyword that matches "man" and a keyword that matches "guy". E.g. matches {cool, guy, man} but not {cool, man}.
'man guy
same thing. NB: no closing quote
a special identifier that indicates the group of all things in this room. This will actually have a different set of things matched for each command that operates on it. For instance, "get all" means to pick up all dealies, but "kill all" means start attacking all mobs.
same as "all"
all the things in this room that have a keyword matching "knife"
all.'sharp knife'
matches all the things in the room with a keyword matching "sharp" and a keyword matching "knife". E.g. matches {sharp, blade, knife} but not {dull, knife}.
a special identifier that always refers to my own mob
the first thing of any kind in this room
same as 1.

Once you have the target string and the set of keywords, doing the prefix matching against the set of keywords uses the obvious approach.


Each command takes zero or more arguments. For example, "look" can take zero arguments, which means to look around in the current room, or it can take one argument, a target string indicating the thing to look at. "Get" takes one or two arguments: the item to get, and optionally the container to get it out of (both target strings). "Tell" takes two arguments: the person to tell something to, and the string to send to them.

The process of turning an input string into an array of arguments to pass to the command is called (by me and the code) "argification," because the function that does it is called argify. The caller passes in the string to parse and the maximum number of arguments it wants. argify gives back an array of at most that many elements.

So how would you go about parsing input into arguments? Here are some of the rules:

  1. Arguments are space-delimited ("one two" => ["one", "two"])
  2. Quoted strings become a single argument ("'one two'" => ["one two"])
  3. Quoted strings in the middle of an argument are assimilated into that argument ("1.'one two'" => ["1.'one two'"])
  4. If the string is too long for the max requested items, everything at the end is bundled into the last argument ("a b c d" with max 3 args => ["a", "b", "c d"])
  5. A non-terminated quote means to take all of the rest of the string as part of that argument ("'hello goodbye hello" => ["hello goodbye hello"])
  6. Anything else is probably undefined.

Do you scan through the string, keeping track of whether you've seen a quote and are waiting for an end quote? That solution is tricky for inputs like "a'b'c'" (I mean, what should that even do? Probably just give back the entire string in the first argument). So then you need to track quotes only at certain points. Which points? Word boundaries? When preceded by whitespace? What if the string starts with a quote? I'm asking all these questions because these are all the bugs I found in my original implementation of argify, which tried to use a StringScanner and a single pass through the input.

I eventually abandoned that plan in favor of splitting the string by whitespace and combining arguments together that are part of the same quoted string or are at the tail end of the string.

Even this has a few caveats, though. Consider this naive way of splitting (warning: assumes familiarity with regular expressions):

tsp = text.split(/\s+/)
# join arguments back together that belong together

This doesn't work when an argument needs its whitespace preserved, like this command: "tell man hello       mister". By the end, you will get ["man", "hello mister"] instead of ["man", "hello       mister"]. The trick is to use some special regex magic:

tsp = text.split(/(?=\s)/)

This is called a "zero-width lookahead." It matches the thing in bold without actually consuming it, so the items in the array after the split may have leading or trailing whitespace, which I can then trim off.

Who cares?

This may seem uninteresting to you, but there's one aspect of it I find interesting. When writing progams that accept input of any kind, if possible it is usually desirable to accept that input in a very strict way. In fact, that was a key design goal of XML. Unlike HTML, if your XML document is malformed, a conformant XML parser will reject it outright. HTML parsers, on the other hand, sometimes go to great lengths to guess what you meant when you fed it something that makes no logical sense (e.g. <b><i>overlapping end tags</b></i>).

With target strings, a key design goal is that they are relatively lax. They serve a dual purpose: firstly, to unambiguously identify a thing; and secondly, to give a shorthand for identifying a thing. I was faced with decisions around questionable inputs. For example, I decided to allow an unterminated quoted string to grab all input until the end of the line. I had to make sure that an opening quote running till a proper closing quote is captured properly into a single argument, but pathological cases like "a'b'c d'" are captured as two arguments. Actually, that last one probably falls into the undefined category.

At this point, I think I've implemented most or all of anything I ever used when I was actively MUDding. I wonder if I will get requirements for something more elaborate eventually.



as i grow older, i am going to have to come to terms with not being exempt from the effects of aging. throughout my childhood i've taken a lot of things for granted, and I am just starting to realize that over time, more and more such things will apply to me. for example, i've come to the shocking realization that i have allergies. i've never had them before. after a full 24 years I went to the dentist and told I had a cavity. My first cavity! again, shocking.

What's next? freak heart attack?

as an aside, i realize this does not put me in a terribly sympathetic position...


cuttin on my foot

like an idiot, i managed to cut my foot last night. the circumstances are utterly laughable.

We had pizza for dinner, so i used the big, kind of heavy pizza cutter. later, when i was cleaning up dinner, I decided the best way to pick up the pizza cutter to put it in the dishwasher was not by the actual clean handle, but instead by trying to pinch the greasy, slippery round blade.

at this point you can probably see where this is going. as my hand passes over my foot, the weight of it inevitably causes the thing to fall straight onto my toe, which promptly started bleeding.



awesome drummer

I'm on the bus right now. We were just on the highway, and I saw a lady pass us on the left. Instead of actually holding the wheel with her hands, she was drumming on it with two actual drumsticks, one in each hand. Definitely haven't seen that before.

Half Life Squared

I just beat Half Life 2 (“squared”, if the 2 stylized as a superscript means anything). Since it’s fresh in my mind, and because it was quite striking, I felt like saying a little bit about it. I wouldn’t call this a review... but maybe you would. I dunno.

Aside from just being a really good game all around, it had a number of things I felt made it stand out.

The graphics. Actually, the graphics weren't above and beyond what you see in other games. Well, maybe they were for their time, but nowadays with games like Halo 3 and Gears of War, this fell somewhere in the middle of the pack. I'm willing to cut it some slack, since it was originally made for PC several years ago. Anyway, I hardly care about graphics if the game is good in other areas.

The voice acting was good. This is surprising, because most voice acting in games, frankly, sucks. And it's not just that the voice acting was good. The dialogue was good. The lines weren't cheesy. They weren't dripping with machismo or gratuitously cursing. Heck, at one point you hear some squad captain berating his soldiers for ineptitude; he uses the words "upbraiding" and "provocateur" in his little speech.

The gameplay was solid for a first person shooter. I think this is a well-established genre on consoles now, so it takes something special to get it wrong. Still, you sometimes get FPSes that just aren't polished well and which have sloppy controls. Thank god this wasn't one of them; I wouldn't have bothered to beat it.

You get a decent variety of guns through the game, though the balance was a little off. I basically stopped using my pistol once ammo for my machine guns and shotgun were readily available. The crossbow was mad cool, but ammo was so rare that I felt the need to hoard it instead of use it.

Oh wait, I was supposed to be talking about things that stood out.

Platforming. This is an FPS with platforming. In case this isn't familiar to you, platformers are games where you need some amount of precision and timing when jumping from place to place, usually involving some amount of moving platforms. With responsive controls, this works reasonably well from a side-scrolling point of view. From a first person POV, though, it's tricky to get right. If platforms are too small, your character runs too fast, or your character doesn't land onto other platforms when you feel they "should have," the player gets frustrated easily. The player being me, of course. HL2 did a solid job all around of making these parts hard but rewarding. For comparison, another FPS with good platforming is the Metroid Prime series.

The fact that it has platforming leads to another interesting characteristic. The route that you are supposed to take through a level is not always obvious. Sometimes it is frustratingly difficult to find. Sometimes you go right by it (several times) without noticing it. Sometimes it's in some far corner. Other times it is hopping across narrow cliffs. Sometimes it's going down some hole in the floor. I'm making it sound like I don't like it, but I actually felt pretty cool finding the way. In some strange way, it felt more like it "would be" if I were actually there. In real life, nobody lays out an obvious trail for you to follow... I think. Along these lines, the level design was pretty brilliant in terms of variety, scenery, exploration, vantage points, and so on.

Finally--and this isn't really anything to do with the game itself--I thought the ending credits were awesome. The Valve logo scrolled up, followed by roughly a hundred names in alphabetical order. These were all the developers, artists, sound guys, etc., but with no categorization, job titles, or anything like that. The estimable Gabe Newell's name was right in the middle with all the other Ns. Those were followed by about 50 other names/studios for voice acting and such. They finished in about 2 minutes. Compare that to something like Gears of War, with every one of the executives' names, titles, and quotes. I guess neither is necessarily better than the other, but you tend to find fewer like HL2's.


burgers round here

Somewhere randomly I saw a sign advertising for this article in the Seattle Metropolitan magazine about the best burgers in the area. I found a link to it today (on an ad on Facebook, of all things), and I have to say I’m a little disappointed.

No Five Guys? I realize it’s a chain, and not even from around here, but come on, their burgers are huge and awesome!

No Triple X? You can get a burger as big as your face (no joke) with hot dogs across it as toppings. Their patties are a little thin, but that’s just a different style, right? I don’t see that necessarily as a mark against their burgers.

I did also click their link for other notable burger places.

That being said, the pictures in their article showed some pretty rad burgers. Despite my annoyance at my favorite establishments not being recognized, I might end up checking out some of them. What can I say? I’ve come to the relatively recent realization that burgers might just be my favorite food.


Windbg Reference

Sometimes I paste debugger spew. In this debugger spew, there are invariably debugger commands. If you don't know Windbg commands, these can render the spew incomprehensible. To help a little, I'm putting up this page as a quick reference for commands that I actually use in posts. If you want a full reference, go get the actual debugger package and look at the CHM file, which is very thorough.


List current breakpoints.
bu <symbol>
Set a breakpoint on the specified symbol.
db <addr> [L<count>]
Display count bytes starting from addr. Also displays ASCII decoding of the bytes off to the side.
Step out of the current function call.
dd <addr> [L<count>]
Display count double words starting from addr.
Step over instruction (do not step into function call).
Step to next call or ret instruction.
r [<reg> [= <expr>]]
Display all registers, display a single register, or set a register's value.
Step into function.
x <pattern>
Examine symbols, allowing wildcard matches. I usually use it to look up function names in a module.



no coding this week. i’ve got “finals” next week. I put that in quotes because our professor avoided giving us an actual final in favor of turning the last homework into it. we did memory consistency models for our last lecture, which is utterly mind-bending and which I so far have never had to think about, because x86 pampers its programmers with sequential consistency (at least mostly). but I still see people ask questions on discussion aliases at work about “do i need to insert a write barrier here?” and stuff like that. again, utterly mind bending for me right now. this last homework is going to be fun.


working on it

i have a little trouble coming to terms with the possibility that not all of my posts need to be several paragraphs long, well formatted, inaccessible, and checked into my subversion repository