Java - Check 2D Array for 3-6 of the same value - java

I have a 2D Array map[6][6] and the values are randomly generated in a for loop
This is what the output looks like (In integer values)
There are 5 different brick colors
I want to be able to check for 3-6 of the same brick color in a row (Horizontally and Vertically) when they are randomly generated, and when the user changes a brick value
I am also fairly new to Java (3 Months or so) so I would like a simple way to do this (I do not know things like objects)

Sorry for the delay John. Holiday stuff to do and guests. It's that time of year. :)
In any case. I quickly developed two run-able classes you can use to play with a method you have actually named. It's called the hasThreeInSix() even though it's not limited to any three or six that's the name we're going to give it.
Even though it's specifically designed for 2D integer Arrays it wouldn't take much effort to modify it for whatever.
The first run-able below is for testing only. It simply shows you what is going on via the output console (pane)
The second run-able is is what you may want to apply to carry out your task. Take a close look at your randomBoard() method so that you can see how we've used the hasThreeInSix() method.
Here is the code for the run-able Test Class:
import java.util.ArrayList;
import java.util.Scanner;
public class TESTThreeAndSixMethod {
public static void main(String[] args) {
Scanner userInput = new Scanner(System.in);
String input = "";
while (!input.equals("quit")) {
Echo("\nPress ENTER to generate random number blocks\n"
+ "for 2 dimensional array or enter 'quit' to exit:");
input = userInput.nextLine();
if (input.toLowerCase().equals("quit")) { System.exit(0); }
int[][] x = new int[6][6];
randomBoard(x);
}
userInput.close();
}
public static void randomBoard (int[][] x) {
int[][] map = new int[6][6];
Echo("");
for (int i = 0 ; i < x.length ; i++) {
String arrayString = "";
for (int j = 0 ; j < x[i].length ; j++) {
int tmp = 1 + (int) (Math.random () * 5);
map[i][j] = tmp;
arrayString+= String.valueOf(map[i][j]);
}
// Play with the maxHorizontal, maxVertical, and numberToCheckFor
// parameters. What you see here now will never allow any array
// row of elements contain 3 of any same consecutive single digit
// values either horizontally of vertically. Nowhere should there
// ever be any three of the same digits either vertically or hor-
// zontally. If you just want to deal with a specific number from
// 0 to 9 then change the -1 to that number.
String result = hasThreeInSix(map, i, 3, 3, -1);
if (!"".equals(result)) {
Echo(arrayString + " -- " + result);
//i--;
}
else { Echo(arrayString); }
}
}
/**
* Detect specified same single digit elements either or horizontally and or vertically within
* a 2D Array. This method is to be used during the creation of the 2D Array so as to eliminate
* specified same elements from being placed into the Array.<br><br>
*
* #param array (Integer 2D Array) the array being created.<br>
*
* #param currentIndexRow (Integer) The most currently added ROW index number.<br>
*
* #param maxHorizontal (Integer) The number of same digit elements to detect horizontally. If
* 0 is supplied then no horizontal check is done. 1 can not be supplied. If it is then the method
* simply returns null string which ultimately indicates that the array row is good. 1 is not
* permitted because this will just lead to a infinite loop.<br>
*
* #param maxVertical (Integer) The same number of digit elements to detect vertically. If 0 is
* supplied then no Vertical check is done. 1 can not be supplied. If it is then the method simply
* returns null string which ultimately indicates that the array row is good. 1 is not permitted
* because this will just lead to a infinite loop.<br>
*
* #param numberToCheckFor (Integer) The number to check for to see if there is a repetitive
* sequence horizontally or vertically within the Array. Any single digit number from 0 to 9
* can be suppled. If -1 is supplied then this method will check for repetitive sequences for
* ALL numbers from 0 to 9 both horizontally and vertically.<br>
*
* #return (String) If a null string ("") is returned then this indicates that the Array Row is
* good. If a vertical and or horizontal sequence is detected then a string is returned indicating
* either the row sequence value for horizontal detection or the rows and columns detected for
* vertical detection.
*/
public static String hasThreeInSix(int[][] array, int currentIndexRow, int maxHorizontal,
int maxVertical, int numberToCheckFor) {
String indexString = "";
int n = 1, check = numberToCheckFor;
if (maxHorizontal > 0) {
// Check for horizontal values...
String aStrg = "";
if (maxHorizontal < 2 || maxVertical < 2) {
Echo("\n\u001B[31mmaxHorizontal and or maxVertical Parameter Error!\n"
+ "\u001B[34mNeither of these parameters can be less than 2\n"
+ "otherwise an infinite loop will occure! Exiting Method!\u001B[39;49m");
return "";
}
for (int i = 0; i < array[currentIndexRow].length; i++) {
aStrg+= array[currentIndexRow][i];
}
if (numberToCheckFor == -1) { n = 10; }
for (int c = 0; c < n; c++) {
String valToCheckFor = "";
if (numberToCheckFor == -1) { check = c; }
for (int i = 1; i <= maxHorizontal; i++) {
valToCheckFor+= String.valueOf(check);
}
if (aStrg.contains(valToCheckFor)) { return "Horizontal " + maxHorizontal + " Detected! (" + aStrg + ")"; }
}
}
if (maxVertical > 0) {
// Check for vertical values...
ArrayList<String> listString = new ArrayList<>();
for (int i = 0 ; i < array.length ; i++) {
String aString = "";
for (int j = 0 ; j < array[i].length ; j++) {
aString+= String.valueOf(array[i][j]);
}
if (!"000000".equals(aString)) { listString.add(aString); }
}
n = 1; check = numberToCheckFor;
if (numberToCheckFor == -1) { n = 10; }
for (int c = 0; c < n; c++) {
if (numberToCheckFor == -1) { check = c; }
String itemToLocate = String.valueOf(check);
String foundInfo = "";
for (int i = 0; i < listString.get(0).length(); i++) {
int counter = 0;
for (int j = 0; j < listString.size(); j++) {
if (listString.get(j).substring(i,i+1).equals(itemToLocate)) {
if ("".equals(foundInfo)) { foundInfo = "Vertical " + maxVertical + " Detection in Column " + (i+1) + " On Rows: -> " + (j+1); }
else { foundInfo+= ", " + (j+1); }
counter++;
}
else {counter = 0; foundInfo = ""; }
if (counter == maxVertical) {
indexString = foundInfo;
break;
}
}
if (!"".equals(indexString)) { break; }
}
if (!"".equals(indexString)) { break; }
}
}
return indexString;
}
private static void Echo(Object object) {
System.out.println(object);
}
}
And here is the code for the runable class which contains the workable hasThreeInSix() method:
import java.util.ArrayList;
import java.util.Scanner;
public class ThreeAndSixMethod {
public static void main(String[] args) {
Scanner userInput = new Scanner(System.in);
String input = "";
while (!input.equals("quit")) {
Echo("\nPress ENTER to generate random number blocks\n"
+ "for 2 dimensional array or enter 'quit' to exit:");
input = userInput.nextLine();
if (input.toLowerCase().equals("quit")) { System.exit(0); }
int[][] x = new int[6][6];
randomBoard(x);
}
userInput.close();
}
public static void randomBoard (int[][] x) {
int[][] map = new int[6][6];
Echo("");
for (int i = 0 ; i < x.length ; i++) {
String arrayString = "";
for (int j = 0 ; j < x[i].length ; j++) {
int tmp = 1 + (int) (Math.random () * 5);
map[i][j] = tmp;
// you can remove the line below if you don't want to
// display anything in output.
arrayString+= String.valueOf(map[i][j]);
}
// Play with the maxHorizontal, maxVertical, and numberToCheckFor
// parameters. What you see here now will never allow any array
// row of elements contain 3 of any same consecutive single digit
// values either horizontally of vertically. Nowhere should there
// ever be any three of the same digits either vertically or hor-
// zontally. If you just want to deal with a specific number from
// 0 to 9 then change the -1 to that number.
String result = hasThreeInSix(map, i, 3, 3, -1);
if (!"".equals(result)) { i--; }
// You can remove the else{} line below if you
// don't want to display anything in output.
else { Echo(arrayString); }
}
}
/**
* Detect specified same single digit elements either or horizontally and or vertically within
* a 2D Array. This method is to be used during the creation of the 2D Array so as to eliminate
* specified same elements from being placed into the Array.<br><br>
*
* #param array (Integer 2D Array) the array being created.<br>
*
* #param currentIndexRow (Integer) The most currently added ROW index number.<br>
*
* #param maxHorizontal (Integer) The number of same digit elements to detect horizontally. If
* 0 is supplied then no horizontal check is done. 1 can not be supplied. If it is then the method
* simply returns null string which ultimately indicates that the array row is good. 1 is not
* permitted because this will just lead to a infinite loop.<br>
*
* #param maxVertical (Integer) The same number of digit elements to detect vertically. If 0 is
* supplied then no Vertical check is done. 1 can not be supplied. If it is then the method simply
* returns null string which ultimately indicates that the array row is good. 1 is not permitted
* because this will just lead to a infinite loop.<br>
*
* #param numberToCheckFor (Integer) The number to check for to see if there is a repetitive
* sequence horizontally or vertically within the Array. Any single digit number from 0 to 9
* can be suppled. If -1 is supplied then this method will check for repetitive sequences for
* ALL numbers from 0 to 9 both horizontally and vertically.<br>
*
* #return (String) If a null string ("") is returned then this indicates that the Array Row is
* good. If a vertical and or horizontal sequence is detected then a string is returned indicating
* either the row sequence value for horizontal detection or the rows and columns detected for
* vertical detection.
*/
public static String hasThreeInSix(int[][] array, int currentIndexRow, int maxHorizontal,
int maxVertical, int numberToCheckFor) {
String indexString = "";
int n = 1, check = numberToCheckFor;
if (maxHorizontal > 0) {
// Check for horizontal values...
String aStrg = "";
if (maxHorizontal < 2 || maxVertical < 2) {
Echo("\n\u001B[31mmaxHorizontal and or maxVertical Parameter Error!\n"
+ "\u001B[34mNeither of these parameters can be less than 2\n"
+ "otherwise an infinite loop will occure! Exiting Method!\u001B[39;49m");
return "";
}
for (int i = 0; i < array[currentIndexRow].length; i++) {
aStrg+= array[currentIndexRow][i];
}
if (numberToCheckFor == -1) { n = 10; }
for (int c = 0; c < n; c++) {
String valToCheckFor = "";
if (numberToCheckFor == -1) { check = c; }
for (int i = 1; i <= maxHorizontal; i++) {
valToCheckFor+= String.valueOf(check);
}
if (aStrg.contains(valToCheckFor)) { return "Horizontal " + maxHorizontal + " Detected! (" + aStrg + ")"; }
}
}
if (maxVertical > 0) {
// Check for vertical values...
ArrayList<String> listString = new ArrayList<>();
for (int i = 0 ; i < array.length ; i++) {
String aString = "";
for (int j = 0 ; j < array[i].length ; j++) {
aString+= String.valueOf(array[i][j]);
}
if (!"000000".equals(aString)) { listString.add(aString); }
}
n = 1; check = numberToCheckFor;
if (numberToCheckFor == -1) { n = 10; }
for (int c = 0; c < n; c++) {
if (numberToCheckFor == -1) { check = c; }
String itemToLocate = String.valueOf(check);
String foundInfo = "";
for (int i = 0; i < listString.get(0).length(); i++) {
int counter = 0;
for (int j = 0; j < listString.size(); j++) {
if (listString.get(j).substring(i,i+1).equals(itemToLocate)) {
if ("".equals(foundInfo)) { foundInfo = "Vertical " + maxVertical + " Detection in Column " + (i+1) + " On Rows: -> " + (j+1); }
else { foundInfo+= ", " + (j+1); }
counter++;
}
else {counter = 0; foundInfo = ""; }
if (counter == maxVertical) {
indexString = foundInfo;
break;
}
}
if (!"".equals(indexString)) { break; }
}
if (!"".equals(indexString)) { break; }
}
}
return indexString;
}
private static void Echo(Object object) {
System.out.println(object);
}
}
I hope this helps.

