import java.util.*; /** The StringChooser interface requires classes that implement the interface to implement * a method called getNext that is defined in terms of zero parameters and returns a value * of type String. */ interface StringChooser { String getNext(); } /** The PseudoRandomNumbers class and the classes it depends on define a program that * outputs a series of values where each value is a fixed length string denoting an * integer. The values in the series may contain leading zeros and are each followed by * a delimiter value, which may be an empty string. If the array of String values passed * to the program's main method is not null and the length of the array is greater than * zero, then the delimiter is the value of the first String value in the array; * otherwise, the delimiter is a String value comprised of a single space character. * * Example 1 * * At 3 AM (PST) on 7-FEB-2019, the author used PseudoRandomNumbers to generate the * following series of values. * * 853 927 068 972 146 503 149 431 675 802 802 068 853 503 149 972 * * Questions * * 1. In what ways are the value of the sequence shown in Example 1 not random? * 2. What simple change can you make to the main method so that the program produces * sequences of length 16 that are more random than the one shown in Example 1? * 3. What command line argument(s), if any, were used to generate the following output? * * 6120078098105940923042307410070065803650423036505940741065800780 */ public class PseudoRandomNumbers { private static final int numCount = 16; private static final int numLength = 3; public static void main(String args[]) { final String delimiter = args != null && args.length > 0 ? args[0] : " "; final StringChooser chooser = new FixedLengthRandomIntegerChooser(numLength); for (int n = 1; n <= numCount; n++) { System.out.print(chooser.getNext() + delimiter); } } } /** The FixedLengthRandomIntegerChooser class implements the StringChooser interface: it * defines a type of object that has a getNext method, which always returns a String * value of fixed length denoting an integer. When a FixedLengthRandomIntegerChooser * object is constructed, the length of the String values returned by getNext must be * specified; optionally, the maximum number of String values in a pool of values that * strings are randomly selected from may also be specified. When all of the strings * in the pool have been consumed as a result of calling getNext, the pool of strings * is replenished with the same set of strings that it contained when the * FixedLengthRandomIntegerChooser object was constructed. */ final class FixedLengthRandomIntegerChooser implements StringChooser {
private static final int defaultNumberPoolSize = 10; private static final String digitPool = "0123456789"; private final RandomStringChooser chooser; public FixedLengthRandomIntegerChooser(final int numberLength, final int numberPoolSize) { final String[] numberPool = getIntegersAsStrings(numberLength, numberPoolSize); chooser = new RandomStringChooser(numberPool); } public FixedLengthRandomIntegerChooser(final int numberLength) { this(numberLength, defaultNumberPoolSize); } public String getNext() { String next = chooser.getNext(); if (next.equals("NONE")) { chooser.reset(); next = chooser.getNext(); } return next; } public static String[] getIntegersAsStrings(final int length, final int count) { final String[] numbers = new String[count]; RandomDigitChooser digitChooser = new RandomDigitChooser(digitPool); for (int i = 0; i < count; i++) { String number = ""; while (number.length() < length) { Integer digit = digitChooser.getNext(); if (digit == null) { digitChooser.reset(); digit = digitChooser.getNext(); } number += digit; } numbers[i] = number; } return numbers; }
} /** The ResettableItemChooser<T> interface requires classes that implement the interface * to implement: a method called reset that returns no value (i.e. has a void return type) * and is defined in terms of zero parameters; a method called getNext that returns a value * of type T and is defined in terms of zero parameters. */ interface ResettableItemChooser<T> { void reset(); T getNext(); } /** The RandomItemChooser<T> class implements the ResettableItemChooser<T> interface: * it defines a generic type of object that maintains a set of available items of type T, * any one of which may be chosen at random and removed from the set using the object's * getNext method, which is defined in terms of zero parameters. A RandomItemChooser<T> * object is constructed from either a non-null array of items of type T or from a non-null * array of items of type T and a value of type T (passed to the constructor in that order), * the latter of which is the value returned by getNext when the set of items maintained by * the RandomItemChooser<T> object is empty; if not otherwise specified, the value null * is returned by getNext when the set is empty. An object of type RandomItemChooser<T> * has a method called reset (defined in terms of zero parameters) that, when called, * removes all items from the set of available items and then adds all of the items that * were originally included in the set when the object was first created, assuming the array * of items that was passed to the constructor function was not subsequently modified. */ class RandomItemChooser<T> implements ResettableItemChooser<T> {
private final T none; private final T[] items; private final List<T> list; public RandomItemChooser(final T[] items, final T none) { this.items = items; this.none = none; list = new ArrayList<T>(items.length); reset(); } public RandomItemChooser(final T[] items) { this(items, null); } final public void reset() { list.clear(); for (T item : items) { list.add(item); } } public T getNext() { final int n = list.size(); final int i = (int)(Math.random() * n); return n > 0 ? list.remove(i) : none; }
} /** The RandomStringChooser class extends RandomItemChooser<T>. A RandomStringChooser * object is constructed from an array of String values. When the set of String values * maintained by a RandomStringChooser object is empty, the value returned by invoking * the object's getNext method is the String value "NONE". */ class RandomStringChooser extends RandomItemChooser<String> {
public RandomStringChooser(final String[] strings) { super(strings, "NONE"); }
} /** The RandomIntegerChooser class extends RandomItemChooser<T>. A RandomIntegerChooser * object is constructed from a non-null array of Integer values. When the set of Integer * values maintained by a RandomIntegerChooser object is empty, the value returned by * invoking the object's getNext method is the value null. */ class RandomIntegerChooser extends RandomItemChooser<Integer> {
public RandomIntegerChooser(final Integer[] integers) { super(integers); }
} /** The RandomDigitChooser class extends RandomIntegerChooser. A RandomDigitChooser object * is constructed from a non-null String value composed of one or more characters in the * set {'0', '1', '2', ...., '9'}. The class has a static method called getDigits that * takes a String of digit characters as input and returns a corresponding array of * Integer values. */ final class RandomDigitChooser extends RandomIntegerChooser {
public RandomDigitChooser(final String digits) { super(getDigits(digits)); } public static Integer[] getDigits(final String digits) { final int n = digits.length(); final Integer[] array = new Integer[n]; for (int i = 0; i < n; i++) { final String digit = digits.substring(i, i + 1); array[i] = Integer.parseInt(digit); } return array; }
}