Saving a Integer[] as an array - java

I am trying to figure out how to save the return value of the method which is Integer[]{longest, count, possible} as a local variable and use the local variable as the return.
One problem I am running into, when I compile my code I get an error that a int cannot be converted into a boolean, and it is referring to "possible" in the return statement.
private Integer[] longestLength(int col, int row, boolean color)
{
// longest equals length of the longest pattern of the same color
// count equals number of the longest pattern of the same color
// possible equals number of spots, that you can play off of.
int longest = 0;
int count = 0;
int possible = 0;
//this for loop counts to 4, the patterns of the 4 possible wins
for (int i = 1; i <= 4; i++) {
//lengthOfColor saves the lengthOfColor() method to avoid calling it multiple times throughout longestLength.
Integer[] lengthOfColor = lengthOfColor(col, row, i, color);
int length = lengthOfColor[0];
//if a new longest is found, its new value is now set to itself
if (length > longest) {
longest = length;
count = 0;
possible = lengthOfColor[1];
}
//if length is the same as longest, we increase the count, and make possible equal too the larger one
if (longest != 0 && length == longest) {
count++;
possible = Math.max(lengthOfColor[1], possible);
}
}
return new Integer[]{longest, count, possible};
}
Here is my lengthOfColor method
private Integer[] lengthOfColor(int col, int row, int pattern, boolean color) {
int x = 0;
int y = 0;
if (pattern == 1) {
// vertical pattern
y = 1;
} else if (pattern == 2) {
// horizontal pattern
x = 1;
} else if (pattern == 3) {
// diagonal slope left pattern
x = 1;
y = 1;
} else {
// diagonal slope right pattern
x = 1;
y = -1;
}
// length = how many neighbor slots are of same color
// possible equals number of slots, that you can play off of.
// whichSide = left or right if horizontal and top or bottom if vertical.
int length = 0;
int possible = 0;
Integer[] whichSide = new Integer[]{1, -1};
for (int side : whichSide) {
int i = 1;
boolean complete = false;
//while complete is false continue the loop
while (!complete) {
//mainX == horizontal pattern distance
//mainY == vertical pattern distance
int mainX = x * i * side;
int mainY = y * i * side;
//if still inbounds and if the same slot is filled and it matches the color, increment length
if (!outOfBounds(col, row, mainX, mainY) && getIsFilled(col, row, mainX, mainY) &&
checkColor(col, row, mainX, mainY) == color)
{
length++;
}
//if still inbounds and if the same slot is empty, increment possible number of spots and change complete to true
else if (!outOfBounds(col, row, mainX, mainY) && !getIsFilled(col, row, mainX, mainY) &&
getLowestEmptyIndex(myGame.getColumn(col + mainX)) == getLowestEmptyIndex(myGame.getColumn(col)) + mainY - row)
{
possible++;
complete = true;
}
//finish the statement to avoid a infinite loop if neither conditions are met.
else
{
complete = true;
}
// If not complete, then check one slot further.
i = i + 1;
}
}
return new Integer[] {length, possible};
}

Figured it out, I was thinking to hard. I simply need to save the integer before returning it, so it is easier to access later on and has a name.
Integer[] longestLengthArray = new Integer[]{longest, count, possible};
return longestLengthArray;

