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
Related
I am writing a bin packing program in one dimension. I want only one possible bin. So it does not include a lot of bin its only one. This program is only searching quad groups and explode if quad groups are not equal to the searching number. I want to search every possible group that is bigger than quads.
In example we have 60 60 50 40 45 35 25 15 and we are looking for summing equal to 180 and answer is 60 60 45 15 that's fine but if we search 250 it will not working.
Can you help me?
That's the link for program https://github.com/omerbguclu/BinPacking1D
That's the code for the algorithm o array is the numbers, a array is the location of answers
public BinPacking() {
}
public void binpack(ArrayList<Integer> o, ArrayList<Integer> a, int wanted) {
int sum = 0;
if (wanted > 0) {
control(o, a, wanted);
if (is) {
return;
}
for (int i = 0; i < o.size(); i++) {
sum += o.get(i);
summing(o, a, wanted - sum, i + 1);
if (is) {
a.add(i);
return;
}
for (int j = i; j < o.size(); j++) {
if (i != j) {
sum += o.get(j);
summing(o, a, wanted - sum, j + 1);
if (is) {
a.add(i);
a.add(j);
return;
}
sum -= o.get(j);
}
}
sum -= o.get(i);
// "/////////////*******************////////////////////");
}
if (wanted != sum) {
System.out.println("There is not an answer with quad summing method");
}
}
}
public void summing(ArrayList<Integer> o, ArrayList<Integer> a, int wanted, int loop) {
int sum = 0;
if (loop < o.size() && wanted > 0) {
for (int i = loop; i < o.size(); i++) {
if (wanted == o.get(i)) {
a.add(i);
is = true;
return;
}
for (int j = loop; j < o.size(); j++) {
if (i != j) {
sum = o.get(i) + o.get(j);
if (wanted != sum) {
sum = 0;
} else {
a.add(i);
a.add(j);
is = true;
return;
}
}
// System.out.println("///////////////////////////////////");
}
}
System.out.println("There is not an answer with binary summing method");
}
}
public void control(ArrayList<Integer> o, ArrayList<Integer> a, int wanted) {
for (int i = 0; i < o.size(); i++) {
if (o.get(i) == wanted) {
a.add(i);
is = true;
break;
}
}
}
There is a pretty well established and efficient mechanism for getting every possible combination of a set of objects. Essentially you treat membership of the combination as a BitSet which represents whether each member of the set is in the combination. Then visiting every combination is just visiting every BitSet combination.
Here's how I tend to implement it:
public class Combo<T> implements Iterable<List<T>> {
private final List<T> set;
public Combo(List<T> set) {
this.set = set;
}
public Iterator<List<T>> iterator() {
BitSet combo = new BitSet(set.size());
return new Iterator<List<T>>() {
public boolean hasNext() {
return combo.cardinality() < set.size();
}
public List<T> next() {
int i = 0;
while (combo.get(i))
combo.clear(i++);
combo.set(i);
return combo.stream().mapToObj(set::get).collect(Collectors.toList());
}
};
}
}
So your solution would become:
for (List<Integer> combo: new Combo<>(...)) {
if (combo.size >= 4 && combo.stream.reduce(0, Integer::sum) == total)
....
}
A hackier version of the same idea would be:
for (long l = 0; l < 1 << (input.size() - 1); l++) {
List<Integer> combo = BitSet.valueOf(new long[]{l}).stream()
.mapToObj(input::get).collect(Collectors.toList());
if (combo.stream().mapToInt(n -> n).sum() == total) {
System.out.println(combo);
}
}
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.
}
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;
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.
Hey all, back again. Working on a dungeon generator and I'm actually surprising myself with the progress. Yet I still have a straggling room every now and then. I was wondering if there was a way to loop through an array and see if all the '1s' (the floor tiles) are connected, and if not, how to connect them.
Thanks!
EDIT: The array is randomly filled with rooms and corridors; here's the code:
import java.util.Random;
public class Level
{
Random random = new Random();
int[][] A = new int[100][100];
int minimum = 3;
int maximum = 7;
int xFeature = 0;
int yFeature = 0;
private void feature()
{
int i = 0;
while(i>=0)
{
xFeature = random.nextInt(100-1) + 1;
yFeature = random.nextInt(100-1) + 1;
if(A[xFeature][yFeature]==1)//||A[xFeature++][yFeature]==1||A[xFeature][yFeature--]==1||A[xFeature][yFeature++]==1)
break;
i++;
}
}
private void room()
{
int safeFall = 0;
int xCoPLUS = minimum + (int)(Math.random()*minimum);
int yCoPLUS = minimum + (int)(Math.random()*minimum);
if(yCoPLUS >= xCoPLUS)
{
for(int across = xFeature; across < xFeature+xCoPLUS+2; across++)
{
for(int vert = yFeature; vert < yFeature+yCoPLUS+1; vert++)
{
if(A[vert][across] == 0)
safeFall++;
else
break;
}
}
}
if(yCoPLUS < xCoPLUS)
{
for(int across = xFeature; across < xFeature+xCoPLUS+1; across++)
{
for(int vert = yFeature; vert < yFeature+yCoPLUS+2; vert++)
{
if(A[vert][across] == 0)
safeFall++;
else
break;
}
}
}
if((safeFall== (xCoPLUS+1) * (yCoPLUS+2)) || ((safeFall== (xCoPLUS+2) * (yCoPLUS+1))))
{
for(int across = xFeature; across < xFeature+xCoPLUS; across++)
{
for(int vert = yFeature; vert < yFeature+yCoPLUS; vert++)
{
A[vert][across] = 1;
}
}
}
}
private void corridor()
{
int xCoONE = xFeature;
int yCoONE = yFeature;
int xCoTWO = random.nextInt(10)+10;
int yCoTWO = random.nextInt(10)+10;
while(xCoONE > xCoTWO)
{
A[xCoONE][yCoONE] = 1;
xCoONE--;
}
while(xCoONE < xCoTWO)
{
A[xCoONE][yCoONE] = 1;
xCoONE++;
}
while(yCoONE > yCoTWO)
{
A[xCoONE][yCoONE] = 1;
yCoONE--;
}
while(yCoONE < yCoTWO)
{
A[xCoONE][yCoONE] = 1;
yCoONE++;
}
}
public Level()
{
firstroom();
for(int i = 0; i < 500; i++)
{
int x = random.nextInt(50);
feature();
if(x > 1)
room();
else
corridor();
}
troubleShoot();
}
So basically what happens when I create an object of this class is that a 100x100 array is filled with corridors and rooms determined by a random number. (well, a couple of them) But with how I have my room non-overlapping failsafe (safeFall in room()), I get stuck with a room that is one title out of reach every now and then.
The article Maze Generation Algorithm discusses several approaches to generating a maze. It includes links to Java examples.