I once went on a European tour through the university that I went to. The same university where I studied computer science for two years before finishing with a degree in philosophy. The same university that, for whatever reason, gave me a masters degree in English.
On this trip to Europe, we had a lot of downtime on a bus, traveling from one fascinating country to another. On those bus rides, we were allowed to drink beer and be irresponsible. It was the most liberated I have ever been, despite the fact that I was really just riding a rail to its terminus (an airport in Frankfurt that brought us back to America). I spent that time, of course, drinking Swiss beer (the bus driver sold us beer on the bus; he was an Australian expat living in Switzerland). I also spent that time reading.
I read several books that had been on my reading list for quite some time. One of those books was Zen and the Art of Motorcycle Maintenance. It’s actually a deeply flawed book in several respects, but about the first two-thirds of it are very, very good. There’s a lot of very interesting discussion about the scientific method. In it, Robert Pirsig discusses some of the general techniques that a person can use to solve a problem when a motorcycle is not working. One of these is to employ the scientific method. The scientific method is very akin to the process of elimination. Form a hypothesis for what might be causing the problem, and then, test that hypothesis. If that doesn’t work, you know one thing that isn’t the problem.
It also hearkens to Sherlock Holmes: “Once you eliminate the impossible, whatever is left, however improbable, must be the truth.” Not sure if that’s the exact quote.
So, with the code I was using to generate this noise, there were several function calls. One would generate the base noise. One would “perturb” it, creating a wobbly effect. One creates an erosion-like effect. The last one smooths it all out.
I commented all of these out, leaving just the noise function call. The output looked great. It was just cloudy noise (although I still have the problem that my returned values are in the float range of -1 to 1, and I want them to be from 0 to 1; this is why there are dark “rivers” running through it because to work around it, any number that was negative was raised to 0). The point is, there was no line. I brought back the perturb function call. No line. Just a nice, perturbed version of the original output. The bug was not in the perturb function.
Finally, I added the erosion function back in. And there it was. A fine, one-pixel-thick line from the top left to the bottom right corner. The smooth function just widened it and gave it that peculiar bar-like quality. Success! I went back to erode function in the heightmap class and went through it line by line (it’s only about 15 lines or so). And I found that, where I was using nested for() loops, using i and j as my iterators, there was an i that should have been a j. Fixed it. Re-ran the code, outputted it to a bmp, and there was my heightmap. Nothing weird, just nice, coherent noise.
What’s weird is that I didn’t need to know how the code worked. And I still don’t. I saw the error, not fully understanding why it was causing that bar, but fixing it anyway, and eliminating the bug.
It took longer to write this post than it did to fix the bug.