Simplest solution:
return new Integer[]{longest, count, possible? 1 : 0};
But in general it is good idea create new helper class:
class LongestLengthRersponse{
private int longest;
private int count;
private boolean possible;
//constructor, and getters

Related

What is wrong with my recursive back-tracker

I wanted to make an algorithm to create a maze using recursive back-tracker algorithm. I get this problem when running the program:
Exception in thread "main" java.util.NoSuchElementException
at java.base/java.util.Vector.firstElement(Vector.java:481)
at DC_files.Maze.RBT(MazeAlgorithm.java:131)
at DC_files.MazeAlgorithm.main(MazeAlgorithm.java:222)
and honestly, at this point after finding couple of bugs and error i have no idea what might be wrong. The only clue that i have, is that in the switch there is an error, that the stack.firstElement() doesn't update and is always the same and in the cases something is being inserted wrongly.
while(vis < toVis){
Vector<Integer> neighbours = new Vector<>();
int x = stack.firstElement().getKey(); (line 131 with the error.)
int y = stack.firstElement().getValue();
//North neighbour
if(y-1 >= 0 && !matrix[y - 1][x].vis){
neighbours.add(0);
}
entire code
package DC_files;
import javafx.util.Pair;
import java.util.Random;
import java.io.*;
import java.util.*;
class Cell{
/*
each Cell holds information of:
-the state of it's walls,
-the value that the Cell holds(will be used later to customize rooms in the maze),
-and information if the Cell was visited(will be used in the algorithm)
*/
boolean[] walls;
boolean vis;
int value;
public boolean isVis() {
return vis;
}
public boolean[] getWalls() {
return walls;
}
public int getValue() {
return value;
}
/*
by default, each Cell has the value of each wall set to true(they exist/there are no corridors),
vis as visited set to false, because we weren't in the room yet,
value set to zero, for further development phase (0 - not visited, 1 - visited, 2 - ??? (...))
*/
Cell(){
walls = new boolean[]{true, true, true, true}; // {N, S, E, W}
vis = false;
value = 0;
}
}
class Maze{
/*
Maze class was created in order to generate an array of Cells,
that will be later used in the algorithm.
First we create integer ,,size,, to store size of the array, then
we create a matrix, that will hold Cell objects.
In the constructor of the class, we set the required integer s as size,
allocate memory to the matrix, by setting its dimensions to size x size
and we create Cell objects for each spot int the matrix, without any modifications.
*/
int size;
Cell[][] matrix;
Maze(int s){
size = s;
matrix = new Cell[size][size];
for(int y = 0; y < size; y++){
for(int x = 0; x < size; x++){
matrix[y][x] = new Cell();
//System.out.print("1");
}
}
}
void showMaze(){
for(int y = 0; y < size; y++){
for(int x = 0; x < size; x++){
System.out.print(matrix[y][x].getValue() + " ");
}
System.out.println();
}
}
/*
Class ,,MazeAlgorithm'' is responsible for creating connections between cells in matrix.
It uses RBT, which stands for Recursive Back-Tracker, to achieve that goal.
In order to use RBT, we need to give it starting point. After we do that,
it will check, if there is any neighbour, that fulfills the required conditions,
and then goes to that neighbour setting visited to true and value to 1.
After that, it repeats the process, and constantly adds the cells coordinates
on top of the stack, to keep track of the road it went through. If it gets stuck,
it will go back to the previous cell, by removing the top coordinates of the stack,
and going to NOW top coordinates (previous move), checking if that cell has any
neighbours which can fulfill the conditions. If it cannot find any neighbour,
it means the maze was created.
*/
void RBT(int startX, int startY){
//Setting cells to visit to size x size, and the value of visited cells to 0
int toVis = size*size;
int vis = 0;
//Declaring a stack, that will hold the information about our road
Stack<Pair<Integer, Integer>> stack = new Stack<>();
//Setting starting position: pushing it onto the stack,
//setting it's values as visited and 1,
//incrementing visited rooms.
stack.push(new Pair<>(startX, startY));
matrix[startY][startX].vis = true;
matrix[startY][startX].value = 1;
vis += 1;
//we will check, if our current node has any neighbours we can go to,
//saving those neighbours inside a vector
while(vis < toVis){
Vector<Integer> neighbours = new Vector<>();
int x = stack.firstElement().getKey();
int y = stack.firstElement().getValue();
//North neighbour
if(y-1 >= 0 && !matrix[y - 1][x].vis){
neighbours.add(0);
}
//South neighbour
if(y+1 < size && !matrix[y + 1][x].vis){
neighbours.add(1);
}
//East neighbour
if(x+1 < size && !matrix[y][x + 1].vis){
neighbours.add(2);
}
//West neighbour
if(x-1 >= 0 && !matrix[y][x - 1].vis){
neighbours.add(3);
}
//checking, if there are any neighbours we can visit
//if yes, we do our job
//if not, we pop our stack and repeat the process
if(!neighbours.isEmpty()){
Random rand = new Random();
int randDir = neighbours.get(rand.nextInt(neighbours.size()));
switch (randDir) {
//North
case 0 -> {
matrix[y][x].walls[0] = false;
stack.push(new Pair<>(x, y - 1));
matrix[y - 1][x].value = 1;
matrix[y - 1][x].vis = true;
matrix[y - 1][x].walls[1] = false;
}
//South
case 1 -> {
matrix[y][x].walls[1] = false;
stack.push(new Pair<>(x, y + 1));
matrix[y + 1][x].value = 1;
matrix[y + 1][x].vis = true;
matrix[y + 1][x].walls[0] = false;
}
//East
case 2 -> {
matrix[y][x].walls[2] = false;
stack.push(new Pair<>(x + 1, y));
matrix[y][x + 1].value = 1;
matrix[y][x + 1].vis = true;
matrix[y][x + 1].walls[3] = false;
}
//West
case 3 -> {
matrix[y][x].walls[3] = false;
stack.push(new Pair<>(x - 1, y));
matrix[y][x - 1].value = 1;
matrix[y][x - 1].vis = true;
matrix[y][x - 1].walls[2] = false;
}
}
vis += 1;
}else{
stack.pop();
}
}
}
}
public class MazeAlgorithm {
public static void main(String[] args){
Maze m = new Maze(3);
m.RBT(1, 1);
m.showMaze();
}
so i just run the code again, and the error line changed to line 131, i am also watching some tutorial about the Intellij debugger rn.
EDIT: Problem resolved. Had to change lines:
int x = stack.firstElement().getKey();
int y = stack.firstElement().getValue();
into:
int x = stack.peek().getKey();
int y = stack.peek().getValue();
Turns out method .firstElement() doesn't give you first element (the one on top of the stack) but the one that was first inserted (always the same object) so in the end all the operation were performed on one, single element and not multiple ones.

if statement throws incompatible types: unexpected return value

I'm currently creating a minesweeper game, at the moment I'm just finishing up a method that counts neighboring mines, it also has parameters for the number of rows, columns and mines, I also declared a maxMines variable that doesn't allow more than 20 mines on the grid... Now, I want to make this method return true if the square was successfully mined, and false if the maximum number of mines was exceeded, or the square has already been mined.
Also I want this method to use the parameters to check whether a mine would be on those coordinates and I have no idea where to begin, if anyone can give me a starting point, it would be greatly appreciated.
Here is my code (The error lies at the very bottom of mineTile; if statement):
import java.util.Random;
public class Minefield extends Minesweeper{
boolean[][] minefield;
int[][] minedNeighbour;
Random random = new Random();//random number generator
int row;
int column;
int mines;
public int emptySpaces = column*row;
int maxMines = 20;
public Minefield(int row, int column, int mines) {
this.row = row;
this.column = column;
this.mines = mines;
int x,y;
minedNeighbour = new int[10][10];
//initializeMines(); //fill with zero's
//placeMines(); //get the random numbers and place 10 mines
//fillNoOfSurroundingNeighbours(); //based on the mines 8 boxes surronding the mine will be calculated and shown to the player
//startBoard(); //This fills the actual board
}
public void mineTile(int x, int y){
int i,j; //loop variables
if(minedNeighbour[x][y]!= -1)return; //already used
minedNeighbour[x][y] = 0;//square used
emptySpaces--;//decreases the emptyspaces counter
for (i = x-1 ;i<=x+1 ; i++)
{
for(j = y-1 ;j<=y+1 ; j++)
{
if(minedNeighbour[i][j] == 99)
{
minedNeighbour[x][y]++;
}
if(i >= 0 && j >= 0 && i < 5 && j < 5)
{
if(minedNeighbour[i][j] == 99)
{
minedNeighbour[x][y]++;
}
}
}
}
if(mines > maxMines)
{
return false;
}
else {
return true;
}
}
}
Your method is set to return a void, so that means you can't return anything. If you want to return a boolean, change your method header to reflect that, i.e. by changing it to
public boolean mineTile(int x, int y)

DFS Algorithm - 8-Puzzle or nXn-Game

I want to solve an DFS algorithm. It is about the game 8-puzzles or N x N puzzle. At the beginning i have two arrays like (the Zero represents an empty field):
int[][] start = {{0,1,2}, {4,5,3}, {7,8,6}};
int[][] target = {{1,2,3}, {1,5,6}, {7,8,0}};
This arrays goes into my generic DFS class, which works fine. I used it of other tasks correctly. But for the completeness here is the basic part of my DFS class:
private static boolean search(State node, State target) {
if (node.equals(target))
return true;
for (State neighbour : node.getNeighbours()) {
if (!visited.contains(neighbour)) {
predMap.put(neighbour,node);
visited.add(neighbour);
if (search(neighbour, target)){
return true;
}
}
}
return false;
}
So at first my start array will pass as the first parameter and my target array as the second.
In my Stateclass i want to implement the getNeighbours()method which should return all possibles states. In the first Round something like:
First:
|0|1|2|
|4|5|3|
|7|8|6|
Second (rotated zero):
|1|0|2|
|4|5|3|
|7|8|6|
etc...
And here is my problem. How can u do that? It works for the first 4 operations but then i get an exception (The zero or the empty field is not on the position as excepted or there are two zeros). What is wrong there?
#Override
public List<State> getNeighbours() {
List<State> neighbours = new LinkedList<>();
// possibles moves...
final int startX = (freeX - 1 < 0) ? freeX : freeX - 1;
final int startY = (freeY - 1 < 0) ? freeY : freeY - 1;
final int endX = (freeX + 1 > N - 1) ? freeX : freeX + 1;
final int endY = (freeY + 1 > N - 1) ? freeY : freeY + 1;
for (int row = startX; row <= endX; row++) {
for (int column = startY; column <= endY; column++) {
int tmp = board[row][column];
board[row][column] = board[freeX][freeY];
board[freeX][freeY] = tmp;
// Just show the table...
System.out.println("=== BEFORE ===");
for (int[] x : board) {
System.out.println(Arrays.toString(x));
}
neighbours.add(new State(board, freeX + row, freeY + column));
board[freeX][freeY] = board[row][column];
board[row][column] = tmp;
// Just show the table...
System.out.println("=== AFTER ===");
for (int[] x : board) {
System.out.println(Arrays.toString(x));
}
}
}
return neighbours;
}
complete code https://gist.github.com/T0bbes/66d36326aa8878d5961880ce370ba82d
I checked your code, the reason of get that exception is, the board array is shared by every state. You should make a deep copy of that array, and you can try this code:
public Board(int[][] board, int x, int y){
if (board[x][y]!=0)
throw new IllegalArgumentException("Field (" +x+","+y+") must be free (0).");
this.board = new int[board.length][board[0].length];
for (int i = 0; i < this.board.length; i++)
for (int j = 0; j < this.board[i].length; j++)
this.board[i][j] = board[i][j];
this.freeX = x;
this.freeY = y;
this.N = board.length;
}
But there are still some problems in your code:
DFS may recursion a lot and get a StackOverflow -- you should increase stack size(-Xss100m works for me). After increase stack size, your code can output a solution, but it takes 197144 steps...
Indeed, as you see, DFS output only a valid solution(if your code is correct), not optimal solution. You should try BFS.

write 0's and 1's on each line where the last 2 weren't the same

There's an error in the logic of what I've build at the moment.
What should be happening is that my code should display a grid of 0's and 1's.
Like so:
001001
101101
010110
110010
001101
So what has to happen here is that:
For each row there can't be more than 2 numbers of the same type consecutively
the numbers are picked randomly
for each column there can't be more than 2 numbers of the same type consecutively
there can be a maximum of 3 of each type of number going by column or row
edit: to further clarify
ok so I have a row like this:
0 1 0 1 1 0
- As you can see there will always be 3 x 1, and 3 x 0
- the order of numbers is picked randomly (so it might go 0 1, or 1 1, or 0 0 to start etc)
- there can never be more than 2 numbers of the same type consecutively, for instance if it's 001100, you can see that there were 2 0's, then it had to display a 1, but then there were 2 1's, so it had to display an 0. So 011100 couldn't happen (3 1's consecutively) or 000101 (3 0's consecutively)
Based upon this, but for now not essential, the same no 2 numbers consecutively must apply in columns (so in my successful example it goes 001001 across, there are at most 2 0's consecutively. But looking down you get 010101 (that is to say, once again, no more than 2 consecutively)
So my code is as follows:
import java.util.Random;
public class Main {
public static void main(String[] args) {
int l = 6;
int w = 6;
Random rd = new Random();
// Create a grid that is 6 x 6
int[][] grid = new int[l][w];
// for each row
for (int i = 0; i < l; i++) {
int zCount = 0;
int oCount = 0;
int current;
int lastA = 2;
int lastB = 2;
// for each item in the row
for (int j = 0; j < w; j++) {
// set the current item to either 0 or 1
current = rd.nextInt(2);
// make sure there aren't already (e.g. 3 items out of 6)
// items in the row
if (j % 2 == 1) {
// hold every second element
lastA = current;
} else {
// hold every first element
lastB = current;
}
if (current == 1) {
if (oCount != 3) {
if (lastA != lastB) {
// if the two previous items aren't the same
grid[i][j] = current;
// add to the counter
oCount++;
}
}
}
if (current == 0) {
if (zCount != 3) {
if (lastA != lastB) {
// if the two previous items aren't the same
grid[i][j] = current;
// add to the counter
zCount++;
}
}
}
System.out.print(grid[i][j]);
}
System.out.println(" ");
}
}
}
The problem is it generates as follows:
010010
100001
100010
000010
100001
001000
So obviously it doesn't conform to the first, third or fourth points.
I have absolutely no idea why! Except for the columns (third point) which I haven't initialised.
Can anybody work out what the logical failure is in my code?
Thanks for your help!
Here is my procedural solution which tries to keep the amount of required code as small as possible. It is capable of computing 2D-Arrays with arbitrary rows and columns like [6, 6] or [4, 7] or [3, 8] for example. The complexity of the algorithm is O(n) with n = rows * columns.
The program computes an arbitrary 2D-Array (grid) populated with either a 0 or 1. The grid guarantees the following characteristics, formulated mathematically:
∀ r,c ∈ Integer | 0 ≤ r < grid.rows, 0 ≤ c < grid.columns :
r - 2 ≥ 0 ⇒ cardinality( distinct( grid[r][c], grid[r-1][c], grid[r-2][c] )) = 2
r + 2 < grid.rows ⇒ cardinality( distinct( grid[r][c], grid[r+1][c], grid[r+2][c] )) = 2
c - 2 ≥ 0 ⇒ cardinality( distinct( grid[r][c], grid[r][c-1], grid[r][c-2] )) = 2
c + 2 < grid.columns ⇒ cardinality( distinct( grid[r][c], grid[r][c+1], grid[r][c+2] )) = 2
or in other words:
the grid does neither contain a row nor a column which has three or more consecutive 0's or 1's.
Below the Java code I will explain how the algorithm works and why it is designed as it is:
public static void main(String[] args) {
int[][] grid = anyGrid(8, 13);
}
private static int[][] anyGrid(int rows, int cols) {
int[][] grid = new int[rows][cols];
int row = 0;
for (int col = 0; col - row < cols; col++) {
for (int r = row; r >= 0 && col - r < cols;) {
setBit(grid, r, col - r--);
}
if (row < rows - 1) row++;
}
return grid;
}
private static void setBit(int[][] grid, int row, int col) {
int vInd = calcVerticalIndicator(grid, row, col);
int hInd = calcHorizontalIndicator(grid, row, col);
if (isPartiallyRestricted(vInd, hInd)) {
grid[row][col] = flip(vInd);
} else if (isFullyRestricted(vInd, hInd)) {
grid[row][col] = vInd;
grid[row - 1][col] = flip(vInd);
} else {
grid[row][col] = Math.abs(vInd) <= 1
? flip(vInd)
: Math.abs(hInd) <= 1 ? flip(hInd) : anyBit();
}
}
private static boolean isPartiallyRestricted(int vInd, int hInd) {
return vInd == hInd;
}
private static boolean isFullyRestricted(int vInd, int hInd) {
return vInd + hInd == 1;
}
private static int calcVerticalIndicator(int[][] grid, int row, int col) {
return calcIndicator(grid, row - 1, col, row - 2, col, 2);
}
private static int calcHorizontalIndicator(int[][] grid, int row, int col) {
return calcIndicator(grid, row, col - 1, row, col - 2, 4);
}
private static int calcIndicator(int[][] grid, int row1, int col1, int row2, int col2, int unrestricted) {
try {
return grid[row1][col1] * grid[row2][col2] + (grid[row1][col1] - grid[row2][col2]) * unrestricted;
} catch (IndexOutOfBoundsException e) {
return unrestricted;
}
}
private static int anyBit() {
return (int) (Math.random() * 2);
}
private static int flip(int bit) {
return bit == 0 ? 1 : 0;
}
The challenge we face is not to ensure that there are no three consecutive 0's or 1's in a row only or in a column only. The challenge is to ensure that no three consecutive 0's or 1's are neither in a row nor in a column by providing an efficient algorithm.
The tricky situation we may run into looks like this:
Let's consider the situation where all the cells at the top and to the left of the cell outlined in blue are already populated and do not violate the rules define above.
picture a) we want to populate the cell having a blue outline. The two cells at it's top are populated with two 0's while the cells at it's left are populated with two 1's. Which value should we choose? Due to symmetry it doesn't matter if we choose a 0 or a 1. Hence, let's go with a 0.
picture b) populating the cell outlined in blue with a 0 violates one rule defined above: the grid does not contain a column with three or more consecutive 0's or 1's. Hence we have to change the value of one of the two cells above of the blue cell.
picture c) say we change the value of the cell which is immediately above the blue cell, from 0 to 1. This could result in the violation of some rules, caused by the already populated cells to the left of the modified cell.
picture d) but a violation would mean that both cells to the left must have a value of 1.
picture e) this would imply that both cells to their top must have a value of 0 which is a contradiction to a situation we assumed. Therefore, changing the cell immediately at the top of the cell outlined in blue will not cause any violation of the rules.
To address the precondition, that no cells to the right of the modified cell are already populated, the algorithm populates the grid in a diagonal way. The population of cells occur in the order as shown below:
The final thing I like to explain is how the algorithm decides which values are available to choose from for each cell. For each cell it inspects the two top-most and two left-most cells and calculates an indication value. This value is used to determine the possible values for a cell by using arithmetic calculation as follows:
if the two cells inspected are both populated with 0's return an indicator value of 0.
if the two cells inspected are both populated with 1's return an indicator value of 1.
I have selected those two values because they communicate the fact, that this values are not permitted, in an intuitive way.
Then I selected a function to communicate if both, the column cells and the row cells, restrict the cell to populate by the same value. This is the case if both indicator values are equal. Keep this characteristic in mind, because we have to find values for the situation when no restriction applies from the column cells or the row cells.
If both indicators restrict the value to populate the cell with by a different value, the sum of them is 1. This is the second characteristic we have to keep in mind when searching for proper indicator values when no restriction applies.
The last thing the algorithm has to achieve is to find proper values when no restriction applies without compromising the unique indicators defined above.
Preserving the indication when the cell is restricted by the same value can be achieved by selecting values for the row and column indicators which are different from 0 and 1 and different from each other.
Preserving the indication when the cell is restricted by both values can be achieved by selecting values being greater than 1 and having a delta to each other of at least 2.
The algorithm does indicate no restriction for a row by the values 2 and -2 and for a column by the values 4 and -4. This values do not conflict with the operations used to identify the other two cases.
I hope this documentation helps to understand the whole program and how it does solve the problem statement. I am glad to hear your comments.
Many of the solutions given are extremely long and complicated. Here's a solution with very minimal code (Ideone Example here):
int row, col, n = 8;
int[][] grid = new int[n][n], cCount = new int[n][2], rCount = new int[n][2];
Deque<Entry<Integer,Integer>> freeInd = new ArrayDeque<Entry<Integer,Integer>>();
Random rand=new Random();
for(int i = 0; i < grid.length; i++){
for(int j = 0; j < grid[0].length; j++){
// Calcualte constraints: row, col = {-1, 0, 1}, -1 => no constraint.
row = j > 1 && grid[i][j-2] == grid[i][j-1] ? (grid[i][j-1] == 0 ? 1:0):
(rCount[i][0] >= n/2 ? 1: // too many 0's
(rCount[i][1] >= n/2 ? 0:-1)); // too many 1's
col = i > 1 && grid[i-2][j] == grid[i-1][j] ? (grid[i-1][j] == 0 ? 1:0):
(cCount[j][0] >= n/2 ? 1: // too many 0's
(cCount[j][1] >= n/2 ? 0:-1)); // too many 1's
grid[i][j] = row == -1 && col == -1 ? rand.nextInt(2):(row > -1 ? row:col);
// Handle Constraints
if( row == -1 && col == -1){ // no constraint
freeInd.push(new SimpleEntry<Integer,Integer>(i, j)); // add to free indices
} else if( (row > -1 && col > -1 && row != col) // constraint conflict
|| (row > -1 && rCount[i][row] >= n/2) // count conflict
|| (col > -1 && cCount[j][col] >= n/2)){ // count conflict
Entry<Integer, Integer> last = freeInd.pop(); // grab last free index
while(i > last.getKey() || j > last.getValue()){
j = (j-1+ n)%n; // step indices back
i = (j == n-1) ? i-1:i;
rCount[i][grid[i][j]]--; // reduce counters
cCount[j][grid[i][j]]--;
}
grid[i][j] = grid[i][j] == 0 ? 1:0; // flip value
}
rCount[i][grid[i][j]]++; // increment counters
cCount[j][grid[i][j]]++;
}
}
The idea here is that you walk along each row of the matrix adding 0's and 1's abiding by the following rules:
If the current index is unconstrained (i.e. it can be 0 or 1) we choose a value randomly.
If the current index is constrained we force it to have the constrained value.
If there are multiple constraints that do not agree, we revert back to the last unconstrained index (freeInd) by first incrementally stepping backwards along the rows of the matrix, decrementing the count for the given value (0 or 1). E.g. this is done for rows with rCount[i][grid[i][j]]--. When the unconstrained vertex is finally reached, flip it's value.
Finally, increment the count of the value (0 or 1) for the current row and column. E.g. this is done for rows with rCount[i][grid[i][j]]++
The 1st problem which i found in your solution is it's initializing the value of counter value (ocount and zcount) as zero and the only way grid(array) is assigned a value is when if it's greater than three, and the way i see if i am not mistaken the value of counter is incremented in the loop in which they are checked to be greater than 3, and that condition can never be reached .
To solve this problem use the algo of backtracking by assigning the new value to a different value if the calue
A working code in jsFiddle (for 6x6 grids):
$(function(){
function print(str){
$("body").append(str + "<br/>");
}
function toBin(num, length){
if(!length){
length = 3;
}
var str = num.toString(2);
while(str.length < length){
str = 0 + str;
}
return str;
}
var wrongAnds = [
parseInt('000000111', 2),
parseInt('000111000', 2),
parseInt('111000000', 2),
parseInt('100100100', 2),
parseInt('010010010', 2),
parseInt('001001001', 2),
];
var wrongOrs = [
parseInt('111111000', 2),
parseInt('111000111', 2),
parseInt('000111111', 2),
parseInt('011011011', 2),
parseInt('101101101', 2),
parseInt('110110110', 2),
];
function test(mask){
for (var i = 0; i < 6; i++) {
if((wrongAnds[i] & mask) == wrongAnds[i]){
return false;
}
if((wrongOrs[i] | mask) == wrongOrs[i]){
return false;
}
}
return true;
}
var threeGrid = [];
var toRight = [];
var toBottom = [];
for(var mask = 1<<9-1; mask >= 0; mask--){
if(test(mask)){
threeGrid.push(mask);
}
}
function numberOfSetBits(i)
{
i = i - ((i >> 1) & 0x55555555);
i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
}
function getCol(grid, col){
var ret = 0;
for(var i=0; i<3; i++){
ret += (grid & (1 << (i*3+col))) >> (i*2+col);
}
return ret;
}
var wrongAnds6 = [
parseInt('011100', 2),
parseInt('001110', 2)
];
var wrongOrs6 = [
parseInt('100011', 2),
parseInt('110001', 2)
];
for(var i = 0; i < threeGrid.length; i++){
for(var j = 0; j < threeGrid.length; j++){
var grid1 = threeGrid[i];
var grid2 = threeGrid[j];
var toRightOk = true;
var toBottomOk = true;
var printit = (i==0);
for(var k=0;k<3;k++){
var row = ((grid1 & wrongAnds[k]) << 3 >> (k*3)) + ((grid2 & wrongAnds[k]) >> (k*3));
var col = ((getCol(grid1, k)) << 3) + ((getCol(grid2, k)));
if(numberOfSetBits(row) != 3
|| ((wrongAnds6[0] & row) == wrongAnds6[0])
|| ((wrongAnds6[1] & row) == wrongAnds6[1])
|| ((wrongOrs6[0] | row) == wrongOrs6[0])
|| ((wrongOrs6[1] | row) == wrongOrs6[1])
) {
toRightOk = false;
}
if(numberOfSetBits(col) != 3
|| ((wrongAnds6[0] & col) == wrongAnds6[0])
|| ((wrongAnds6[1] & col) == wrongAnds6[1])
|| ((wrongOrs6[0] | col) == wrongOrs6[0])
|| ((wrongOrs6[1] | col) == wrongOrs6[1])
) {
toBottomOk = false;
}
}
if(toRightOk){
if(!toRight[grid1]){
toRight[grid1] = [];
}
toRight[grid1].push(grid2);
}
if(toBottomOk){
if(!toBottom[grid1]){
toBottom[grid1] = [];
}
toBottom[grid1].push(grid2);
}
}
}
function intersect(arr1, arr2){
var results = [];
for (var i = 0; i < arr1.length; i++) {
if (arr2.indexOf(arr1[i]) !== -1) {
results.push(arr1[i]);
}
}
return results;
}
var found = false;
while(!found){
var grid1 = threeGrid[0];
var grid1 = threeGrid[Math.floor(Math.random()*threeGrid.length)];
var grid2 = toRight[grid1][Math.floor(Math.random()*toRight[grid1].length)];
var grid3 = toBottom[grid1][Math.floor(Math.random()*toBottom[grid1].length)];
var arr4 = intersect(toBottom[grid2], toRight[grid3]);
if(arr4.length > 0){
var grid4 = arr4[Math.floor(Math.random()*arr4.length)];
found = true;
}
}
function gridToStrings(grid){
var rowS = [];
for(var i=0; i<3; i++){
rowS.push(toBin(((grid & wrongAnds[i]) >> (i*3))));
}
return rowS;
}
var grid1S = gridToStrings(grid1);
var grid2S = gridToStrings(grid2);
var grid3S = gridToStrings(grid3);
var grid4S = gridToStrings(grid4);
print(grid1S[0] + grid2S[0]);
print(grid1S[1] + grid2S[1]);
print(grid1S[2] + grid2S[2]);
print(grid3S[0] + grid4S[0]);
print(grid3S[1] + grid4S[1]);
print(grid3S[2] + grid4S[2]);
});
Theory:
Find all possible 3x3 grids
Find all possible left-to-right and top-to-bottom pairings
get 4 random grids to form the 6x6 grid
Implementation:
Represent 3x3 grids as 9bit integers. A 3x3 grid is wrong if there are 3 1s or 3 0s in it. This can be easily filtered with a couple bitwise operations.
Test the Cartesian product of these 3x3 grids (Compare every grid with every grid). Check if there are exactly 3 0s and 3 1s in all rows and columns (put the second grid right to the first grid to check 3 rows, and put it below the first grid to check 3 columns), and that there are no consecutive 3 0s or 1s.
get the top-left, top-right and bottom-right grids. Check if there is an available 4th grid that can go below the top-right grid and right to the bottom-left grid. If there is none, restart step 4, otherwise pick one.
A couple outputs:
011010
100101
001011
110100
101100
010011
110010
101100
010011
001101
100110
011001
001101
110010
010011
101100
110100
001011
Edit:
there is only 1120 solutions to this problem (jsFiddle). There are 2^36 ways to fill a 6x6 grid with 0s and 1s. If you used brute force (get a random 6x6 grid, then check if its right), that would mean an average ~61356676 (6.1*10^7) executions to find a correct solution. Even thought your method is somewhat faster (it can fail sooner if its not the last digit thats wrong), it might still be slow.
I think there are two problems with your code:
If oCount or zCount have become 3 there are no more assignments grid[i][j]=current if the random value is not acceptable. You get zeroes at these positions (to which the grid was initialized).
Near the right bottom there might not be any more valid solutions. You would have to undo previous assignments, i.e. you would need to do some kind of backtracking.
I would recommend starting with a valid solution and transforming this solution step by step according to random values for grid positions - but only if this is possible without breaking validity. If have prepared an example implementation:
public static void main(String[] args) {
int l = 6, w = 6;
Grid g = new Grid(l, w);
Random rd = new Random();
// initialize with checkerboard pattern (which is a valid solution)
for (int y = 0; y < l; y++) for (int x = 0; x < w; x++) g.arr[y][x] = (x ^ y) & 1;
// construct a valid grid by transformation of grids while preserving validity
for (int y = 0; y < l; y++) for (int x = 0; x < w; x++) {
int v = rd.nextInt(2), v2 = v ^ 1;
if (g.arr[y][x] == v) continue;
// try to modify current grid by exchanging values: 01/10=>10/01 or 10/01=>01/10
// (keep parts of the grid which have already been adapted to random values)
rotating: for (int y2 = y + 1; y2 < l; y2++) for (int x2 = x; x2 < w; x2++) {
if (g.arr[y2][x] == v && g.arr[y][x2] == v && g.arr[y2][x2] == v2) {
g.rotate(x, y, x2, y2);
// keep result if grid is still valid, undo otherwise
if (g.rotatedOk(x, y, x2, y2)) break rotating;
g.rotate(x, y, x2, y2);
}
}
}
g.printOn(System.out);
}
public static class Grid {
int l, w;
int[][] arr;
Grid(int l, int w) {
this.arr = new int[this.l = l][this.w = w];
}
void rotate(int x, int y, int x2, int y2) {
int v;
v = arr[y][x]; arr[y][x] = arr[y2][x]; arr[y2][x] = v;
v = arr[y][x2]; arr[y][x2] = arr[y2][x2]; arr[y2][x2] = v;
}
boolean rotatedOk(int x, int y, int x2, int y2) { // check after rotation
return okAt(x, y) && okAt(x2, y) && okAt(x, y2) && okAt(x2, y2);
}
private boolean okAt(int x, int y) { // check single position in grid
int v = arr[y][x];
if (count(x, y, -1, 0, v) + count(x, y, 1, 0, v) > 1) return false;
if (count(x, y, 0, -1, v) + count(x, y, 0, 1, v) > 1) return false;
return true;
}
private int count(int x, int y, int dx, int dy, int v) {
for (int n = 0; ; n++) {
x += dx; y += dy;
if (x < 0 || x >= w || y < 0 || y >= l || arr[y][x] != v) return n;
}
}
void printOn(PrintStream s) {
for (int y = 0; y < l; y++) { for (int x = 0; x < w; x++) s.print(arr[y][x]); s.println(); }
}
}
The problem with your approach is that you need a mechanism that handles when a new value can't be used because it follows two similar values, but the other value can't be used because it is under two other values. For example, say your grid has got this far:
101010
011010
00?
You would then need to slowly roll back positions and try different values.
The following code solves that problem using recursion:
import java.util.Random;
public class Main {
final int height = 6;
final int width = 6;
int[][] grid;
Random rd = new Random();
public static void main(final String[] args) {
Main main = new Main();
main.process();
}
private void process() {
// Create a grid that is 6 x 6
grid = new int[height][width];
for(int x = 0; x < width; x++) {
for(int y = 0; y < height; y++) {
grid[x][y] = -1;
}
}
recurseFillMatrix(0, 0);
}
private boolean recurseFillMatrix(final int x, final int y) {
// first, try putting a random number in the cell
int attempt = 1;
grid[x][y] = Math.abs(rd.nextInt()%2);
do {
if(isGridValid()) {
if(x == (width - 1) && y == (height - 1)) {
printGrid();
return true;
}
boolean problemSolved;
if(x == (width - 1)) {
problemSolved = recurseFillMatrix(0, y + 1);
} else {
problemSolved = recurseFillMatrix(x + 1, y);
}
if(problemSolved) {
return true;
}
}
attempt++;
grid[x][y] = 1 - grid[x][y];
} while(attempt <= 2);
grid[x][y] = -1;
return false;
}
private boolean isGridValid() {
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
// if the current item is -1, then we are finished
if(grid[x][y] == -1) {
return true;
}
// if we are after the second column
if(x > 1) {
if(grid[x-2][y] == grid[x-1][y] && grid[x-1][y] == grid[x][y]) {
return false;
}
}
// if we are after the second row
if(y > 1) {
if(grid[x][y-2] == grid[x][y-1] && grid[x][y-1] == grid[x][y]) {
return false;
}
}
// total the values in this column
int total = 0;
for(int i = 0; i <= y; i++) {
total += grid[x][i];
}
if(y == (height - 1)) {
if(total != 3) {
return false;
}
} else {
if(total > 3) {
return false;
}
}
// total the values in this row
total = 0;
for(int i = 0; i <= x; i++) {
total += grid[i][y];
}
if(x == (width - 1)) {
if(total != 3) {
return false;
}
} else {
if(total > 3) {
return false;
}
}
}
}
return true;
}
private void printGrid() {
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
System.out.print(grid[x][y]);
}
System.out.println("");
}
}
}
The isGridValid() method uses your defined rules to check if the grid (as it is filled so far) complies with the rules. At the first sign that it does not, it returns false.
If I have to change your solution to achieve the result, here is what it should look like..
Take the incrementors for oCount and zCount in a separate if-else
Take the assignment to grid(i,j) outside the loop
Your if-else block is not taking into account every condition possible, like
What about when last 2 items are same
What about when the zCount or oCount has reached 3
Taking into account these consideration, this code works fine.
import java.util.Random;
public class Main {
public static void main(String[] args) {
int l = 6;
int w = 6;
Random rd = new Random();
// Create a grid that is 6 x 6
int[][] grid = new int[l][w];
// for each row
for (int i = 0; i < l; i++) {
int zCount = 0;
int oCount = 0;
int current;
int lastA = 2;
int lastB = 2;
// for each item in the row
for (int j = 0; j < w; j++) {
// set the current item to either 0 or 1
current = rd.nextInt(2);
// make sure there aren't already (e.g. 3 items out of 6)
// items in the row
if (current == 1) {
if (oCount != 3) {
if (lastA == lastB) {
current = lastA == 1 ? 0 : 1;
}
} else {
current = current == 1 ? 0 : 1;
}
} else if (current == 0) {
if (zCount != 3) {
if (lastA == lastB) {
current = lastA == 1 ? 0 : 1;
}
} else {
current = current == 1 ? 0 : 1;
}
}
grid[i][j] = current;
if (current == 1) {
oCount++;
} else {
zCount++;
}
if (j % 2 == 1) {
// hold every second element
lastA = current;
} else {
// hold every first element
lastB = current;
}
System.out.print(grid[i][j]);
}
System.out.println(" ");
}
}
}
Again, This solution takes care of row conditions only. You would need to do similar checks for columns as well, to achieve the full result
HTH
here I tested you problem and seems that it is what you need.
I used a functional approach using Guava, it is quite simple, readable and has a short code.
#Test
public void test_permutations()
{
List<Integer> binary = Lists.newArrayList(1,0,1,0,1,0); // Domain list
Set<String> flattenSet = Sets.newHashSet(); // Store non-repetitive values
// Create list of possible values
Collection<List<Integer>> permutations = Collections2.permutations(binary);
for (List<Integer> permutation : permutations)
{
String joinString = StringUtils.join(permutation, "");
flattenSet.add(joinString);
}
// Create predicate to filter positive values
Predicate<String> predicate = new Predicate<String>() {
public boolean apply(String input) {
// Discard wrong values
if (input.contains("000") || input.contains("111")) {
return false;
} else {
return true;
}
}
};
// Use predicate to filter values
Collection<String> filteredList = Collections2.filter(flattenSet, predicate);
// Display result
for (String result : filteredList) {
System.out.println(result);
}
}
It is simple, I've commented the code to be clear but you can debug it to understand step by step.
The generated output is:
010011
110010
010101
010110
100110
101001
011010
110100
001011
001101
011001
101010
101100
100101
Hope to help
I think that its a mistake to think of generating it one element at at time. Instead imagine that I generate the entire set of permissible rows {001100,101010,....etc} There are only 6!/(3!3!)=20 ways to arrange three ones and three and some of them will be excluded. Now I am going to generate a game tree by saying that a move is selecting a valid row for the next row. If I discover at some point that there are no more valid moves then i will back track and try a different move.
To generate a move I randomly select a row, if its a valid move, I try to select another move, if that is impossible I backtrack, effectively doing a (random) depth first search of the game tree.
public class gametree {
public static ImmutableList<Row> allValidRows = // create a list of all valid rows.
public static List<Rows> getValidMoves(Move parent){ //Backtracks up the
//tree to the root to find the current state of the board, and returns
//which ever of allValidRows are valid given the game board.
}
public class Move {
public final Move parent;
public List<Rows> validMoves;
public final Row thisMove;
public int depth=0;
Move(Move parent, Row thisMove){
this.thisMove = thisMove;
this.parent = parent;
this.validMoves = getValidMoves(parent);
Move hold=parent;
while(hold!=null){
depth++; hold = parent.parent;
}
}
}
void run {
//pick first move
Move Root = new Move(null, Collections.Shuffle(allValidRows).get(0));
Move FinalMove = search(Root);
//Something to print out the answer here
}
public Move search(Move move){
if(depth==5){ return Move} //If I get to row six I win.
else if(move.validMoves.isEmpty()) { //If there are no valid moves,
//then this move wasnt valid, to strip it from the parent's
//possible moves and try again
move.parent.validMoves.remove(move.thisMove);
search(move.parent);
} else { //pick a random valid move and create a nextMove
Move nextMove = new Move(move, Collection.Shuffle(move.getValidMoves).get(0))
search(nextMove);
}
}
The worst case for this algorithm is that there is only one victory state and it has to try every possible state, but in practice this game does not seem very restrictive so it will probably not take long at all.
This code is strictly illustrative.

Can't figure out how to make method recursive

For my programming course I have to write recursive functions, but aside from the theoretical questions given during the classes I can't figure out how to do it with my own code.
If anyone could help me out and give me a pointer on where to start it'd be great!
The method is as follows:
public boolean hasColumn(Marble m) {
boolean hasColumn = false;
for (int i = 0; i < DIM && hasColumn == false; i++) {
int winCount = 0;
for (int j = 0; j < DIM && hasColumn == false; j++) {
if (j == 0) {
winCount = 1;
} else {
if (getField(j, i).equals(getField(j - 1, i))
&& getField(j, i).equals(m)) {
winCount++;
if (winCount == WINLENGTH) {
hasColumn = true;
}
} else {
winCount = 1;
}
}
if (!(getField(j, i).equals(m))) {
hasColumn = false;
}
}
}
return hasColumn;
}
There's a field[DIM][DIM], which stores Marbles. Marble has a Mark, which is 0-4, with 0 being empty and 1-4 being colour values. The method determines whether someone has a marble column of 5 and wins.
Input is the Marble type of a player. Output is boolean hasColumn true or false. The output value is correct, there's just no recursion.
The idea is to make it find a vertical column in a recursive way. This also has to be done with horizontal/vertical, but I figured when I get this figured out I'll manage those by myself.
Thank you in advance!
public boolean hasColumn(Marble m, int i, int j, int wincount) {
if (wincount == WINLENGTH)
return true;
if (i == DIM)
return false;
if (j == DIM)
return hasColumn(m, i + 1, 0, 0);
return hasColumn(m, i, j + 1, getField(j, i).equals(m) ? wincount + 1 : 0);
}
Depending on whether you'd like to find a line/column of elements equal to a given Marble element or rather of same value, you may call this method:
hasColumn(aMarble, 0, 0, 0);
hasColumn(getField(0, 0), 0, 0, 0);
There's a duality between certain types of recursion and iteration.
Consider that in your iterative function you are iteratinng over columns using two variables, i and j. Could you transform those local variables into parameters to the function? You would be transforming state internal to the function (local variables) into state implicit in the function call.
Looks like task sounds like:
1. We have a square matrix of Marble elements(it can be simple integers) with dimension DIM.
2. We have a method getField(int, int) return a marble from this matrix
3. We have an iterative decision to discover if this matrix has any column with equal values of marble elements
Our goal is write recursive variant of this method
So, look here. Recursive algorithm check ROW existing with same value:
public class Marble {
public static final int DIM = 10;
public int[][] marbleAr = new int[DIM][DIM];
public void init(){
for(int i=0;i<DIM;i++){
for(int j=0;j<DIM;j++){
marbleAr[i][j] = new Random().nextInt(10);
if(i == 2){
marbleAr[i][j] = 7;
}
}
}
}
public int get(int i, int j){
return marbleAr[i][j];
}
public void printMarbleAr(){
for(int i=0;i<DIM;i++){
for(int j=0;j<DIM;j++){
System.out.print(marbleAr[i][j] + " ");
}
System.out.println();
}
}
public boolean hasColumn(int val, int col, int row){
if(row == 0){
return true;
}
if(this.hasColumn(val, col, row-1)){
if(this.get(col, row) == this.get(col,row-1)){
return true;
}else{
if(col == DIM-1){
return false;
}
return this.hasColumn(val, col+1, row);
}
}
return false;
}
public static void main(String[] args) {
int v = 7;
Marble marble = new Marble();
marble.init();
marble.printMarbleAr();
System.out.println(marble.hasColumn(v, 0, DIM-1));
}
}
Your method name is hasColumn and return variable
name is hasColumn. That's BAD.
I don't see hasColumn invoked inside the method again to actually
go down to recursion path.

Categories