Related

Dynamic naming of variable (E1, E2, E3 ...)

I was wondering if there is a way or a library I can use to do the following:
I have an arraylist of objects where each obj has a name.
The list needs to always be unique with a maximum of 5 elements like [E1,E2,E3]
If for example the list has initial form [E3,E5] and I add an object, its name should be E1 and the list will be [E1,E3,E5] or [E3,E5,E1] it doesn't matter, as long as the name is unique and the item is added to the list starting from 1 to 5.
If add another item, it should be [E3,E5,E1,E2], always a unique name and between 1 and 5
These are my failed attempts,
StartNode node = new StartNode();
node.setName("E1");
for (int i = 0; i < circuit.getNbStartNodes(); i++) {
for (int j = 1; j <= circuit.getNbStartNodes(); j++) {
String test = ((StartNode) circuit.getStartNode(j)).getName();
if (("E"+j).equalsIgnoreCase(test) && ("E"+j).equalsIgnoreCase(node.getName()) ) {
break;
}
else
node.setName("E" + j);
}
}
/*while (t <= circuit.getNbStartNodes()) {
for (int j = 0; j < circuit.getNbStartNodes(); j++) {
String test = ((StartNode) circuit.getStartNode(j)).getName();
if (("E" + t).equalsIgnoreCase(test) || ("E" + t).equalsIgnoreCase(node.getName()))
break;
else {
node.setName("E" + t);
}
}
t++;
}
*/
/* for (int i = 1; i <= circuit.getNbStartNodes(); i++) {
for (int j = 0; j < circuit.getNbStartNodes(); j++) {
String test = ((StartNode) circuit.getStartNode(j)).getName();
if (!("E" + i).equalsIgnoreCase(test)) {
node.setName("E" + i);
t=0;
break;
}
}
if (t==0)
break;
else
continue;
*/
//String test = ((StartNode) circuit.getStartNode(i)).getName();
//for (int j = 1; j <= circuit.getNbStartNodes(); j++) {
// if (!("E" + j).equalsIgnoreCase(test))
// node.setName("E" + j);
//}
What did I do wrong in my code?
Create a small boolean array to track which names are already used and populate it with accordingly
Find the first unused element and use it as id.
boolean[] used = new boolean[circuit.getNbStartNodes()];
for (int i = 0; i < used.length; i++) {
int index = Integer.parseInt(((StartNode) circuit.getStartNode(j)).getName().substring(1)) - 1; // should be in range 0..4
used[index] = true;
}
String name = "E";
for (int i = 0; i < used.length; i++) {
if (!used[i]) {
name += String.valueOf(i + 1); // starting from 1
break;
}
}
System.out.println("free name: " + name);
StartNode node = new StartNode();
node.setName(name);
// add new node to circuit, etc.
With small values, Alex' solution works fine.
However, if you ever come across a use case where the number of elements become potentially large, then you could use a TreeSet to keep track of the unused numbers. Further, the nextCeilValue is the next number to pick when there are no removed numbers.
In the below code, I have created a UniqueNumber class, which is able to get the next number, or remove a given number. Note that this code provides integers starting from 0. Of course, you could easily convert this to your E-numbers using the function i -> "E" + (i + 1).
public class UniqueNumber {
private int nextCeilValue;
private final TreeSet<Integer> removedNumbers = new TreeSet<>(Integer::compare);
public int get() {
if (removedNumbers.isEmpty()) {
return nextCeilValue++;
}
else {
int number = removedNumbers.first();
removedNumbers.remove(number);
return number;
}
}
public boolean remove(int number) {
if (number < 0 || number > nextCeilValue) {
return false;
}
if (number == nextCeilValue) {
nextCeilValue--;
}
else {
removedNumbers.add(number);
}
return true;
}
public int size() {
return nextCeilValue - removedNumbers.size();
}
}
In order to test this, we first need to simulate your initial situation. In our integer-starting-from-zero-world, we need the numbers 2 and 4 (representing E3 and E5). In below code, we need to call get five times, and then remove element 0, 1 and 3. Of course, we could have created a UniqueNumber(int... initialValues) constructor which does this under the hood.
UniqueNumber un = new UniqueNumber();
for (int i = 0; i < 5; i++) {
un.get();
}
un.remove(0); // Remove E1
un.remove(1); // Remove E2
un.remove(3); // Remove E4
In order to get the next value, simply use this:
StartNode node = new StartNode();
node.setName("E" + (un.get() + 1));

