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(" " + "*******");
}
}
Related
I am assigning 3 chars (two 'T's and one 'S') to a 10 x 10 grid. I have that down but I want to know how I could re randomize the char's positions if they end up on the same spot. Basically I am creating a little game where I am a soldier (S) and am on a grid with two Targets (T). Eventually I will have to eliminate the targets but I fist I want to make sure each one ends up in it's own spot. here is my code
import java.lang.Math;
public class PaintBall_Thomas{
public static void fillGrid(char[][] battleField){
for ( int i = 0; i < battleField.length; i++){
for ( int j = 0; j < battleField[i].length; j++){
battleField[i][j] = '-';
}
}
battleField[((int)(Math.random()*10))][((int)(Math.random()*10))] = 'S';//assigns a random number between 1-10 and assigns it to either soldier/target
battleField[((int)(Math.random()*10))][((int)(Math.random()*10))] = 'T';
battleField[((int)(Math.random()*10))][((int)(Math.random()*10))] = 'T';
for ( int i = 0; i < battleField.length; i++){
for ( int j = 0; j < battleField[i].length; j++){
System.out.print(battleField[i][j] + " ");
}
System.out.println();
}
}//end of fillGrid method
public static void main(String[] args) {
int columns = 10;
int rows = 10;
System.out.println("----------GRID----------");
//end of main
char[][] battleField = new char [rows][columns];
fillGrid(battleField);
}
}
this could be a good use for recursion, so like
public void addChar(char type) {
int row = (int)(Math.random() * battleField.length); // choose rand spot
int col = (int)(Math.random() * battleField.length);
if (battleField[row][col] == '-') { // if chosen space is free
battleField[row][col] = type; // add it
} else {
addChar(type) // try again if space was occupied
}
}
so this could have some problems... such as possibilities of getting a stack overflow if the board is already full... but if the method's only intended use is to add the two Ts and one S, it should be fine
so you could just add them like
addChar('T');
addChar('T');
addChar('S');
and none of the chosen spots will be duplicates
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]);
}
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.
So, I have been making this Tic Tac Toe program for a while now.
It's a basic Tic Tac Toe game but the game board is scalable. The program is almost finished but one little feature is missing.
I have to make the game end if player gets five or more marks in a row when the game board is larger than 4x4.
F.E. If the game board is 9x9 the game has to end when the player or the computer gets five marks in a row.
(Mark = "O" or "X").
The game now ends when someone gets marks in a row equals to the size of the board (if 9x9 you need 9 marks in a row to win).
I have to implement a feature in the playerHasWon and I've been having a lot of trouble finding out how. I think it's a simple to implement thing but I have not found out how to do it.
Hope my explanation is easy enough to understand. Here's the code:
package tictac;
import java.util.Scanner;
import java.util.Random;
public class Tictac {
public static final int DRAW = 0; // game ends as a draw
public static final int COMPUTER = 1; // computer wins
public static final int PLAYER = 2; // player wins
public static final char PLAYER_MARK = 'X'; // The "X"
public static final char COMPUTER_MARK = 'O'; // The "O"
public static int size; // size of the board
public static String[][] board; // the board itself
public static int score = 0; // game win score
public static Scanner scan = new Scanner(System.in); // scanner
/**
* Builds the board with the integer size and user input.
*
* Displays game win message and switches play turns.
*
* #param args the command line parameters. Not used.
*/
public static void main(String[] args) {
while (true) {
System.out.println("Select board size");
System.out.print("[int]: ");
try {
size = Integer.parseInt(scan.nextLine());
} catch (Exception e) {
System.out.println("You can't do that.");
continue; // after message, give player new try
}
break;
}
int[] move = {};
board = new String[size][size];
setupBoard();
int i = 1;
loop: // creates the loop
while (true) {
if (i % 2 == 1) {
displayBoard();
move = getMove();
} else {
computerTurn();
}
switch (isGameFinished(move)) {
case PLAYER:
System.err.println("YOU WIN!");
displayBoard();
break loop;
case COMPUTER:
System.err.println("COMPUTER WINS!");
displayBoard();
break loop;
case DRAW:
System.err.println("IT'S A DRAW");
displayBoard();
break loop;
}
i++;
}
}
/**
* Checks for game finish.
*
* #param args command line parameters. Not used.
*
* #return DRAW the game ends as draw.
* #return COMPUTER the game ends as computer win.
* #return PLAYERE the game ends as player win.
*/
private static int isGameFinished(int[] move) {
if (isDraw()) {
return DRAW;
} else if (playerHasWon(board, move,
Character.toString(COMPUTER_MARK))) {
return COMPUTER;
} else if (playerHasWon(board, move,
Character.toString(PLAYER_MARK))) {
return PLAYER;
}
return -1; // can't be 0 || 1 || 2
}
/**
* Checks for win for every direction on the board.
*
* #param board the game board.
* #param move move on the board.
* #param playerMark mark on the board "X" or "O".
* #return the game is won.
*/
public static boolean playerHasWon(String[][] board, int[] move,
String playerMark) { //playermark x || o
// horizontal check
for (int i = 0; i < size; i++) {
if (board[i][0].equals(playerMark)) {
int j;
for (j = 1; j < size; j++) {
if (!board[i][j].equals(playerMark)) {
break;
}
}
if (j == size) {
return true;
}
}
}
// vertical check
for (int i = 0; i < size; i++) {
if (board[0][i].equals(playerMark)) {
int j;
for (j = 1; j < size; j++) {
if (!board[j][i].equals(playerMark)) {
break;
}
}
if (j == size) {
return true;
}
}
}
// diagonals check
int i;
for (i = 0; i < size; i++) {
if (!board[i][i].equals(playerMark)) {
break;
}
}
if (i == size) {
return true;
}
for (i = 0; i < size; i++) {
if (!board[i][(size - 1) - i].equals(playerMark)) {
break;
}
}
return i == size;
}
/**
* Checks for draws.
*
* #return if this game is a draw.
*/
public static boolean isDraw() {
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
if (board[i][j] == " ") {
return false;
}
}
}
return true;
}
/**
* Displays the board.
*
*
*/
public static void displayBoard() {
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
System.out.printf("[%s]", board[i][j]);
}
System.out.println();
}
}
/**
* Displays the board.
*
*
*/
public static void setupBoard() {
for (int i = 0; i < size; i++) {
for (int j = 0; j < size; j++) {
board[i][j] = " ";
}
}
}
/**
* Takes in user input and sends it to isValidPlay.
*
* #return null.
*/
public static int[] getMove() {
Scanner sc = new Scanner(System.in);
System.out.println("Your turn:");
while (true) {
try {
System.out.printf("ROW: [0-%d]: ", size - 1);
int x = Integer.parseInt(sc.nextLine());
System.out.printf("COL: [0-%d]: ", size - 1);
int y = Integer.parseInt(sc.nextLine());
if (isValidPlay(x, y)) {
board[x][y] = "" + PLAYER_MARK;
return new int[]{x, y};
} else { // if input is unallowed
System.out.println("You can't do that");
continue; // after message, give player new try
}
} catch (Exception e) {
System.out.println("You can't do that.");
}
return null;
}
}
/*
* Randomizes computer's turn, where it inputs the mark 'O'.
*
*
*/
public static void computerTurn() {
Random rgen = new Random(); // Random number generator
while (true) {
int x = (int) (Math.random() * size);
int y = (int) (Math.random() * size);
if (isValidPlay(x, y)) {
board[x][y] = "" + COMPUTER_MARK;
break;
}
}
}
/**
* Checks if a move is possible.
*
* #param inX x-move is out of bounds.
* #param inY y-move is out of bounds.
* #return false
*/
public static boolean isValidPlay(int inX, int inY) {
// Play is out of bounds and thus not valid.
if ((inX >= size) || (inY >= size)) {
return false;
}
// Checks if a play have already been made at the location,
// and the location is thus invalid.
return (board[inX][inY] == " ");
}
}
// End of file
Took a quick look, detected the problem and came up with a quick fix:
public static boolean checkDiagonal(String markToLook) {
// how many marks are we looking for in row?
int sizeToWin = Math.min(size, 5);
// running down and right
// don't need to iterate rows that can't be the starting point
// of a winning diagonal formation, thus can exlude some with
// row < (size - (sizeToWin - 1))
for (int row = 0; row < (size - (sizeToWin - 1)); row++) {
for (int col = 0; col < size; col++) {
int countOfMarks = 0;
// down and right
for (int i = row; i < size; i++) {
if (board[i][i] == null ? markToLook == null :
board[i][i].equals(markToLook)) {
countOfMarks++;
if (countOfMarks >= sizeToWin) {
return true;
}
}
}
countOfMarks = 0;
// down and left
for (int i = row; i < size; i++) {
if (board[i][size - 1 - i] == null ? markToLook == null :
board[i][size - 1 - i].equals(markToLook)) {
countOfMarks++;
if (countOfMarks >= sizeToWin) {
return true;
}
}
}
}
}
return false;
}
And call it from your PlayerHasWon method instead of performign the checks there. Basically we iterate each possible starting square on the board for a diagonal winning formation, and run check down+left and down+right for each of the squares.
I am in awful hurry and did not test it much, but will return in couple of hours to improve this solution. Seems to work.
Edit: My previous solution I found lacking in further tests, I've updated the above code to function as desired.
First, I think playerMark should be a char and not a String. That said, let's go for the answer. The "horizontal" case would be:
// This is the number of marks in a row required to win
// Adjust formula if necessary
final int required = size > 4 ? 5 : 3;
for (int i = 0; i < size; i++) {
int currentScore = 0;
for (j = 0; j < size; j++) {
if (board[i][j].equals(playerMark)) {
currentScore++;
if (currentScore >= required)
return true;
}
else {
currentScore = 0;
}
}
}
}
The vertical case would be analogous. The diagonal one is a bit trickier as now it would require board[i][i+k] for the main diagonal and board[i][k-i] for the secondary; and it may not be obvious which values k and i must traverse. Here's my attempt (variable required as in horizontal case):
Note: everything from here down has been completely rewritten on 2015-12-16. The previous versions didn't work and the algorithm was not explained.
After two failed attempts I decided to do my homework and actually sort things out instead of doing everything in my head thinking I can keep track of all variables. The result is this picture:
Main diagonals are painted in blue, secondary diagonals in green.
Each diagonal is identified by a value of k, with k=0 being always being the longest diagonal of each set. Values of k grow as diagonals move down, so diagonals above the longest one have negative k while diagonals below the longest one have positive k.
Things that hold for both diagonals:
Diagonal contains size-abs(k) elements. Diagonals in which size-abs(k) is less than required need not be searched. This means that, for board size size and required length required, we'll search values of k from required-size to size-required. Notice that these have the same absolute value, with the first being <=0 and the second >=0. These values are both zero only when required==size, i.e. when we need the full diagonal to claim a win, i.e. when we only need to search k=0.
For k<=0, possible values of i (row) go from 0 to size+k. Values greater than or equal to size+k cross the right edge of the board and are thus outside the board.
For k>=0, possible values of i (row) go from k to size. Values below k cross the left edge of the board and are thus outside the board.
Only for main (blue) diagonals:
Value of j (column) is k+i.
Only for secondary (green) diagonals:
Value of j (column) is size-1+k-i. In case this is not obvious, just pick the top right corner (k=0,i=0) and notice j=size-1. Then notice that adding 1 to k (keeping i constant) always moves j by 1 right (it would go out of the board if done from k=0,i=0, just think about the intersection of horizontal line i=0 with diagonal k=1), and adding 1 to i (keeping k constant) always moves j by 1 to the left.
The ressulting code would be:
// Main diagonal
for (int k = required - size; k < size - required; k++)
{
int currentScore = 0;
startI = Math.max (0, k);
endI = Math.min (size, size+k);
for (int i = startI, i < endI; i++)
{
if (board[i][k+i].equals (playerMark))
{
currentScore++;
if (currentScore >= required)
return true;
}
else
currentScore = 0;
}
}
// Secondary diagonal
for (int k = required - size; k < size - required; k++)
{
int currentScore = 0;
startI = Math.max (0, k);
endI = Math.min (size, size+k);
for (int i = startI, i < endI; i++)
{
if (board[i][size-1+k-i].equals (playerMark))
{
currentScore++;
if (currentScore >= required)
return true;
}
else
currentScore = 0;
}
}
At this point, the code is nearly identical in both cases, changing only the j index in board[i][j]. In fact, both loops could be merged, taking care only of keeping two currentScore variables, one for the main (blue) diagonal and the other for the secondary (green) diagonal.
I've tried running this, but printing out circleCounter only prints 0. If I were to put the counter code under the tester function in the bottom part, then it would work. What am I doing wrong? Am I missing out on something?
public class Project1 {
public int circleCounter; // Number of non-singular circles in the file.
public int posFirstLast; // Indicates whether the first and last circles overlap or not.
public double maxArea; // Area of the largest circle (by area).
public double minArea; // Area of the smallest circle (by area).
public double averageArea; // Average area of the circles.
public double stdArea; // Standard deviation of area of the circles.
public double medArea; // Median of the area.
public int stamp = 189375;
public Project1() {
// This method is complete.
}
public void results(String fileName) {
MaInput F1 = new MaInput("DataFile.data");
double x, y, rad;
int circleCounter = 0;
double sumArea = 0;
Circle A = new Circle();
while (!F1.atEOF()) {
x = F1.readDouble();
y = F1.readDouble();
rad = F1.readDouble();
circleCounter++;
if (A.area() > maxArea) {
maxArea = A.area();
}
if (A.area() < minArea) {
minArea = A.area();
}
sumArea += A.area();
averageArea = sumArea / circleCounter;
stdArea = Math.sqrt((Math.pow(A.area() - averageArea, 2) / circleCounter));
//Array for points
Circle[] points = new Circle[circleCounter];
for (int j = 0; j < points.length; j++) {
if (rad > Point.GEOMTOL) {
points[j] = A;
}
}
posFirstLast = points[1].overlap(points[points.length]);
//Array of areas
double[] areas = new double[circleCounter];
for (int i = 0; i < areas.length; i++) {
if (rad > Point.GEOMTOL) {
areas[i] = A.area();
}
}
//Bubble Sort
for (int i = 0; i < areas.length; i++) {
if (areas[i + 1] < areas[i]) {
double temp = areas[i + 1];
areas[i + 1] = areas[i];
areas[i] = temp;
}
}
//Median
if (areas.length % 2 == 0) {
medArea = (0 / 5) * (areas[(areas.length / 2) - 1] + areas[areas.length / 2]);
} else {
medArea = (0.5) * (areas[((areas.length) - 1) / 2]);
}
}
}
public static void main(String args[]) {
Project1 pleasework = new Project1();
System.out.println("Number of (non-singular) circles: " + pleasework.circleCounter);
System.out.println("Whether the first and last circles overlap: " + pleasework.posFirstLast);
System.out.println("Maximum Area: " + pleasework.maxArea);
System.out.println("Minimum Area: " + pleasework.minArea);
System.out.println("Average Area: " + pleasework.averageArea);
System.out.println("Standard deviation of the areas: " + pleasework.stdArea);
System.out.println("Median of the areas: " + pleasework.medArea);
}
}
So, if it's only your circleCounter that's still giving you 0, then you should be aware of shadowing your variables.
private int circleCounter = 0; is applicable to the global scope.
int circleCounter = 0; is applicable to the scope local to your method results. The most local scope takes precedence with variables, so you've thus shadowed your global variable by redeclaring it here.
Simply take out that declaration and your variable won't be shadowed.
Edit: This also presumes that you actually call the method, too.
The main in your code does not invoke the results() method and hence all the default values of the fields are printed on your console i.e either 0 or 0.0(for double)
as main is the only entry point for java in your program.