0

Here is my code for a cellular automaton I am working on:

public class Life1D {

    private Rule rule;
    private int stepCount;

    public static void main (String [ ] args) {
            Life1D simulation = new Life1D ( );
            simulation.processArgs (args);
            simulation.producePBM ( );
    }

    // Print, in Portable Bitmap format, the image corresponding to the rule and step count
    // specified on the command line.
    public void producePBM ( ) {
            int width = (stepCount*2+1);
            System.out.println("P1 " + width + " " + (stepCount+1));
            String prev_string = "";
            // constructs dummy first line of rule
            for (int i = 0; i < width; i++){
                    if (i == stepCount+1){
                            prev_string += "1";
                    } else {
                            prev_string += "0";
                    }
            }
            // contructs and prints out all lines prescribed by the rule, including the first
            for (int i = 0; i < stepCount; i++) {
                    String next_string = "";
                    for (int j = 0; j < width; j++) {
                        // prints next line, one character at a time

                            System.out.print(prev_string.charAt(j) + " ");
                            // specifies cases for the edges as well as for normal inputs to Rule
                            if (j == 0) {
                                    next_string += rule.output(0, prev_string.charAt(0), prev_string.charAt(1));
                            } else if (j == width-1) {
                                    next_string += rule.output(prev_string.charAt(width-2), prev_string.charAt(width-1), 0);
                            } else {
                                    String rule_input = prev_string.substring(j-1, j+2);
                                    int first = rule_input.charAt(0);
                                    int second = rule_input.charAt(1);
                                    int third = rule_input.charAt(2);
                                    next_string += rule.output(first, second, third);
                            }
                    }
                    // sets prev_string to next_string so that string will be the next string in line to be printed
                    prev_string = next_string;
                    System.out.println();
            }
    }


    // Retrieve the command-line arguments, and convert them to values for the rule number
    // and the timestep count.
    private void processArgs (String [ ] args) {
            if (args.length != 2) {
                    System.err.println ("Usage: java Life1D rule# rowcount");
                    System.exit (1);
            }
            try {
                    rule = new Rule (Integer.parseInt (args[0]));
            } catch (Exception ex) {
                    System.err.println ("The first argument must specify a rule number.");
                    System.exit (1);
            }
            try {
                    stepCount = Integer.parseInt (args[1]);
            } catch (Exception ex) {
                    System.err.println ("The second argument must specify the number of lines in the output.");
                    System.exit (1);
            }
            if (stepCount < 1) {
                    System.err.println ("The number of output lines must be a positive number.");
                    System.exit (1);
            }
    }
}

 class Rule {

    private int a, b, c;
    private String rulebin;

    public Rule (int ruleNum) {
            rulebin = Integer.toBinaryString(ruleNum);
    }

    // Return the output that this rule prescribes for the given input.
    // a, b, and c are each either 1 or 0; 4*a+2*b+c is the input for the rule.
    public int output (int a, int b, int c) {
        return rulebin.charAt(7 - 4*a + 2*b + c);
    }
}

Here is the error message when I run it:

P1 7 4
0 Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index      out of range: 151
    at java.lang.String.charAt(String.java:686)
    at Rule.output(Life1D.java:90)
    at Life1D.producePBM(Life1D.java:35)
    at Life1D.main(Life1D.java:9)

What the heck? Why am I getting this error, and how can I fix it? I've been trying to find the error for hours, and it'll a blessing if I could be helped.

2 Answers2

0

In this particular part you are converting integer to binary string:

 rulebin = Integer.toBinaryString(ruleNum);

Now let suppose your parameters are:
first parameter = 12
second parameter = any number

Now when this code will convert this number into binary string then you will get:
rulebin = "1100" (length 4)

Now in this function:

 public int output (int a, int b, int c) {
    return rulebin.charAt(7 - 4*a + 2*b + c);
}

When a = b = c = 0 then this function will try to access your "rulebin's character 8" but length of your rulebin is 4. That's why you are getting String Index out of bound exception.

Note: I am not sure if you have put any restrictions on your input parameters but this can be a potential problem.

