I'm trying to solve a 9x9 sudoku puzzle using Simulated Annealing, but my implementation doesn't seem to be working correctly. It does not even get closer to a lower-cost solution but instead keeps circling around results that cost between 60 and 80.
My cost function returns the sum of three things: Number of repeating digits in each row, column and block (3x3).
And the successor (neighbour) function i implemented changes two randomly selected digits from the 9x9 grid with random values.
And here is my SA function that doesn't work as expected:
public static void simulatedAnnealing() {
Sudoku neighbour; // candidate successor object
final Double temperature = 2.0; // initial temperature
final Double coolingFactor = 0.999; // cooling constant
final int maxIterations = 1000; // number of iterations
for(Double t = temperature; t>1; t*=coolingFactor) {
for(int i = 0; i < maxIterations; i++) {
neighbour = sudoku.generateSuccessor(); // set random neighbour
int delta = neighbour.cost() - sudoku.cost(); // calculate delta
if (delta <= 0) {
sudoku = neighbour; // always accept good step.
} else {
if (Math.exp(-delta / temperature) > Math.random()) { // Simulated annealing
sudoku = neighbour;
}
}
}
System.out.println(sudoku.cost());
if(sudoku.cost() == 0) { break; } // if puzzle is solved
} }
Function for generating successors:
public Sudoku generateSuccessor() {
int[][] newGrid = new int[9][9];
for(int o = 0; o < 9; o ++) { // cloning current grid array
for(int g = 0; g < 9; g ++) {
newGrid[o][g] = grid[o][g];
}
}
Sudoku rndm = new Sudoku(newGrid); // random Sudoku object.
for (int i = 0; i < 2; i++) { // will randomize 2 cells in 9x9 grid.
int rndmCell = rndmValue(); // random digit for randomizing.
int randomRow = rndm(); // random row that will be randomized
int randomCol = rndm(); // random column that will be randomized
// prevent randomizing given cells in sudoku (in problem definition)
boolean shouldContinue = false;
for (Coordinate c : SudokuSolver.concreteCoordinates) {
if (c.row == randomRow && c.col == randomCol) {
shouldContinue = true;
break;
}
}
if (shouldContinue) {
i--;
continue;
}
// prevention end.
rndm.grid[randomRow][randomCol] = rndmCell;
}
return rndm;
}
Cost function:
public int cost() {
if(hasZeros()) { // if grid is not totally filled with numbers don't calculate its cost.
return -1;
}
int cost = 0;
for(int i = 0; i< 9; i++) { // find total collusions in rows&columns.
cost += findNumberOfCollusions(grid[i]); // find collustions at row 'i'.
cost += findNumberOfCollusions(getColumn(grid,i)); // find collustions at column 'i'.
}
for(int r = 0; r < 9; r += 3) { //find total colusions in blocks (3x3).
for(int c = 0; c < 9; c += 3) {
int[] block = new int[9];
int ctr = 0;
for (int i = r; i < r + 3; i++) {
for (int y = c; y < c+ 3; y++) {
block[ctr] = grid[i][y];
ctr++;
}
}
cost += findNumberOfCollusions(block);
}
}
return cost;
}
When i run the program the output is costs between 60 and 80. After that the temperature goes below the limit and the program outputs a solution that costs around that interval. Can anyone tell me what am i doing wrong? Thanks in advance.
I also had a similar problem to the one you describe, my fitness remained stuck (actually though, my problem was with not copying lists in Python). I can't really assure why your code gets stuck, but if I had to guess: the neighbor generation (int rndmCell = rndmValue(); int randomRow = rndm(); int randomCol = rndm();) may be actually doing more harm than good. Imagine that you have a nearly complete sudoku, but out of the blue two of the correct cells that you had now change their value to a complete opposite one, which is not only wrong on the cell itself but also on the row, column and/or 3x3 square. I'm no mathematician, but logic tells me that the more fitting the sudoku is (i.e. the closer its fitness is to 0), the more chances there are to mess up the sudoku by randomly changing cells. This approach may get you stuck on a local minimum easily.
A more "informed" solution for this problem would be to keep one of the three basic restrictions of the sudoku puzzle fixed by, for instance, generating rows that are permutations of the values [1..9], swapping two cells of a random row (thus still fulfilling the restriction), and calculating the fitness only on the columns and on the 3x3 squares. This choice of neighbor generation is usually more effective. If you are interested, this idea comes from the paper Metaheuristics can solve Sudoku puzzles. I can say that this idea helped me a lot and now the algorithm completes sudokus that I provide :)
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();
}
}
}
}
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;
}
I decided to write a logic solving algorithm for my Sudoku application. What I wrote works for a limited amount of grid values, but then the recursion stops way too soon.
What my methods do:
addToThirdDimension(): A three dimensional array stores any possible values that can be put into the grid value at logicGrid[x][y]. This method refreshes the three dimensional array. It does this by testing values 1-9 in every grid index, and if it's valid, it adds that number to the array. If not, it sets that value to zero.
checkValues(): Checks how many possibilities are left in the three dimensional grid. It goes through the logicGrid and returns the number of non-zero values are in the grid.
checkSingleValue(int row, int col): Checks logicGrid[row][col] to see if there is one and only one value left in there (If there is one value left, it is the only possibility for the grid element at [row, col]). It returns the amount of non-zero values that are in that grid location.
getSingleValue(int row, int col): Returns the single number that's left in logicGrid[row][col]
immutableValues: A two dimensional boolean array that stores whether or not a specific grid element is immutable or not. If it is immutable, the solve method should not touch it.
public boolean solveWithLogic(){
addToThirdDimension();
if(checkValues() == 0){
return true;
}
for(int row = 0; row < 9; row++){
for(int col = 0; col < 9; col++){
if(!immutableValues[row][col]){
if(checkSingleValue(row, col) == 1){
sGrid[row][col] = getSingleValue(row, col);
setValues[row][col] = true;
addToThirdDimension();
}
}
}
}
if(checkValues() != 0){
solveWithLogic();
} else{
return true;
}
return false;
}
I cannot see where I am going wrong. After a certain number of tries, checkValues returns 0 even though there should be more possibilities. Here is the code for addToThirdDimension() as I am sure that if something is wrong, it is here.
sGrid is the main two-dimensional integer array that stores the values for the puzzle.
public void addToThirdDimension(){
logicGrid = new int[9][9][9];
for(int x = 0; x < 9; x++){
for(int y = 0; y < 9; y++){
for(int z = 0; z < 9; z++){
logicGrid[x][y][z] = z + 1;
}
}
}
int[][] temp1 = sGrid;
for(int row = 0; row < 9; row++){
for(int col = 0; col < 9; col++){
if(setValues[row][col]){
for(int i = 0; i < 9; i++){
logicGrid[row][col][i] = 0;
}
} else{
for(int i = 1; i <= 9; i++){
temp1[row][col] = i;
if(!isColumnValid(col, temp1) && !isRowValid(row, temp1) &&
!isQuadrantValid(row, col, temp1){
logicGrid[row][col][i-1] = 0;
}
}
}
temp1[row][col] = sGrid[row][col];
}
}
}
The code isn't too efficient at the moment. I want to get it working before I start minimizing solve times.
The first thing I would do is create a SudukoCell object that stores your possible values in it. Then create a SudukoBoard with a 2d array of SudukoCells. Also give it an array of SudukoAreas. One area for rows, one area for cols, and one area for blocks.
Add your suduko cells appropriately.
This will help you consolidate your legwork and prevent silly mistakes.
then every time you solve a number, you can go to the cells in each of its areas and remove the number you solved from them.
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);
}