I got a question about recursion for an entry exam of a job, but I failed to do it within 2 hours. I am very curious about how to do this after the pre-exam but I cannot work out a solution.
You can imagine there is a coin pusher with size n*m (2D array).
Each operation (moving up or down or left or right) will throw away one row or one column of coins
The question requires me to find the shortest possible moves that remains k coins at last. If it is impossible to remain k coins at last, then return -1
I stuck on how to determine the next move when there is more than one operation that having the same maximum number of coins (same value to be thrown away)
I believe that I need to calculate recursively that simulates all future possible moves to determine the current move operation.
But I do not know how to implement this algorithm, can anyone help?
Thank you!
Question :
There is a rectangular chessboard containing N‘M cells. each of
which either has one coin or nothing.
You can move all the coins together in one direction (such as up,
down, left, and right), but each time you can move these coins by
only one cell.
If any coins fall out of the chessboard, they must be thrown away.
If it is required to keep K coins on the board, what is the minimum
moves you have to take?
Output -1 if you can not meet this requirement.
The first line of the input are two positive
integers n, representing the size of the board.
For the next n line(s), each line has m numbers of
characters, with 'o' indicating a coin, '.' indicates an empty grid.
The last line is a positive integer k,
indicating the number of coins to be retained.
30% small input: 1 <= n,m <= 5, 0 < k < 25
40% medium input: 1 <= n,m <= 10, 0 < k < 100
30% large input: 1 <= n,m <= 100, 0 < k < 10000
sample input:
3 4
.o..
oooo
..o.
3
sample output:
2
My temporary answer
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
public class main {
String[][] inputArray;
int n;
int m;
int k;
int totalCoin = 0;
int step = 0;
public static void main(String[] args) {
main temp = new main();
temp.readData();
}
public void readData() {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
m = sc.nextInt();
inputArray = new String [n][m];
sc.nextLine(); // skipping
for (int i = 0; i < n; i++) {
String temp = sc.nextLine();
for (int j = 0; j < m; j++) {
if ((temp.charAt(j) + "").equals("o")) totalCoin++;
inputArray[i][j] = temp.charAt(j) + "";
}
}
k = sc.nextInt();
int result = 0;
if (totalCoin >= k) {
result = findMaxAndMove();
System.out.println(result);
}
}
public String findNextMove() {
Map<String,Integer> tempList = new HashMap<String,Integer>();
tempList.put("up", up());
tempList.put("down", down());
tempList.put("left", left());
tempList.put("right", right());
Map.Entry<String, Integer> maxEntry = null;
for (Entry<String,Integer> temp : tempList.entrySet()) {
if (maxEntry == null || temp.getValue() > maxEntry.getValue()) {
maxEntry = temp;
}
}
Map<String,Integer> maxList = new HashMap<String,Integer>();
for (Entry<String,Integer> temp : tempList.entrySet()) {
if (temp.getValue() == maxEntry.getValue()) {
maxList.put(temp.getKey(), temp.getValue());
}
}
// return maxList.entrySet().iterator().next().getKey();
if (maxList.size() > 1) {
// how to handle this case when more than 1 operations has the same max value???????????
return ??????????????
}
else {
return maxList.entrySet().iterator().next().getKey();
}
//
}
public int findMaxAndMove() {
int up = up();
int down = down();
int left = left();
int right = right();
if ((totalCoin - up) == k) {
step++;
return step;
}
if ((totalCoin - down) == k) {
step++;
return step;
}
if ((totalCoin - left) == k) {
step++;
return step;
}
if ((totalCoin - right) == k) {
step++;
return step;
}
if (totalCoin - up < k && totalCoin - down < k && totalCoin - left < k && totalCoin - right < k) return -1;
else {
switch (findNextMove()) {
case "up" :
totalCoin -= up;
this.moveUp();
break;
case "down" :
totalCoin -= down;
this.moveDown();
break;
case "left" :
totalCoin -= left;
this.moveLeft();
break;
case "right" :
totalCoin -= right();
this.moveRight();
break;
}
step++;
return findMaxAndMove(); // going to next move
}
}
public String[] createBlankRow() {
String[] temp = new String[m];
for (int i = 0; i < m; i++) {
temp[i] = ".";
}
return temp;
}
public int up() {
int coinCounter = 0;
for (int i = 0; i < m; i++) {
if (inputArray[0][i].equals("o")) {
coinCounter++;
}
}
return coinCounter;
}
public void moveUp() {
// going up
for (int i = 0; i < n - 1; i++) {
inputArray[i] = inputArray[i + 1];
}
inputArray[n-1] = createBlankRow();
}
public int down() {
int coinCounter = 0;
for (int i = 0; i < m; i++) {
if (inputArray[n-1][i].equals("o")) {
coinCounter++;
}
}
return coinCounter;
}
public void moveDown() {
// going down
for (int i = n-1; i > 1; i--) {
inputArray[i] = inputArray[i - 1];
}
inputArray[0] = createBlankRow();
}
public int left() {
int coinCounter = 0;
for (int i = 0; i < n; i++) {
if (inputArray[i][0].equals("o")) {
coinCounter++;
}
}
return coinCounter;
}
public void moveLeft() {
// going left
for (int i = 0; i < n; i++) {
for (int j = 0; j < m-1; j++) {
inputArray[i][j] = inputArray[i][j+1];
}
inputArray[i][m-1] = ".";
}
}
public int right() {
int coinCounter = 0;
for (int i = 0; i < n; i++) {
if (inputArray[i][m-1].equals("o")) {
coinCounter++;
}
}
return coinCounter;
}
public void moveRight() {
// going right
for (int i = 0; i < n; i++) {
for (int j = m-1; j > 0; j--) {
inputArray[i][j] = inputArray[i][j-1];
}
inputArray[i][0] = ".";
}
}
public void printboard() {
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
System.out.print(inputArray[i][j]);
}
System.out.println();
}
}
}
I suspect you didn't find the right algorithm to solve the problem. To find a solution, not only the reachable boards with some special coin count are of concern but all. You must build up a tree of reachable boards. Each node in this tree is connected to its child nodes by an operation. That's were recursion enters the scene. You stop
when you reach your goal (mark this branch as possible solution) or
when it got impossible to reach the goal with further operations (too few coins left)
when the next operation would reach a board already visited in this branch.
In this tree all shortest branches marked as possible solution are the actual solutions. If no branch is marked as possible solution there is no solution and you have to output -1.
Here is my solution
public class CoinsMover {
public static List<String> getMinMoves(Character[][] board, int k, List<String> moves) {
if (!movesAreValid(moves, board)) {
return null;
}
int currentAmountOfCoins = getCoinsOnBoard(board);
// All good no need to move any thing
if (currentAmountOfCoins == k) {
moves.add("done");
return moves;
}
// Moved to much wrong way
if (currentAmountOfCoins < k) {
return null;
}
List<String> moveRight = getMinMoves(moveRight(board), k, getArrayWithApendded(moves, "right"));
List<String> moveLeft = getMinMoves(moveLeft(board), k, getArrayWithApendded(moves, "left"));
List<String> moveUp = getMinMoves(moveUp(board), k, getArrayWithApendded(moves, "up"));
List<String> moveDown = getMinMoves(moveDown(board), k, getArrayWithApendded(moves, "down"));
List<List<String>> results = new ArrayList<>();
if (moveRight != null) {
results.add(moveRight);
}
if (moveLeft != null) {
results.add(moveLeft);
}
if (moveUp != null) {
results.add(moveUp);
}
if (moveDown != null) {
results.add(moveDown);
}
if (results.isEmpty()) {
return null;
}
List<String> result = results.stream().sorted(Comparator.comparing(List::size)).findFirst().get();
return result;
}
private static boolean movesAreValid(List<String> moves, Character[][] board) {
long ups = moves.stream().filter(m -> m.equals("up")).count();
long downs = moves.stream().filter(m -> m.equals("down")).count();
long lefts = moves.stream().filter(m -> m.equals("left")).count();
long rights = moves.stream().filter(m -> m.equals("right")).count();
boolean verticalIsFine = ups <= board.length && downs <= board.length;
boolean horizontalIsFine = lefts <= board[0].length && rights <= board[0].length;
return verticalIsFine && horizontalIsFine;
}
private static List<String> getArrayWithApendded(List<String> moves, String move) {
List<String> result = new ArrayList<>(moves);
result.add(move);
return result;
}
private static Character[][] moveRight(Character[][] board) {
Character result[][] = new Character[board.length][board[0].length];
// Cleaning left column
for (int i = 0; i < board.length; i++)
result[i][0] = '.';
for (int row = 0; row < board.length; row++) {
for (int column = 0; column < board[row].length - 1; column++) {
result[row][column + 1] = board[row][column];
}
}
return result;
}
private static Character[][] moveLeft(Character[][] board) {
Character result[][] = new Character[board.length][board[0].length];
// Cleaning right column
for (int i = 0; i < board.length; i++)
result[i][board[i].length - 1] = '.';
for (int row = 0; row < board.length; row++) {
for (int column = 1; column < board[row].length; column++) {
result[row][column - 1] = board[row][column];
}
}
return result;
}
private static Character[][] moveDown(Character[][] board) {
Character result[][] = new Character[board.length][board[0].length];
// Cleaning upper row
for (int i = 0; i < board[board.length - 1].length; i++)
result[0][i] = '.';
for (int row = board.length - 1; row > 0; row--) {
result[row] = board[row - 1];
}
return result;
}
private static Character[][] moveUp(Character[][] board) {
Character result[][] = new Character[board.length][board[0].length];
// Cleaning upper row
for (int i = 0; i < board[board.length - 1].length; i++)
result[board.length - 1][i] = '.';
for (int row = 0; row < board.length - 1; row++) {
result[row] = board[row + 1];
}
return result;
}
private static int getCoinsOnBoard(Character[][] board) {
int result = 0;
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[i].length; j++) {
if (board[i][j] == 'o') {
result++;
}
}
}
return result;
}
public static void main(String... args) {
Character[][] mat = {{'.', 'o', '.', '.'}, {'o', 'o', 'o', 'o'}, {'.', '.', 'o', '.'}};
List<String> result = getMinMoves(mat, 3, new ArrayList<>());
if (result == null) {
System.out.println(-1);//output [right, right, done]
}
System.out.println(result);
}
}
I admit it was hard for me to search for duplicates so instead I am using a list of string which wrights the path you need to take to get to the solution. Now let's look at stopping condition first if current moves are invalid return null example of invalid moves is if you have a table with 4 columns in you moved right 5 times same goes for rows and moves up/down. Second, if board holds the neede amount we are done. And the last if board hold less we have failed. So now what algorithm is trying to do is to step in each direction in search of result and from here proceed recursivly.
You can find the solution below. A few points to note.
Whenever you see a problem that mentions moving an array in 1 direction, it's always a good idea to define an array of possible directions and loop through it in the recursive function. This would prevent you from confusing yourself.
The idea is to count coins by row and column so that you have a way to find out the remaining coins after each move in linear time.
The remaining job is to just loop through the possible directions in your recursive functions to find a possible solution.
As the recursive function may run in a circle and come back to one of the previous locations, you should/can improve the recursive function further by maintaining a Map cache of previous partial solutions using the curRowIdx and curColIdx as key.
public static void main(String[] args) {
char[][] board = {{'.', 'o', '.', '.'},
{'o', 'o', 'o', 'o'},
{'.', '.', 'o', '.'}};
CoinMoveSolver solver = new CoinMoveSolver(board);
System.out.println(solver.getMinimumMove(3));
}
static class CoinMoveSolver {
int[][] directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
char[][] board;
int[] rowCount;
int[] colCount;
int height;
int width;
int totalCoins;
public CoinMoveSolver(char[][] board) {
// Set up the board
this.board = board;
this.height = board.length;
this.width = board[0].length;
// Count how many coins we have per row,
// per column and the total no. of coins
this.rowCount = new int[height];
this.colCount = new int[width];
for (int i = 0 ; i < board.length ; i++) {
for (int j = 0 ; j < board[i].length ; j++) {
if (board[i][j] == 'o') {
this.rowCount[i]++;
this.colCount[j]++;
totalCoins++;
}
}
}
}
// Returns the number of coins if the top left
// corner of the board is at rowIdx and colIdx
private int countCoins(int rowIdx, int colIdx) {
int sumRow = 0;
for (int i = rowIdx ; i < rowIdx + height ; i++) {
if (i >= 0 && i < height)
sumRow += rowCount[i];
}
int sumCol = 0;
for (int j = colIdx ; j < colIdx + width ; j++) {
if (j >= 0 && j < width)
sumCol += colCount[j];
}
return Math.min(sumRow, sumCol);
}
public int getMinimumMove(int targetCoinCount) {
if (totalCoins < targetCoinCount)
return -1;
else if (totalCoins == targetCoinCount)
return 0;
else
return this.recursiveSolve(0, 0, -1, 0, targetCoinCount);
}
private boolean isOppositeDirection(int prevDirectionIdx, int curDirectionIdx) {
if (prevDirectionIdx < 0)
return false;
else {
int[] prevDirection = directions[prevDirectionIdx];
int[] curDirection = directions[curDirectionIdx];
return prevDirection[0] + curDirection[0] + prevDirection[1] + curDirection[1] == 0;
}
}
private int recursiveSolve(int curRowIdx, int curColIdx, int prevDirectionIdx, int moveCount, int targetCoinCount) {
int minMove = -1;
for (int i = 0 ; i < directions.length ; i++) {
if (!this.isOppositeDirection(prevDirectionIdx, i)) {
int[] direction = directions[i];
int nextRowIdx = curRowIdx + direction[0];
int nextColIdx = curColIdx + direction[1];
int coinCount = this.countCoins(nextRowIdx, nextColIdx);
// If this move reduces too many coins, abandon
if (coinCount < targetCoinCount)
continue;
// If this move can get us the exact number of
// coins we're looking for, break the loop
else if (coinCount == targetCoinCount) {
minMove = moveCount + 1;
break;
} else {
// Look for the potential answer by moving the board in 1 of the 4 directions
int potentialMin = this.recursiveSolve(nextRowIdx, nextColIdx, i, moveCount + 1, targetCoinCount);
if (potentialMin > 0 && (minMove < 0 || potentialMin < minMove))
minMove = potentialMin;
}
}
}
// If minMove is still < 0, that means
// there's no solution
if (minMove < 0)
return -1;
else
return minMove;
}
}
Related
I need to find all the permutations for a given n(user input) without backtracking.
What i tried is:
import java.util.Scanner;
import java.util.Vector;
class Main {
private static int n;
private static Vector<Vector<Integer>> permutations = new Vector<>();
private static void get_n() {
Scanner user = new Scanner(System.in);
System.out.print("n = ");
n = user.nextInt();
}
private static void display(Vector<Vector<Integer>> permutations) {
for (int i = 0; i < factorial(n) - 1; ++i) {
for (int j = 0; j < n; ++j) {
System.out.print(permutations.elementAt(i).elementAt(j) + " ");
}
System.out.println();
}
}
private static int factorial(int n) {
int result = 1;
for (int i = 1; i <= n; ++i) {
result *= i;
}
return result;
}
private static int max(Vector<Integer> permutation) {
int max = permutation.elementAt(0);
for (int i = 1; i < permutation.size(); ++i)
if (permutation.elementAt(i) > max)
max = permutation.elementAt(i);
return max;
}
// CHECKS FOR ELEMENT COUNT AND 0 - (n-1) APPARITION
public static int validate_permutation(Vector<Integer> permutation) {
// GOOD NUMBER OF ELEMENTS
if (max(permutation) != permutation.size() - 1)
return 0;
// PROPER ELEMENTS APPEAR
for (int i = 0; i < permutation.size(); ++i)
if (!permutation.contains(i))
return 0;
return 1;
}
private static Vector<Integer> next_permutation(Vector<Integer> permutation) {
int i;
do {
i = 1;
// INCREMENT LAST ELEMENT
permutation.set(permutation.size() - i, permutation.elementAt(permutation.size() - i) + 1);
// IN A P(n-1) PERMUTATION FOUND n. "OVERFLOW"
while (permutation.elementAt(permutation.size() - i) == permutation.size()) {
// RESET CURRENT POSITION
permutation.set(permutation.size() - i, 0);
// INCREMENT THE NEXT ONE
++i;
permutation.set(permutation.size() - i, permutation.elementAt(permutation.size() - i) + 1);
}
} while (validate_permutation(permutation) == 0);
// OUTPUT
System.out.print("output of next_permutation:\t\t");
for (int j = 0; j < permutation.size(); ++j)
System.out.print(permutation.elementAt(j) + " ");
System.out.println();
return permutation;
}
private static Vector<Vector<Integer>> permutations_of(int n) {
Vector<Vector<Integer>> permutations = new Vector<>();
// INITIALIZE PERMUTATION SET WITH 0
for (int i = 0; i < factorial(n); ++i) {
permutations.addElement(new Vector<>());
for(int j = 0; j < n; ++j)
permutations.elementAt(i).addElement(0);
}
for (int i = 0; i < n; ++i)
permutations.elementAt(0).set(i, i);
for (int i = 1; i < factorial(n); ++i) {
// ADD THE NEXT PERMUTATION TO THE SET
permutations.setElementAt(next_permutation(permutations.elementAt(i - 1)), i);
System.out.print("values set by permutations_of:\t");
for (int j = 0; j < permutations.elementAt(i).size(); ++j)
System.out.print(permutations.elementAt(i).elementAt(j) + " ");
System.out.println("\n");
}
System.out.print("\nFinal output of permutations_of:\n\n");
display(permutations);
return permutations;
}
public static void main(String[] args) {
get_n();
permutations.addAll(permutations_of(n));
}
}
Now, the problem is obvious when running the code. next_permutation outputs the correct permutations when called, the values are set correctly to the corresponding the vector of permutations, but the end result is a mass copy of the last permutation, which leads me to believe that every time a new permutation is outputted by next_permutation and set into the permutations vector, somehow that permutation is also copied over all of the other permutations. And I can't figure out why for the life of me.
I tried both set, setElementAt, and an implementation where I don't initialize the permutations vector fist, but add the permutations as they are outputted by next_permutation with add() and I hit the exact same problem. Is there some weird way in which Java handles memory? Or what would be the cause of this?
Thank you in advance!
permutations.setElementAt(next_permutation(permutations.elementAt(i - 1)), i);
This is literally setting the vector at permutations(i) to be the same object as permutations[i-1]. Not the same value - the exact same object. I think this the source of your problems. You instead need to copy the values in the vector.
I am doing a game called 1010! Probably some of you have heard of it. Bascially I encouter some trouble when writing the Algorithm for clearance.
The rule is such that if any row or any column is occupied, then clear row and column respectively.
The scoring is such that each move gains a+10*b points. a is the number of square in the input piece p and b is the total number of row&column cleared.
To start, I create a two dimensional Array board[10][10], poulate each elements in the board[][] with an empty square.
In the class of Square, it has public void method of unset()-> "empty the square" & boolean status() -> "judge if square is empty"In the class of piece, it has int numofSquare -> "return the number of square in each piece for score calculation"
In particular, I don't know how to write it if both row and column are occupied as they are inter-cross each other in an two dimensional array.
It fail the test under some condition, in which some of the squares are not cleared but they should have been cleared and I am pretty sure is the logic problem.
My thinking is that:
Loop through squares in first row and first column, record the number of square that are occupied (using c and r); if both are 10, clear row&column, otherwise clear row or column or do nothing.
reset the c &r to 0, loop through square in the second row, second column…
update score.
Basically the hard part is that if I seperate clear column and clear row algorithm ,I will either judge row or column first then clear them . However, as every column contains at least one square belong to the row, and every row contains at least one square belong to the column, there will be mistake when both row and column are full.
Thanks for help.
import java.util.ArrayList;
public class GameState{
public static final int noOfSquares = 10;
// the extent of the board in both directions
public static final int noOfBoxes = 3;
// the number of boxes in the game
private Square[][] board; // the current state of the board
private Box[] boxes; // the current state of the boxes
private int score; // the current score
// initialise the instance variables for board
// all squares and all boxes are initially empty
public GameState()
{
getboard();
score = 0;
board = new Square[10][10];
for(int i =0;i<board.length;i++){
for(int j =0;j<board[i].length;j++){
board[i][j] = new Square();
}
}
boxes = new Box[3];
for(int k =0;k<boxes.length;k++){
boxes[k] = new Box();
}
}
// return the current state of the board
public Square[][] getBoard()
{
return board;
}
// return the current score
public int getScore()
{
return score;
}
// place p on the board with its (notional) top-left corner at Square x,y
// clear columns and rows as appropriate
int r =0;
int c = 0;
int rowandcolumn = 0;
for (int row=0;row<10;row++){
for (int column=0;column<10;column++) {
if (board[row][column].status() == true){
c = c + 1;
if( c == 10 ) {
rowandcolumn = rowandcolumn + 1;
for(int z=0;z<10;z++){
board[row][z].unset(); //Clear column
}
}
}
if (board[column][row].status() == true){
r = r + 1;
if( r == 10) {
rowandcolumn = rowandcolumn + 1;
for(int q=0;q<10;q++){
board[q][row].unset(); //Clear row
}
}
}
}
r=0; //reset
c=0;
}
score = score + p.numberofBox()+10*rowandcolumn;
}
how about this
void Background::liquidate(int &score){
int arr_flag[2][10]; //0 is row,1 is column。
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 10; j++)
{
arr_flag[i][j] = 1;
}
}
//column
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
if (arr[i][j].type == 0)
{
arr_flag[0][i] = 0;
break;
}
}
}
//row
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
if (arr[j][i].type == 0)
{
arr_flag[1][i] = 0;
break;
}
}
}
//clear column
for (int i = 0; i < 10; i++)
{
if (arr_flag[0][i] == 1)
{
for (int j = 0; j < 10; j++)
{
arr[i][j].Clear();
}
}
}
//clear row
for (int i = 0; i < 10; i++)
{
if (arr_flag[1][i] == 1)
{
for (int j = 0; j < 10; j++)
{
arr[j][i].Clear();
}
}
}
}
I tried to write somme code for the idea I posted
// place p on the board with its (notional) top-left corner at Square x,y
// clear columns and rows as appropriate
int r =0;
int c = 0;
int rowandcolumn = 0;
int row=FindFirstRow();
int column=FindFirstColumn();
if(row!=-1 && column!=-1)
{
rowandcolumn++;
//actions here: row found and column found
//clear row and column
clearRow(row);
clearColumn(column);
}
else if(row!=-1)
{
//only row is found
//clear row
clearRow(row);
}
else if(column!=-1)
{
//only column is found
//clear column
clearColumn(column);
}
else
{
//nothing is found
}
public void clearRow(int row)
{
for(int i=0; i<10;i++)
{
board[row][i].unset();
}
}
public void clearColumn(int column)
{
for(int i=0; i<10;i++)
{
board[i][column].unset();
}
}
//this method returns the first matching row index. If nothing is found it returns -1;
public int FindFirstRow()
{
for (int row=0;row<10;row++)
{
int r=0;
for (int column=0;column<10;column++)
{
if (board[row][column].status() == true)
{
r = r + 1;
if( r == 10)
{
//row found
return row;
}
}
}
r=0; //reset
}
//nothing found
return -1;
}
//this method returns the first matching column index. If nothing is found it returns -1;
public int FindFirstColumn()
{
for (int column=0;column<10;column++)
{
int c=0;
for (int row=0;row<10;row++)
{
if (board[row][column].status() == true)
{
c = c + 1;
if( c == 10 )
{
//matching column found
return column;
}
}
}
c=0; //reset
}
//nothing found
return -1;
}
I'm attempting to write a program which solves the 8 Queens Problem using a 2 dimensional array of booleans. I will use backtracking to find the solution. I know this is not the optimal way to solve this problem, and that I should probably go for a 1D array for simplicity, but I want to solve it this way.
Right now I'm stuck on the function which is supposed to check whether a queen fits at a given coordinate. My row, column and down-right diagonal checks work, but I can't get the down-left diagonal check to work. I'm struggling to find the correct indexes of i and j (x and y) to start at, and which counter to increment/decrement for each iteration. Right now my function looks like this:
public static boolean fits(int x, int y) {
for(int i = 0; i < N; i++) {
if(board[x][i]) {
return false; // Does not fit on the row
}
}
for(int i = 0; i < N; i++) {
if(board[i][y]) {
return false; // Does not fit on the column
}
}
for(int i = Math.max(x-y, 0), j = Math.max(y-x, 0); i < N && j < N; i++, j++) {
if(board[i][j]) {
return false; // Down right diagonal issue
}
}
for(int i = Math.min(x+y, N-1), j = Math.max(N-1-x, 0); i >= 0 && j < N; i--, j++) {
if(board[i][j]) {
return false; // Supposed to check the down-left diagonal, but does not work.
}
}
return true;
}
As you can see there's a problem with the last loop here. I'd be very, very happy if someone could give me a working for-loop to check the down-left diagonal. Thanks in advance!
Edit: Here's the working code:
public class MyQueens {
static boolean[][] board;
static final int N = 8;
public static void main(String[] args) {
int p = 0;
board = new boolean[N][N];
board[1][1] = true;
System.out.println(fits(0, 2));
System.out.println(fits(2, 2));
}
public static boolean fits(int x, int y) {
for(int i = 0; i < N; i++) {
if(board[x][i]) {
return false; // Row
}
}
for(int i = 0; i < N; i++) {
if(board[i][y]) {
return false; // Column
}
}
for(int i = 0, j = 0; i < N && j < 0; i++, j++) {
if(board[i][j]) {
return false; // for right diagonal
}
}
int mirrorx = (N-1)-x;
for(int i = Math.max(mirrorx-y, 0), j = Math.max(y-mirrorx, 0); i < N && j < N; i++, j++) {
if(board[(N-1)-i][j]) {
return false;
}
}
return true;
}
}
I'm attempting to write a program which solves the 8 Queens Problem using a 2 dimensional array of booleans.
This is not the optimal representation, because you must use four loops to check if a queen can be placed or not. A much faster way of doing it is available.
For the purposes of your program, there are four things that must be free of threats in order for a queen to be placed:
A row,
A column,
An ascending diagonal, and
A descending diagonal
Each of these four things can be modeled with a separate array of booleans. There are eight rows, eight columns, fifteen ascending diagonals, and fifteen descending diagonals (including two degenerate cases of one-cell "diagonals" in the corners).
Declare four arrays row[8], col[8], asc[15] and desc[15], and use these four methods to work with it:
public static boolean fits(int r, int c) {
return !row[r] && !col[c] && !asc[r+c] && !desc[c-r+7];
}
public static void add(int r, int c) {
set(r, c, true);
}
public static void remove(int r, int c) {
set(r, c, false);
}
private static void set(int r, int c, boolean q) {
row[r] = col[c] = asc[r+c] = desc[c-r+7] = q;
}
Just flip the board horizontally and reuse the same algorithm as for the down right diagonal:
int mirrorx = (N-1)-x;
for(int i = Math.max(mirrorx-y, 0), j = Math.max(y-mirrorx, 0); i < N && j < N; i++, j++) {
if(board[(N-1)-i][j]) {
return false;
}
}
You could re-arrange it to make it more optimal.
Why don't you just use:
for(int i = 0, j = 0; i < N && j < 0; i++, j++) {
if(board[i][j]) {
return false; // for right diagonal
}
}
Similarly:
for(int i = 0, j = N-1; i < N && j >= 0; i++, j--) {
if(board[i][j]) {
return false; // for left diagonal
}
}
I'm currently writing a small function which should return how many items of an array are exactly on the same position as the other array and how many are there but on different positions.
the function currently looks like this:
public static int[] numCorrects(char[] leftarray, char[] rightarray){
int counter[] = new int[2];
counter[0] = 0;
counter[1] = 0;
for (int i = 0; i < leftarray.length; i++) {
if(leftarray[i]==rightarray[i]) counter[0]++;
else {
for (int n = 0; n < leftarray.length; n++) {
if (leftarray[i] == rightarray[n] && leftarray[n] != rightarray[n]) {
counter[1]++;
break;
}
}
}
}
return counter;
}
This works kinda well if i have lets say the leftarray of (1, 2, 3, 4) and the rightarray of (4, 3, 2, 2)
it the returns (0, 3) (0 exact match, 3 there but on different position)
but now the problem:
if I swap the inputs with leftarray of (4, 3, 2, 2) and rightarray of (1, 2, 3, 4) the output is (0, 4) which is wrong (should be the same as the 1st one)
hope anyone can help me. thx
You have to decide how to handle repeated elements. This is what's causing the discrepancy. The repeated 2 means that the "different positions" counter is incremented twice when the arrays are swapped.
try this:
public static int[] numCorrects(char[] leftarray, char[] rightarray){
int counter[] = new int[2];
counter[0] = 0;
counter[1] = 0;
boolean taken[] = new boolean[rightarray.length];
for (int i=0;i<taken.length;i++)
taken[i] = false;
for (int i = 0; i < leftarray.length; i++) {
if(leftarray[i]==rightarray[i]){ counter[0]++; taken[i] = true; }
else {
for (int n = 0; n < leftarray.length; n++) {
if (leftarray[i] == rightarray[n] && leftarray[n] != rightarray[n] && !taken[n]) {
taken[n] = true;
counter[1]++;
break;
}
}
}
}
return counter;
}
Remove the break and you will get the same result.
public static int[] numCorrects(char[] leftarray, char[] rightarray){
int counter[] = new int[2];
counter[0] = 0;
counter[1] = 0;
boolean taken[] = new boolean[rightarray.length];
for (int i=0;i<taken.length;i++)
taken[i] = false;
for (int i = 0; i < leftarray.length; i++) {
if(leftarray[i]==rightarray[i])
{
counter[0]++;
taken[i]=true;
}
}
for (int i = 0; i < leftarray.length; i++)
{
if (!taken[i])
{
for (int j = 0; j < rightarray.length; j++) {
if (leftarray[i] == rightarray[j] && i!=j && !taken[j]) { // you can remove i!=j because its already don't apply because of !taken[i]
taken[j] = true;
counter[1]++;
break;
}
}
}
}
return counter;
}
I'm working on the Conway's game of life program. I have the first two generations of cells printed out, but I can not get anymore printed. So I decided to use recursion so multiple batches of cells can be printed. My NewCells method creates the second generation. I thought that If I were to repeat said method by returning NewCells(c) instead of c, It would print out different results, but it prints out the same batch of cells over and over again.
public class Life {
public static boolean[][] NewCells(boolean[][] c)
{
int N = 5;
int o=0;
int p=0;
int livecnt = 0; //keeps track of the alive cells surrounding cell
int store = 0; //amount of surrounding cells for each individual cell
int livestore[] = new int[N*N];
System.out.println("Next Generation");
// Checks for the amount of "*" surrounding (o,p)
for (o=0; o < N; o++)
{
for (p=0; p<N; p++)
{
for (int k=(o-1); k <= o+1; k++)
{
for (int l =(p-1); l <=p+1; l++)
{
if ( k >= 0 && k < N && l >= 0 && l < N) //for the border indexes.
{
if (!(k== o && l==p)) //so livecnt won't include the index being checked.
{
if (c[k][l] == true)
{
livecnt++;
}
}
}
}
}
livestore[store]= livecnt;
livecnt = 0;
store++;
}
}
//Prints the next batch of cells
int counter= 0;
for (int i2 = 0; i2 <N; i2++)
{
for (int j2 = 0; j2 < N; j2++)
{
if (c[i2][j2] == false)
{
if (livestore[counter] ==3)
{
c[i2][j2]=true;
System.out.print("* ");
}
else
System.out.print("- ");
}
else if (c[i2][j2] == true)
{
if (livestore[counter] ==1)
{
c[i2][j2]= false;
System.out.print("- ");
}
else if (livestore[counter] >3)
{
c[i2][j2]= false;
System.out.print("- ");
}
else
System.out.print("* ");
}
counter++;
}
System.out.println();
}
return NewCell(c);
}
/*************************************************************************************************************************************************/
public static void main(String[] args)
{
int N = 5;
boolean[][] b = new boolean[N][N];
double cellmaker = Math.random();
int i = 0;
int j = 0;
int o=0;
int p=0;
int livecnt = 0; //keeps track of the alive cells surrounding cell
int store = 0; //amount of surrounding cells for each individual cell
int livestore[] = new int[N*N];
System.out.println("First Generation:");
// Makes the first batch of cells
for ( i = 0; i < N ; i++)
{
for ( j = 0; j< N; j++)
{
cellmaker = Math.random();
if (cellmaker > 0.5) // * = alive; - = dead
{
b[i][j]=true;
System.out.print( "* ");
}
if (cellmaker < 0.5)
{ b[i][j] = false;
System.out.print("- ");
}
}
System.out.println();
}
boolean[][] newcells = new boolean[N][N];
newcells = NewCells(b);
}
}
I do not think recursion is a good idea for this application. It leads to a StackOverflowError because each generation pushes another call stack frame. Recursion, as this program uses it, has no advantage over iteration.
Instead, put the main method call to NewCells in a loop. That way, you can run as many iterations as you like, regardless of stack size.
You are not calling NewCell from within NewCell, which is how recursion works.
I'm assuming it's not a typo in your question, but rather a lack of understanding of what it is and how it works, I recommend some reading on recursion in Java.
After you understand the basics, come back here for more help!