我想创建一个程序,创建一个零和一个零的网格,没有三个连续(一个或零,垂直和水平)。程序应该在每次调用时生成网格的随机排列。程序应该每行和每列产生等量的1和0(例如:12x12 - 6个零和6个)。我已经准备了一个二维整数数组,其中将存储零和1。我还准备了一个随机数发生器。我的问题是我不知道从哪里开始,如何在没有连续的情况下这样做?
以下是我到目前为止所做的示例程序:
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
import javax.swing.border.*;
import java.util.*;
public class
SampleGrid
{
int noOfTiles = 0;
int status [][] = new int [12][12];
Container contentPane;
JFrame frame = new JFrame ();
JPanel pnlCenter = new JPanel ();
JPanel pnlGrid = new JPanel ();
JPanel pnlArray [][] = new JPanel [12][12];
JPanel pnlButton = new JPanel (new GridLayout (1, 2));
JButton btnArray [][] = new JButton [12][12];
JButton btnNewGame = new JButton ("New Game");
JButton btnRestart = new JButton ("Restart");
/**
* Constructors
*/
/* Default Constructors */
public
SampleGrid ()
{
}
public
SampleGrid (int noOfTiles)
{
this.noOfTiles = noOfTiles;
this.status = new int [noOfTiles][noOfTiles];
this.pnlGrid.setLayout (new GridLayout (noOfTiles, noOfTiles));
this.pnlArray = new JPanel [noOfTiles][noOfTiles];
this.btnArray = new JButton [noOfTiles][noOfTiles];
}
public void
launchFrame ()
{
Random rand = new Random ();
int oneCounter = 0;
int zeroCounter = 0;
int first = rand.nextInt (2 - 1 + 1) + 1;
int even = rand.nextInt (2 - 1 + 1) + 1;
int counter = 0;
int pointer = 0;
boolean isFirst = true;
contentPane = frame.getContentPane ();
for (int count = 0; count < noOfTiles; count++) {
for (int count2 = 0; count2 < noOfTiles; count2++) {
int random = rand.nextInt (2 - 1 + 1) + 1;
pointer = (count + 1) * (count2 + 2);
pnlArray [count][count2] = new JPanel ();
btnArray [count][count2] = new JButton ();
pnlArray [count][count2].add (btnArray [count][count2]);
pnlArray [count][count2].setBorder (BorderFactory.createEtchedBorder (EtchedBorder.RAISED, Color.BLACK, Color.BLACK));
// Generate the first Row
if (count != 0) {
isFirst = false;
}
try {
if (isFirst) {
if (random == 2) {
if (oneCounter != 3) {
if (count2 != 0 || count2 != 1) {
if (status [count][count2 - 1] != 2 && status [count][count2 - 2] != 2) {
btnArray [count][count2].setText ("1");
status [count][count2] = 1;
oneCounter++;
} else {
btnArray [count][count2].setText ("0");
status [count][count2] = 0;
zeroCounter++;
}
} else {
btnArray [count][count2].setText ("1");
status [count][count2] = 1;
oneCounter++;
}
} else {
if (count2 != 0 || count2 != 1) {
if (status [count][count2 - 1] != 2 && status [count][count2 - 2] != 2) {
btnArray [count][count2].setText ("0");
status [count][count2] = 0;
zeroCounter++;
} else {
btnArray [count][count2].setText ("1");
status [count][count2] = 1;
oneCounter++;
}
} else {
btnArray [count][count2].setText ("0");
status [count][count2] = 0;
zeroCounter++;
}
}
} else {
if (zeroCounter != 3) {
if (count2 != 0 || count2 != 1) {
if (status [count][count2 - 1] != 2 && status [count][count2 - 2] != 2) {
btnArray [count][count2].setText ("0");
status [count][count2] = 0;
zeroCounter++;
} else {
btnArray [count][count2].setText ("1");
status [count][count2] = 1;
oneCounter++;
}
} else {
btnArray [count][count2].setText ("0");
status [count][count2] = 0;
zeroCounter++;
}
} else {
if (count2 != 0 || count2 != 1) {
if (status [count][count2 - 1] != 2 && status [count][count2 - 2] != 2) {
btnArray [count][count2].setText ("1");
status [count][count2] = 1;
oneCounter++;
} else {
btnArray [count][count2].setText ("0");
status [count][count2] = 0;
zeroCounter++;
}
} else {
btnArray [count][count2].setText ("1");
status [count][count2] = 1;
oneCounter++;
}
}
}
isFirst = false;
}
} catch (ArrayIndexOutOfBoundsException aiobe) {
System.out.println (aiobe);
}
btnArray [count][count2].setOpaque(false);
btnArray [count][count2].setContentAreaFilled(false);
btnArray [count][count2].setBorderPainted(false);
pnlGrid.add (pnlArray [count][count2]);
}
zeroCounter = 0;
oneCounter = 0;
}
pnlButton.add (btnNewGame);
pnlButton.add (btnRestart);
pnlCenter.add (pnlGrid, BorderLayout.CENTER);
contentPane.add (pnlCenter, BorderLayout.CENTER);
contentPane.add (pnlButton, BorderLayout.SOUTH);
if (noOfTiles == 6) {
frame.setSize (500, 525);
} else if (noOfTiles == 8) {
frame.setSize (650, 650);
} else {
frame.setSize (975, 975);
}
frame.setLocationRelativeTo (null);
frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
frame.setVisible (true);
}
public static void main (String args []) {
System.out.println ("Enter the number of Tiles (6 / 8 / 10): ");
Scanner scan = new Scanner (System.in);
int N = scan.nextInt ();
SampleGrid grid = new SampleGrid (N);
grid.launchFrame ();
}
}
提前致谢!
答案 0 :(得分:0)
作为一个评论:没有任何令人费解的事情(在纸面上,在思想中)。
首先在没有GUI的情况下进行纯数据。
int[] generateLineHalf1sNo111(int n, Random rand) {
int[] line = new int[n]; // All 0.
int onesNeeded = n / 2;
int consecutiveOnes = 0;
for (int i = 0; i < n && onesNeeded > 0; ++i) {
// Because of past filling:
boolean mustBe0 = consecutiveOnes == 2;
// Because of following free space
// To be at most filled two third: 110110
boolean mustBe1 = n - i - onesNeeded / 3 < onesNeeded;
assert !mustBe0 || !mustBe1;
// Can always fill up with 011 011 011...
int picked;
if (mustBe0) {
picked = 0;
} else if (mustBe1) {
picked = 1;
} else {
picked = rand.nextInt(2);
}
if (picked == 0) {
consecutiveOnes = 0;
} else if (picked == 1) {
++consecutiveOnes;
line[i] = 1;
--onesNeeded;
}
}
return line;
}
n - i - onesNeeded / 3
是可供其使用的空间。
这里的问题是,除了填写随机的1和0之外, future 填写必须足以解决问题。
顺便说一下,我没试过。
答案 1 :(得分:0)
这是一个次优解决方案,在填充网格时使用回溯,以便满足两个约束:最多两个连续的单元格在水平和垂直方向上都应该具有相同的值,并且0和1的数量必须是在每一行和每一列都是一样的。
/**
* Creates a m * n-grid where each entry is either 0 or 1,
* each row contains the same amount of 1's and 0's and where no
* three consecutive cells in horizontal or vertical direction
* contain the same entry.
*/
public int[][] makeGrid(int n, int m) {
// since we want the same number of 1's and 0's per row and
// per column, both n and m must be even numbers
if (n % 2 == 1) {
throw new IllegalArgumentException("n must be an even number");
}
if (m % 2 == 1) {
throw new IllegalArgumentException("m must be an even number");
}
int[][] grid = new int[n][m];
// initialize grid: cells that have not yet been assigned a
// value shall be marked with -1
for (int y = 0; y < m; y++) {
for (int x = 0; x < n; x++) {
grid[x][y] = -1;
}
}
Random random = new Random();
int[][] colCounts = new int[n][2];
int[][] rowCounts = new int[m][2];
// we're filling the grid from top to bottom and from left to
// right. Instead of using two ints (say, x and y), we
// awkwardly use an int-array with two entries. The only
// reason for that is hideous construction is so that we can
// implement 'backtrack' as a separate method.
int[] xy = new int[2];
for (xy[1] = 0; xy[1] < m; xy[1]++) {
for (xy[0] = 0; xy[0] < n; xy[0]++) {
// if the grid cell we're currently looking at is
// empty, we set it to either 1 or 0 at random, unless
// we've already exhausted the maximum number of 1's
// or 0's per row or column, in which case we have to
// use whatever is the opposite value.
if (grid[xy[0]][xy[1]] == -1) {
int cell;
if (rowCounts[xy[1]][0] == n / 2) {
if (colCounts[xy[0]][1] == n / 2) {
backtrack(xy, n, m);
continue;
} else {
cell = 1;
}
} else if (rowCounts[xy[1]][1] == n / 2) {
if (colCounts[xy[0]][0] == n / 2) {
backtrack(xy, n, m);
continue;
} else {
cell = 0;
}
} else {
cell = random.nextInt(2);
}
// if the chosen value resulted in a constraint
// violation, we cannot leave it. By decrementing
// xy[0], we make sure that the inner for-loop above
// will come back here again in the next
// step. When it does, it will go into the 'else'
// case below because grid[xy[0]][xy[1]] is now no longer
// -1
if (!setGrid(grid, xy[0], xy[1], cell, n, m, colCounts, rowCounts)) {
xy[0]--;
}
} else {
// the grid value at (xy[0],xy[1]) was set before, but the
// value then chosen apparently lead to a
// constraint violation. Whatever value that was,
// let's try the other value instead.
if (!setGrid(grid, xy[0], xy[1], 1 - grid[xy[0]][xy[1]], n, m, colCounts, rowCounts)) {
// the other value did not work either, so we
// have to backtrack further to find a remedy.
// Undo the grid value and move back to
// previous grid position.
colCounts[xy[0]][grid[xy[0]][xy[1]]]--;
rowCounts[xy[1]][grid[xy[0]][xy[1]]]--;
grid[xy[0]][xy[1]] = -1;
backtrack(xy, n, m);
}
}
}
}
return grid;
}
protected boolean setGrid(int[][] grid, int x, int y, int cell, int n, int m, int[][] colCounts, int[][] rowCounts) {
// if a grid value was already set before at (x,y) the
// colCounts and rowCounts were changed accordingly, too. We
// have to undo that change first.
if (grid[x][y] != -1) {
colCounts[x][grid[x][y]]--;
rowCounts[y][grid[x][y]]--;
}
grid[x][y] = cell;
// now, we can update the colCounts and rowCounts according to
// the value we just set
colCounts[x][cell]++;
rowCounts[y][cell]++;
// check whether no more than two cells in a row have the same
// value
if (x-2 >= 0) {
if (grid[x-2][y] == cell &&
grid[x-1][y] == cell) {
return false;
}
}
// check whether no more than two cells in a column have the
// same value
if (y-2 >= 0) {
if (grid[x][y-2] == cell &&
grid[x][y-1] == cell) {
return false;
}
}
return true;
}
private void backtrack(int[] xy, int n, int m) {
// move one column to the left, if possible, otherwise move
// one row up
if (xy[0] == 0) {
if (xy[1] == 0) {
// we cannot backtrack any further
throw new IllegalArgumentException("No solution possible for n=" + n + ", m=" + m);
}
// backtrack to the last column in the
// previous row
xy[0] = n - 2;
xy[1]--;
} else {
// backtrack to the previous column
xy[0] -= 2;
}
}
除了由于这里使用的可怕的xy
数组而接近不可读之外,当单元格值的随机分配做出“坏”决定时,该解决方案也会遇到问题,这只会导致问题。在这种情况下,它必须一直回溯到最初引入问题的位置。如果您考虑12x12网格,其中每个单元格为0或1,则会创建2 ^ 144个可能分配的搜索空间。你可以想象,在那个空间进行详尽的搜索是很棘手的。
由于代码的可读性问题以及上述实用性考虑因素,我不情愿地发布此解决方案。不过,您可能仍希望了解一下,或许它可以激励您(或其他人)获得更好的解决方案。