Вопрос

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!

Это было полезно?

Решение 2

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:

  1. If the current index is unconstrained (i.e. it can be 0 or 1) we choose a value randomly.
  2. If the current index is constrained we force it to have the constrained value.
  3. 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.
  4. 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]]++

Другие советы

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:

conflicting situation

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:

population order

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.

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:

  1. Find all possible 3x3 grids
  2. Find all possible left-to-right and top-to-bottom pairings
  3. get 4 random grids to form the 6x6 grid

Implementation:

  1. 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.
  2. 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.
  3. 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..

  1. Take the incrementors for oCount and zCount in a separate if-else
  2. Take the assignment to grid(i,j) outside the loop
  3. Your if-else block is not taking into account every condition possible, like
    1. What about when last 2 items are same
    2. 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.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top