Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 months ago.
Improve this question
DISCLAIMER This problem is part of a COMPLETED competition and will not be reused
I was hoping someone could create and explain a solution efficient enough to run file sizes at most 15 x 15 tiles. Below is the problem:
Tiled Floor (40 points)
Sam recently hired a tile installer to tile a kitchen floor. The floor was supposed to be very colorful with no two
adjacent tiles having the same color. Unfortunately, the installer failed to ensure adjacent tiles have different
colors. The mortar is still wet, but it is difficult to lift just one tile at a time, so the installer is limited to swapping
adjacent tiles. The question is how to exchange adjacent tiles in as few moves as possible so that the floor meets
the criteria that no two adjacent tiles have the same color.
A sample input is
RGR
RPC
GRB
YPG
Representing the tiles on a three by four floor where R is a red tile, G is green, B is blue, C is cyan, P is purple, and
Y is yellow. In general, the input will be a series of lines of R, G, B, C, P, and Y. Each line will have the same length
and there will be a maximum of 15 lines with 15 characters in each line. The output is to be an integer
representing the number of swaps of adjacent tiles. For this problem, “adjacent” means touching and in the same
row or column; for example, the only two tiles are adjacent to the yellow tile in the lower left corner of the above
floor: the green tile at the start of the third row and the purple tile in the middle of the fourth row.
The output for the above floor will be
2
since the red tile at the start of row 2 can be swapped with the green tile at the start of row three, and then the
red tile in middle of row 3 can be swapped with the blue tile at the end. This gives the arrangement
RGR
GPC
RBR
YPG
Other fixes are possible such as exchanging the first two tiles on row 2 to get PRC and then exchanging the middle
tiles in rows 3 and 4. Your program does not print the resulting floor arrangement, just the minimum number of
tile swaps that must take place. Sometimes it is not possible to fix a floor:
GGYGP
CGGRG
This isn’t possible to tile because there are 6 Gs and a floor this size can fit only 5 without two being adjacent. In
cases where there is no solution, the output is to be
not possible
I have created a solution but it works only for approximately 16 tiles (4 x 4), any more takes an enormous amount of time. This is because of the recursive and naive nature of this function, for every call it calls itself at least 4 times.
Below is my attempted solution, keep in mind that there are extra methods from previous attempts and that minimumSwaps() is the main recursive method:
import java.util.*;
import java.io.*;
class Main {
private static ArrayList<String[][]> solutions = new ArrayList<String[][]>();
private static ArrayList<Integer> moves = new ArrayList<Integer>();
private static int min = Integer.MAX_VALUE;
public static void main(String[] args) throws Exception {
File file = new File("Tiles.txt");
Scanner scan = new Scanner(file);
Scanner scan1 = new Scanner(file);
int length = 0;
while (scan1.hasNextLine()) {
scan1.nextLine();
length++;
}
String[][] tiles = new String[length][];
for (int i = 0; i < length; i++) {
String line = scan.nextLine();
tiles[i] = new String[line.length()];
for (int l = 0; l < tiles[i].length; l++) {
tiles[i][l] = line.substring(l, l + 1);
}
}
System.out.println("Start");
minimumSwaps(tiles, 0, new ArrayList<String>());
//System.out.println(Arrays.toString(findCount(tiles)));
//findSolutions(new String[tiles.length][tiles[0].length], findCount(tiles), 0, 0);
//System.out.println(solutions.size());
System.out.println(min);
//display();
}
//tilesIDs: more efficient way to check if computer has seen previous situation
//how to know if there are moves that do not involve problem areas that reduces total number of moves?
public static void minimumSwaps (String[][] tiles, int moves, ArrayList<String> tilesIDs) {
if (moves < min) {
String newID = computeID(tiles);
if (linearSearch(tilesIDs, newID)) return;
tilesIDs.add(newID);
if (solved(tiles)) {
//Main.moves.add(moves);
if (moves < min) min = moves;
//solutions.add(cloneTiles(tiles));
}
else if (moves < min - 1) {
for (int i = 0; i < tiles.length; i++) {
for (int l = 0; l < tiles[i].length; l++) {
if (adjacentPresent(tiles, tiles[i][l], i, l)) {
try {
String[][] newTiles = cloneTiles(tiles);
String current = newTiles[i][l];
newTiles[i][l] = newTiles[i][l - 1];
newTiles[i][l - 1] = current;
minimumSwaps(newTiles, moves + 1, (ArrayList<String>)(tilesIDs.clone()));
}
catch (Exception e) {}
try {
String[][] newTiles = cloneTiles(tiles);
String current = newTiles[i][l];
newTiles[i][l] = newTiles[i][l + 1];
newTiles[i][l + 1] = current;
minimumSwaps(newTiles, moves + 1, (ArrayList<String>)(tilesIDs.clone()));
}
catch (Exception e) {}
try {
String[][] newTiles = cloneTiles(tiles);
String current = newTiles[i][l];
newTiles[i][l] = newTiles[i - 1][l];
newTiles[i - 1][l] = current;
minimumSwaps(newTiles, moves + 1, (ArrayList<String>)(tilesIDs.clone()));
}
catch (Exception e) {}
try {
String[][] newTiles = cloneTiles(tiles);
String current = newTiles[i][l];
newTiles[i][l] = newTiles[i + 1][l];
newTiles[i + 1][l] = current;
minimumSwaps(newTiles, moves + 1, (ArrayList<String>)(tilesIDs.clone()));
}
catch (Exception e) {}
}
}
}
}
}
}
public static boolean linearSearch(ArrayList<String> IDs, String newID) {
for (String ID : IDs) if (ID.equals(newID)) return true;
return false;
}
public static String computeID(String[][] tiles) {
String ID = "";
for (String[] letters : tiles) {
for (String letter : letters) {
ID += letter;
}
}
return ID;
}
public static String[][] cloneTiles(String[][] tiles) {
String[][] newTiles = new String[tiles.length][tiles[0].length];
for (int i = 0; i < tiles.length; i++) {
newTiles[i] = tiles[i].clone();
}
return newTiles;
}
public static boolean solved(String[][] tiles) {
for (int i = 0; i < tiles.length; i++) {
for (int l = 0; l < tiles[i].length; l++) {
if (adjacentPresent(tiles, tiles[i][l], i, l)) return false;
}
}
return true;
}
public static int minMoves() {
int min = Integer.MAX_VALUE;
for (int num : moves) if (num < min) min = num;
return min;
}
public static void findSolutions(String[][] tiles, int[] count, int i, int l) {
String[] colors = {"R", "G", "B", "C", "P", "Y"};
for (int z = 0; z < 6; z++) {
//System.out.println("testing");
if (!adjacentPresent(tiles, colors[z], i, l) && count[z] > 0) {
String[][] newTiles = new String[tiles.length][tiles[0].length];
for (int a = 0; a < newTiles.length; a++) {
for (int b = 0; b < newTiles[0].length; b++) {
newTiles[a][b] = tiles[a][b]; // clone does not work properly?
}
}
newTiles[i][l] = colors[z];
//System.out.println(Arrays.deepToString(newTiles));
int[] newCount = count.clone();
newCount[z]--;
if (l == tiles[0].length - 1 && i != tiles.length - 1) {
findSolutions(newTiles, newCount, i + 1, 0);
}
else if (l < tiles[0].length - 1) {
findSolutions(newTiles, newCount, i, l + 1);
}
else if (l == tiles[0].length - 1 && i == tiles.length - 1) {
solutions.add(newTiles);
}
}
}
}
public static boolean adjacentPresent(String[][] tiles, String color, int i, int l) {
try {
if (tiles[i][l + 1].equals(color)) return true;
}
catch (Exception e) {}
try {
if (tiles[i][l - 1].equals(color)) return true;
}
catch (Exception e) {}
try {
if (tiles[i + 1][l].equals(color)) return true;
}
catch (Exception e) {}
try {
if (tiles[i - 1][l].equals(color)) return true;
}
catch (Exception e) {}
return false;
}
public static int[] findCount(String[][] tiles) {
int[] count = new int[6];
for (String[] line : tiles) {
for (String letter : line) {
switch (letter) {
case "R": count[0]++;
break;
case "G": count[1]++;
break;
case "B": count[2]++;
break;
case "C": count[3]++;
break;
case "P": count[4]++;
break;
case "Y": count[5]++;
break;
}
}
}
return count;
}
public static void display() {
for (String[][] lines : solutions) {
for (String[] line : lines) {
for (String letter : line) {
System.out.print(letter);
}
System.out.println();
}
System.out.println("\n\n");
}
}
}
Improving the algorithm
A breadth-first search would yield, as first result, an optimal solution. It could still be slow on larger problems where the solution is deeper in; or in the worst case, when there is no solution at all.
Your current algorithm looks like backtracking, which is depth-first, and therefore you need to look at all possible solutions before being sure you have found the shortest one. This is very wasteful.
Improving the data representation
You have 6 colors in a 15x15 grid. You are currently storing up to 15x15=225 strings, and constantly copying that String[][] over. It would be a lot more efficient to use a single byte[] (of length dim x dim), which can be copied over faster. Use integers (1, 2, ...) instead of color-chars ("R", "Y", ...). With a single dimension you have to do some math to check for adjacency, but it is nothing too fancy; and you win a lot of memory locality.
Related
I'm making battleships and I've currently come across an issue where my ships overlap. I've tried to incorporate an if statement that will judge whether it can be placed. Here's an example of me placing two ships of length 3 down.
public static void PlaceCruiser(String[][] board) {
ThreadLocalRandom random = ThreadLocalRandom.current();
int timesplaced = 0;
int size = 3;
while (timesplaced < 2) {
int randomcruisercheck =(int)(Math.random()*2);
if (randomcruisercheck == 0) {
int column = random.nextInt(0,9);
int row = random.nextInt(0,7);
if (row + 2 < 11 && board[row][column] == "." && board[row + 1][column] == "." && board[row + 2][column] == ".") {
for(int i = 0; i<size; i++)
{
board[row+i][column] = "#";
}
System.out.println(board[row][column]);
}
timesplaced++;
}
else if (randomcruisercheck == 1) {
int column = random.nextInt(0,9);
int row = random.nextInt(0,7);
if (column + 2 < 11 && board[row][column] == "." && board[row][column + 1] == "." && board[row][column + 2] == ".") {
for (int i = 0; i<size; i++)
{
board[row][column + i] = "#";
}
System.out.println(board[row][column]);
}
timesplaced++;
}
}
}
Basically, I use "#" to represent a ship in a 10x10 2D array of ".". I feel like the if statement about if the row or column plus 1 then plus 2 is a dot i.e a free space, a ship will be generated but this does not seem to be the case. Can anyone help me out?
Your code works well, you only need to take care of the indexes and initialize the board:
public class Main {
public static String[][] board;
public static void main(String[] args) {
PlaceCruiser pc = new PlaceCruiser();
board = new String[10][10];
// Initialize the board
for (int i=0;i<10;i++) {
for (int j=0;j<10;j++) {
board[i][j]=".";
}
}
pc.placeCruiser(board);
// Show thew board
for (int i=0;i<10;i++) {
for (int j=0;j<10;j++) {
System.out.print(board[i][j]);
}
System.out.println();
}
}
}
Result:
..........
..###.....
..........
..........
....#.....
....#.....
....#.....
..........
..........
..........
Also check that your initial position is not already "#".
Stylistical remarks:
if you use ThreadLocalRandom for generating position, you should also use it for other randomness (in other words: (int)(Math.random()*2) could rather be random.nextBoolean(), because actually a boolean could decide if ship should be horizontal or vertical)
nextInt(0,x) is just a longer variant of nextInt(x).
Actual bugs:
due to a presumably copy-paste issue, column (0-"9") and row (0-"7") are generated in the same way in both cases, making it possible to index out of the array when placing a vertical ship
which you seem to have noticed, but fixed it with that row + 2 < 11 check which has two problems in itself:
when row+2 ends up being 10 (which is <11), that is an invalid index (valid indices are 0...9)
as row stays between 0 and "7", there will not be horizontal ships in the last few rows
nextInt(a,b) generates numbers a...b-1, so it will not generate b itself
as the other answer points out string comparison with == generally and usually does not work, use equals()
Generally I would suggest having a single check+placement function, which can deal with an entire rectangle (given position+size). Also, I switched to array of characters, that simplifies both comparisons and printing.
boolean tryPlace(int x,int y,int width,int height) {
for(int i=0;i<height;i++) {
for(int j=0;j<width;j++) {
if(board[y+i][x+j]!='.') {
return false; // ship can not be placed
}
}
}
// if we reach here, ship can be placed
for(int i=0;i<height;i++) {
for(int j=0;j<width;j++) {
board[y+i][x+j]='#';
}
}
return true; // ship placed successfully
}
This routine could be called to place a pair of 3-long ships this way:
board=new char[10][10];
for(int i=0;i<10;i++)
for(int j=0;j<10;j++)
board[i][j]='.';
int size=3;
int amount=2;
while(amount>0) {
if(random.nextBoolean()) {
// horizontal
if(tryPlace(random.nextInt(10-size+1),random.nextInt(10),size,1)){
amount--; // one placed
}
} else {
// vertical
if(tryPlace(random.nextInt(10),random.nextInt(10-size+1),1,size)){
amount--; // one placed
}
}
}
// and a 4x2 mothership
while(!(random.nextBoolean()
?tryPlace(random.nextInt(7),random.nextInt(9),4,2)
:tryPlace(random.nextInt(9),random.nextInt(7),2,4)
));
for(int i=0;i<10;i++)
System.out.println(board[i]); // char[] has special overload for print/ln()
Test: https://ideone.com/DjYqjB
However, when I was a kid we had a rule that ships could not match, there had to be empty space (or a border of the board) around them. If you need that, tryPlace() could check a larger block, and put the ship into the middle of it. Also, a usual trick of implementing board games is that you can keep a larger array in the memory than what you will actually display. So instead of fighting with "check if field is empty or it is outside the board", it is simpler to have a 12x12 board, and place ships into the middle 10x10 portion of it:
boolean tryPlaceWithBorder(int x,int y,int width,int height) {
for(int i=0;i<height;i++)
for(int j=0;j<width;j++)
if(board[y+i][x+j]!='.')
return false; // ship can not be placed
// if we reach here, ship can be placed
for(int i=1;i<height-1;i++)
for(int j=1;j<width-1;j++)
board[y+i][x+j]='#';
return true; // ship placed successfully
}
and modified usage:
board=new char[12][12];
for(int i=0;i<12;i++)
for(int j=0;j<12;j++)
board[i][j]='.';
int size=3;
int amount=2;
while(amount>0) {
if(random.nextBoolean()) {
// horizontal
if(tryPlaceWithBorder(random.nextInt(12-size-1),random.nextInt(10),size+2,3))
amount--; // one placed
} else {
// vertical
if(tryPlaceWithBorder(random.nextInt(10),random.nextInt(12-size-1),3,size+2)){
amount--; // one placed
}
}
}
// and a 4x2 mothership
while(!(random.nextBoolean()
?tryPlaceWithBorder(random.nextInt(7),random.nextInt(9),6,4)
:tryPlaceWithBorder(random.nextInt(9),random.nextInt(7),4,6)
));
for(int i=1;i<11;i++)
System.out.println(String.valueOf(board[i],1,10));
Test: https://ideone.com/LXAD7T
I am teaching myself java using the cs106a course from Stanford.
Currently I am on chapter 10 of the book "The Art and Science of Java".
The problem is to write a 3x3 Magic Square.
The exercise:
You have to write a 3x3 array
Each side of the array(Magic Square) has to equal 15
The problem:
The program I wrote works, the assignment is complete, this question is for self learning. As a beginner I would like to improve the method SumOfSides() and make it smaller and more efficient. I tried iterating the array in this method but still have issues. Is there a way to make it more efficient?
public void run() {
//set the font
setFont("Helvetica-40");
//fill the array
fillArray();
//sum up all sides
SumOfSides();
//check if all of the sides in the magic square array equal 15:
checkSides(mSqr);
//I used this for debugging purposes only:
//showSides();
}
//for debugging purposes:
public void showSides() {
println(sumRight0);
println(sumRight1);
println(sumRight2);
println(sumBottom0);
println(sumBottom1);
println(sumBottom2);
println(sumDiagonalUp);
println(sumDiagonalDown);
}
public void SumOfSides() {
sumRight0 = mSqr[0][0] + mSqr[0][1] + mSqr[0][2];
sumRight1 = mSqr[1][0] + mSqr[1][1] + mSqr[1][2];
sumRight2 = mSqr[2][0] + mSqr[2][1] + mSqr[2][2];
sumBottom0 =mSqr[0][0] + mSqr[1][0] + mSqr[2][0];
sumBottom1 =mSqr[0][1] + mSqr[1][1] + mSqr[2][1];
sumBottom2 =mSqr[0][2] + mSqr[1][2] + mSqr[2][2];
sumDiagonalUp = mSqr[2][0] + mSqr[1][1]+ mSqr[0][2];
sumDiagonalDown = mSqr[0][0] + mSqr[1][1] + mSqr[2][2];
}
/*This predicate method checks if the sides
of the array add up to 15: */
public boolean checkSides(int[][] myArray) {
if (sumRight0 ==15 && sumRight1 ==15&& sumRight2==15 && sumBottom0==15&& sumBottom1==15&&
sumBottom2==15&& sumDiagonalUp==15&&sumDiagonalDown==15) {
println("True, this is a Magic Square");
return true;
} else {
println("False, the sides do not equal 15");
return false;
}
}
public void fillArray() {
int num =0;
for(int row=0; row <3; row++) {
for (int col=0; col<3; col++) {
num=readInt("");
mSqr[row][col]=num;
}
}
/*Test array values here to see
* if they were entered correctly.
*/
//println(mSqr[1][2]); //should be 6
//println(mSqr[2][0]); //should be 7
}
//instance variables:
int[][] mSqr= new int[3][3];
List<List<Integer>> new1 = new ArrayList<>();
private int sumRight0;
private int sumRight1;
private int sumRight2;
private int sumBottom0;
private int sumBottom1;
private int sumBottom2;
private int sumDiagonalUp;
private int sumDiagonalDown;
}
Perhaps the only thing is readability. You could take the values and move them into more readable variables:
int topLeft = mSqr[0][0];
int topMid = mSqr[0][1];
...
int sumLeft = topLeft + midLeft + bottomLeft;
int sumRight = topRight = midRight + bottomRight;
...
To address your concern of making it smaller, I would argue that converting the sums into loops, as you mentioned, is certainly not worth it in the case that you are doing 6 sums of 3 values each. Furthermore, each term of each sum is common to either one or two other sums, which does not provide much overlap. If you were performing larger sums (larger in number of terms in the sum, not the total value), then perhaps it would be worth it on a readability/SLOC argument.
Suppose you did want to do a loop still though, you could do something like
sumLeft = 0;
sumRight = 0;
sumTop = 0;
sumBottom = 0;
sumDiagonalUp = 0;
sumDiagonalDown = 0;
for(int i = 0; i < mSqr.length; i++) {
for(int j = 0; j < mSqr[i].length; j++) {
if (i == 0) {
sumLeft += mSqr[i][j];
}
if (i == mSqr.length - 1) {
sumRight += mSqr[i][j];
}
if (j == 0) {
sumTop += mSqr[i][j];
}
if (j == mSqr[i].length) {
sumBottom += mSqr[i][j];
}
if (i == j) {
sumDiagonalDown += mSqr[i][j];
}
if (i + j == mSqr.length - 1) {
sumDiagonalUp += mSqr[i][j];
}
}
}
The loops only provide benefit on large magic squares.
Also, I am confused by your description contrasted with your implementation. It seems you are summing each row and column, and the two diagonals of the square, as opposed to the 4 sides and the diagonals.
I have a problem I am trying to do to practice, and I'm having trouble figuring out how to write a recursive algorithm for it. I have a file that is laid out like so:
4
(())
()((
(()(
))))
This problem is from USACO. http://www.usaco.org/index.php?page=viewproblem2&cpid=189
The problem statement is copy-pasted below:
Although Bessie the cow finds every string of balanced parentheses to
be aesthetically pleasing, she particularly enjoys strings that she
calls "perfectly" balanced -- consisting of a string of ('s followed
by a string of )'s having the same length. For example:
(((())))
While walking through the barn one day, Bessie discovers an N x N grid
of horseshoes on the ground, where each horseshoe is oriented so that
it looks like either ( or ). Starting from the upper-left corner of
this grid, Bessie wants to walk around picking up horseshoes so that
the string she picks up is perfectly balanced. Please help her
compute the length of the longest perfectly-balanced string she can
obtain.
In each step, Bessie can move up, down, left, or right. She can only
move onto a grid location containing a horseshoe, and when she does
this, she picks up the horseshoe so that she can no longer move back
to the same location (since it now lacks a horseshoe). She starts by
picking up the horseshoe in the upper-left corner of the grid. Bessie
only picks up a series of horseshoes that forms a perfectly balanced
string, and she may therefore not be able to pick up all the
horseshoes in the grid.
I am having issues trying to figure out how I would create an algorithm that found the best possible path recursively. Can anyone point me in the right direction, or have any examples I could look at to get an idea? I've been searching but all examples I've found are from one point to another, and not finding all possible paths within a matrix/array.
package bessiehorseshoe;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class BessieHorseShoe {
int answer = 0;
int matrixSize = 0;
public static void main(String[] args) throws IOException {
BessieHorseShoe goBessieGo = new BessieHorseShoe();
}
BessieHorseShoe() throws IOException {
int rowFilled = 0;
int currentColumn = 0;
int character = 0;
BufferedReader inputFile = new BufferedReader(new FileReader("hshoe.in"));
String inputLine = inputFile.readLine();
matrixSize = Character.digit(inputLine.charAt(0), 10);
System.out.println(matrixSize);
char[][] pMatrix = new char[matrixSize][matrixSize];
while ((character = inputFile.read()) != -1) {
char c = (char) character;
if (c == '(' || c == ')') {
pMatrix[rowFilled][currentColumn] = c;
System.out.print(pMatrix[rowFilled][currentColumn]);
rowFilled++;
if (rowFilled == matrixSize) {
currentColumn++;
rowFilled = 0;
System.out.println();
}
}
}
matchHorseShoes(pMatrix);
}
public int matchHorseShoes(char[][] pMatrix) {
if (pMatrix[0][0] == ')') {
System.out.println("Pattern starts with ')'. No possible path!");
return 0;
}
System.out.println("Works");
return 0;
}
}
The following algorithm will solve your problem. You can also use memoization to speed up the running time.
The idea is simple:
while opening parentheses increment the count of opened parentheses;
if you star closing, you must continue to close and increment the closed parentheses;
if you are closing and the number of closed parentheses are greater or equal to the number of opened parentheses, stop and return this value.
All the rest of the code is syntactic sugar. (From the returned list of items visited is trivial obtail the output you desire).
import java.util.LinkedList;
import java.util.List;
public class USACO {
static class Path {
public List<String> items;
public int value;
public Path() {
this.items = new LinkedList<String>();
this.value = 0;
}
}
public static void main(final String[] args) {
final int n = 5;
final String[][] input = new String[n][n];
// Create a random input of size n
for (int y = 0; y < n; y++) {
for (int x = 0; x < n; x++) {
input[y][x] = Math.random() < 0.5 ? "(" : ")";
System.out.print(input[y][x] + " ");
}
System.out.println();
}
final Path bestPath = longestPath(n, input, 0, 0, 0, 0, input[0][0] == "(");
System.out.println("Max:" + bestPath.value + "\n" + bestPath.items);
}
public static Path longestPath(final int n, final String[][] input, final int x, final int y, int numberOpened, int numberClosed,
final boolean wasOpening) {
if (input == null) {
return new Path();
} else if (!wasOpening && (numberClosed >= numberOpened)) { // Reached a solution
final Path path = new Path();
path.value = numberOpened;
path.items.add("(" + x + "," + y + ")");
return path;
} else if ((x < 0) || (y < 0) || (x >= n) || (y >= n)) { // Out of bound
return new Path();
} else if (input[y][x] == "") { // Already visited this item
return new Path();
} else {
final String parenthese = input[y][x];
// Increment the number of consecutive opened or closed visited
if (parenthese.equals("(")) {
numberOpened++;
} else {
numberClosed++;
}
input[y][x] = ""; // Mark as visited
Path bestPath = new Path();
bestPath.value = Integer.MIN_VALUE;
// Explore the other items
for (int dy = -1; dy <= 1; dy++) {
for (int dx = -1; dx <= 1; dx++) {
if (((dy == 0) || (dx == 0)) && (dy != dx)) { // go only up, down, left, right
final boolean opening = (parenthese == "(");
if (wasOpening || !opening) {
// Find the longest among all the near items
final Path possiblePath = longestPath(n, input, x + dx, y + dy, numberOpened, numberClosed, opening);
if (possiblePath.value > bestPath.value) {
bestPath = possiblePath;
bestPath.items.add("(" + x + "," + y + ")");
}
}
}
}
}
input[y][x] = parenthese; // mark as not visited
return bestPath;
}
}
}
i've been trying to write a java class to solve the n queens problem using some sort of stacking and recursion, the answers are stored in grids(two dimensionnal arrays), but i've hit a dead wall which is stack overflow for recursion at n=8 (max recursion depth reached 2298)
So i've been wondering if there is some way to bypass this dead by doing something complex like allocating more heap space in java(if possible?) or using multi thread(point me out to a tutorial/examples)... or please do advice on how to optimize the code...
Thanks in advance
public void resoudre(){
this.gridPile.push(copyGrid(grid));
try{
int row = gridPile.size()-1;
if(gridPile.size()==0)row = 0;
chooseGridSpace(this.grid, locateFirstAvailable(grid, row));
if(gridPile.size() == this.taille){
gridSolutions.push(copyGrid(grid));
grid = gridPile.pop();
boolean erronous = true;
while(erronous){
try{
MakeNextUnavailable(grid, gridPile.size());
erronous = false;
}
catch(UnavailabilityException r1){
try{
grid = gridPile.pop();
}
catch(java.util.EmptyStackException r2){
return;
}
}
}
}
}
catch(InvalidPositionException e1){
this.grid = gridPile.pop();
boolean error = true;
while(error){
try{
MakeNextUnavailable(grid, gridPile.size());
error = false;
}
catch(UnavailabilityException er){
try{
this.grid = gridPile.pop();
}
catch(java.util.EmptyStackException err){
return;
}
}
}
}
catch(java.lang.ArrayIndexOutOfBoundsException e2){
return;
}
this.resoudre();
}
private static void chooseGridSpace(int[][] grid, Position a){
grid[a.getLigne()][a.getColonne()] = 1;
fillNotAvailable(grid, a);
}
Direct answer: There's no need to push whole grids onto the stack, and you might want to represent the grid as array of 8 integers denoting the Queen position at each row.
Real problem: Your code is too long and too complicated. Keep it simple! The queen's problem is usually solved by 2 functions of <10 lines each. Is is as simple as:
public static boolean isSolution(final int[] board)
{
for (int i = 0; i < board.length; i++) {
for (int j = i + 1; j < board.length; j++) {
if (board[i] == board[j]) return false; // same column "|"
if (board[i]-board[j] == i-j) return false; // diagonal "\"
if (board[i]-board[j] == j-i) return false; // diagonal "/"
}
}
return true;
}
public static void solve(int depth, int[] board)
{
if (depth == board.length && isSolution(board)) {
outputSolution(board);
}
if (depth < board.length) { // try all positions of the next row
for (int i = 0; i < board.length; i++) {
board[depth] = i;
solve(depth + 1, board);
}
}
}
Add some output code and a main program, and you're finished!
public static void outputSolution(final int[] board)
{
System.out.println("--- Solution ---");
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[i]; j++) System.out.print(" ");
System.out.println("Q");
}
}
public static void main(String[] args)
{
int n = 8;
solve(0, new int[n]);
}
Reading the code, it looks like your program is using a Stack<..> and not Java recursion. Therefore it is probably running out of Java heap space rather than Java stack space. If that is the case, you can use the -Xms and -Xmx options to increase the initial and maximum heap sizes.
No reason to reach stack depth of 2298 for N = 8!
The correct algorithm is to represent the queens by an array of 8 integers, each representing the row position of the ith queen (queen per column).
Your max stack size should be 8.
In Java, the commands -ss and -oss can both be used to change the stack size.
$java -ss156k (native)
$java -oss600k (Java)
The argument is the stack size you would like in kbytes or mbytes. Experiment with some increased values until you don't overflow.
The goal of the assignment that I'm currently working on for my Data Structures class is to create a of Quantum Tic Tac Toe with an AI that plays to win.
Currently, I'm having a bit of trouble finding the most efficient way to represent states.
Overview of current Structure:
AbstractGame
Has and manages AbstractPlayers (game.nextPlayer() returns next player by int ID)
Has and intializes AbstractBoard at the beginning of the game
Has a GameTree (Complete if called in initialization, incomplete otherwise)
AbstractBoard
Has a State, a Dimension, and a Parent Game
Is a mediator between Player and State, (Translates States from collections of rows to a Point representation
Is a StateConsumer
AbstractPlayer
Is a State Producer
Has a ConcreteEvaluationStrategy to evaluate the current board
StateTransveralPool
Precomputes possible transversals of "3-states".
Stores them in a HashMap, where the Set contains nextStates for a given "3-state"
State
Contains 3 Sets -- a Set of X-Moves, O-Moves, and the Board
Each Integer in the set is a Row. These Integer values can be used to get the next row-state from the StateTransversalPool
SO, the principle is
Each row can be represented by the binary numbers 000-111, where 0 implies an open space and 1 implies a closed space.
So, for an incomplete TTT board:
From the Set<Integer> board perspective:
X_X R1 might be: 101
OO_ R2 might be: 110
X_X R3 might be: 101, where 1 is an open space, and 0 is a closed space
From the Set<Integer> xMoves perspective:
X_X R1 might be: 101
OO_ R2 might be: 000
X_X R3 might be: 101, where 1 is an X and 0 is not
From the Set<Integer> oMoves perspective:
X_X R1 might be: 000
OO_ R2 might be: 110
X_X R3 might be: 000, where 1 is an O and 0 is not
Then we see that x{R1,R2,R3} & o{R1,R2,R3} => board{R1,R2,R3}
The problem is quickly generating next states for the GameTree. If I have player Max (x) with board{R1,R2,R3}, then getting the next row-states for R1, R2, and R3 is simple..
Set<Integer> R1nextStates = StateTransversalPool.get(R1);
The problem is that I have to combine each one of those states with R1 and R2.
Is there a better data structure besides Set that I could use? Is there a more efficient approach in general? I've also found Point<->State mediation cumbersome. Is there another approach that I could try there?
Thanks!
Here is the code for my ConcretePlayer class. It might help explain how players produce new states via moves, using the StateProducer (which might need to become StateFactory or StateBuilder).
public class ConcretePlayerGeneric extends AbstractPlayer {
#Override
public BinaryState makeMove() {
// Given a move and the current state, produce a new state
Point playerMove = super.strategy.evaluate(this);
BinaryState currentState = super.getInGame().getBoard().getState();
return StateProducer.getState(this, playerMove, currentState);
}
}
EDIT: I'm starting with normal TTT and moving to Quantum TTT. Given the framework, it should be as simple as creating several new Concrete classes and tweaking some things.
My suggestion:
Consider representing individual squares rather than rows, whereby +1 == O, -1 == X and 0 implies an empty square. This allows you to detect an end state by checking whether the sum of a horizontal, vertical or diagonal row equals +3 or -3.
Secondly "flatten" this 2D 3x3 matrix into a single array whereby elements[0-2] represent the first row, elements[3-5] represent the second row and elements[6-8] represent the third row.
Use either recursion or an iterative approach to generate subsequent game states given the current state of the board.
EDIT
I got bored and so decided to write some "toy code" to implement the game board, including methods to determine if it is in a terminal state and to generate the set of board states after the next move is made. It should generalise to any size board although I haven't tried. Enjoy ...
Sample Output
$ java Board
Creating board:
---
---
---
Initialising board:
-OX
O--
XO-
Terminal state: false
Generating next move states:
XOX
O--
XO-
-OX
OX-
XO-
-OX
O-X
XO-
-OX
O--
XOX
Code
import java.util.List;
import java.util.LinkedList;
import java.util.Random;
public class Board {
private final int[] squares;
public Board() {
this.squares = new int[9];
}
protected Board(int[] squares) {
this.squares = squares;
}
public void init() {
Random rnd = new Random();
int turn = 1; // 'O' always goes first.
for (int i=0; i<squares.length; ++i) {
double d = rnd.nextDouble();
if (d < 0.75) {
squares[i] = turn;
turn = turn == 1 ? -1 : 1; // Flip to other player's turn.
} else {
squares[i] = 0; // Empty square.
}
if (isTerminalState()) {
break;
}
}
}
public boolean isTerminalState() {
boolean ret = false;
boolean foundEmpty = false;
int hSum = 0;
int[] vSum = new int[3];
for (int i=0; i<squares.length; ++i) {
hSum += squares[i];
if (isWinningRow(hSum)) {
ret = true;
break;
} else if (i == 2 || i == 5) {
hSum = 0;
}
int col = i % 3;
vSum[col] += squares[i];
if (isWinningRow(vSum[col])) {
ret = true;
break;
}
if (squares[i] == 0) {
foundEmpty = true;
}
}
if (!ret) {
if (!foundEmpty) {
ret = true;
} else {
int diag1 = 0;
int diag2 = 0;
int rowSz = (int)Math.sqrt(squares.length);
for (int i=0; i<squares.length; ++i) {
if (i % (rowSz + 1) == 0) {
diag1 += squares[i];
if (isWinningRow(diag1)) {
ret = true;
break;
}
}
if (i > 0 && i % (rowSz - 1) == 0) {
diag2 += squares[i];
if (isWinningRow(diag2)) {
ret = true;
break;
}
}
}
}
}
return ret;
}
private boolean isWinningRow(int rowSum) {
return rowSum == 3 || rowSum == -3;
}
public List<Board> getNextStates() {
List<Board> ret = new LinkedList<Board>();
int tmp = 0;
for (int i=0; i<squares.length; ++i) {
tmp += squares[i];
}
// Next turn is 'O' (i.e. +1) if the board sums to 0.
// Otherwise it's 'X's turn.
int turn = tmp == 0 ? 1 : -1;
if (!isTerminalState()) {
for (int i=0; i<squares.length; ++i) {
if (squares[i] == 0) { // Empty square
int[] squaresA = new int[squares.length];
System.arraycopy(squares, 0, squaresA, 0, squares.length);
squaresA[i] = turn;
ret.add(new Board(squaresA));
}
}
}
return ret;
}
public String toString() {
StringBuilder sb = new StringBuilder();
for (int i=0; i<squares.length; ++i) {
if (squares[i] == 1) {
sb.append('O');
} else if (squares[i] == -1) {
sb.append('X');
} else {
assert squares[i] == 0;
sb.append('-');
}
if (i == 2 || i == 5) {
sb.append('\n');
}
}
return sb.toString();
}
public static void main(String[] args) {
System.err.println("Creating board:\n");
Board bd = new Board();
System.err.println(bd);
System.err.println("\nInitialising board:\n");
bd.init();
System.err.println(bd);
System.err.println("Terminal state: " + bd.isTerminalState() + '\n');
System.err.println("\nGenerating next move states:\n");
List<Board> nextStates = bd.getNextStates();
for (Board bd1 : nextStates) {
System.err.println(bd1.toString() + '\n');
}
}
}
Shouldn't each square have only three possible states (, X, O)?
Either store a grid of 3-state squares, or store 2 lists of moves. You don't need to store the overall board because it is defined by the moves.
Also, what do you mean by:
generating next states for the
GameTree
What is a GameTree? and what are some examples of "next states"?