I'm fairly new to java but, I'm making an encryption program that places each character in a grid. In this case I'll just be using "abcde" as my string. When put through the program, it's supposed to place each character in a 3x2 (height x width) grid. The program reads the grid from top to bottom then moving on to the next row and it'll be read as, "acebd." This part of the program is loading each character into char [height][width].
line length: 5, height: 3, width: 2, longColumn: 1
//longColumn -- the number of valid columns in the last row
static char[][] loadGrid(String line, int width, int height, int longColumn) {
char grid[][] = new char[height][width];
int charCount = 0;
for (int i = 0; i <= line.length()-1; i++){
if (i < line.length()-1) {
for (int c = 0; c < width; c++) {
for (int r = 0; r < height; r++) {
if (r < height - 1 || c < longColumn) {
grid[r][c] = line.charAt(charCount);
charCount += 1;
}
}
}
}
}
return grid;
}
When I run it I get this error:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
at GridEncrypt.loadGrid(GridEncrypt.java:93)
at GridEncrypt.processInput(GridEncrypt.java:65)
at GridEncrypt.main(GridEncrypt.java:19)
To my understanding the charCount isn't going to 4, just staying at 3. I've tired messing around with it but it either just stays at 3 or goes to 5. Also, I'm thinking that it goes through the first two for loops once and then just doesn't go back to it after it runs through the 3rd loop. Which then the 3rd loop is the only one that's being looped properly. Any help is appreciated. Thanks.
I don't see the point of longColumn, and I think you wanted something like
static char[][] loadGrid(String line, int width, int height) {
char grid[][] = new char[height][width];
int charCount = 0;
for (int r = 0; r < height; r++) {
for (int c = 0; c < width; c++) {
if (charCount < line.length()) {
grid[r][c] = line.charAt(charCount);
charCount++;
}
}
}
return grid;
}
I would recommend using the debugger, and stepping through the program. Make sure to keep track of array sizes and variables (especially r and c). The error is being caused by (r,c) being outside the array. Also, a few other things.
1.charcount += 1; can be replaced with charcount++;
2. Remember that when dealing with integers, if (r < height - 1) is essentially the same as if(r <= height - 2)
3. The variables i and charcount are saying the same thing anyways, so you can combine those variables.
Related
I have a string of characters for which I want to encrypt by loading into a 2D array by rows and then printing the array by column. Such that:
|A|B|
|C|D|
|E|
encrypts to "ACEBD".
However I cant seem to be able to avoid dropping characters in the last row in my output getting "ACBD". Any idea how to solve this?
public static void main(String[] args) throws FileNotFoundException {
if (handleArguments(args))
System.out.println("encrypt");
// get input
Scanner input = new Scanner(inputFile);
String line = input.nextLine();
// calculate height of the array
int height = line.length() / width;
// Add one to height if there's a partial last row
if (line.length() % width != 0)
height += 1;
loadUnloadGrid(line, width, height);
}
static void loadUnloadGrid(String line, int width, int height) {
// make an empty array
char grid[][] = new char[height][width];
// fill the array row by row with character from line
int charCount = 0;
for (int r = 0; r < height - 1; r++) {
for (int c = 0; c < width; c++) {
// check to make sure accessing past end of the line
if (charCount < line.length()) {
grid[r][c] = line.charAt(charCount);
charCount++;
}
}
}
// print to standard output the characters in array
System.out.printf("Grid width %d: \"", width);
for (int r = 0; r < width; r++) {
for (int c = 0; c < height; c++) {
System.out.print(grid[c][r]);
}
}
// !!Special handling for last row!!
int longColumn = line.length() % width;
if (longColumn == 0)
longColumn = width;
for (int c = 0; c < longColumn; c++) {
System.out.print(grid[height - 1][c]);
}
System.out.println();
}
You need to loop the rows before you loop the columns, i.e., just the way you usually don't do it.
for (int i = 0; i < array[0].length; i++) {
for (int j = 0; j < array.length; j++) {
// prints columns before rows
}
}
However, be aware that you cannot check whether one row has less columns than another within the loop. Usually array[i].length avoids any NPEs. In this case you might want to define a check whether the array at row j even has column i. This could be done within the second loop by checking:
if (array[j].length > i)
// System.out.println(...);
else
break;
Edit: I see your loop should be working correctly. Most likely height is only 1 instead of 2 and thus, the last row gets cut off. My code as it is works for your input and your loop should be working the same way. Try to print height and check if it is correct or debug your program and go through it step by step.
I need to figure out how to turn the 3x3 array
{{7,2,3},
{0,4,8},
{5,6,1}}
into a 9x9 array where each 3x3 section is the original array o, but each value n is n+(9*c) where c is the corresponding section. In other words, section 0, 0 (top left) should have each of its values changed to originalValue+(9*7) since the top-left section of the original array is 7. Similar with the bottom-right, but the formula would be originalValue+(9*1) since the bottom-right section of the original array is 1.
The new array should look like (just including the two sections mentioned)
{{70,65,66,0,0,0,0,0,0},
{63,67,70,0,0,0,0,0,0},
{68,69,64,0,0,0,0,0,0},
{00,00,00,0,0,0,0,0,0},//leading zeros added for easy legibility
{00,00,00,0,0,0,0,0,0},
{00,00,00,0,0,0,0,0,0},
{0,0,0,0,0,0,16,11,12},
{0,0,0,0,0,0,09,13,17},
{0,0,0,0,0,0,14,15,10}}
Now here is the hard part: I then need to repeat the process, but using this 9x9 array as the original array to get a 27x27 array, and then repeat it even more times to get a bigger array each time (81x81 then 243x243, etc.).
I have been able to get the method addAllValues() but I am stuck from going further.
public static int[][] addAllValues(int[][] data, int value2){
int value = value2 * 9;
int[][] temp = data.clone();
int[][] newData = temp.clone();
for (int i = 0; i < temp.length; i++) {
for (int j = 0; j < temp[0].length; j++) {
newData[i][j] = temp[i][j] + value;
}
}
return newData;
}
Can anyone help me with this? Thanks in advance!
Here is what I have tried:
public static int[][] gen(int amount) {
if (amount == 0) {
return normal;
} else {
int[][] newArray = gen(amount-1);
int[][] temp = new int[newArray.length*3][newArray.length*3];
int[][][][] newArrays = {{addAllValues(newArray,7),addAllValues(newArray,2),addAllValues(newArray,3)},{addAllValues(newArray,0),addAllValues(newArray,4),addAllValues(newArray,8)},{addAllValues(newArray,5),addAllValues(newArray,6),addAllValues(newArray,1)}};
for (int i = 0; i < temp.length; i++) {
for (int j = 0; j < temp.length; j++) {
int x=0,y=0;
if (0 <= i && i < 3){
x = 0;
} else if (3 <= i && i < 6){
x = 1;
} else if (6 <= i && i < 9){
x = 2;
}
if (0 <= j && j < 3){
y = 0;
} else if (3 <= j && j < 6){
y = 1;
} else if (6 <= j && j < 9){
y = 2;
}
temp[i]
[j] = newArrays[x]
[y]
[i]
[j];
}
}
return temp;
}
}
Ok this is pretty basic.
You have a square matrix A.
[a b c]
A = [e f g]
[h i j]
You copy the matrix 3 times to the right (horizontally) to get [A A A], and then you copy the strip 3 times to the bottom (vertically) to get a square strip of matrices
[A A A]
B = [A A A]
[A A A]
The new matrix is 3 times bigger per dimension, or totally 9 times bigger (per "area"). Now what you need to do is modify each submatrix -- add the corresponding element from the original matrix. You need to find the indices of the submatrix (the indices of the subsections), and use those same indices in the original matrix to get the corresponding scalar.
[9*A(0,0)+A 9*A(0,1)+A 9*A(0,2)+A]
[9*A(1,0)+A 9*A(1,1)+A 9*A(1,2)+A]
[9*A(1,0)+A 9*A(1,1)+A 9*A(1,2)+A]
The last link we need to set is to know which element in the new matrix B corresponds to which section.
B is 3 times bigger, e.g. B[0..8, 0..8] so if we divide the indices of element in B by 3 (integer division) we get it's section and this the indices of the scalar in A.
We say an element B(r,c) lays in section (i,j)=(r/3, c/3) and thus this element shall be modified with A(i,j). This last sentence pretty much sums it up.
I'm working on a Java program that checks if a sudoku puzzle is solved or not. I have finished the horizontal and vertical number check part. But when trying to check squares, I can't do anything. Here is how my check system works.
This is what I want to make. Hope someone helps because I'm on a hard situation with square check.
int[][] SudokuBoard = new int[9][9];
// I didn't wrote the sudoku board completely hope you understood how sudoku table looks like.
public static boolean checkSquares(int[][] SquareBoard) {
int retr = false;
int loop = 0;
int[] extraboard = new int[9];
int[] truelist ={1,2,3,4,5,6,7,8,9};
for(int i = 1; i <=9 ; I++) {
//here , extraboard will have the numbers in " i " numbered sudoku square.( i is like first //,second)
Arrays.sort(extraboard);
for(int j = 0; j < 9; j++) {
if(extraboard[j] == truelist[j])
loop += 1;
}
extraboard = new int[9];
}
if(loop == 81)
retr == true;
return retr;
}
You could do
int count = 0;
for(int k = 0; k < 9; k++) {
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++) {
extraboard[count++] = SquareBoard[i+3*k/3][j+k%3*3];
}
}
Arrays.sort(extraboard);
for(int j = 0; j < 9; j++) {
if(extraboard[j] == truelist[j])
loop += 1;
}
extraboard = new int[9];
count = 0;
}
The actual formula to calculate the location in the box is quite simple. As the board is split into rows and column, getting the location of the row and column needs to get offset based on the location of the box in the full area.
i here counts the index within the box of the row. As each row of boxes has a length of 3 in a 9x9 sudoku we need to increase the row number by 3 each time we get 3 boxes in. To figure out and only add 3 we can use some integer division.
For example:
i+i.length*k/i.length
This is obviously an syntax error as i doesn't have length but can consider it as the limit of i in the loop (in this case 3).
This would then get the current row in the box (the first i) and add that to the offset of boxes in the sudoki. That is for every 3 boxes k/i.length becomes 1 more, and we then multiply that with 3 to get the offset of 3.
In the column part we have a bit of an bigger issue as we need to offset it for every 3 we move left in the array and reset it when we get back to boxes on the far left.
So the forumla would become
j + (k%i.length)*j.length
This would give us the column in the box we are in, then we offset by the box location with k%i.length. The reason we use the i.length and not the j.length is that we need to calculate the offset by rows and then offset it by the length of the box column wise.
With this you can then apply to this to any size board. 2x2, 2x3, 3x2, 3x3 or bigger even.
public static boolean checkSquares(int[][] SquareBoard) {
int i=0, extraboard=0;
for (;i<9;i++,extraboard=0) {
for (int j=0;j<9;j++)
extraboard+=1<<(SquareBoard[i/3*3+j/3][i%3*3+j%3]-1);
if (extraboard!=(1<<9)-1) // 511, binary(511) = 111111111
break;
}
return i==9;
}
This is a solution i came up with. it uses 4 nested loops but the time complexity is still O(n^2). Basically i check the first 3 boxes on top, then the 3 boxes in the middle, then the last 3 boxes.
for (int l = 0; l < 9; l+= 3){
for (int i = 0; i < 9; i += 3){
HashSet<Character> set = new HashSet<>();
for (int j = l; j < l+3; j++){
for (int k = i; k < i+3; k++){
if (!set.contains(board[j][k])){
if (board[j][k] != '.')
set.add(board[j][k]);
}
else
return false;
}
}
}
}
return true;
and note that the sudoku might not be complete, and the missing numbers are replaced by ' . '
I'm a complete newbie when it comes to Java and I've been working on a simple program which creates a grid with multiple slots. Each slot has an X and a Y value and is stored in an ArrayList called "s".
Here's my code:
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
s.add(new Slot(j, i));
}
}
Height and width are user inputed values.
It's a simple loop within a loop and essentially it should work but instead of creating multiple slots with the values 0, 0, 1,0 2, 0 3, 0 and so forth until it should increase the Y axis by one it never increases the Y-value. Instead after doing the first loop it will go back to 0, 0 instead of 0, 1.
Also here's the how it's supposed to print the values:
for (int i = 0; i <= height; i++) {
for (int j = 0; j <= width; j++) {
System.out.print(s.get(j));
}
System.out.println("");
}
Example:
0,0
1,0
2,0
3,0
...
9,0
0,0 (instead of 0,1)
My question is why on earth doesn't my first loop ever increase the value of i? Sorry if I sound like an idiot, I'm a total noob.
You have a problem in your printing function.
I don't know what s is but:
for (int i = 0; i <= height; i++) {
for (int j = 0; j <= width; j++) {
System.out.print(s.get(j));
}
System.out.println("");
}
Get objects based on j value only. You need to get objects based on i and j in order to get all values.
Or you can just iterate over all objects in s (if s is a Collection):
for (Slot sl : s) {
System.out.println(sl);
}
The j value only ranges between 0 and width - 1 so s.get(j) is only going to access the first width items in s. Try this instead:
for (int i = 0; i <= height; i++) {
for (int j = 0; j <= width; j++) {
System.out.print(s.get(i * width + j));
}
System.out.println("");
}
Or you could just iterate over the contents of s and not use nested for loops for the retrieval.
You don't need the nested loop when printing, Just iterate over the ArrayList:
for(Slot slot : s )
{
System.out.println(slot);
}
Your problem is the print function. Just iterate over s and print each slot:
for (Slot slot : s) {
System.out.println(slot);
}
As it is implemented now, you print items in s from indexes 0 -> width over and over again, height times.
Also, learn about the for-each loop, available from Java 5 instead of using get(index):
Oracle Tutorial
The problem is you are storing height * width elements in a one dimensional array - ArrayList but retreiving only width number of elements.
Instead of arraylist of Slot for s, use two dimensional array.
Slot[][] s = new Slot[width][height];
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
s[j][i](new Slot(j, i));
}
}
for (int i = 0; i <= height; i++) {
for (int j = 0; j <= width; j++) {
System.out.print(s[j][i]);
}
System.out.println("");
}
you only print j from the same place every time
To clarify, this IS a homework assignment. I'm merely looking for advice, I'm not looking for someone to do my homework for me.
I've already done the first half. It uses two arrays to print an Asterisk design (in this case, the letter 'S'. That works fine. Then, I skip two lines and print the design but flipped (so each line is reversed). It seems to be working fine, but when I run the program, it prints two S's and the second one isn't reversed. Any ideas of what I'm doing wrong?
public class Design {
public static void main (String [] args) {
char [] array = new char [150];
for (int index = 0; index < array.length; index ++)
{
array [index] = '#';
}
int [] indexNumbers = {
0,1,2,3,4,5,6,7,8,9,10,20,30,40,50,
60,70,71,72,73,74,75,76,77,78,79,89,99,109,119,129,139,140,
141,142,143,144,145,146,147,148,149
};
for (int i = 0; i < indexNumbers.length; i++)
{
array [indexNumbers[i]] = ' ';
}
for (int index = 0; index < array.length; index ++)
{
if (index % 10 == 0 && index > 0)
System.out.println();
System.out.print (array[index]);
}
//Now, to reverse the letter
System.out.println();
System.out.println();
int lines = 5;
for (int i = 0; i< array.length; i++){
if (i >= lines)
lines += 10;
char temp = array [i];
array [i] = array [lines - i - 1];
array [lines - i - 1] = temp;
}
for (int index = 0; index < array.length; index ++)
{
if (index % 10 == 0 && index > 0)
System.out.println();
System.out.print (array[index]);
}
}
}
EDIT: Yeah... the design is in spaces, everything else is asterisks.
your reversing is a bit confused.... makes it easier if you do it in two loops.
for (int row = 0; row < (array.Length / 10); row++)
{
for (int col = 0; col < 5; col++)
{
int rowStart = row * 10;
int rowEnd = rowStart + 9;
char temp = array[rowStart + col];
array[rowStart + col] = array[rowEnd - col];
array[rowEnd - col] = temp;
}
}
First, why don't you use String[] or char[][]? Instead you are using a simple array to put multiple lines within. This makes your code confuse and brittle.
To swap an array, the rule is generally simple: Get the first and the last line and swap them. Get the second and the second last, and swap them, get the third and the third last and swap them... Until you get to the middle. This will be much easier if you have an array where each element is a line (like in an String[] or in an char[][]).
If you need to keep the idea of a simple char[] where each 10-char block is a line, simply swap each 10-char block like I stated above.
If you don't want to change the general behaviour of your program, this is the problematic block:
int lines = 5;
for (int i = 0; i< array.length; i++){
if (i >= lines)
lines += 10;
char temp = array [i];
array [i] = array [lines - i - 1];
array [lines - i - 1] = temp;
}
You are not swapping lines here, instead you are swapping chars. This way, your if is not checking and skipping lines, but is instead checking and skipping chars.
This is better:
int lines = array.length / 10;
for (int i = 0; i<= lines / 2; i++){
for (int j = 0; j < 10; j++) {
char t = array[i * 10 + j];
array[i * 10 + j] = array[(lines - i - 1) * 10 + j];
array[(lines - i - 1) * 10 + j] = t;
}
}
So..
First of all, start by printing '#' instead of ' ', and '.' instead of '#'. You will see more clearly what's going on.
Second, you have a problem in the reverse, you are actually not reversing anything, the way you calculate the index lines - i - 1 is wrong. The good way is (i / 10) * 10 + (10 - (i % 10)) -1. Yep, is kinda horrible, but if you want that in one line, using a one-dimension array, there it is. Now it's up to you to understand it, and integrate it in your code ;)