Error launching my program, how can i fix it?

I have this assignment for my university https://cs1331.gitlab.io/fall2018/hw2/hw2-source-model.html. I wrote the code but when I run the program I get this message at the console :
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: begin 0, end -1, length 2
at java.base/java.lang.String.checkBoundsBeginEnd(String.java:3107)
at java.base/java.lang.String.substring(String.java:1873)
at homework1.SourceModel.main(SourceModel.java:127)
Here is my code for this assignment with comments :
package homework1;
import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;
public class SourceModel {
//initialize variables so they can be accessed everywhere
private String modelName;
private int[][] characterCount;
private double[] rowCount;
private double[][] probability;
/**
*
* #param name takes the name of the corpus
* #param fileName takes the filesName of corpus
*/
public SourceModel(String name, String fileName) {
modelName = name;
characterCount = new int[26][26];
rowCount = new double[26];
probability = new double[26][26];
System.out.println("Training " + name + "model...");
try {
Scanner scan = new Scanner(new File(fileName));
String temp = "";
//append all of the text
while (scan.hasNext()) {
temp += scan.next();
}
//only keeps the letters and makes them lowercase
temp = temp.replaceAll("[^A-Za-z]+", "").toLowerCase();
System.out.println(temp);
//iterates trough each letter then puts the letters
//sequence to the respective row and column
for (int i = 0; i < (temp.length() - 1); i++) {
char firstLetter = temp.charAt(i);
char secondLetter = temp.charAt(i + 1);
//index based on ASCII values
characterCount[(int) firstLetter - 97][(int) secondLetter - 97]++;
rowCount[(int) firstLetter - 97]++;
}
//calculates the probability by dividing the count
//by the total counts in each row
for (int i = 0; i < probability.length; i++) {
for (int j = 0; j < probability[i].length; j++) {
if (rowCount[i] == 0) {
rowCount[i] = 0.01;
}
probability[i][j] = (((double) characterCount[i][j]) / rowCount[i]);
if (probability[i][j] == 0) {
probability[i][j] = 0.01;
}
}
}
System.out.println("done");
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
}
/**
*
* #return a string which contains the name
*/
public String getName() {
return modelName;
}
/**
* #return a string with the matrix
*/
public String toString() {
String matrix = "";
matrix += "";
for (int i = 97; i < 123; i++) {
matrix += " ";
matrix += (char) i;
}
matrix += ("\n");
for (int i = 0; i < probability.length; i++) {
matrix += ((char) (i + 97) + " ");
for (int j = 0; j < probability[i].length; j++) {
matrix += String.format("%.2f", probability[i][j]);
matrix += ("");
}
matrix += "\n";
}
return matrix;
}
/**
*
* #param test a set of letters to test
* #return the probability for the word
*/
public double probability(String test) {
test = test.replaceAll("[^A-Za-z]+", "").toLowerCase();
double stringProbability = 1.0;
for (int i = 0; i < test.length() - 1; i++) {
int firstIndex = (int) (test.charAt(i)) - 97;
int secondIndex = (int) (test.charAt(i + 1)) - 97;
stringProbability *= probability[firstIndex][secondIndex];
}
return stringProbability;
}
/**
*
* #param args the command line arguments
*/
public static void main(String[] args) {
SourceModel[] models = new SourceModel[args.length - 1];
for (int i = 0; i < args.length - 1; i++) {
models[i] = new SourceModel(args[i].substring(0, args[i].indexOf(".")), args[i]);
}
System.out.println("Analyzing: " + args[args.length - 1]);
double[] normalizedProbability = new double[args.length - 1];
double sumProbability = 0;
for (int i = 0; i < args.length - 1; i++) {
sumProbability += models[i].probability(args[args.length - 1]);
}
//normalize the probability in respect to the values given
for (int i = 0; i < normalizedProbability.length; i++) {
normalizedProbability[i] = models[i].probability(args[args.length - 1]) / sumProbability;
}
int highestIndex = 0;
for (int i = 0; i < args.length - 1; i++) {
System.out.print("Probability that test string is");
System.out.printf("%9s: ", models[i].getName());
System.out.printf("%.2f", normalizedProbability[i]);
System.out.println("");
if (normalizedProbability[i] > normalizedProbability[highestIndex]) {
highestIndex = i;
}
}
System.out.println("Test string is most likely " + models[highestIndex].getName() + ".");
}
}
Others have already pointed this out, but for this line:
models[i] = new SourceModel(args[i].substring(0, args[i].indexOf(".")), args[i]);
the substring method is apparently causing the problem because indexOf returns -1 if the . isn't found.
In this case, though, the code actually isn't the problem, since the assignment states that you can assume that the file names are of the form <source-name>.corpus. That being said, really, all of the command line parameters should have a . in them, so this shouldn't be happening.
I'd check to see what command line parameters you're passing. One guess I have is that you might have a file name with a space in it or something. For example, if you passed English GB.corpus, then this would show up as 2 separate arguments (one of which doesn't have a .).
Edit: As #Pshemo pointed out in the comments, if you have a file name that has a space in it, you can just put it in quotes so that it'll be interpreted as a single command line parameter - for example, instead of English GB.corpus, write "English GB.corpus". That'll prevent the exception.
In your main method, you have:
args[i].indexOf(".")
The dot (.) is not found so it returns -1.
You try to create a substring:
models[i] = new SourceModel(args[i].substring(0, args[i].indexOf(".")), args[i]);
But since args[i].indexOf(".") is invalid, it throws an exception.
What you can do is check if the dot (.) exists, if yes continue:
if(args[i].contains(".")){
models[i] = new SourceModel(args[i].substring(0, args[i].indexOf(".")), args[i]);
}

int array toString method that displays the values with spaces in between and a new line every ten values

I am a beginner when it comes to java and am having some issues(been sitting in front of this all day). I have searched far and wide for a solution, yet to no avail. My professor has asked me to fill out the blank methods, and I am especially having trouble with the toString method(although I am not feeling to good about the rest either), any help would be appreciated.
import java.util.Random;
public class SmartArray {
// declare an array of ints
int[] list;
Random r = new Random();
int pos = 0;
/**
* Creates and initializes an array of size n. It does not initialize the
* contents of the array.
*/
public SmartArray(int n) {
list = new int[n];
}
/**
*
* Initializes the contents of the array with random
*
* non-negative* numbers.
*
*/
public void initRandom() {
int i = 0;
int hold = 0;
while (i < list.length) {
hold = r.nextInt();
if (hold % 2 == 0) {
list[i] = hold;
i++;
} else {
hold = hold + 1;
list[i] = hold;
i++;
}
}
}
/**
*
* Allows client code to add an element to the array
*
* at the given position. Throws an ArrayIndexOutOfBounds
*
* exception with a message if the
*
* position is out of bounds.
*
*/
public void insert(int value, int pos) {
if (list.length > pos) {
list[pos] = value;
} else {
throw new ArrayIndexOutOfBoundsException("The position of your value is greater than the array");
}
}
/**
*
* Returns the position of target if target is
*
* one of the values in the array, otherwise -1.
*
* Implemented with a loop.
*
*/
public int find(int target) {
int position = 0;
for (int i = 0; i < list.length; i++) {
if (list[i] == target) {
position = i;
} else {
position = -1;
}
}
return position;
}
/**
*
* Same as the find method, except that it's implemented
*
* using recursion. (Hint: use a helper method.)
*
*/
public int recursiveFind(int pos, int target) {
if (pos >= list.length) {
return -1;
} else if (list[pos] == target) {
return pos;
} else {
return recursiveFind(pos + 1, target);
}
}
/**
*
* Returns the elements of the array, separated by
*
* spaces, with a newline after every 10 elements,
*
* so they can be easily displayed.
*
*/
public String toString() {
String listString = "";
int pos = 0;
for (int i = 0; i < list.length; i++) {
//list[i].toString();
listString = listString + (String) list[i] + " ";
pos++;
if (pos > 9) {
list = list + "\n";
pos = 0;
}
return listString;
}
}
}
Your method looks almost fine.
To add the newline, you should check for the remainder of the index.
You're also returning the resulting String inside the loop. You should only return after it.
public String toString() {
String listString = "";
for (int i = 0; i<list.length; i++){
listString = listString + (String)list[i] + " ";
if (i%9 == 0){ // if remainder of i%9 = 0, then add a newline
list = list + "\n";
}
}
return listString;
}
I don't want to give too much away since it's an academic assignment, but instead of pos, consider mod (%), which you use, so I know you're familiar with it.
Consider starting i at 1 and iterating through all values (no need to take 10 at a time). But test for the need for a newline like this:
i % 10 == 0
Whenever the ith value is divisible by 10, insert a newline.
Also, consider using Integer instead of int. In this way, you could simply do this:
listString = listString + list[i].toString() + " ";
Take a look at this post on SO.
Good luck!
How about:
public String toString() {
String listString = "";
for (int i = 1; i < list.length; i++) {
listString += list[i - 1] + (i % 10 == 0 ? "\n" : " ");
}
return listString;
}

Java Program : Generate christmas tree : formatting?

So in my CS class, we have a little hw question and it isn't due for a week or so and it almost works except one little piece. Here is the assignment:
Write a program named ChrisTree that produces images of Christmas trees as output. It should have a method with two parameters: one for the number of segments in the tree and one for the height of each segment. For example, the tree shown here on the left has three segments of height 4 and the one on the right has two segments of height 5.
So my code works except on some trees where the last line of the tree is and the trunk are both off by a space. I can't seem to plug up that hole without making a new one. Any one see a possible "root" of the issue? PS the tree segments and heights are variable by changing class constants (I know, its a terrible method of changing them, but thats what this guy wants)(I know its probably horribly redundant as well)
public class ChrisTree {
public static final int SEGMENTS = 4;
public static final int HEIGHT = 4;
public static void main(String[] args){
makeTree();
}
// makeTree: code that prints the tree; params: num. of segments of tree, height of tree segments
public static void makeTree(){
// maxStars: calculation the length of each line which is the sum of spaces and stars for any line
int maxStars = 2*HEIGHT+2*SEGMENTS-3;
// maxStr: master variable string that will be changed and printed for each line
String maxStr = "";
// populates maxStr will spaces; will be used with substring to generate needed spaces
for (int len=0; len < maxStars; len++){
maxStr+=" ";
}
// loops once per segment
for (int i=1; i <= SEGMENTS; i++){
// starStr: variable string that changes perline that holds the stars
// populates starStr with stars
// loops through each line
for (int line=1; line <= HEIGHT; line++){
String starStr = "";
for (int j=1; j <= 2*line+2*i-3; j++){
starStr+="*";
}
for (int space=0; space <= maxStars-(HEIGHT+line+i); space++){
starStr = " " + starStr;
}
System.out.println(starStr);
}
}
for (int i=0; i <= maxStars/2;i++){
System.out.print(" ");
}
System.out.print("*\n");
for (int i=0; i <= maxStars/2;i++){
System.out.print(" ");
}
System.out.print("*\n");
for (int i=0; i <= maxStars/2-3;i++){
System.out.print(" ");
}
System.out.print("*******\n");
}
}
In my defense of doing obvious homework problems, the solutions here just hurt my eyes too much. (And I know these are standard homework problems, I did them back in the 80's, in Pascal).
package com.edwinbuck.christmas;
/**
* Draws a ChristmasTree.
* #author Edwin Buck
*/
public class ChristmasTree {
public static final int SEGMENTS = 4;
public static final int HEIGHT = 4;
public static void main(String[] args) {
int maxSize = 1 + 2 * (SEGMENTS - 1) + 2 * (HEIGHT - 1);
// for each segment beyond zero, we need 2 more asterisks.
for (int segmentContrib = 0; segmentContrib < 2 * SEGMENTS; segmentContrib += 2) {
// for each segment slice beyond zero, we need 2 more asterisks.
for (int sliceContrib = 0; sliceContrib < 2 * HEIGHT; sliceContrib += 2) {
drawCentered(maxSize, 1 + segmentContrib + sliceContrib);
}
}
// draw the trunk
drawCentered(maxSize, 1);
drawCentered(maxSize, 1);
// draw the base
drawCentered(maxSize, 7);
}
/**
* Draws a line of asterisks, centered within size spaces.
*
* #param size The size to center on.
* #param asterisks The number of asterisks to draw.
*/
private static void drawCentered(int size, int asterisks) {
int before = (size - asterisks) / 2;
int after = size - before - asterisks;
print(before, " ");
print(asterisks, "*");
print(after, " ");
System.out.println();
}
/**
* Draws a character a number of times.
*
* #param count The number of time to draw the character.
* #param character The character to draw.
*/
private static void print(int count, final String character) {
for (int i = 0; i < count; i++) {
System.out.print(character);
}
}
}
The key is to realize that all of the lines are centered asterisks of variable size. Once you do that, then you only need to figure out the loop to draw the sections (and the maximum line size).
The maximum line size is controlled by the bottom most section. Each input (SEGMENTS and HEIGHT) needs to be converted from "count from 1" to "count from 0". Each additional segment adds two to the asterisk size, as does each additional slice. The tree must have at least one asterisk, the one (trunk) running down the center. This leads to the formula
1 + 2*(SEGMENTS-1) + 2(HEIGHT-1)
which many have simplified to
2*SEGMENTS + 2*HEIGHT - 3
I didn't simplify it because it hides intent, something that's hard to recover in code once lost.
Then while walking through the loops, I decided to have the contributors to the size increment by two. It makes the rest of the math easier as we don't have to put "magic" formulas and math in odd places. This means that we can reuse our drawCentered(...) with the parameter 1 + segmentContrib + sliceContrib where the two other variables are the segment and slice "asterisk" contributions.
Finally, we draw a trunk of two vertical asterisks and the base.
I know this is extremely late, but I just wrote this and it worked.
public class ChrisTree {
public static final int SEGMENTS = 4;
public static final int HEIGHT = 4;
public static void main(String[] args) {
makeTree();
}
public static void makeTree() {
int maxStars = 2 * HEIGHT + 2 * SEGMENTS - 3;
String maxStr = "";
for (int l = 0; l < maxStars; l++) {
maxStr += " ";
}
for (int i = 1; i <= SEGMENTS; i++) {
for (int line = 1; line <= HEIGHT; line++) {
String starStr = "";
for (int j = 1; j <= 2 * line + 2 * i - 3; j++) {
starStr += "*";
}
for (int space = 0; space <= maxStars - (HEIGHT + line + i); space++) {
starStr = " " + starStr;
}
System.out.println(starStr);
}
}
for (int i = 0; i <= maxStars / 2; i++) {
System.out.print(" ");
}
System.out.println(" " + "*" + " ");
for (int i = 0; i <= maxStars / 2; i++) {
System.out.print(" ");
}
System.out.println(" " + "*" + " ");
for (int i = 0; i <= maxStars / 2 - 3; i++) {
System.out.print(" ");
}
System.out.println(" " + "*******");
}
}

Strange Stack Overflow Error in Sudoko Backtracker

(Disclaimer: There are maybe 20 different versions of this question on SO, but a reading through most of them still hasn't solved my issue)
Hello all, (relatively) beginner programmer here. So I've been trying to build a Sudoku backtracker that will fill in an incomplete puzzle. It seems to works perfectly well even when 1-3 rows are completely empty (i.e. filled in with 0's), but when more boxes start emptying (specifically around the 7-8 column in the fourth row, where I stopped writing in numbers) I get a Stack Overflow Error. Here's the code:
import java.util.ArrayList;
import java.util.HashSet;
public class Sudoku
{
public static int[][] puzzle = new int[9][9];
public static int filledIn = 0;
public static ArrayList<Integer> blankBoxes = new ArrayList<Integer>();
public static int currentIndex = 0;
public static int runs = 0;
/**
* Main method.
*/
public static void main(String args[])
{
//Manual input of the numbers
int[] completedNumbers = {0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,3,4,
8,9,1,2,3,4,5,6,7,
3,4,5,6,7,8,9,1,2,
6,7,8,9,1,2,3,4,5,
9,1,2,3,4,5,6,7,8};
//Adds the numbers manually to the puzzle array
ArrayList<Integer> completeArray = new ArrayList<>();
for(Integer number : completedNumbers) {
completeArray.add(number);
}
int counter = 0;
for(int i = 0; i < 9; i++) {
for(int j = 0; j < 9; j++) {
puzzle[i][j] = completeArray.get(counter);
counter++;
}
}
//Adds all the blank boxes to an ArrayList.
//The index is stored as 10*i + j, which can be retrieved
// via modulo and integer division.
boolean containsEmpty = false;
for(int i = 0; i < 9; i++) {
for(int j = 0; j < 9; j++) {
if(puzzle[i][j] == 0) {
blankBoxes.add(10*i + j);
containsEmpty = true;
}
}
}
filler(blankBoxes.get(currentIndex));
}
/**
* A general method for testing whether an array contains a
* duplicate, via a (relatively inefficient) sort.
* #param testArray The int[] that is being tested for duplicates
* #return True if there are NO duplicate, false if there
* are ANY duplicates.
*/
public static boolean checkDupl(int[] testArray) {
for(int i = 0; i < 8; i++) {
int num = testArray[i];
for(int j = i + 1; j < 9; j++) {
if(num == testArray[j] && num != 0) {
return false;
}
}
}
return true;
}
/**
* If the puzzle is not full, the filler will be run. The filler is my attempt at a backtracker.
* It stores every (i,j) for which puzzle[i][j] == 0. It then adds 1 to it's value. If the value
* is already somewhere else, it adds another 1. If it is 9, and that's already there, it loops to
* 0, and the index beforehand is rechecked.
*/
public static void filler(int indexOfBlank) {
//If the current index is equal to the size of blankBoxes, meaning that we
//went through every index of blankBoxes, meaning the puzzle is full and correct.
runs++;
if(currentIndex == blankBoxes.size()) {
System.out.println("The puzzle is full!" + "\n");
for(int i = 0; i < 9; i++) {
System.out.println();
for(int j = 0; j < 9; j++) {
System.out.print(puzzle[i][j]);
}
}
System.out.println("\n" + "The filler method was run " + runs + " times");
return;
}
//Assuming the puzzle isn't full, find the row/column of the blankBoxes index.
int row = blankBoxes.get(currentIndex) / 10;
int column = blankBoxes.get(currentIndex) % 10;
//Adds one to the value of that box.
puzzle[row][column] = (puzzle[row][column] + 1);
//Just used as a breakpoint for a debugger.
if(row == 4 && column == 4){
int x = 0;
}
//If the value is 10, meaning it went through all the possible values:
if(puzzle[row][column] == 10) {
//Do filler() on the previous box
puzzle[row][column] = 0;
currentIndex--;
filler(currentIndex);
}
//If the number is 1-9, but there are duplicates:
else if(!(checkSingleRow(row) && checkSingleColumn(column) && checkSingleBox(row, column))) {
//Do filler() on the same box.
filler(currentIndex);
}
//If the number is 1-9, and there is no duplicate:
else {
currentIndex++;
filler(currentIndex);
}
}
/**
* Used to check if a single row has any duplicates or not. This is called by the
* filler method.
* #param row
* #return
*/
public static boolean checkSingleRow(int row) {
return checkDupl(puzzle[row]);
}
/**
* Used to check if a single column has any duplicates or not.
* filler method, as well as the checkColumns of the checker.
* #param column
* #return
*/
public static boolean checkSingleColumn(int column) {
int[] singleColumn = new int[9];
for(int i = 0; i < 9; i++) {
singleColumn[i] = puzzle[i][column];
}
return checkDupl(singleColumn);
}
public static boolean checkSingleBox(int row, int column) {
//Makes row and column be the first row and the first column of the box in which
//this specific cell appears. So, for example, the box at puzzle[3][7] will iterate
//through a box from rows 3-6 and columns 6-9 (exclusive).
row = (row / 3) * 3;
column = (column / 3) * 3;
//Iterates through the box
int[] newBox = new int[9];
int counter = 0;
for(int i = row; i < row + 3; i++) {
for(int j = row; j < row + 3; j++) {
newBox[counter] = puzzle[i][j];
counter++;
}
}
return checkDupl(newBox);
}
}
Why am I calling it a weird error? A few reasons:
The box that the error occurs on changes randomly (give or take a box).
The actual line of code that the error occurs on changes randomly (it seems to usually happen in the filler method, but that's probably just because that's the biggest one.
Different compilers have different errors in different boxes (probably related to 1)
What I assume is that I just wrote inefficient code, so though it's not an actual infinite recursion, it's bad enough to call a Stack Overflow Error. But if anyone that sees a glaring issue, I'd love to hear it. Thanks!
Your code is not backtracking. Backtracking implies return back on failure:
if(puzzle[row][column] == 10) {
puzzle[row][column] = 0;
currentIndex--;
filler(currentIndex);// but every fail you go deeper
}
There are must be something like:
public boolean backtrack(int currentIndex) {
if (NoBlankBoxes())
return true;
for (int i = 1; i <= 9; ++i) {
if (NoDuplicates()) {
puzzle[row][column] = i;
++currentIndex;
if (backtrack(currentIndex) == true) {
return true;
}
puzzle[row][column] = 0;
}
}
return false;
}

Categories

Resources