Software, technology, sysadmin war stories, and more. Feed
Wednesday, March 6, 2013

Some programmers scare me

Hacker News: love it or hate it, but it frequently gives me things to ponder. Most of the best stuff comes from the comments. Sometimes I sift through the "new posts" list to find the things which will never make it onto the front page. That's when I find all sorts of bizarre web log posts and other things on the fringe.

A couple of years ago, I found someone who was talking about solving some kind of puzzle. I kept a small piece of it in my notes as an example of just how "out there" some solutions can be. It looked something like this (any transcription errors are mine):

def turn_to_left
  case @directions
    when 'N' :  @directions = 'W'
    when 'E' :  @directions = 'N'
    when 'S' :  @directions = 'E'
    when 'W' :  @directions = 'S'

There was some context, too: apparently you're supposed to be simulating some kind of space vehicle which roams the fourth planet from the sun. (I'm being deliberately vague here, and am not using the term "m--- r-v-r" because I don't want this post to be found for those searches). You are given the dimensions of a flat space, your X and Y coordinates, your initial heading, and a series of commands.

The commands are simple enough: turn left, turn right, or move forward. Turns are just simple pivots, just like the good old turtle used to do, and they're always 90 degrees. You only ever move in the four cardinal directions, in other words.

Anyway, given the initial conditions and the list of commands, you're supposed to say where you end up and which way you're pointing at the end.

Now that you know the context, look back at that snippet of code and feel the pain. Apparently he started worrying about "branching" and was asked to do the job without that case-when block and some other if-else block too, and wasn't able to give them what they wanted.

This is about the point where I started thinking I was pretty weird since I did not think of this problem like this at all. The directions aren't these four discrete things. They are just part of the spectrum which is a circle around your position.

They give you commands as letters. Big deal. A L is a -90 and a R is a +90. See where this is going yet? Do a little modulo magic on them to keep them in the appropriate range. Maybe add 270 instead of subtracting 90, then always take it mod 360. Whatever. The point is, it's a heading, so think of it as just one number, not a series of letters, or enums, or ... well, I've seen a lot of crazy things. I went looking for other implementations, and I think one person had a different class for each direction the thing could be pointed. No, I'm not exaggerating.

Again, they give you a starting direction as a letter: N/E/S/W. Those translate into 0, 90, 180, 270. That's nothing special, either.

There's only one part left, and that's the movement command (M). For that you have to take your heading (one of those four numeric values) and somehow turn it into a meaningful adjustment to your position. These changes... deltas, if you will, are simple enough. Your X position will only ever change by -1, +1, or not at all (0). The same applies for your Y position: -1, +1 or 0.

So now there are these numbers swirling around. 0, 90, 180, 270. -1, 0, 1. This is when "sin" and "cos" pop into my head. They'll take those headings and will give you very nice values which can be used to adjust your position.

The only mildly funky part with this so far is that sin() and cos() in C think in radians, not degrees, so you have to remember 10th grade math and figure out how to convert again. (I hated that stuff, so I had to look it up when I got to this point.) Degrees * PI / 180.

Anyway, fiddling around with sin and cos will show that one of them gives the expected values for X changes and the other does the same for Y, so you do "x += (the one)" and "y += (the other)", more or less. There's one more step involving the fact that you probably won't get exactly -1 or 1 out and will need to do some rounding, but that's part of the fun of floats!

That's the whole "engine". Give it an initial X and Y, heading, and command sequence, and it'll give you the final X, Y, and heading.

Still, if you go looking for this online, you will find countless examples of implementations which go absolutely gaga with their "enterprise grade code", "design patterns" and more.

Reading those comments just blew my mind. It's like, I know all of the words you're using, but those sentences make no sense to me. One solution had "six main components". I found out that by "components", they meant "classes". They somehow found a way to turn that dumb little rotate and move thing I described into a six-class program. Another one had a "HeadingFactory" and even an "UnknownHeadingFactory", and again, I assure you, I am not making this up.

Most of my interest in looking at these other solutions online was to see if anyone had used a heading and trig functions. I never was able to find anything of the sort. Everything I do find is along the lines of "case NORTH: y += 1; break;".

Here's how you can find dozens of posts about this, most with code attached. Just use your favorite web search engine to look for "LMLMLM" and then append "LMM". Again, I'm purposely not putting the whole 9-character string in here verbatim since I'd rather not have this post come up on that topic.

I can think of one final bit of insanity for this whole situation. I bet there are companies out there who actually want to see the implementations which are piled higher and deeper with "enterprise" design goo. If you show them anything shorter, they think something's wrong with it.

I mean, a program which is short can't possibly work, right?