About a month ago, at a LAN party, I was getting a bit bored (and tired as hell), so I decided to make a quick "update" program for my parents' computer. Often they'll ask me for help, and yell at me when they're confused. So, I decided to plan an April Fool's prank on them in advance. The program starts with "Upgrading Win98x -- Do not abort -- Do not abort -- Hard drive failure may result after abortion. Press any key to continue."

The program then continues to follow an algorithm to pick fairly plausible file name (my parents don't need real file names to believe it), and "update them", full with a percent counter. The thing is, it is in an infinite loop. So far, I've had my dad waiting for it to finish for an hour. I predict he will be waiting for quite some time longer.


The gig is up. I finally told my father after 5+ hours of running the program, and him not using the computer.


Source code in C++ (feel free to reproduce):



#include <iostream.h>
#include <time.h>  //gets time
#include <stdlib.h>
#include <conio.h>  //getch function

int rnd(int range);
void seedrnd(void);
void anykey();  //my own anykey fuction

void main()
{
	seedrnd();
	int lets;
	char consonants[22]="bcdfghjklmnpqrstvwxyz";
	char vowels[6]="aeiou";
	char letters[27]="abcdefghijklmnopqrstuvwyxz";
	char ext[34]="datexebatdllsyscfgpwlreghlpinisav";
	int name;
	int start;
	int percent;
	// starting message:
	cout << "----------------\nUpgrading Win98x -- Do not abort -- ";
	cout << "Do not abort\nHard drive failure may result after abortion";
	cout << "\n----------------\n";
	cout << "Press any key to continue";
	anykey();  //here's the quick anykey
	cout << "\n\n";
	while(;;)  // infinite loop
	{
		cout << "Updating: ";
		lets=rnd(7)+3;  //how many letters will the filename have?  3-7
		for(int i=0; i<lets; i++)
		{
			if(i==0||i==2||i==3||i==6||i==7)
//randomly picks the letter.
//First, third, fourth, seventh, and eighth letters are consonants
			{
				name=rnd(20);
				cout << consonants[name];
			}
			if(i==1||i==4||i==5)
//second, fifth, and sixth are vowels
//(for easy pronunciation of "filenames", and you don't get "gjwp.exe")
			{
				name=rnd(4);
				cout << vowels[name];
			}
		}
		lets=rnd(3)+1; // 1/3 chance of adding numbers
		if(lets==3)
		{
			lets=rnd(2)+1;  // either one or two numbers
			for(int i=0; i<lets; i++)
			{
				name=rnd(9)+1;  //numbers 1-9
				cout << name;
			}
			lets=rnd(2)+1;
// If the numbers are displayed,
//there is an additional 1/2 chance of additional letters
			if(lets==2)
			{
				lets=rnd(5)+1;
// 1-5 additional letters, these can be either consonant or vowel
				for(int i=0; i<lets; i++)
				{
					name=rnd(25);
					cout << letters[name];
				}
			}
		}
		cout << ".";
		lets=rnd(10);  // 10 different file extentions.
			// Some might even be known by my parents!
		lets=lets*3;
		cout << ext[lets] << ext[lets+1] << ext[lets+2];
		cout << "\n     ";
		percent=0;
		start=time(NULL);
		lets=rnd(5)+1;  // waits 1-5 seconds for next percent update.
		percent=0;
//this is the percent counter, doesn't work all that well,
//I'm thinking because of the speed of today's computers.
		while(percent!=100)
		{
			cout << percent << "%"; // displays percent
			while(time(NULL)-lets<start) //waiting
			{
			}
			if(percent<=9)
				cout << "\b\b";  // backspace (if you didn't know)
			if(percent>9)
				cout << "\b\b\b";
			percent=percent+1;
		}
		cout << "\n----File update complete\n";
	}
}

int rnd(int range)
{
	//do: int rnd(int range);
	//and: void seedrnd(void);
	//when I'm ready to call up a random number,
	//do it like this:
//variable=rndputhighestnumberhere+putlowestnumberhere;
	//in main when declaring int, etc, put: seedrnd();
	int r;

	r=rand()%range;
	return(r);
}

void seedrnd(void)
{
	srand((unsigned)time(NULL));
}

void anykey()
{
	cout << endl;
	getch();
}

Thanks to Magenta and OldMiner for pointing various things out to me to fix this writeup.

Magenta's Mini-C++ Tutorial

Lesson 1: Making code more compact

Rather than use a lot of if-then expressions for selecting a letter, do this:

char consonant() {
        static string consonants("BCDFGHJKLMNPQRSTVWXYZ");
        return consonants[rand()%consonants.length()];
}

char vowel() {
        static string vowels("AEIOU");
        return vowels[rand()%vowels.length()];
}

char letter() {
        return 'A' + rand()%26;
}
and then call consonant(), vowel(), or letter().

Lesson 2: The auxiliary things you didn't notice from lesson 1

There's still some improvements to be made... rather than doing "int ha = 1; while (ha==1) ...", just do "for (;;) ...", which is the blessed-by-the-gods way of doing an infinite loop. Sane compilers won't generate a warning on that, because it's the accepted style.

You also seem to be missing a fair amount of code (it abruptly ends), and you forgot to turn your [s into &#91;s so that they don't try to hardlink your array sizes.

Using a string (as I did above) instead of a char[] is considered much cleaner and safer, though in this case it doesn't really matter.

There's no reason to declare an array of "letters," since the nth letter is just 'a'+n. That is, 'a'+3 == 'd'. This is standardized on all ASCII-speaking machines, as well as most other character sets. Remember, in C/C++, a character constant is an int, it's just formatted in a human-readable way. You're also thinking like a human, rather than a programmer, by counting from 1 instead of 0.

The loops for doing a random number of things can be made much more simple as well. Rather than saying:

int lets=rand()%7;
for (int i = 0; i < lets; i++)
do this:

for (int i = rand()%7; i > 0; i--)
They're equivalent, assuming you're not using the loop index variable within the loop. If you do strictly need to count upwards, though, and aren't just repeating a loop a specific number of times, you still have to use a temporary variable though.

That way of doing extensions is fugly, though it works well enough. I'd personally do something like this:

const int NUM_EXTENSIONS = 6;
const char *EXTENSIONS[NUM_EXTENSIONS] = {"dat"
                                         ,"bat"
                                         ,"exe"
                                         ,"sys"
                                         ,"vxd"
                                         ,"drv"
                                         }
or the like. And the reason I format my array in that weird-looking way is twofold - it's much more readable, and it's the way that XEmacs' code-indentation stuff likes it to be done.

As far as array lengths and such, you really shouldn't hard-code those numerically. If you really don't care about changing the contents of the arrays dynamically (that's why I always use string for that stuff), then at least do something like this:

const char *vowels="aeiou";
const int numvowels=strlen(vowels);

...

char myvowel = vowels[rand()%numvowels];

That way, if you decide to add in, say, y or w (FWIW, w is sometimes - but very rarely - considered a vowel, such as in the word cwm), you just add it into the string and everything keeps on working. And if you later decide to take them out, you don't have to worry about segfaults/GPFs or other weird behavior (such as getting garbage characters).

I don't deny that I used to code pretty sloppy, myself. Learning proper coding style or methodology isn't something which happens overnight, but I hope that I am, at the very least, being helpful in showing you The Right Way of doing these things. :)

Log in or register to write something here or to contact authors.