/* File: fiveRandomWords * -------------- * This program generates random "words," just random letters stuck together. The characters of the word are * random, but must be an upcase letter-- these are integers that correspond to the ASCII characters of the * upcase alphabet. The length of the word is also random, but bounded by the constants MIN_LETTERS and * MAX_LETTERS. * * The run method of the program simply starts of with blank String instance and keeps pulling random letters * out of the random generator until the word length is reached. It relies on a private method to generate the * random characters and to set the word length. */ import acm.program.*; import acm.util.RandomGenerator; public class FiveRandomWords extends ConsoleProgram { public void run() { for (int i = 0; i < 5; i++) { int wordLength = rgen.nextInt(MIN_LETTERS, MAX_LETTERS); String myRandomWord = " "; for (int j = 0; j < wordLength; j++) { myRandomWord += randomLetter(); } println(myRandomWord); } } private char randomLetter() { return (char) rgen.nextInt((int) 'A', (int) 'Z'); } private RandomGenerator rgen = RandomGenerator.getInstance(); private static final int MIN_LETTERS = 3; private static final int MAX_LETTERS = 10; }
What made it tough:
This simple problem is all about getting comfortable with scalar types: data values that can be represented as numbers. The key snippet in the program is this:
private char randomLetter() {
return (char) rgen.nextInt((int) 'A', (int) 'Z');
}
How do you return a *character* that's random but bounded by the *integers* A and Z? Because the "char" data type in Java maps directly to Unicode and ASCII. Unicode and ASCII are both systems that match characters (letters, punctuations marks, etc) to integers so that it's easier for the computer to understand.
Fun facts I learned:
- Precursors to ASCII literally mapped 'A' to 1, 'Z' to 26, and everything in-between, but ASCII didn't do so since there are additional characters that precede letters.
- The ASCII system came first, Unicode second. ASCII characters don't encode most non-Western characters, so Unicode was created with thousands of new characters to account for these.
- Unicode contains everything that's in ASCII, and to be completely backwards-compatible, the first 128 digits of Unicode map directly to ASCII
Because characters are mapped this way, you can perform some numeric operations on *letters* as specifying a range like I did above, or taking a letter 'A' and adding 5 to get 'F.' When specifying the range of characters, you could either provide the character or the number equivalent-- the computer can handle each one and in fact the (int) cast isn't necessary- it's there to make things clearer for humans so they don't think, "Why are you bounding nextInt with characters?" You must specify the (char) cast however to make sure that when you do rgen.nextInt, you get a letter back, not a number.