Shifting a pixel image left and right - java

I have a set of arrays (which are "pixels" - RGB representation) for e.g.
(0,0,0)(0,0,0)(0,0,0)(0,0,0)
(1,1,1)(1,1,1)(1,1,1)(1,1,1)
(2,2,2)(2,2,2)(2,2,2)(2,2,2)
I want to shift left/right the columns and up/down the rows. for example:
ShiftCol + 2 will yield the output:
(0,0,0)(0,0,0)(0,0,0)(0,0,0)
(0,0,0)(0,0,0)(1,1,1)(1,1,1)
(0,0,0)(0,0,0)(2,2,2)(2,2,2)
ShiftRow - 1 will yield the output:(after ShiftCol +2)
(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)(1,1,1)(1,1,1)
(what happend in the above output is: First row move to second row, second row to third row, and first row became black (just zero's), the third row is just replaced with the second row.
ShiftCol- 1 will yield the output:
(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)(1,1,1)(1,1,1)(0,0,0)
I just need your help to show me how can I "move" every column to the right, that will be enough. What I managed to do is when ShiftCol +2 is called, the first column is moved 2 columns to the right (and is appeared on the third column) and the first two columns are turned to (0,0,0) which is black color. the problem is I don't know how to move EVERY column to the right according the the number it is called to move right, for example - if i call ShiftCol(2) and the pixel image array is 3x4 as you can see in the outputs what should happen is that: first column will be moved twice to the right - to the third column, and first column will become black (0,0,0), second column will be moved to twice to the right too and will become the fourth column. third and fourth columns will just be replaced by first and second columns.
It'll be enough if you just guide me somehow how to manage that, anyhow you can focus on the method "ShiftCol" only in RGBImage class and you'll see what I've accomplished so far within code. Thanks on advance!
*PLEASE, keep the answer simple with code. I learned just for loops, while loops, if statements, arrays.. I don't want to use in this project any other advanced material.
Here's my code:
RGBColor class:
public class RGBColor {
/**
* attributes: red, green and blue component of a color.
*/
private int _red,_green,_blue;
/**
* final variables.
*/
private final int MAX_VALUE = 255,MIN_VALUE = 0;
private final double THIRTY_PERCENT = 0.3,FIFTY_NINE_PERCENT = 0.59,ELEVEN_PERCENT = 0.11;
/**
* Consctructor which gets 3 colors (RGB), we check here if their range is valid (0 - 255), if not we assign black to it.
*
* #param red - The red color component value.
* #param green - The green color component value.
* #param blue - The blue color component value
*/
public RGBColor(int red, int green, int blue)
{
if(isValid(red,green,blue))
{
_red = red;
_green = green;
_blue = blue;
}
else
doBlack();
}
/**
* Construct a black RGBColor. i.e. red = green = blue = 0
*/
public RGBColor()
{
doBlack();
}
/**
* Here we check if the color number was entered correctly.
* It has to be an integer (whole number) between 0-255.
*
* #param nums - a component value, should be the number between 1-4
* #param return - return true if the number is between 1-4, false otherwise.
*/
private boolean isValid(int nums)
{
return ((nums >= MIN_VALUE) && (nums <= MAX_VALUE));
}
/**
* Here we check if the color number was entered correctly.
* It has to be an integer (whole number) between 0-255.
*
* #param red - the red component
* #param green - the green component
* #param blue - the red component
* #param return true if values are correct, false otherwise.
*/
private boolean isValid(int red, int green, int blue)
{
return ((red <= MAX_VALUE && red >= MIN_VALUE &&
green <= MAX_VALUE && green >= MIN_VALUE &&
blue <= MAX_VALUE && blue >= MIN_VALUE));
}
/**
* Returns RGB color string triplet with numbers between 0-255, i.e. (0,127,127)
*/
public String toString()
{
return ("(" + _red + "," + _green + "," + _blue + ")");
}
/**
* RGBColor will become the color Black. (0,0,0)
*/
private void doBlack()
{
_red = _green = _blue = 0;
}
}
RGBImage class:
public class RGBImage
{
private int _rows, _cols;
private RGBColor[][] _pixels;
private int _offset = 0;
public RGBImage(int rows, int cols)
{
_rows = rows;
_cols = cols;
_pixels = new RGBColor[_rows][_cols];
for(int i = 0; i < _rows; i++)
for(int j = 0; j < _cols; j++)
_pixels[i][j] = new RGBColor();
}
public RGBImage(RGBColor[][] pixels)
{
_rows = pixels.length;
_cols = pixels[0].length;
_pixels = new RGBColor[_rows][_cols];
for(int i = 0; i < _rows; i++)
for(int j = 0; j < _cols; j++)
_pixels[i][j] = new RGBColor(pixels[i][j]);
}
public void shiftCol (int offset)
{
if(_offset == 0)
_offset = offset;
else
_offset += offset;
int currentShift = 1;
if( (_offset == _cols) || (-_offset == _cols) ){
makeBlack(_rows,_cols); //make black
}
else if( (_offset < _cols) || (-_offset < _cols) )
{
if(_offset > 0){
for(int j = currentShift; j < _cols && j <= _offset; j++){
for(int i = 0; i < _rows; i++){
setPixel(i,j + 1,this._pixels[i][j]);
setPixel(i,j,this._pixels[i][j] = new RGBColor());
}
}
_offset++;
currentShift++;
}
else if(offset < 0){
offset = -offset;
for(int j = currentShift; j < _cols && j <= offset; j++){
for(int i = 0; i < _rows; i++){
setPixel(i,_cols - 1 - j,this._pixels[i][_cols - j]);
setPixel(i,_cols,this._pixels[i][_cols - j] = new RGBColor());
}
currentShift++;
}
}
}
}
public void setPixel(int row, int col, RGBColor pixel)
{
if ((pixel != null) && (row < _pixels.length) && (col < _pixels[0].length))
_pixels[row][col] = new RGBColor(pixel);
}
public String toString()
{
String pixelSet ="";
for (int i = 0; i < _rows; i++){
for(int j = 0; j < _cols; j++){
pixelSet += this._pixels[i][j].toString();
}
pixelSet += "\n";
}
//pixelSet += tester;
return pixelSet;
}
}
and my Output tester class:
StudentTester class:
public class StudentTester {
public static void main(String[] args) {
System.out.println("Black Image Constructor:");
RGBImage rgbImg0 = new RGBImage(3,4);
System.out.println(rgbImg0);
System.out.println("Constructor with RGBColor[][] Array Parameter:");
RGBColor[][] rgbArray1 = new RGBColor[5][4];
for (int i=0; i<rgbArray1.length;i++)
for (int j=0; j<rgbArray1[0].length;j++)
rgbArray1[i][j] = new RGBColor(i,i,i);
RGBImage rgbImg1 = new RGBImage(rgbArray1);
System.out.println(rgbImg1);
System.out.println("Copy Constructor:");
RGBImage rgbImg2 = new RGBImage(rgbImg1);
System.out.println(rgbImg2);
System.out.println("flipVertical:");
rgbImg1.flipVertical();
System.out.println(rgbImg1);
System.out.println("rotateClockwise:");
rgbImg1.rotateClockwise();
System.out.println(rgbImg1);
System.out.println("shiftCol 2:");
rgbImg1.shiftCol(3);
System.out.println(rgbImg1);
System.out.println("shiftCol 2:");
rgbImg1.shiftCol(-2);
System.out.println(rgbImg1);
System.out.println("shiftCol 2:");
rgbImg1.shiftCol(1);
System.out.println(rgbImg1);
}
}

First, you don't really need the _offset field. The only place you are using it is the shiftCol() method, and it is not really a part of the state of the image as an object. It should therefore be a local variable. But really, the parameter offset is doing the job quite well, you don't need an extra variable. Remember, parameters are passed by value, even if you change the value of offset, it's not going to change anything in the calling code.
Second, you really don't need the variable currentShift, either. You are adding one to it, but the first currentShift++ is not in a loop and there is no further use of it, and the second currentShift++ is in a loop, but it doesn't affect anything in the loop and is not used after it. So - get rid of it.
Now, to your real problem. Let's look at the positive offset first. What you do for each column is:
Put the value of the pixel in the pixel to its right
Change the current value of the pixel to black - twice (first by setting it directly in the _pixels[i][j] and then again by the call to setPixel()).
This has several problems. First, since you run with j from 0 to offset, what happens is this:
The pixel that was in column 0 is placed in column 1, and column 0 is blackened.
The pixel that is in column 1 (which we actually changed in the previous step) is placed in column 2, and column 1 is blackened.
Then the pixel is moved to column 3, and so on.
Why all these moves of one pixel? And the creation of a new pixel object each time you do it.
And you just moved a single column, destroying all the column values along the way. Doing so, you lost all the information in them that should have also been moved!
And then, of course, the double assignment of new objects, one of which goes straight to the garbage.
Now to untangle this knot.
As a rule, when you copy a portion of an array onto itself, it's always important to copy in the right order. Let's look at a simple array of characters:
0 1 2 3 4 5
┌─┬─┬─┬─┬─┬─┐
│A│B│C│D│E│F│
└─┴─┴─┴─┴─┴─┘
Suppose you want to move the "BCD" part two spaces to the right, so that the result would be "ABCBCD" (not caring about erasing the moved part at the moment). Naively, you think that moving:
arr[3] = arr[1];
arr[4] = arr[2];
arr[5] = arr[3];
is going to do the right thing. but in fact, what you get is:
0 1 2 3 4 5
┌─┬─┬─┬─┬─┬─┐
│A│B│C│B│C│B│
└─┴─┴─┴─┴─┴─┘
Why is there a "B" in position 5? Because we have already changed arr[3] in our first assignment. Doing that destroyed the D, so when we come to assign arr[3] to arr[5], it's already "B".
The correct way to copy to the right is therefore to start from the right:
arr[5] = arr[3];
arr[4] = arr[2];
arr[3] = arr[1];
But... if we wanted to shift left, doing it in the reverse order like that would not work. Start again from our original "ABCDEF". Suppose we want to shift the "CDE" 2 positions to the left to get "CDEDEF". If we do it in reverse:
arr[2] = arr[4];
arr[1] = arr[3];
arr[0] = arr[2];
Then again, we get:
0 1 2 3 4 5
┌─┬─┬─┬─┬─┬─┐
│E│D│E│D│E│F│
└─┴─┴─┴─┴─┴─┘
Because arr[2] was already changed when we got to it.
Conclusion:
To shift part of an array to the right, you have to start your loop from the high indexes and go down to the low indexes.
To shift part of an array to the left, you have to start your loop from the low indexes and go up to the high indexes.
Also note that there is no point in moving the block one place and then one more place etc. - it just wastes time (and memory if you create new objects). You should shift it directly to where it is supposed to be. If you are supposed to move it by 2, then its new index is j+2.
Now, let's suppose our array is like the rows in your problem. We want to shift all the contents, not just part, and fill in with blanks.
So if I want to shift this array 2 positions to the right:
0 1 2 3 4 5
┌─┬─┬─┬─┬─┬─┐
│A│B│C│D│E│F│
└─┴─┴─┴─┴─┴─┘
I expect to get:
0 1 2 3 4 5
┌─┬─┬─┬─┬─┬─┐
│ │ │A│B│C│D│
└─┴─┴─┴─┴─┴─┘
I now know I have to start on the right to do it correctly. What I do is look at each position from 5 down to 0, and think: what is the source for this position? It's supposed to be the cell such that I'm currently two positions to the right of. That is, the cell that's two position to my left. Is there such a cell? If so, put its value in the current index. If not (because the source position is negative), then I fill in with a blank:
for ( i = arr.length - 1; i >= 0; i-- ) {
if ( i - offset >= 0 ) {
arr[i] = arr[i-offset];
} else {
arr[i] = ' ';
}
}
If you got the idea, you'll now be able to apply what I did with the array of characters to your row of pixels.
Your next task should be applying the reverse logic to negative offsets (remember, left to right!)
One final note: don't use setPixel() for this copy operation. It creates new pixel objects, and that's really unnecessary (except for the black parts). I suppose setPixel() does that because it's a public method and gives a protective copy of the pixel so that if its contents are changed it won't affect our image. But for an internal operation, that's not necessary.

Try this method:
public void shiftCol (int offset)
{
if(offset > 0){
for(int j = _cols - 1; j >= 0; j--){
for(int i = 0; i < _rows; i++){
if (j - offset >= 0)
_pixels[i][j] = _pixels[i][j-offset];
else
_pixels[i][j] = new RGBColor();
}
}
} else {
for(int j = 0; j <=_cols - 1; j++){
for(int i = 0; i < _rows; i++){
if (j - offset < _cols)
_pixels[i][j] = _pixels[i][j-offset];
else
_pixels[i][j] = new RGBColor();
}
}
}
}

Related

Adjusting intensity on an image

I am trying to increase the intensity of a grayscale image while maintaining the outline of the image.The algorithm I'm creating only looks at values in the left, right, upper and lower neighbors of each cell, effectively only processing the interior cells of the array. Obviously there are lines and lines of code but I am being thrown the ArrayOutOfBoundsException on this one block (I can provide it all if needed). Can someone tell me what my problem is or offer advice on what needs a second look?
public Image getEdgeImage(){
Image edge = new Image(this);
for(int row = 1; row < numRows; row++) {
for(int col = 1 ; col < numColumns; col++) {
double Lx = -.5 * edge.pixels[row -1][col].getRed() + (.5 * edge.pixels[row + 1][col].getRed()) ;
double Ly = -.5 * edge.pixels[row][col -1].getRed() + (.5 * edge.pixels[row][col + 1].getRed());
int L = (int) Math.sqrt((Lx * Lx) + (Ly * Ly));
edge.pixels[row][col] = new Color(L, L, L);
}
}
return edge;
}
If your getting ArrayOutOfBoundException, Please do watch on the area your accessing the Array element by +/- the index.
In your program the line No 5 & 6, your accusing the next elements with out checking the array length.
edge.pixels[row + 1]
edge.pixels[row][col + 1]
Array Index will start from 0 to length-1, Suppose your array has the length of 10, and on the 9th iteration your program will check for the index 10 in line 5&6 the code highlighted above.

Scrolling through all color combinations on a vertical column of pixels

I'm trying to scroll through every single RGB color combination possible on a vertical set of pixels. In this example assume that the pixel column is 1080. I understand that all possible combinations amount to approximately 18 billion at that number. I can't seem to wrap my head around the loop structure. I have the loop for figuring all color combinations for one pixel here.
for(int r = 0;r < 256;r++){
for(int g = 0;g < 256;g++){
for(int b = 0;b < 256;b++){
pixelC =
Integer.toString(r)+":"+
Integer.toString(g)+":"+
Integer.toString(b)+";";
}
}
}
Now I need something that can apply the pixel color to the column. I'm just not sure how to work out the logic of doing this because I have to apply the color in all possible combinations. So having a vertical strip of all white with a vertical strip of all black is not my goal. Rather a sporadic peppering of pixels in all possible combinations.
What you are trying to accomplish is too difficult and cumbersome with for loops.
Basically, you are trying to count in base 256^3 = 16,777,216. And with a column height of 1080, the number of combinations is astronomical!
(256^3)^1080 ≈ 4.983 × 10^7802
Let me explain with a simplified example. Instead of a column height of 1080, let's say it is of height 4. And instead of having 16,777,216 different color combinations for each pixel, say we only have 10 different color combinations.
Furthermore, instead of color values being composed of RGB, let's say each color can have a value from 0-9. In this example, the column (of 4 pixels) can be in 10^4 = 10,000 different states.
Let's visualize this: Think about the column being on its side so it is horizontal and let's treat it like it's one of those combination locks with dials that can spin from 0-9.
This would be the initial state (All 4 dials/pixels at color = 0):
-------------------------
| 0 | 0 | 0 | 0 |
-------------------------
This would be the final state (All 4 dials/pixels at color = 9):
-------------------------
| 9 | 9 | 9 | 9 |
-------------------------
In your case, you would have a combination lock that has 1080 dials and each dial can spin from 0-16,777,215
Now, I was interested in how I can simplify the code so that you don't have to have 1080 for loops or n for loops in the general case where n is the height of the column.
Here's what I came up with:
// This represents the combination lock with 4 dials
int [] arr = new int [4];
// This represents how many states each dial can be in
int base = 10; // (0-9)
boolean done = false;
while (!done)
{
// just for printing out the current state of the array
System.out.println(Arrays.toString(arr));
int index = 0;
// get to the first dial that has not reached its max value
while (index < arr.length && arr[index] == base - 1)
{
index++;
}
// all dials are at the max value -> we are done
if (index == arr.length)
{
done = true;
}
else
{
// increase the first dial we found to not have a max value
arr[index]++;
// set all dials before it to 0
for (int i = 0; i < index; i++)
{
arr[i] = 0;
}
}
}
Note: This algorithm increases the values from left to right. I figured this made sense in adapting it to actual problem with a column in a graphic since you would start changing colors from the top down vs. bottom up. If you want colors to start changing from the bottom up, then it can easily be adapted by changing the indices, increments to decrements, etc.
Now, this example is for simple integer values and int arrays. How can we adapt it to your problem with colors?
First, let's assume that the column slice is an array of java.awt.Color
That is, int [] arr = new int [4]; becomes Color [] arr = new Color [4];
Next, instead of int base = 10; // (0-9) we would have int base = 16777216; // (0-16,777,215)
Now, the rest of the code is pretty much the same except we have to adapt a few things:
This:
while (index < arr.length && arr[index] == base - 1)
{
index++;
}
Needs to become this:
while (index < arr.length && arr[index].equals(Color.WHITE))
{
index++;
}
This:
// increase the first dial we found to not have a max value
arr[index]++;
Needs to become this:
// increase the first color we found to not have a max value
Color current = arr[index];
arr[index] = new Color(current.getRGB() + 1);
Lastly, for this portion:
// set all dials before it to 0
for (int i = 0; i < index; i++)
{
arr[i] = 0;
}
We can simply do:
// set all colors before it to 0
for (int i = 0; i < index; i++)
{
arr[i] = Color.BLACK;
}
Also, keep in mind you will need to initialize the Color array. This can be done like so:
for (int i = 0; i < arr.length; i++)
{
arr[i] = Color.BLACK;
}
I hope this helps. Good luck!

Trouble finding path in a grid

I am trying to find number of paths between top left and bottom right cells on a checker board. i can only move to the adjacent right and adjacent bottom cell. This way i can have a maximum of 2 non intersecting simple paths. I am using a recursive approach.
private void processMatrix()
{
if(matrix[0][0]!=1 || matrix[0][0]!=matrix[ROWS-1][COLUMNS-1])
System.out.println("No Path Exists between bottom right and top left cells");
int row=0;
int col=0;
traverse(row,col);
}
private boolean traverse(int row, int col)
{
path.add(new Point(row,col));
if(row+1<ROWS)
{
if(matrix[row+1][col]==0)
{
return false;
}
if(matrix[row+1][col]==1)
{
traverse(row+1,col);
}
}
if(col+1<COLUMNS)
{
if(matrix[row][col+1]==0)
{
return false;
}
if(matrix[row][col+1]==1)
{
traverse(row,col+1);
}
}
if(col==COLUMNS-1 && row==ROWS-1)
return true;
return false;
}
But with this code i am only able to traverse the lower triangular matrix. And when i reverse the order of if blocks in the traverse() function i am only able to traverse a path in the upper triangular matrix. Unable to figure out what is wrong. I also want to detect intersecting paths. Please help.
EDIT:
The matrix consists of 0s and 1s.
A path exists if it is connected by adjacent cells containing only 1s. In other words the path will be a chain of 1s.
You seem to be overcomplicating things with your code. If your matrix is 0s and 1s, use boolean instead of int. Non-intersecting paths seems a bit silly, since all paths are equally valid in taxicab geometry. Here's the simple solution for finding the number all paths, it will show you how it works with the block of system.out prints:
int rows = 9;
int columns = 8;
boolean[][] matrix = new boolean[rows][columns];
for (boolean[] arr : matrix) {/* Set values of matrix such that true = can pass thru that space, false = space blocked */
Arrays.fill(arr, true);
}
matrix[4][6] = false;
matrix[2][5] = false;
int[][] paths = new int[rows][columns];//number of paths reaching each space in i steps
paths[0][0] = 1; //Starting space
for (int i = 0; i < rows + columns - 2; i++) {//Taxicab distance is always x+y, i = distance travelled so far
int[][] newPaths = new int[rows][columns]; //number of paths reaching each space in i+1 steps
for (int x = i >= columns ? i - columns + 1 : 0; x <= i && x < rows;) { //x is traditionally columns but it doesn't matter
int y = i - x; //if statement is x declaration ensures that this is < columns
int newX = x + 1; //will be used repeatedly
int newY = y + 1; //will be used repeatedly
if (newX < rows && matrix[newX][y]) newPaths[newX][y] += paths[x][y];
if (newY < columns && matrix[x][newY]) newPaths[x][newY] += paths[x][y];
x = newX;
}
paths = newPaths;
for (int x = 0; x < rows; x++) { //optional, show the algorithm at work
for (int y = 0; y < columns; y++) {
int r = paths[x][y];
System.out.print(r);
if (r < 100) System.out.print(" ");
if (r < 10) System.out.print(" ");
}
System.out.println();
}
System.out.println();
}
System.out.println(paths[rows - 1][columns - 1]); //result
If all you want to determine is whether a path exists, replace int[][] paths with boolean[][] paths and change the operations accordingly.
This is a fundamental dynamic programming problem.
Let dp[R][C] be the number of paths from the top-left cell to the cell on row R and column C (1-indexed).
Initial values (when R or C is 1):
dp[R][1] = 1 if matrix[i][1] has value 1 for i = 1..R, otherwise dp[R][1] = 0.
dp[1][C] = 1 if matrix[1][j] has value 1 for j = 1..C, otherwise dp[1][C] = 0.
Then dp[R][C] = dp[R-1][C] + dp[R][C-1] if matrix[R][C] = 1, otherwise dp[R][C] = 0 (for R, C >= 2)
And this is it. The intuition behind this idea is that if we know that we can get to cell on row R-1, column C by N different roads, then if we go down once, we will get N different roads to cell [R, C]. Analogically for going right from cell [R, C-1] to [R, C].
Finally, the answer is in dp[N][M], where N and M are the dimensions of the matrix.

Finding Zeroes in Sudoku

I had a class assignment (it's already past) where I had to write a Sudoku solver. I was able to create a method that can solve for each missing number. But I'm having trouble creating a method to find which cells I need to solve. I'm supposed to take a 2D array and fill in the missing number (represented by 0's).
I've put some of my code below, but not all of it (even though the assignment has passed, I respect the profs wishes).
public class SolveSudoku {
private static int[][] grid = new int[9][9];
public static int[][] getSolution(int[][] grid) {
for (int i = 0; i < 9; i++) {
System.arraycopy(grid[i], 0, SolveSudoku.grid[i], 0, 9);
}
int n = getZero();
return getSolution(n);
}
private static int[][] getSolution(int n) {
if (n == 0) {
return grid;
}
Cell cell = getZero();
int row = cell.row;
int column = cell.column;
for (int number = 1; number <= 9; number++) {
//checks cell using another method
//I have booleans that return true if the number works
}
return null;
}
private static int getZero() {
return 0;
}
private static class Cell {
int cell = 0;
int row = 0;
int column = 0;
int number;
}
}
I have the getZero method which has to find each zero in the grid (0's represent a missing number) so I can solve it. What should I do in getZero to find the cells I need to replace?
You don't check if the number is repeated in the same 3x3 square (only rows and columns).
I don't get what do you mean by "finding zeroes". In fact it is meaningless, solving the sudoku from the first row or the last one has no effect in the solution. I'll explain what did I do for the same trouble.
A cell is not an int, is an object. In the object I store a value (the number if it is found, 0 if not) and a boolean[9]. False means (index + 1) is discarded because it is in the same row/column/square, true means it is not decided yet. Also, 3 Lists (Vectors, Sets, whatever).
A list of 81 cells (you can make it a bidimensional array if you wish).
9 Lists/Vectors/Sets representing rows, 9 representing columns, 9 representing square. Each of the 81 cells is assigned to its row/column/square. Inside each cell you store the references to the list to which it belongs to.
Now comes the execution part. In a first iteration, every time you find a non-zero (a number fixed in the sudoku), you loop through the lists to which the cell belongs. For each cell in those lists, you mark the boolean assigned to that number to false.
You loop through cells, each time you find a 0 you check how many of the booleans in the cell are true. If it is 1 (all other 8 possible values have been discarded), it is the value of the cell. You set it, and as in 4) you get the list to which it belongs and mark that number to false in every cells. Loop until you get a solution, or an iteration in which you cannot set any number (no solution available directly, must start with backtracking or similar).
Remember before getting at the keyboard, to have a clear idea about what the question is and how would you resolve it without a computer. If you do not know what you want to do, the computer won't help (unless you post in stackoverflow)-
From what I can tell you want to find the first 0-valued cell in grid. I'll define first as the first zero containing column in the lowest zero-containing row.
This can be done using a naive search:
private Cell getZeroCell(){
int rz = -1;
int cz = -1;
outer: for(int row = 0; row < grid.length; row++){
for(int col = 0; col < grid[row].length; col++){
if(grid[row][col] == 0){
rz = row;
cz = col;
break outer;
}
}
}
if(rz == -1 || cz == -1){
// no zeros found
return null;
}else{
// first zero found at row `rz` and column `cz`
Cell cell = new Cell();
cell.row = rz;
cell.column = cz;
return cell;
}
}
Get the "number" of the first cell containing a zero (counting left to right, then top to bottom, 0-indexed):
private int getZeroInt(){
int rz = -1;
int cz = -1;
outer: for(int row = 0; row < grid.length; row++){
for(int col = 0; col < grid[row].length; col++){
if(grid[row][col] == 0){
rz = row;
cz = col;
break outer;
}
}
}
if(rz == -1 || cz == -1){
// no zeros found
return -1;
}else{
return rz * grid[0].length + cz;
}
}
Get the number of cells containing a zero:
private int getNumZeros(){
int count = 0;
for(int row = 0; row < grid.length; row++){
for(int col = 0; col < grid[row].length; col++){
if(grid[row][col] == 0){
count++;
}
}
}
return count;
}

how to traverse though a 2d char array searching for words in java?

I am having trouble with a school assignment and would really appreciate some insight. I am asked to create a wordsearch using a 25x25 2d char array and somehow go through that array by developing an algorithm that will search through it to find 21 pre-defined words.
So far I have been able to create a ragged array of the words that I need to find and the 2d array with the chars placed in each position.
in = new ASCIIDataFile("wordsearch.txt");
display = new ASCIIDisplayer();
int numberWords = in.readInt();
wordlist = new char[numberWords][];
for (int i =0; i<wordlist.length; i++){
wordlist[i] = in.readLine().toUpperCase().toCharArray();
}
for(int i = 0;i<wordlist.length; i++){
display.writeLine(" ");
for(int j = 0;j<wordlist[i].length; j++){
display.writeChar(wordlist[i][j]);
}
}
//done wordlists
int gridLength = in.readInt();
int gridHeight = in.readInt();
grid = new char[gridHeight][gridLength];
for(int i = 0;i<gridLength; i++){
grid[i] = in.readLine().toCharArray();
}
My problem in creating the algorithm to search though the 2d array and match it with a character in the wordlist.
I am supposed to make different methods, for searching forwards, backwards and diagonal.
I have been struggling for days just to do the forward search.
I really how no idea about how to go about this problem, so far all I have is
for(int k = 0; k<wordlist.length; k++){
int p = 0;
for(int row = 0;row<gridLength; row++){
for(int col = 0;col<gridHeight; col++){
while(p<wordlist[k].length){
if(grid[row][col] == wordlist[k][p]){
//do something
}
}
}
}
}
}
Any help or pointers would be greatly appreciated!
The trick is, you don't need to consider all 8 possible directions separately. You can represent each with a vector. E.g., 'forward' direction would be (0, 1) (first row number, then column) - a vector pointing to the right. Diagonal top-left direction would be (-1, -1). Well, you get the idea.
Then, just create a function
boolean findWord(int row, int col, int d_row, int d_col, char[] word);
It can take current matrix position ((row, col), where word is supposed to start), search direction ((d_row, d_col)) and a word to look for. It returns whether the given word is here.
Then you can invoke it for different directions, e.g.
findWord(row, col, -1, 0, word);
findWord(row, col, -1, 1, word);
findWord(row, col, 0, 1, word);
...
(I'm listing them in clock-wise order)
Implementing findWord is just incrementing current position by d_row and d_col, until we find mismatch in characters or word ends. The basic routine is like this
while (row < total_rows && row >= 0 && col < total_columns && col >= 0) {
// check character here
...
row += d_row;
col += d_col;
}
I bet you'll have all processing code (except input-reading) in 40 lines.
You first need to understand how to search a short string inside a bigger string. There are couple of options here: from the simplest algorithm up to more complex (like Knuth Morris Pratt and the family). You can get a list of their descriptions here: http://en.wikipedia.org/wiki/String_searching_algorithm. I strongly recommend you try the naive search first.
Once you can search a string inside another string you will need to abstract the way you access the bigger string and adapt the matrix data to it.
Basically assuming this matrix:
1 2 3 4
-------
1| a b c d
2| b c d a
3| c d a b
4| d a b c
and this string abc
you will first make some code to be able to find abc inside abcd or bcda or cdab etc.
Once you can do that you should build the intermediate step of extracting (for each possible lookup type: horizontal, vertical, diagonal, reverse diagonal) series of chars and apply the previous algorithm on them.
For example if we want to search diagonally we would generate 7 strings from the matrix:
a
bb
ccc
dddd
aaa
bb
c
if you want to search horizontally you would generate those strings:
abcd
bcda
cdab
dabc
and seach inside each string.
Once this is working you should combine the searching with reading the proper chars from the matrix. Hopefully if you follow this path you will be able to figure it out :).
Good luck.
To travel diagonally in any 2D matrix of arbitrary dimensions, hope the below function helps.
public static void prinDiagonalsInGrid(char[][] grid, int rows, int cols)
{
String result = "";
int min = Math.min(rows, cols);
int max = Math.max(rows, cols);
int sameLengthDiagonals = max - min + 1;
int totalDiagonals = (rows + cols) - 1;
for (int p = 0; p < totalDiagonals; p++)
{
int xIndex;
int maxCnt;
if (p < (min - 1)) // First diagonals
{
maxCnt = xIndex = p;
}
// diagonals of equal length in the middle
else if (sameLengthDiagonals != 0 &&
p >= (min - 1) && p < (sameLengthDiagonals + min - 1))
{
if (rows < cols)
xIndex = rows - 1;
else
xIndex = p;
maxCnt = min - 1;
}
else // Last diagonals
{
xIndex = rows - 1;
maxCnt = totalDiagonals - p - 1;
}
for (int cnt = 0; cnt <= maxCnt; cnt++)
{
result += grid[xIndex][p - xIndex] + " ";
--xIndex;
}
result += "\n";
}
System.out.println(result);
}

Categories