This is all about the famous NQueens problem. My program works fine (backtrack approach). It finds all the solutions for a given board size.
Code is shown below.
I'm trying to modify the code so that I can find all the solutions for a given column of the first queen. I don't want to change the position of first queen. For an example it will provide me with the solution of
[2, 0, 3, 1, 4] and [2, 4, 1, 3, 0]
when I set the first queen at 2, board size 5 (third column, index starts from zero).
I tried this by setting different values for k (and board[k] as well) but doesn't quite reach the goal.
Any hints will be appreciated.
Here is my code. Removed details about place method since it shouldn't be changed to achieve my new goal.
public class NQueensAllSolutions
{
// Board size
static int size = 8;
// One dimensional array to store the column number for all queens.
static int[] board = new int[size];
// This method will check the validity for a new queen. works fine.
static boolean place(int k)
{
.
.
}
public static void main(String[] args)
{
int k;
long t=0; // for counting total found solutions
k = 0;
board[k] = -1;
while(k >= 0) {
board[k]++;
while(board[k] < size && !(place(k))) board[k]++;
if(board[k] < size) {
if(k == size-1) { // a solution is found.
t++;
//System.out.println("\n\nTotal: "+t+" --> "+Arrays.toString(board));
}
else {
k++; board[k] = -1;
}
}
else {
k--; // backtrack.
}
}
System.out.println("\n\nTotal: "+t);
}
}
Just keep k greater than 0 in the while loop:
import java.util.Arrays;
public class Queens
{
static int size = 5;
static int[] board = new int[size];
static boolean isValid(int k)
{
int c1 = board[k];
int c2 = board[k];
for(int r=k-1;r>=0;r--)
{
c1--;
c2++;
if(board[r] == board[k] || board[r] == c1 || board[r] == c2)
return false;
}
return true;
}
public static void main(String[] args)
{
int t = 0;
// Set the first queen position
board[0] = 2;
int k = 1;
board[k] = -1;
// k must stay greater than 0
while(k >= 1) {
board[k]++;
while(board[k] < size && !isValid(k))
board[k]++;
if(board[k] < size) {
if(k == size-1) {
t++;
System.out.println("Solution "+t+" --> "+Arrays.toString(board));
}
else {
k++;
board[k] = -1;
}
}
else {
k--;
}
}
}
}
Output:
Solution 1 --> [2, 0, 3, 1, 4]
Solution 2 --> [2, 4, 1, 3, 0]
UPDATE
Here is a generalized version that can force a queen at position (fixedRow, fixedCol).
The key change is the new getNextCol() method, which is used to get the next possible column for a queen. On row fixedRow, the only possible column is fixedCol. On the other rows, all columns are possible.
import java.util.Arrays;
public class Queens
{
static int size = 5;
static int fixedRow = 2;
static int fixedCol = 0;
static int[] board = new int[size];
static boolean isValid(int k)
{
int c1 = board[k];
int c2 = board[k];
for(int r=k-1;r>=0;r--)
{
c1--;
c2++;
if(board[r] == board[k] || board[r] == c1 || board[r] == c2)
return false;
}
return true;
}
static int getNextCol(int k, int col)
{
if(k == fixedRow) {
// Only one possible move on this row
return col == -1 ? fixedCol : size;
}
else {
// Try the next column
return col+1;
}
}
public static void main(String[] args)
{
int t = 0;
int k = 0;
board[k] = -1;
while(k >= 0) {
board[k] = getNextCol(k, board[k]);
while(board[k] < size && !isValid(k))
board[k] = getNextCol(k, board[k]);
if(board[k] < size) {
if(k == size-1) {
t++;
System.out.println("Solution "+t+" --> "+Arrays.toString(board));
}
else {
k++;
board[k] = -1;
}
}
else {
k--;
}
}
}
}
Output:
Solution 1 --> [1, 3, 0, 2, 4]
Solution 2 --> [4, 2, 0, 3, 1]
I'm creating a 2d top down game where the enemy AI is constantly following the player and avoiding obstacles. I did some research about path-finding algorithms and I decided to implement the breadth first search, but for some reason, the xy coordinates of the path are reversed, even though the grid is correct.
Code:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class BFSTest {
// 1 = normal node
// 0 = obstacle
// S = start
// D = destination
private static char[][] nodes = {
{'S', '1', '1', '1'},
{'0', '0', '0', '1'},
{'0', '0', '0', '1'},
{'1', '1', '1', 'D'}
};
public static void main(String[] args) {
shortestPath();
}
public static List<Node> shortestPath() {
// key node, value parent
Map<Node, Node> parents = new HashMap<Node, Node>();
Node start = null;
Node end = null;
// find the start node
for (int row = 0; row < nodes.length; row++) {
for (int column = 0; column < nodes[row].length; column++) {
if (nodes[row][column] == 'S') {
start = new Node(row, column, nodes[row][column]);
break;
}
}
}
if (start == null) {
throw new RuntimeException("can't find start node");
}
// traverse every node using breadth first search until reaching the destination
List<Node> temp = new ArrayList<Node>();
temp.add(start);
parents.put(start, null);
boolean reachDestination = false;
while (temp.size() > 0 && !reachDestination) {
Node currentNode = temp.remove(0);
List<Node> children = getChildren(currentNode);
for (Node child : children) {
// Node can only be visited once
if (!parents.containsKey(child)) {
parents.put(child, currentNode);
char value = child.getValue();
if (value == '1') {
temp.add(child);
} else if (value == 'D') {
temp.add(child);
reachDestination = true;
end = child;
break;
}
}
}
}
if (end == null) {
throw new RuntimeException("can't find end node");
}
// get the shortest path
Node node = end;
List<Node> path = new ArrayList<Node>();
while (node != null) {
path.add(0, node);
node = parents.get(node);
}
printPath(path);
return path;
}
private static List<Node> getChildren(Node parent) {
List<Node> children = new ArrayList<Node>();
int x = parent.getX();
int y = parent.getY();
if (x - 1 >= 0) {
Node child = new Node(x - 1, y, nodes[x - 1][y]);
children.add(child);
}
if (y - 1 >= 0) {
Node child = new Node(x, y - 1, nodes[x][y - 1]);
children.add(child);
}
if (x + 1 < nodes.length) {
Node child = new Node(x + 1, y, nodes[x + 1][y]);
children.add(child);
}
if (y + 1 < nodes[0].length) {
Node child = new Node(x, y + 1, nodes[x][y + 1]);
children.add(child);
}
return children;
}
private static void printPath(List<Node> path) {
for (int row = 0; row < nodes.length; row++) {
for (int column = 0; column < nodes[row].length; column++) {
String value = nodes[row][column] + "";
// mark path with X
for (int i = 1; i < path.size() - 1; i++) {
Node node = path.get(i);
if (node.getX() == row && node.getY() == column) {
value = "X";
break;
}
}
if (column == nodes[row].length - 1) {
System.out.println(value);
} else {
System.out.print(value + " ");
}
}
}
System.out.println("Path: " + path);
}
}
class Node {
private int x;
private int y;
private char value;
public Node(int x, int y, char value) {
this.x = x;
this.y = y;
this.value = value;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public char getValue() {
return value;
}
#Override
public String toString() {
return "(x: " + x + " y: " + y + ")";
}
#Override
public int hashCode() {
return x * y;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null) return false;
if (this.getClass() != o.getClass()) return false;
Node node = (Node) o;
return x == node.x && y == node.y;
}
/* Output:
* S X X X
* 0 0 0 X
* 0 0 0 X
* 1 1 1 D
* Path: [(x: 0 y: 0), (x: 0 y: 1), (x: 0 y: 2), (x: 0 y: 3), (x: 1 y: 3), (x: 2 y: 3), (x: 3 y: 3)]
*/
}
Thanks!
Think about this for a moment. Remember that your first array index is row, and the second is column. Now, in terms of conventional x and y:
the y index always refers to the row (because you count rows vertically);
the x index always refers to the column (because you count columns horizontally).
So, the correct way to index your grid is nodes[y][x]
Given an array of integers f, I want to see if f[k]=k for some k in the array. I'm having some trouble because I would like to return on the left and right half of the array, but I am not sure how to go about doing that. This is what I have so far:
public class Find {
int a = 0;
public boolean find(int[] f) {
if(f.length < 1) {
return false;
}
System.out.println(f[0] + " " + a);
if(f.length == 1 && f[0] == a) {
return true;
}
if(f.length == 1 && f[0] != a) {
return false;
}
int[] L = Arrays.copyOfRange(f, 0, f.length / 2);
int[] R = Arrays.copyOfRange(f, f.length / 2, f.length);
find(L);
a++;
//find(R);
return find(R); //only finds in the right half...
}
public static void main(String[] args) {
Find F = new Find();
int[] test = {0, 13, 2, 3, 4};
System.out.println(F.find(test));
}
}
You could do the following, you currently search the left side but do not return the result:
return find(R) || find(L);
I've been learning Java for about 4 months now, it's the first programming language I learn. For school we have to do a project, a console-based game. I chose for Boggle.
I have an ArrayList with dices, each one gets a random 'side up', and then the ArrayList gets shuffled and a two-dimensional array gets filled with the values of each side up. At this moment the Array is filled with Strings, chars may be a better option but something that's fairly easy to change.
The problem I'm facing is that I need to be able to find words in the array. Words in Boggle can go in any direction, each unique block can be used only once per word, but the path can cross, you can search diagonally too. I managed to find if the first letter is present in the array. If not than the search can be aborted, if it is present there needs to start a search that searches for the second character of the word, that has to be around the first character's block.
I did some math and found that it's always for example "i-1 and j-1" as the upper left corner of the surrounding blocks. I worked this out but can't seem to be able to find words... Also, if there are 2 "e"'s surrounding, I have no clue how to search for the word trying each "e". Here is my code so far:
This is my most important class at this moment, the class Gameboard
public class Gameboard {
private List<Dice> dices = new ArrayList<Dice>();
private final int boardSize;
private String[][] board;
private boolean [][] blocksAvailable;
private Random random = new Random();
public GameBoard() {
// Making the board with a given size (will be changeable later but is "4" for now)
boardSize = 4;
board = new String[boardSize][boardSize];
blocksAvailable = new boolean[boardSize][boardSize];
for(int i = 0; i < boardSize; i++) {
for(int j = 0; j < boardSize; j++) {
blocksAvailable[i][j] = true;
}
}
}
public String[][] getBoard() {
return board;
}
public int getFullSize() {
return boardSize*boardSize;
}
public void makeBoard() {
//random "side up" for each dice
for(int i = 0; i < dices.size(); i++) {
dices.get(i).setSideUp();
}
// Shuffle all dices
Collections.shuffle(dices);
// Fill the board with the values of the dices
int counter = 0;
for(int i = 0; i < boardSize; i++) {
for(int j = 0; j < boardSize; j++) {
board[i][j] = dices.get(counter++).getSideUp();
}
}
}
public String showBoard() {
//Show the board, each block divided by "|"
String str = "";
for(int i = 0; i < boardSize; i++) {
for(int j = 0; j < boardSize; j++) {
str += String.format("|%s|", board[i][j].toString());
if(j == 3) {
str += "\n";
}
}
}
return str;
}
public void addDices() {
dices.add(new dice("R", "I", "F", "O", "B", "X"));
dices.add(new dice("I", "F", "E", "H", "E", "Y"));
dices.add(new dice("D", "E", "N", "O", "W", "S"));
dices.add(new dice("U", "T", "O", "K", "N", "D"));
dices.add(new dice("H", "M", "S", "R", "A", "O"));
dices.add(new dice("L", "U", "P", "E", "T", "S"));
dices.add(new dice("A", "C", "I", "T", "O", "A"));
dices.add(new dice("Y", "L", "G", "K", "U", "E"));
dices.add(new dice("Q", "B", "M", "J", "O", "A"));
dices.add(new dice("E", "H", "I", "S", "P", "N"));
dices.add(new dice("V", "E", "T", "I", "G", "N"));
dices.add(new dice("B", "A", "L", "I", "Y", "T"));
dices.add(new dice("E", "Z", "A", "V", "N", "D"));
dices.add(new dice("R", "A", "L", "E", "S", "C"));
dices.add(new dice("U", "W", "I", "L", "R", "G"));
dices.add(new dice("P", "A", "C", "E", "M", "D"));
}
public boolean searchWord(String word) {
String wordUp = woord.toUpperCase();
String firstLetter = Character.toString(wordUp.charAt(0));
for(int i = 0; i < boardSize;i++) {
for(int j = 0; j < boardSize;j++) {
if(firstLetter.equals(board[i][j]) == true) {
int a = i;
int b = j;
String theLetter = "";
// First letter found, continue search
for(int h = 1; h < hetWoord.length(); h++) {
theLetter = Character.toString(wordUp.charAt(h));
int[] values = searchLetter(theLetter, a, b);
if(values[0] > -1) {
a = values[0];
b = values[1];
} else {
return false;
}
}
return true;
}
}
}
return false;
}
public int[] searchLetter(String letter, int i, int j) {
int[] values = new int[2];
try{if(board[i-1][j-1].equals(letter) && blocksAvailable[i-1][j-1] == true) {
values[0] = i-1;
values[1] = j-1;
blocksAvailable[i-1][j-1] = false;
} else if(board[i-1][j].equals(letter) && blocksAvailable[i-1][j] == true) {
values[0] = i-1;
values[1] = j;
blocksAvailable[i-1][j] = false;
} else if(board[i-1][j+1].equals(letter) && blocksAvailable[i-1][j+1] == true) {
values[0] = i-1;
values[1] = j+1;
blocksAvailable[i-1][j+1] = false;
} else if(board[i][j-1].equals(letter) && blocksAvailable[i][j-1] == true) {
values[0] = i;
values[1] = j-1;
blocksAvailable[i][j-1] = false;
} else if(board[i][j+1].equals(letter) && blocksAvailable[i][j+1] == true) {
values[0] = i;
values[1] = j+1;
blocksAvailable[i][j+1] = false;
} else if(board[i+1][j-1].equals(letter) && blocksAvailable[i+1][j-1] == true) {
values[0] = i+1;
values[1] = j-1;
blocksAvailable[i+1][j+1] = false;
} else if(board[i+1][j].equals(letter) && blocksAvailable[i+1][j] == true) {
values[0] = i+1;
values[1] = j;
blocksAvailable[i+1][j] = false;
} else if(board[i+1][j+1].equals(letter) && blocksAvailable[i+1][j+1] == true) {
values[0] = i+1;
values[1] = j+1;
blocksAvailable[i+1][j+1] = false;
} else {
values[0] = -1; // If not found, negative values, easy to check in searchWord if letter was found
values[1] = -1;
}}catch (ArrayIndexOutOfBoundsException e) {
}
return values;
}
}
This may get deleted, because I am not going to answer your question. But please, pretty please, use:
// instead of: board[i-1][j-1]
public String getBoardValue(int x, int y) {
if (x<0 || x>=boardSize) return "";
if (y<0 || y>=boardSize) return "";
return board[x][y];
}
Using such helper method you will
ensure no IndexArrayOutOfBoundsException is thrown
always have a non-null board value
Well, what you have asked is little complex.You have to look at all the possible directions for the word in your Array.I would suggest you should look at the mini projects and see their logic of evaluation.You can find many projects on google.Example http://1000projects.org/java-projects-gaming.html
I am not asking you to copy paste,but just to get an idea of doing things in a proper way.
Few years back i made an X-O game in c/c++, can give you the code(if you want) of checking the combinations of x's and o's(you can make out the code,the syntax in not much different).
Your method searchLetter can be rewritten to be more understandable.
public boolean isValid(int x, int y) {
return x>= 0 && x < boardSize && y >=0 && y < boardSize;
}
public int[] searchLetter(String letter, int i, int j) {
int[] values = new int[2];
//initialization as not found.
values[0] = -1;
values[1] = -1;
for(int ix = i-1; ix <= i+1 ; ix++){
for(int jx = j-1; jx <= j+1 ; jx++){
if(i == ix && j == jx)
//skip the cell from were the search is performed
continue;
if(isValid(ix,jx)
&& board[ix][jx].equals(letter)
&& blocksAvailable[ix][jx] == true) {
values[0] = ix;
values[1] = jx;
blocksAvailable[ix][jx] = false;
//early return
return values;
}
}
return values;
}
Even without comments, a reader has the hint that this is some kind of neighboring search.
The fact is your algorithm should return a list of possible next positions.The code above return the first occurrence. If you put each pair of indices in a list rather than returning the first one, you will see all the candidate letters for your word. And while doing so, you will be implementing the getNeighbour or adjancentVertexes of a Breath first search.
One tip: Once you find the initial letter, instead of looking for the next letters one by one, just compute the 8 possible words of same length you can get from that point. You might find less than 8 depending on the position of that letter on the board.
Once you are able to figure this out for one direction, it is going to be easier to translate that logic to the rest of possible directions.
Then you just need to compare those words and if none of then match, find the initial letter and repeat the same process.
I got asked this on an interview, I didn't have much time left so I explained my interviewer how I would approach this problem. He seemed ok with my answer and didn't even ask me to try to code it, probably because he knew this problem is not as trivial as it might look and we didn't have enough time. I gave it a try at home after my interview finished but my solution had some bugs. Kept thinking about it and came up with the ideas I posted previously, then noticed this post is 3 years old so I decided to code it. This solution works but has room for improvements:
import java.util.LinkedHashSet;
import java.util.Set;
public class StringsArrays {
public static void main(String[] args) {
final char[][] matrix = new char[4][4];
matrix[0] = new char[] { 'G', 'A', 'B', 'C' };
matrix[1] = new char[] { 'O', 'O', 'E', 'F' };
matrix[2] = new char[] { 'O', 'H', 'O', 'I' };
matrix[3] = new char[] { 'J', 'K', 'L', 'D' };
System.out.println(search("JOOG", matrix)); //N
System.out.println(search("BEOL", matrix)); //S
System.out.println(search("AB", matrix)); //E
System.out.println(search("FE", matrix)); //W
System.out.println(search("HEC", matrix)); //NE
System.out.println(search("DOOG", matrix)); //NW
System.out.println(search("GOOD", matrix)); //SE
System.out.println(search("FOK", matrix)); //SW
System.out.println(search("HO", matrix));
}
public static boolean search(final String word, char[][] matrix) {
final char firstLetter = word.charAt(0);
for (int y = 0; y < matrix.length; y++) {
for (int x = 0; x < matrix[y].length; x++) {
if (matrix[y][x] == firstLetter) {
final Set<String> words = readInAllDirections(word.length(), x, y, matrix);
if (words.contains(word)) {
return true;
}
}
}
}
return false;
}
enum Direction {
NORTH, SOUTH,
EAST, WEST,
NORTH_EAST, NORTH_WEST,
SOUTH_EAST, SOUTH_WEST
}
private static Set<String> readInAllDirections(final int length, final int x, final int y, final char[][] matrix) {
final Set<String> words = new LinkedHashSet<>();
for (final Direction direction : Direction.values()) {
words.add(readWord(length, x, y, matrix, direction));
}
return words;
}
private static String readWord(final int length, final int xBegin, final int yBegin, final char[][] matrix, final Direction direction) {
final int xEnd = getXEnd(xBegin, length, direction);
final int yEnd = getYEnd(yBegin, length, direction);
int x;
int y;
final StringBuilder matrixWord = new StringBuilder();
if (direction == Direction.SOUTH) {
if (yEnd > matrix.length-1) {
return null;
}
for (y = yBegin; y <= yEnd; y++) {
matrixWord.append(matrix[y][xBegin]);
}
}
if (direction == Direction.NORTH) {
if (yEnd < 0) {
return null;
}
for (y = yBegin; y >= yEnd; y--) {
matrixWord.append(matrix[y][xBegin]);
}
}
if (direction == Direction.EAST) {
if (xEnd > matrix[yBegin].length-1) {
return null;
}
for (x = xBegin; x <= xEnd; x++) {
matrixWord.append(matrix[yBegin][x]);
}
}
if (direction == Direction.WEST) {
if (xEnd < 0) {
return null;
}
for (x = xBegin; x >= xEnd; x--) {
matrixWord.append(matrix[yBegin][x]);
}
}
if (direction == Direction.SOUTH_EAST) {
if (yEnd > matrix.length-1 || xEnd > matrix[yBegin].length-1) {
return null;
}
x = xBegin;
y = yBegin;
while (y <= yEnd && x <= xEnd) {
matrixWord.append(matrix[y][x]);
y++;
x++;
}
}
if (direction == Direction.SOUTH_WEST) {
if (yEnd > matrix.length-1 || xEnd < 0) {
return null;
}
x = xBegin;
y = yBegin;
while (y <= yEnd && x >= xEnd) {
matrixWord.append(matrix[y][x]);
y++;
x--;
}
}
if (direction == Direction.NORTH_EAST) {
if (yEnd < 0 || xEnd > matrix[yBegin].length-1) {
return null;
}
x = xBegin;
y = yBegin;
while (y >= yEnd && x <= xEnd) {
matrixWord.append(matrix[y][x]);
y--;
x++;
}
}
if (direction == Direction.NORTH_WEST) {
if (yEnd < 0 || xEnd < 0) {
return null;
}
x = xBegin;
y = yBegin;
while (y >= yEnd && x >= xEnd) {
matrixWord.append(matrix[y][x]);
y--;
x--;
}
}
return matrixWord.toString();
}
private static int getYEnd(final int y, final int length, final Direction direction) {
if (direction == Direction.SOUTH || direction == Direction.SOUTH_EAST || direction == Direction.SOUTH_WEST) {
// y0 + length + ? = y1
return y + length - 1;
}
if (direction == Direction.NORTH || direction == Direction.NORTH_EAST || direction == Direction.NORTH_WEST) {
// y0 - length + ? = y1
return y - length + 1;
}
// direction == Direction.EAST || direction == Direction.WEST)
return y;
}
private static int getXEnd(final int x, final int length, final Direction direction) {
if (direction == Direction.EAST || direction == Direction.NORTH_EAST || direction == Direction.SOUTH_EAST) {
// x0 + length + ? = x1
return x + length - 1;
}
if (direction == Direction.WEST || direction == Direction.NORTH_WEST || direction == Direction.SOUTH_WEST) {
// x0 - length + ? = x1
return x - length + 1;
}
// direction == Direction.NORTH || direction == Direction.SOUTH)
return x;
}
}