Implement the full class Automaton . Test the class in a main() that works like
ID: 3831756 • Letter: I
Question
Implement the full class Automaton. Test the class in a main() that works like the given main(). Show at least four different sample runs of width 79, giving 100 generations per run (to keep the output manageable). Show me the runs for rules 4, 126 and 130. Add at least one more rule of your choice.
import java.util.Scanner;
public class Driver
{
public static void main(String[] args)
{
int rule, k;
String strUserIn;
Scanner inputStream = new Scanner(System.in);
Automaton aut;
// get rule from user
do
{
System.out.print("Enter Rule (0 - 255): ");
// get the answer in the form of a string:
strUserIn = inputStream.nextLine();
// and convert it to a number so we can compute:
rule = Integer.parseInt(strUserIn);
} while (rule < 0 || rule > 255);
// create automaton with this rule and single central dot
aut = new Automaton(rule);
// now show it
System.out.println(" start");
for (k = 0; k < 100; k++)
{
System.out.println( aut.toStringCurrentGen() );
aut.propagateNewGeneration();
}
System.out.println(" end");
inputStream.close();
}
}
Here is a repeat of the specification of the class.
class Automaton
{
// class constants
public final static int MAX_DISPLAY_WIDTH = 121;
// private members
private boolean rules[]; // allocate rules[8] in constructor!
private String thisGen; // same here
String extremeBit; // bit, "*" or " ", implied everywhere "outside"
int displayWidth; // an odd number so it can be perfectly centered
// public constructors, mutators, etc. (need to be written)
public Automaton(int new_rule)
public void resetFirstGen()
public boolean setRule(int new_rule)
public boolean setDisplayWidth(int width)
public String toStringCurrentGen()
public void propagateNewGeneration()
}
The meaning and behavior of members and methods is in the modules, but here is a summary.
Automaton(int rule) - a constructor. Through the mutator, below, we'll sanitize rule and then convert it to our internal representation. We also need to establish the seed: a single 1 in a sea of 0s (in this assignment a 1 means an asterisk, '*', and a 0 means a blank, ' '. This is accomplished more directly by setting thisGen to "*" and extremeBit to " ".
String toStringCurrentGen() - This returns a string consisting of the current generation, thisGen, but does so by embedding it in a return String whose length is exactly displayWidth long. If thisGen is smaller than displayWidth, it is positioned in the center of the larger return string, with the excess padded by extremeBit characters. If thisGen is longer than displayWidth, it has to be truncated (on both ends) so that it is perfectly centered in the returned string, any excess trimmed off both ends, equally. You can easily do this with simple String objects and concatenation.
Two Mutators:
boolean setRule(int newRule) - converts the int newRule, a number from 0-255, to an array of eight booleans. For example, if the newRule is 182, then this is the binary number 1 0 1 1 0 1 1 0, which means that the resultant array will be
rule[7] = true,
rule[6] = false ,
rule[5] = true,
rule[4] = true,
rule[3] = false,
rule[2] = true,
rule[1] = true ,
rule[0] = false.
I have color coded two of the bits in 182 and their corresponding booleans in the array rule[] so you can easily see how the conversion needs to work. As usual, this must sanitize the int so that only values in the legal range 0-255 are allowed.
boolean setDisplayWidth(int width) - this is described by the earlier description of displayWidth and MAX_DISPLAY_WIDTH. I repeat that only odd widths are allowed (for centering purposes).
void propagateNewGeneration() - this is the workhorse function. It will use the three private members thisGen, extremeBit and rule[], and create the next generation from them. This method must first append two extremeBits to each side of thisGen in order to provide it with enough bits (or chars) on each end needed by rule. This adds four chars to thisGen, temporarily. We then apply rule in a loop to the new, larger, thisGen, which creates a separate (local) nextGen String. If you do this correctly, nextGen will be two characters smaller than the recently augmented thisGen (but still two larger than the original thisGen that entered the method). [You must understand this statement, conceptually, before you write your first line of code, or you will be doomed.] Then, you replace the old thisGen with our new nextGen.
In brief, we pad thisGen with four extremeBits, then apply rule, and we have a new nextGen, two larger than we started out with. We copy that back to thisGen to complete the cycle.
Finally, we have to apply rule to three consecutive extremeBits to figure out what the new extremeBit will be for the next generation (" " or "*"?) . What do I mean by "three consecutive"? We apply rule to an int representing a 3-bit pattern inside the old generation. In this case, we are doing this way out where all the bits are the same: extremeBit. So each input will be three 0s or three 1s -- an int 0 or an int 7 -- depending on the value of extremeBit. The result will enable us determine the new value of extremeBit. We must do this before we return, so extremeBit is correct for the next call to this method.
Supply a sample set of at least four runs which include the rules, 4, 126, 130, and one or more of your choice. One run would look something like this:
Enter Rule (0 - 255): 124
start
*
**
***
* **
*****
* **
** ***
*** * **
* *******
*** **
* ** ***
***** * **
* ** *****
** *** * **
*** * **** ***
* ***** ** * **
*** ** ********
* ** **** **
***** * ** ***
* **** *** * **
** * *** ** *****
*** ** * ***** * **
* ******** ** ** ***
*** ** ****** * **
* ** *** * *******
***** * **** * **
* ** *** ** ** ***
** *** * ** *** *** * **
*** * ** ****** *** ** *****
* ******** *** ***** * **
*** ** * *** **** ***
* ** *** *** ** * ** * **
***** * ** * ***** ** ********
* ** ******** ****** **
** *** * ** * ** ***
*** * ** ** *** ** *** * **
* ********** * ***** * ** *****
end
The above pattern is shorter than an actual run that 100 generations would produce.
Most of you will be able to solve the problem using nothing more than the information contained in the Modules. Spend time trying to do that first. If you get stuck, there are a couple hints you can access. Read them and study them, but only if you need them:
Click on the links:
Understanding How To Apply A Rule to a String (Links to an external site.)Links to an external site.
Understanding How To Implement setRule() (Links to an external site.)Links to an external site.
Attention:
Don't be "verbose". In methods like constructors, mutators, or other non-I/O member functions, do not do any output - even in the case of an error. Leave the decision of how and when to do output to the client.
Methods that should not be instance functions. Some methods should not be instance member functions. If the method does not act on the class data or acts on it in a way that is so specialized that only one application out of a million will make use of it, it should not be in your class. Make this an ordinary (static client or static main class) method, not a method of a lower-level class.
Methods that should be instance functions. On the other hand, if a static method (or a method of some other class) takes only one object of a class as a parameter and works only on that one object, then it probably should be made an instance method of that object's class, and the object parameter should be removed. The reason we can eliminate the parameter once we make the method an instance method (of the previously passed-object's class) is that the object is then passed intrinsically to the method via the "this" object.
Test your code thoroughly and go beyond the scenario(s) that the assignment requests to make sure that it behaves as expected even when the client is not using it properly. (Input filtering)
Explanation / Answer
import java.util.Scanner;
class Automaton
{
// class constants
public final static int MAX_DISPLAY_WIDTH = 121;
// private members
private boolean rules[]; // allocate rules[8] in constructor!
private String thisGen; // same here
String extremeBit; // bit, "*" or " ", implied everywhere "outside"
int displayWidth; // an odd number so it can be perfectly centered
// public constructors, mutators, etc. (need to be written)
public Automaton(int new_rule)
public void resetFirstGen()
public boolean setRule(int new_rule)
public boolean setDisplayWidth(int width)
public String toStringCurrentGen()
public void propagateNewGeneration()
}
public class Driver
{
public static void main(String[] args)
{
int rule, k;
String strUserIn;
Scanner inputStream = new Scanner(System.in);
Automaton aut;
// get rule from user
do
{
System.out.print("Enter Rule (0 - 255): ");
// get the answer in the form of a string:
strUserIn = inputStream.nextLine();
// and convert it to a number so we can compute:
rule = Integer.parseInt(strUserIn);
} while (rule < 0 || rule > 255);
// create automaton with this rule and single central dot
aut = new Automaton(rule);
// now show it
System.out.println(" start");
for (k = 0; k < 100; k++)
{
System.out.println( aut.toStringCurrentGen() );
aut.propagateNewGeneration();
}
System.out.println(" end");
inputStream.close();
}
}