Cowboy Programming Game Development and General Hacking by the Old West

January 12, 2007

Cowboy Scrabble Programming

Filed under: Cowboy Programming — Mick West @ 10:39 am

(This is just a programming anecdote.   If you want to know how to program something that plays scrabble, then look here: http://www.gtoal.com/wordgames/scrabble.html)

A couple of years ago I was trapped in Truckee, California, snowed in somewhere up a mountain in a little cottage, with no electricity. It was the holidays, and I was visiting with the in-laws, and we’d just had a rather unsatisfying game of Scrabble. Unsatisfying because we had no dictionary, and so no way to validate challenges, which makes the game even less visceral than normal.

So my laptop still had a few hours of juice left, so I resolved to write a quick scrabble word checker. As it happened I already had the list of valid scrabble words(ospd.txt), which can be downloaded from http://web.mit.edu/rwbarton/Public/ospd.txt

At first I though a quick batch file would do the trick, but after a few minutes poking I got annoyed, and decided to simply brute force it, and write it in plain old C++, just to pass the time. Half an hour later I came up with this monster (stripped slightly):

		w = (char*)argv[1];

		char * p = new char[10000000];		// 10MB
		FILE * x = fopen ("C:\\ospd.txt","rb");
		for (int i=0;i<10000000;i++)
			p[i] = 0;
		fread (p,1,10000000,x);

		int len= 0;
		while (w[len])
		{
			if (w[len] >= 'A' && w[len] <= 'Z')
				w[len] -= ('A'-'a');
			len++;
		}

		char *s = &p[0];		// w = search pointer to start of word

		int valid = 0;
		while (*s != 0)
		{
			int letter = 0;
			while (letter < len)
			{
				if (s[letter] != w[letter])
					break;
				letter++;
			}
			if (letter == len && (s[letter]==0x0a || s[letter] == 0x00))
			{
				printf ("%s is GOOD\n",w);
				valid = 1;
			}
			while (*s != 0 && *s != 0x0a)
				s++;
			if (*s == 0x0a)
				s++;
		}
		if (valid == 0)
			printf("%s is BAD\n",w);

Now there’s some hackery, quite embarrassing really. It’s a good example of Cowboy Programming because:
– It’s long and messy code
– It’s using an ad hoc solution to something that has been solved many times before

But the key thing is that it works. It’s a perfect solution to the given problem in the sense that it solves the problem perfectly. But it’s nothing beyond that.

Of course, you can do the same thing in one line of Ruby:

puts IO.readlines("ospd.txt").include?(ARGV[0]+"\n")

But I did not have Ruby (or Perl) installed, and since I’m no Ruby expert, and had no Internet access, that one line of Ruby could have taken me longer to write than the 50 lines of C++.

However, had I persevered a little, I could have figured out the batch file:

@echo off
for /F %%f in (ospd.txt) DO if "%%f"=="%1" @echo %%f IS GOOD!

In hindsight, what should I have done, wanting to be a “good” cowboy programmer? Well, my goal was to solve the problem as quickly as possible, and I knew the code was never going to be looked at or used again. I knew that very simple solutions existed, but I did not know how to get to them. I knew I could get to those simple solutions eventually, but I did not know how long it would take. On the other hand, I knew if I programmed in C++, the code would be long and messy, but I knew exactly how I would write it, and I knew roughly how long it would take, about 20 minutes.

So, the choice was a short and elegant solution in between two minutes and two days (if I had to wait until we escaped the snow), or a long and messy solution in twenty minutes. Take the money, or open the box? I experimented briefly, and then chose the known quantity. The messy code was written. Done.

5 Comments »

  1. I can appreciate the sentiment, but I don’t think this a good example of “quick and dirty gets the job done”, nor is it a matter of one language being more powerful or expressive than another. It would serve better as a lesson on why it is useful to learn the standard library of a language well enough so that you don’t have to waste time writing ten lines when of code when one would suffice. Take this solution for example:

    ifstream stream(“ospd.txt”);
    istream_iterator<string> begin(stream), eos;
    bool found = find(begin, eos, argv[1]) != eos;
    cout << argv[1] << ” is ” << (found ? “GOOD” : “BAD”) << endl;
    stream.close();

    Are these lines any harder to follow, for someone decently acquainted with C++ and the STL? More importantly, are they any more difficult to write? They do not make explicit use of pointers, dynamic memory allocation, or ASCII control codes, as your code (which is really more C than C++) does at great length. Nevertheless, there is a more important question to be asked.

    Did you and your in-laws actually use this program to play a more engaging round of Scrabble? I suspect not; if that was your true goal, Notepad’s “find” feature would have sufficed. No – it seems to me this was borne out of a desire to code something, and rather than tackling something more challenging you simply created work for yourself.

    What bothers me most about this post is what it seems to say about Cowboy Programming, if it is to be taken as a “good example” of such. Namely, that Cowboy Programming involves:
    – writing unnecessary code for already-solved problems
    – sticking to what is familiar when it would be more appropriate to try something new
    – ascribing inefficiencies in your code to a language instead of looking to eliminate them
    – having a warped sense of perfection that really puts the special in specialization

    The last one is truly puzzling; does it not bother you when a problem that can be described in a few words has a code representation that is dozens of lines long? I would say this goes beyond breaking something down into subproblems, to the point where you spend time and space on things that are hardly related to your original task. At that stage, you might as well be working it assembly, although I am quite certain this particular problem could be solved in fewer than 50 lines of x86 code.

    In any case, if you happen to be looking for coding practice, I would recommend checking out Project Euler (http://projecteuler.net/). They have a great selection of problems, most of them (in the first 50, anyway) solvable in no more code than would fit on a single screen, if done properly. It is interesting to read the discussion pages – made viewable after solving a particular problem – where people often post their solutions. I’ve been writing all my solutions in C while trying to give those using functional programming languages a run for their money in terms of code length (not an easy task, although not nearly so bad as if I were using Java).

    Good luck, and have fun coding while fading into the Western sunset. And don’t let presumptuous elitist programmers get you down.

    Comment by Invertigo — October 11, 2008 @ 3:59 am

  2. No, we never actually used the Scrabble checker. They were not really that big players of Scrabble. So yes, it was more just for something to do.

    For my purposes, I wanted something (a command line tool) that would simply check if the word was in the file, without showing me partial matches, or the surrounding words. So notepad would not fit the bill. The ideal solution would have been the simple FOR statement batch file, above, and I feel annoyed that I did not persevere and figure that out.

    I did not know the STL very well, and I still don’t. But normally I could have simply looked it up. However, given my sad lack of familiarity with streams, iterators and the functions of the STL, it would probably have still taken me longer to figure out than the C code.

    I agree though that it’s important to learn new things – especially if they can save time in the long run. But there are also sometimes situations where it’s more important to get the task done in the shortest time possible. The key is to be able to judge the difference.

    Heh, I just noticed that there’s only one comment in the code, and it’s wrong :)

    Comment by Mick West — October 11, 2008 @ 7:52 am

  3. A small aside: I stumbled upon this a little while ago, and you might also find it useful. The Windows NT shell includes a command called FINDSTR which is something like a poor man’s grep. You could use it as follows:

    @echo off
    FINDSTR /X “%1” ospd.txt > NUL
    IF ERRORLEVEL 1 (ECHO %1 is BAD) ELSE (ECHO %1 is GOOD)

    The switch /X only lets through entire line matches.

    Comment by Invertigo — October 11, 2008 @ 2:12 pm

  4. If you are running Linux, here’s a really easy one-liner
    in the shell:

    egrep ‘^word$’ ospd.txt

    YARTLL (Yet Another Reason To Love Linux:).

    Comment by Richard Hamilton — April 16, 2009 @ 7:52 am

  5. That code doesn’t look too messy and to me who doesn’t know that much of c++. If you really want something done you can use what ever code you get the fastest done. There is nothing wrong if nobody likes the code if it does what it is supposed to.

    Comment by Seiska — November 11, 2009 @ 12:37 pm

RSS feed for comments on this post. TrackBack URL

Leave a comment

You must be logged in to post a comment.

Powered by WordPress