JackSparrow
  • 707
  • 2
  • 10
  • 24
0

No! the problem is that you're passing char instead of int to

 public int output (int a, int b, int c) {
    return rulebin.charAt(7 - 4*a + 2*b + c);
}

I tried it and when the prevString.charAt(0) and prevString.charAt(1) were 0 it send to the output method those parameters (0,48,48) (try to debug it and you'll) this cause the index out of range!

and also the convertion to binary string doesn't return 7 digits format..

UPDATE:

public class Lif1ID {

private Rule rule;
private int stepCount;

public static void main (String [ ] args) {
        Lif1ID simulation = new Lif1ID ( );
        simulation.processArgs (args);
        simulation.producePBM ( );
}

// Print, in Portable Bitmap format, the image corresponding to the rule and step count
// specified on the command line.
public void producePBM ( ) {
        int width = (stepCount*2+1);
        System.out.println("P1 " + width + " " + (stepCount+1));
        String prev_string = "";
        // constructs dummy first line of rule
        for (int i = 0; i < width; i++){
                if (i == stepCount+1){
                        prev_string += "1";
                } else {
                        prev_string += "0";
                }
        }
        // contructs and prints out all lines prescribed by the rule, including the first
        for (int i = 0; i < stepCount; i++) {
                String next_string = "";
                for (int j = 0; j < width; j++) {
                    // prints next line, one character at a time

                        System.out.print(prev_string.charAt(j) + " ");
                        // specifies cases for the edges as well as for normal inputs to Rule
                        if (j == 0) { 
// take a look at the 'getNumericValue' Method.. in your version it didn't pass 0 or 1, now it does.. 
                                next_string += rule.output(0, Character.getNumericValue(prev_string.charAt(0)), Character.getNumericValue(prev_string.charAt(1)));
                        } else if (j == width-1) {
                                next_string += rule.output(prev_string.charAt(width-2), prev_string.charAt(width-1), 0);
                        } else {
                                String rule_input = prev_string.substring(j-1, j+2);
                                int first = Character.getNumericValue(rule_input.charAt(0));
                                int second = Character.getNumericValue(rule_input.charAt(1));
                                int third = Character.getNumericValue(rule_input.charAt(2));
                                next_string += rule.output(first, second, third);
                        }
                }
                // sets prev_string to next_string so that string will be the next string in line to be printed
                prev_string = next_string;
                System.out.println();
        }
}


// Retrieve the command-line arguments, and convert them to values for the rule number
// and the timestep count.
private void processArgs (String [ ] args) {
        if (args.length != 2) {
                System.err.println ("Usage: java Life1D rule# rowcount");
                System.exit (1);
        }
        try {
                rule = new Rule (Integer.parseInt(args[0]));
        } catch (Exception ex) {
                System.err.println ("The first argument must specify a rule number.");
                System.exit (1);
        }
        try {
                stepCount = Integer.parseInt (args[1]);
        } catch (Exception ex) {
                System.err.println ("The second argument must specify the number of lines in the output.");
                System.exit (1);
        }
        if (stepCount < 1) {
                System.err.println ("The number of output lines must be a positive number.");
                System.exit (1);
        }
   }
}

 class Rule {

private int a, b, c;
private String rulebin;

public Rule (int ruleNum) {
        rulebin = convertToBinary(ruleNum);
}

private String convertToBinary(int input) // get the binary presentation as you want
{                                         // if the input is 2 you'll get "00000010"
    String binary = "";
    for (int i = 0; i < 8; i++){
      if ((1 << i & input) != 0)
        binary += "1";
      else 
          binary+= "0";
    }
    binary = new StringBuffer(binary).reverse().toString();
    return binary;
}

// Return the output that this rule prescribes for the given input.
// a, b, and c are each either 1 or 0; 4*a+2*b+c is the input for the rule.
public char output (int a, int b, int c) {    // here you want to return a char, no?
    return rulebin.charAt(7 - 4*a + 2*b + c); // there is a problem with your formula
}

}

Elior
  • 3,178
  • 6
  • 37
  • 67