randomEmpty() returns a random coordinate on the n x n grid that is empty (Method works). randomAdjacent() uses randomEmpty() to select an EMPTY coordinate on the map. Comparisons are then made to see if this coordinate has an VALID adjacent coordinate that is NON-EMPTY. The PROBLEM is that randomAdjacent does not always return the coordinates of space with an adjacent NON-EMPTY space. It will always return valid coordinates but not the latter. I can't spot the problem. Can someone help me identify the problem?
public int[] randomEmpty()
{
Random r = new Random();
int[] random = new int[2];
int row = r.nextInt(array.length);
int column = r.nextInt(array.length);
while(!(isEmpty(row,column)))
{
row = r.nextInt(array.length);
column = r.nextInt(array.length);
}
random[0] = row+1;
random[1] = column+1;
return random;
}
public int[] randomAdjacent()
{
int[] adjacentToX = new int[8];
int[] adjacentToY = new int[8];
int[] adjacentFrom = randomEmpty();
int count;
boolean isTrue = false;
boolean oneAdjacentNotEmpty = false;
while(!(oneAdjacentNotEmpty))
{
count = 0;
if(validIndex(adjacentFrom,1,-1))
{
adjacentToX[count] = adjacentFrom[0]+1;
adjacentToY[count] = adjacentFrom[1]-1;
count++;
}
if(validIndex(adjacentFrom,0,-1))
{
adjacentToX[count] = adjacentFrom[0];
adjacentToY[count] = adjacentFrom[1]-1;
count++;
}
if(validIndex(adjacentFrom,-1,-1))
{
adjacentToX[count] = adjacentFrom[0]-1;
adjacentToY[count] = adjacentFrom[1]-1;
count++;
}
if(validIndex(adjacentFrom,-1,0))
{
adjacentToX[count] = adjacentFrom[0]-1;
adjacentToY[count] = adjacentFrom[1];
count++;
}
if(validIndex(adjacentFrom,-1,1))
{
adjacentToX[count] = adjacentFrom[0]-1;
adjacentToY[count] = adjacentFrom[1]+1;
count++;
}
if(validIndex(adjacentFrom,0,1))
{
adjacentToX[count] = adjacentFrom[0];
adjacentToY[count] = adjacentFrom[1]+1;
count++;
}
if(validIndex(adjacentFrom,1,1))
{
adjacentToX[count] = adjacentFrom[0]+1;
adjacentToY[count] = adjacentFrom[1]+1;
count++;
}
if(validIndex(adjacentFrom,1,0))
{
adjacentToX[count] = adjacentFrom[0]+1;
adjacentToY[count] = adjacentFrom[1];
count++;
}
for(int i = 0; i < count; i++)
{
if(!(isEmpty(adjacentToX[i],adjacentToY[i])))
{
oneAdjacentNotEmpty = true;
isTrue = true;
}
}
if(isTrue)
break;
else
adjacentFrom = randomEmpty();
}
return adjacentFrom;
}
public boolean validIndex(int[] a,int i, int j)
{
try
{
Pebble aPebble = array[a[0]+i][a[1]+j];
return true;
}
catch(ArrayIndexOutOfBoundsException e)
{
return false;
}
}
public void setCell(int xPos, int yPos, Pebble aPebble)
{
array[xPos-1][yPos-1] = aPebble;
}
public Pebble getCell(int xPos, int yPos)
{
return array[xPos-1][yPos-1];
}
JUNIT Test Performed:
#Test
public void testRandomAdjacent() {
final int size = 5;
final Board board2 = new Board(size);
board2.setCell(1, 1, Pebble.O);
board2.setCell(5, 5, Pebble.O);
int[] idx = board2.randomAdjacent();
int x = idx[0];
int y = idx[1];
boolean empty = true;
for (int i = x - 1; i <= x + 1; i++) {
for (int j = y - 1; j <= y + 1; j++) {
if ((i == x && j == y) || i < 1 || j < 1 || i > size || j > size) {
continue;
}
if (board2.getCell(i, j) != Pebble.EMPTY)
empty = false;
}
}
assertFalse(empty);// NEVER gets SET TO FALSE
assertEquals(Pebble.EMPTY, board2.getCell(x, y));
}
As for the answer: I got carried away optimizing your code for readability. I'd think it's most likely
if (board2.getCell(i, j) != Pebble.EMPTY)
empty = false;
causing the problem as getCell operates in 1-based coordinates, but i, j are in 0-based.
You should think about your logic overall. The way I see it, your code might never terminate as randomEmpty() could keep returning the same field over and over again for an undetermined period of time.
I took the liberty to recode your if-if-if cascade into utility method easier to read:
public boolean hasNonEmptyNeighbor(int[] adjacentFrom) {
for(int i = -1; i <= 1; ++i) {
for(int j = -1; j <= 1; ++j) {
if(validIndex(adjacentFrom, i, j) //Still inside the board
&& // AND
!isEmpty(adjacentFrom[0]+i //not empty
,adjacentFrom[1]+j)) {
return true;
}
}
}
return false;
}
Given my previous comment about random() being not the best of choices if you need to cover the full board, your main check (give me an empty cell with a non-empty neighbor) could be rewritten like this:
public void find() {
List<Point> foundPoints = new ArrayList<Point>();
for(int i = 0; i < Board.height; ++i) { //Assumes you have stored your height
for(int j = 0; j < Board.width; ++j) { //and your width
if(isEmpty(i, j) && hasNonEmptyNeighbor(new int[]{i,j})) {
//Found one.
foundPoints.add(new Point(i, j));
}
}
}
//If you need to return a RANDOM empty field with non-empty neighbor
//you could randomize over length of foundPoints here and select from that list.
}
Related
I'm doing a school assignment (so still a noob) but cannot seem to figure out why i keep getting IndexOutOfBoundsException. any help is appreciation. It's most likely some stupid mistake but i've gotten very good at not noticing those. It's supposed to separate slice objects in to 3 ArrayLists, scramble those lists, then put them back in the correct order based on color.
public void scramble()
{
ArrayList<Slice> temp = new ArrayList<>();
ArrayList<Slice> red = new ArrayList<>();
ArrayList<Slice> black = new ArrayList<>();
ArrayList<Slice> blue = new ArrayList<>();
int blackListCount = 0;
int redListCount = 0;
int blueListCount = 0;
for (Slice s : slices) {
if (s.getColor().equals("red")) {
red.add(s);
} else if (s.getColor().equals("black")) {
black.add(s);
} else if (s.getColor().equals("blue")) {
blue.add(s);
}
}
blueScram(blue);
blackScram(black);
redScram(red);
for (int i = 0; i < slices.size() - 1; i++) {
if (i % 5 == 0) {
temp.add(i, black.get(blackListCount));
blackListCount++;
}
if (i % 2 == 0) {
temp.add(i, blue.get(blueListCount));
blueListCount++;
}
if (i % 2 == 1) {
temp.add(i, red.get(redListCount));
redListCount++;
}
}
slices.clear();
slices = temp;
}
private void blueScram(ArrayList<Slice> blue) {
for (int i = 0; i < blue.size(); i++) {
switchSlice(blue, i, (int) (Math.random() * (blue.size())));
}
}
private void redScram(ArrayList<Slice> red) {
for (int i = 0; i < red.size(); i++) {
switchSlice(red, i, (int) (Math.random() * (red.size())));
}
}
private void blackScram(ArrayList<Slice> black) {
for (int i = 0; i < black.size(); i++) {
switchSlice(black, i, (int) (Math.random() * (black.size())));
}
}
private void switchSlice(ArrayList<Slice> list, int firstIndex, int lastIndex) {
try {
Slice temp = list.get(firstIndex);
list.set(firstIndex, list.get(lastIndex));
list.set(lastIndex, temp);
} catch (IndexOutOfBoundsException e) {
System.out.println("IndexOutBounds while trying to randomize/switch elements of a slice list");
e.printStackTrace();
}
}
Here's the initial (given) slice creation / sorting code
private static int[] getStandardPrizes()
{
int[] arr = new int[20];
for (int i=0; i < 20; i++)
{
if (i%5 == 0)
arr[i] = i*1000;
else if (i%2 == 1)
arr[i] = i*100;
else
arr[i] = i*200;
}
return arr;
}
I get errors at if(i % 5 == 0) and the other if statements within the scope of the surrounding for loop
I am attempting to make a random maze generator using Java and the recursive backtracking algorithm. I am getting stack overflow when I try to run this code. I know some about stack, I don't think this is infinite recursion. My guess is that I have a big logic error. Do I have to allocate more memory?
The stack trace:
Exception in thread "main" java.lang.StackOverflowError
at java.base/java.util.Vector.elementAt(Vector.java:499)
at java.base/java.util.Stack.peek(Stack.java:103)
at java.base/java.util.Stack.pop(Stack.java:84)
at mazeMaker.Maze.generateMaze(Maze.java:115)
at mazeMaker.Maze.generateMaze(Maze.java:115)
...
at mazeMaker.Maze.generateMaze(Maze.java:115)
at mazeMaker.Maze.generateMaze(Maze.java:115)
Main.java
package mazeMaker;
public class Main
{
public static void main(String[] args)
{
Maze mainMaze = new Maze(20, 30);
}
}
Maze.java
package mazeMaker;
import java.util.Random;
import java.util.Stack;
public class Maze
{
public int xSize = 0;
public int ySize = 0;
public int totalDimensions = 0;
Random randomGenerator = new Random();
public Cell[][] cellData;
public Stack<Cell> cellStack = new Stack<Cell>();
Cell tempCell; // Temporary variable used for maze generation
public Maze(int xSize, int ySize)
{
cellData = new Cell[xSize][ySize];
this.xSize = xSize;
this.ySize = ySize;
this.totalDimensions = this.xSize * this.ySize;
// Initialize array objects
for (int i = 0; i < this.xSize; i++)
{
for (int j = 0; j < this.ySize; j++)
{
cellData[i][j] = new Cell();
}
}
// Assign x and y positions
for (int i = 0; i < this.xSize; i++)
{
for (int j = 0; j < this.ySize; j++)
{
cellData[i][j].xPos = i;
cellData[i][j].yPos = j;
}
}
initBoundries();
generateMaze();
}
private void initBoundries()
{
// Initialize the border cells as visited so we don't go out of bounds
int m = this.xSize;
int n = this.ySize;
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
if (i == 0 || j == 0 || i == n - 1 || j == n - 1)
cellData[i][j].hasBeenVisited = true;
}
}
}
private void generateMaze(int x, int y)
{
// Set current cell as visited
cellData[x][y].hasBeenVisited = true;
// While there are unvisited neighbors
while (!cellData[x][y+1].hasBeenVisited || !cellData[x+1][y].hasBeenVisited || !cellData[x][y-1].hasBeenVisited || !cellData[x-1][y].hasBeenVisited)
{
// Select a random neighbor
while (true)
{
int r = randomGenerator.nextInt(4);
if (r == 0 && !cellData[x][y+1].hasBeenVisited)
{
cellStack.push(cellData[x][y]);
cellData[x][y].hasNorthWall = false;
cellData[x][y+1].hasSouthWall = false;
generateMaze(x, y + 1);
break;
}
else if (r == 1 && !cellData[x+1][y].hasBeenVisited)
{
cellStack.push(cellData[x][y]);
cellData[x][y].hasEastWall = false;
cellData[x+1][y].hasWestWall = false;
generateMaze(x+1, y);
break;
}
else if (r == 2 && !cellData[x][y-1].hasBeenVisited)
{
cellStack.push(cellData[x][y]);
cellData[x][y].hasSouthWall = false;
cellData[x][y-1].hasNorthWall = false;
generateMaze(x, y-1);
break;
}
else if (r == 3 && !cellData[x-1][y].hasBeenVisited)
{
cellStack.push(cellData[x][y]);
cellData[x][y].hasWestWall = false;
cellData[x-1][y].hasEastWall = false;
generateMaze(x-1, y);
break;
}
}
}
// There are no unvisited neighbors
tempCell = cellStack.pop();
generateMaze(tempCell.xPos, tempCell.yPos);
}
// Begin generating maze at top left corner
private void generateMaze()
{
generateMaze(1,1);
}
}
Cell.java
package mazeMaker;
public class Cell
{
public boolean isCurrentCell;
public boolean hasBeenVisited;
public boolean hasNorthWall;
public boolean hasSouthWall;
public boolean hasEastWall;
public boolean hasWestWall;
public int xPos;
public int yPos;
}
The method generateMaze can never terminate not even by chance for some simple reason:
For terminating the generateMaze method would need to finish it's execution - it has to return.
There are no return statements in this method, therefore it has to pass the while loops and then continue until the execution reaches and finishes the last statement of the method.
However the last statement is generateMaze(tempCell.xPos, tempCell.yPos); which starts a new recursion, therefore your code can never ever terminate!
I tried to run your project on my own environment but unfortunately, I was not able to reproduce your issue.
However, I was facing an IndexOutOfBound exception in the method generateMaze. While I was solving this, I figured out that there was an issue in the initBoudaries method.
Indeed, when you set the boolean hasBeenVisited to true, you do not use the right variable in the IF clause. Here is the version I tried instead :
private void initBoundries()
{
// Initialize the border cells as visited so we don't go out of bounds
for (int i = 0; i < this.xSize; i++)
{
for (int j = 0; j < ySize; j++)
{
if (i == 0 || j == 0 || i == xSize - 1 || j == ySize - 1)
cellData[i][j].hasBeenVisited = true;
}
}
}
Now about the emptyStackException, I think that if this stack is empty, this means that there is no more cell to handle (as you mentioned in your comment) and the program must end. If I am right, just make sure to test if your stack is empty before call the method pop() on it like this :
// There are no unvisited neighbors
if (!cellStack.isEmpty()) {
tempCell = cellStack.pop();
generateMaze(tempCell.xPos, tempCell.yPos);
}
Hope it will help.
I am trying to write a program which can solve the 8-Puzzle problem.I am using the A* algorithm to find the solution.
I have reviewed my code many times and also tried making some changes.
Even my friends tried to help me find the bug,but they couldn't. I still don't understand where i went wrong.I used javadocs to see if I did something wrong,even that din't solve my problem. I have created three classes to solve this problem.
import java.util.*;
public class Solver implements Iterable<State>
{
ArrayList<State> queue,solQueue;
public int sol[][] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 0 } };
int temp[][],i;
int moves;
int leastPriority,removeIndex;
State removeTemp;
public Solver(State initial)
{
queue = new ArrayList<State>();
solQueue = new ArrayList<State>();
queue.ensureCapacity(16);
solQueue.ensureCapacity(16);
temp = new int[3][3];
i=1;
leastPriority = 100;
removeTemp=initial;
queue.add(removeTemp);
Iterator<State> qu = queue.iterator();
while(removeTemp.m!=sol)
{
leastPriority = 100;
i=0;
queue.iterator();
for (State s : queue)
{
if((s.mh + s.count) <leastPriority)
{
leastPriority = (s.mh + s.count);
removeIndex = i;
}
if(qu.hasNext())
i++;
}
for(State s : removeTemp.neighbours() )
{
queue.add(s);
}
removeTemp=queue.remove(removeIndex);
solQueue.add(removeTemp);
}
this.moves();
this.solution();
}
public int moves()
{
System.out.print("Solution found out in "+ moves+" moves");
moves = removeTemp.count;
return moves;
}
public Iterable<State> solution()
{
for(State s : solQueue)
{
System.out.println(s.m);
System.out.println("");
}
return solQueue;
}
#SuppressWarnings({ "unchecked", "rawtypes" })
#Override
public Iterator iterator() {
return null;
}
}
And the JVM is throwing an exception.
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index: 0,Size: 0
at java.util.ArrayList.rangeCheck(Unknown Source)
at java.util.ArrayList.get(Unknown Source)
at Solver.<init>(Solver.java:41)
at Main.main(Main.java:13)
What i don't understand is that how can the size of the ArrayList be 1 when i have explicitly state it as 16.
The State Class has the heuristic function which is suppose to make the algorithm efficient.The following is the State Class.
import java.util.ArrayList;
import java.util.Iterator;
public class State implements Iterable<State>
{
public int sol[][] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 0 } };
int m[][], bi, bj, count, priority, si, sj;
int i,j,tempm[][];
int mh = 0;
boolean isInitialState, isRepeatedState;
State previousState, tempState;
ArrayList<State> neighbourStates;
public State(State s, int c, int[][] array)
{
neighbourStates = new ArrayList<State>();
neighbourStates.ensureCapacity(16);
tempState =this;
m = new int[3][3];
m=array;
if (s == null)
{
isInitialState = true;
count = 0;
previousState =null;
}
else
{
previousState = s;
count = c+1;
}
this.findZero();
this.manhattanHeuristic();
}
private void findZero()
{
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
{
if(m[i][j]==0)
{
bi=i;
bj=j;
}
}
}
private void manhattanHeuristic() {
int n = 1;
mh = 0;
for (int i = 0; i < 3; i++)
Z: for (int j = 0; j < 3; j++) {
if ((i == bi) && (j == bj)) {
continue Z;
}
else if (m[i][j] == n) {
n++;
}
else {
this.getSolutionIndex();
mh = mh + Math.abs(i - si) + Math.abs(j - sj);
}
}
}
void getSolutionIndex() {
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++) {
if (m[i][j] == 0) {
si = i;
sj = j;
}
}
}
public Iterable<State> neighbours()
{
tempm = m;
this.up();
if(!(equals(tempm)))
{
tempState = new State(this,count,tempm);
neighbourStates.add(tempState);
}
this.down();
if(!(equals(tempm)))
{
tempState = new State(this,count,tempm);
neighbourStates.add(tempState);
}
this.left();
if(!(equals(tempm)))
{
tempState = new State(this,count,tempm);
neighbourStates.add(tempState);
}
this.right();
if(!(equals(tempm)))
{
tempState = new State(this,count,tempm);
neighbourStates.add(tempState);
}
return neighbourStates;
}
public boolean equals(int s[][])
{
if((isInitialState==false)&&(previousState.m == s))
return true;
else
return false;
}
#Override
public Iterator<State> iterator() {
// TODO Auto-generated method stub
return null;
}
public void up()
{
if ((bi > 1) && (bi < 2) && (bj < 3)&& (bj > 1))
{
i = bi;
i = i + 1;
this.move(i,bj);
}
}
public void down()
{
if ((bi > 2) && (bi < 3) && (bj < 3) && (bj > 1))
{
i = bi;
i = i - 1;
this.move(i,bj);
}
}
public void left()
{
if ((bi > 1) && (bi < 3) && (bj < 2)&& (bj > 1)) {
j = bj;
j = j + 1;
this.move(bi, j);
}
}
public void right()
{
if ((bi > 1) && (bi < 3) && (bj < 3) && (bj > 2)) {
j = bj;
j = j - 1;
this.move(bi, j);
}
}
public void move(int x, int y) {
{
tempm = m;
}
if ((tempm[x + 1][y] == 0) || (tempm[x - 1][y] == 0) || (tempm[x][y + 1] == 0)|| (tempm[x][y - 1] == 0)) {
tempm[bi][bj] = tempm[x][y];
tempm[x][y] = 0;
bi = x;
bj = y;
}
}
}
And the finally the class with the main function.
import java.util.Scanner;
public class Main {
public static void main(String[] args)
{
#SuppressWarnings("resource")
Scanner sc = new Scanner(System.in);
int[][] tiles = new int[3][3];
System.out.println("Enter the elements");
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
tiles[i][j] = sc.nextInt();
State initial = new State(null,0,tiles);
Solver solver = new Solver(initial);
solver.solution();
System.out.println("Minimum number of moves = " + solver.moves());
}
}
What i don't understand is that how can the size of the ArrayList be 1 when i have explicitly state it as 16.
You did not set the size of the ArrayList to 16. You've set the capacity:
queue.ensureCapacity(16);
solQueue.ensureCapacity(16);
This does not make the ArrayList have a size of 16.
An ArrayList has an array to hold its data. When you add more elements to the ArrayList and its internal array is full, it will have to allocate a larger array and copy the content of what it currently holds plus the new element.
The capacity of the ArrayList is the minimum size that the internal array has. You can use ensureCapacity to make sure that the ArrayList doesn't have to resize too often (resizing and copying the content is an expensive operation). So, ensureCapacity is a call you make to make it work effiently.
It does not make the ArrayList have 16 elements; it only makes sure that the ArrayList has room for at least 16 elements.
If you want the ArrayList to have 16 elements, you'll have to add those elements one by one.
Size of the collection and the capacity are 2 different concepts.
capacity represents the maximum size of items a collection can hold without a reallocation.
size represents the current number of items in the collection.
IndexOutOfBoundsException is saying that you are trying to access an item with index that does not exist in the collection.
please try the below code in Solver.java
if(!queue.isEmpty())
removeTemp=queue.remove(removeIndex);
else
break;
public class DoubleMatrix
{
private double[][] doubMatrix;
public DoubleMatrix(int row, int col)
{
if(row > 0 && col > 0)
{
makeDoubMatrix(row,col);
}
else
{
row = 1;
col = 1;
}
}
public DoubleMatrix(double[][] tempArray)
{
if(tempArray != null)
{
for(int i = 0; i < tempArray.length-1;i++)
{
if(tempArray[i].length == tempArray[i+1].length)
{
tempArray = doubMatrix;
}
}
}
else
{
makeDoubMatrix(1,1);
}
}
public int getDim1()
{
return doubMatrix.length;
}
public int getDim2()
{
return doubMatrix[0].length;
}
private void makeDoubMatrix(int row, int col)
{
double[][] tempArray = new double[row][col];
for (int i = 0;i < row;i++)
{
for(int j = 0;j < col;j++)
{
tempArray[i][j] = Math.random() * (100);
doubMatrix[i][j] = tempArray[i][j];
}
}
}
public DoubleMatrix addMatrix(DoubleMatrix secondMatrix)
{
//this. doubMatrix = doubMatrix;
double[][] tempArray;
if(secondMatrix.doubMatrix.length == doubMatrix.length)
if(secondMatrix.doubMatrix[0].length == doubMatrix[0].length)
{
tempArray = new double[doubMatrix.length][doubMatrix[0].length];
for(int i = 0; i< secondMatrix.doubMatrix.length;i++)
for(int j = 0; j< secondMatrix.doubMatrix[i].length;j++ )
{
tempArray[i][j] = secondMatrix.doubMatrix[i][j] + doubMatrix[i][j];// add two matrices
}//end for
return new DoubleMatrix (tempArray);
}
return new DoubleMatrix(1,1);
}
public DoubleMatrix getTransposedMatrix()
{
double[][] tempArray = new double[doubMatrix.length][doubMatrix[0].length];
for(int i = 0;i < doubMatrix.length;i++)
for(int j = 0;j < doubMatrix[i].length;j++)
{
tempArray[j][i] = doubMatrix[i][j];// transposed matrix2
}//end for
return new DoubleMatrix(tempArray);
}
public DoubleMatrix multiplyingMatrix(DoubleMatrix secondMatrix)
{
double[][] tempArray = new double[secondMatrix.doubMatrix.length][doubMatrix[0].length];
//check if dimension of matrix1 equal to dimension of matrix2
if(secondMatrix.doubMatrix[0].length == doubMatrix.length)
if(doubMatrix.length == secondMatrix.doubMatrix[0].length)
{
for (int i = 0; i <secondMatrix.doubMatrix.length; i++)
{
for(int j = 0; j < doubMatrix[0].length; j++)
{
for (int k = 0; k < doubMatrix.length; k++)
{
tempArray[i][j] = tempArray[i][j] + secondMatrix.doubMatrix[i][k]*doubMatrix[k][j]; // multiply 2 matrices
}
}
}//end for
}// end if
return new DoubleMatrix(1,1);
}
public void printMatrix(String text)
{
System.out.println(text);// output string
for(int i = 0; i< doubMatrix.length;i++)
{
for(int j = 0; j< doubMatrix[i].length;j++ ) {
System.out.printf("%9.1f", doubMatrix[i][j]);// out put value for matrices
}
System.out.println();
}
}
}
public class Program3
{
public static void main(String[] args)
{
int num1 = (int) (Math.random()*(10-3+1)+3);
int num2 = (int) (Math.random()*(10-3+1)+3);
DoubleMatrix doubMatObj1 = new DoubleMatrix(num1,num2);
DoubleMatrix doubMatObj2 = new DoubleMatrix(doubMatObj1.getDim1(),doubMatObj1.getDim2());
DoubleMatrix doubMatObj3;
doubMatObj2.getDim1();
doubMatObj3 = doubMatObj1.addMatrix(doubMatObj2);
doubMatObj1.printMatrix("First Matrix Object");
doubMatObj2.printMatrix("Second Matrix Object");
doubMatObj3.printMatrix("Result of Adding Matrix Objects");
doubMatObj2 = doubMatObj2.getTransposedMatrix();
doubMatObj2.printMatrix("Result of inverting Matrix Object");
doubMatObj3 = doubMatObj1.multiplyingMatrix(doubMatObj2);
doubMatObj3.printMatrix("Result of Multiplying Matrix Objects");
}
}
Hi, I have a NullPointerException error in the last line statement of the makeDoubMatrix method as well the call makedoubMatrix in side if statement of the first constructor.
doubMatrix seems to be null when I already initialize it. How will I be able to fix this problem ?
You want to initialize the array, i.e.:
private double[][] doubMatrix = new double[size1][size2];
where size1 and size2 are arbitrary sizes. What you probably want is:
if(row > 0 && col > 0)
{
doubMatrix = new double[row][col];
makeDoubMatrix(row,col);
}
else
{
doubMatrix = new double[1][1];
makeDoubMatrix(1,1);
}
which initializes the array doubMatrix to a size of row*col if both row and col are greather than 0, and to 1*1 otherwise, then calls makeDoubMatrix with its initialized size (you could have this method call after the if-else, using doubMatrix.size and doubMatrix[0].size, but I think it's more readable now).
Change the second constructor (which takes a 2D array) using the same reasoning.
You're not initializing doubMatrix. The only line which assigns a value to doubMatrix is this commented out one:
//this. doubMatrix = doubMatrix;
(And that wouldn't help.)
Ask yourself where you think you're initializing it - where do you think you've got something like:
doubMatrix = new double[1][2];
... or an assignment copying a value from another array:
doubMatrix = someOtherVariable;
If you haven't got any statements assigning it a value, you aren't initializing it, so it will always have the default value of null.
I'm trying to solve the problem of positioning N queens on NxN board without row, column and diagonal conflicts. I use an algorithm with minimizing the conflicts. Firstly, on each column randomly a queen is positioned. After that, of all conflict queens randomly one is chosen and for her column are calculated the conflicts of each possible position. Then, the queen moves to the best position with min number of conflicts. It works, but it runs extremely slow. My goal is to make it run fast for 10000 queens. Would you, please, suggest me some improvements or maybe notice some mistakes in my logic?
Here is my code:
public class Queen {
int column;
int row;
int d1;
int d2;
public Queen(int column, int row, int d1, int d2) {
super();
this.column = column;
this.row = row;
this.d1 = d1;
this.d2 = d2;
}
#Override
public String toString() {
return "Queen [column=" + column + ", row=" + row + ", d1=" + d1
+ ", d2=" + d2 + "]";
}
#Override
public boolean equals(Object obj) {
return ((Queen)obj).column == this.column && ((Queen)obj).row == this.row;
}
}
And:
import java.util.HashSet;
import java.util.Random;
public class SolveQueens {
public static boolean printBoard = false;
public static int N = 100;
public static int maxSteps = 2000000;
public static int[] queens = new int[N];
public static Random random = new Random();
public static HashSet<Queen> q = new HashSet<Queen>();
public static HashSet rowConfl[] = new HashSet[N];
public static HashSet d1Confl[] = new HashSet[2*N - 1];
public static HashSet d2Confl[] = new HashSet[2*N - 1];
public static void init () {
int r;
rowConfl = new HashSet[N];
d1Confl = new HashSet[2*N - 1];
d2Confl = new HashSet[2*N - 1];
for (int i = 0; i < N; i++) {
r = random.nextInt(N);
queens[i] = r;
Queen k = new Queen(i, r, i + r, N - 1 + i - r);
q.add(k);
if (rowConfl[k.row] == null) {
rowConfl[k.row] = new HashSet<Queen>();
}
if (d1Confl[k.d1] == null) {
d1Confl[k.d1] = new HashSet<Queen>();
}
if (d2Confl[k.d2] == null) {
d2Confl[k.d2] = new HashSet<Queen>();
}
((HashSet<Queen>)rowConfl[k.row]).add(k);
((HashSet<Queen>)d1Confl[k.d1]).add(k);
((HashSet<Queen>)d2Confl[k.d2]).add(k);
}
}
public static void print () {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
System.out.print(queens[i] == j ? "♕ " : "◻◻◻ ");
}
System.out.println();
}
System.out.println();
}
public static boolean checkItLinear() {
Queen r = choseConflictQueen();
if (r == null) {
return true;
}
Queen newQ = findNewBestPosition(r);
q.remove(r);
q.add(newQ);
rowConfl[r.row].remove(r);
d1Confl[r.d1].remove(r);
d2Confl[r.d2].remove(r);
if (rowConfl[newQ.row] == null) {
rowConfl[newQ.row] = new HashSet<Queen>();
}
if (d1Confl[newQ.d1] == null) {
d1Confl[newQ.d1] = new HashSet<Queen>();
}
if (d2Confl[newQ.d2] == null) {
d2Confl[newQ.d2] = new HashSet<Queen>();
}
((HashSet<Queen>)rowConfl[newQ.row]).add(newQ);
((HashSet<Queen>)d1Confl[newQ.d1]).add(newQ);
((HashSet<Queen>)d2Confl[newQ.d2]).add(newQ);
queens[r.column] = newQ.row;
return false;
}
public static Queen choseConflictQueen () {
HashSet<Queen> conflictSet = new HashSet<Queen>();
boolean hasConflicts = false;
for (int i = 0; i < 2*N - 1; i++) {
if (i < N && rowConfl[i] != null) {
hasConflicts = hasConflicts || rowConfl[i].size() > 1;
conflictSet.addAll(rowConfl[i]);
}
if (d1Confl[i] != null) {
hasConflicts = hasConflicts || d1Confl[i].size() > 1;
conflictSet.addAll(d1Confl[i]);
}
if (d2Confl[i] != null) {
hasConflicts = hasConflicts || d2Confl[i].size() > 1;
conflictSet.addAll(d2Confl[i]);
}
}
if (hasConflicts) {
int c = random.nextInt(conflictSet.size());
return (Queen) conflictSet.toArray()[c];
}
return null;
}
public static Queen findNewBestPosition(Queen old) {
int[] row = new int[N];
int min = Integer.MAX_VALUE;
int minInd = old.row;
for (int i = 0; i < N; i++) {
if (rowConfl[i] != null) {
row[i] = rowConfl[i].size();
}
if (d1Confl[old.column + i] != null) {
row[i] += d1Confl[old.column + i].size();
}
if (d2Confl[N - 1 + old.column - i] != null) {
row[i] += d2Confl[N - 1 + old.column - i].size();
}
if (i == old.row) {
row[i] = row[i] - 3;
}
if (row[i] <= min && i != minInd) {
min = row[i];
minInd = i;
}
}
return new Queen(old.column, minInd, old.column + minInd, N - 1 + old.column - minInd);
}
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
init();
int steps = 0;
while(!checkItLinear()) {
if (++steps > maxSteps) {
init();
steps = 0;
}
}
long endTime = System.currentTimeMillis();
System.out.println("Done for " + (endTime - startTime) + "ms\n");
if(printBoard){
print();
}
}
}
Edit:
Here is my a-little-bit-optimized solution with removing some unused objects and putting the queens on diagonal positions when initializing.
import java.util.Random;
import java.util.Vector;
public class SolveQueens {
public static boolean PRINT_BOARD = true;
public static int N = 10;
public static int MAX_STEPS = 5000;
public static int[] queens = new int[N];
public static Random random = new Random();
public static int[] rowConfl = new int[N];
public static int[] d1Confl = new int[2*N - 1];
public static int[] d2Confl = new int[2*N - 1];
public static Vector<Integer> conflicts = new Vector<Integer>();
public static void init () {
random = new Random();
for (int i = 0; i < N; i++) {
queens[i] = i;
}
}
public static int getD1Pos (int col, int row) {
return col + row;
}
public static int getD2Pos (int col, int row) {
return N - 1 + col - row;
}
public static void print () {
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
System.out.print(queens[i] == j ? "Q " : "* ");
}
System.out.println();
}
System.out.println();
}
public static boolean hasConflicts() {
generateConflicts();
if (conflicts.isEmpty()) {
return false;
}
int r = random.nextInt(conflicts.size());
int conflQueenCol = conflicts.get(r);
int currentRow = queens[conflQueenCol];
int bestRow = currentRow;
int minConfl = getConflicts(conflQueenCol, queens[conflQueenCol]) - 3;
int tempConflCount;
for (int i = 0; i < N ; i++) {
tempConflCount = getConflicts(conflQueenCol, i);
if (i != currentRow && tempConflCount <= minConfl) {
minConfl = tempConflCount;
bestRow = i;
}
}
queens[conflQueenCol] = bestRow;
return true;
}
public static void generateConflicts () {
conflicts = new Vector<Integer>();
rowConfl = new int[N];
d1Confl = new int[2*N - 1];
d2Confl = new int[2*N - 1];
for (int i = 0; i < N; i++) {
int r = queens[i];
rowConfl[r]++;
d1Confl[getD1Pos(i, r)]++;
d2Confl[getD2Pos(i, r)]++;
}
for (int i = 0; i < N; i++) {
int conflictsCount = getConflicts(i, queens[i]) - 3;
if (conflictsCount > 0) {
conflicts.add(i);
}
}
}
public static int getConflicts(int col, int row) {
return rowConfl[row] + d1Confl[getD1Pos(col, row)] + d2Confl[getD2Pos(col, row)];
}
public static void main(String[] args) {
long startTime = System.currentTimeMillis();
init();
int steps = 0;
while(hasConflicts()) {
if (++steps > MAX_STEPS) {
init();
steps = 0;
}
}
long endTime = System.currentTimeMillis();
System.out.println("Done for " + (endTime - startTime) + "ms\n");
if(PRINT_BOARD){
print();
}
}
}
Comments would have been helpful :)
Rather than recreating your conflict set and your "worst conflict" queen everything, could you create it once, and then just update the changed rows/columns?
EDIT 0:
I tried playing around with your code a bit. Since the code is randomized, it's hard to find out if a change is good or not, since you might start with a good initial state or a crappy one. I tried making 10 runs with 10 queens, and got wildly different answers, but results are below.
I psuedo-profiled to see which statements were being executed the most, and it turns out the inner loop statements in chooseConflictQueen are executed the most. I tried inserting a break to pull the first conflict queen if found, but it didn't seem to help much.
Grouping only runs that took more than a second:
I realize I only have 10 runs, which is not really enough to be statistically valid, but hey.
So adding breaks didn't seem to help. I think a constructive solution will likely be faster, but randomness will again make it harder to check.
Your approach is good : Local search algorithm with minimum-conflicts constraint. I would suggest try improving your initial state. Instead of randomly placing all queens, 1 per column, try to place them so that you minimize the number of conflicts. An example would be to try placing you next queen based on the position of the previous one ... or maybe position of previous two ... Then you local search will have less problematic columns to deal with.
If you randomly select, you could be selecting the same state as a previous state. Theoretically, you might never find a solution even if there is one.
I think you woud be better to iterate normally through the states.
Also, are you sure boards other than 8x8 are solvable?
By inspection, 2x2 is not, 3x3 is not, 4x4 is not.