看过很多博客和资料,都是9*9独数游戏,而且还有很多是残缺代码,这个就很恼火,自己写又要花不少时间,所以我这里这里了一份比较灵活的独数游戏,你们可以根据自己的需求生成3*3 6*6 7*7 8*8 或者 9*9 ..........等等独数游戏。
package com.odcchina.fai.util;
public class DoShudu {
static int number = 0;
static int limit = 0;
/**
* 存储数字的数组
*/
static int[][] n = new int[number][number];
static int[] num = null;
public static void main(String[] args) {
int[] numas = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
generateSingular(10,numas);
//输出结果
for (int i = 0; i < number; i++) {
for (int j = 0; j < number; j++) {
System.out.print(n[i][j] + " ");
}
System.out.println();
}
}
/**
* @param numberPas 要生成的位数 6*6 7*7 8*8 9*9 。。。。。。
* @param numPas 生成的数组,里面不能有为0的数字
*/
public static void generateSingular(int numberPas,int[] numPas){
number = numberPas;
limit = numberPas - 1;
n = new int[numberPas][numberPas];
num = numPas;
int code = 0;
//生成数字
for (int i = 0; i < number; i++) {
//尝试填充的数字次数
int time = 0;
//填充数字
for (int j = 0; j < number; j++) {
code++;
if(code > 50000){
//生成失败,重新生成
n = new int[number][number];
generateSingular(numberPas,numPas);
return;
}
//产生数字
n[i][j] = generateNum(time);
//如果返回值为0,则代表卡住,退回处理
//退回处理的原则是:如果不是第一列,则先倒退到前一列,否则倒退到前一行的最后一列
if (n[i][j] == 0) {
//不是第一列,则倒退一列
if (j > 0) {
j -= 2;
continue;
} else {//是第一列,则倒退到上一行的最后一列
i--;
j = limit;
continue;
}
}
//填充成功
if (isCorret(i, j)) {
//初始化time,为下一次填充做准备
time = 0;
} else { //继续填充
//次数增加1
time++;
//继续填充当前格
j--;
}
}
}
}
/**
* * 是否满足行、列和3X3区域不重复的要求 * @param row 行号 * @param col 列号 * @return true代表符合要求
*/
public static boolean isCorret(int row, int col) {
if(number % 3 == 0){
//3的倍数才调checkNine校验
return (checkRow(row) & checkLine(col) & checkNine(row, col));
}else{
return (checkRow(row) & checkLine(col) & true);
}
}
/**
* * 检查行是否符合要求 * @param row 检查的行号 * @return true代表符合要求
*/
public static boolean checkRow(int row) {
for (int j = 0; j < limit; j++) {
if (n[row][j] == 0) {
continue;
}
for (int k = j + 1; k < number; k++) {
if (n[row][j] == n[row][k]) {
return false;
}
}
}
return true;
}
/**
* * 检查列是否符合要求 * @param col 检查的列号 * @return true代表符合要求
*/
public static boolean checkLine(int col) {
for (int j = 0; j < limit; j++) {
if (n[j][col] == 0) {
continue;
}
for (int k = j + 1; k < number; k++) {
if (n[j][col] == n[k][col]) {
return false;
}
}
}
return true;
}
/**
* * 检查3X3区域是否符合要求 * @param row 检查的行号 * @param col 检查的列号 * @return true代表符合要求
*/
public static boolean checkNine(int row, int col) {
//获得左上角的坐标
int j = row / 3 * 3;
int k = col / 3 * 3;
//循环比较
for (int i = 0; i < limit; i++) {
if (n[j + i / 3][k + i % 3] == 0) {
continue;
}
for (int m = i + 1; m < number; m++) {
if (n[j + i / 3][k + i % 3] == n[j + m / 3][k + m % 3]) {
return false;
}
}
}
return true;
}
/**
* * 产生1-N之间的随机数字 * 规则:生成的随机数字放置在数组limit-time下标的位置,
* 随着time的增加,已经尝试过的数字将不会在取到 * 说明:即第一次次是从所有数字中随机,
* 第二次时从前八个数字中随机,依次类推, * 这样既保证随机,也不会再重复取已经不符合要求的数字,
* 提高程序的效率 * 这个规则是本算法的核心 * @param time 填充的次数,0代表第一次填充 * @return
*/
public static int generateNum(int time) {
//第一次尝试时,初始化随机数字源数组
if (time == 0) {
for (int i = 0; i < number; i++) {
num[i] = i + 1;
}
}
//第number次填充,表明该位置已经卡住,则返回0,由主程序处理退回
if (time == number) {
return 0;
}
//不是第一次填充
//生成随机数字,该数字是数组的下标,取数组num中该下标对应的数字为随机数字
int ranNum = (int) (Math.random() * (number - time));
//把数字放置在数组倒数第time个位置,
int temp = num[limit - time];
num[limit - time] = num[ranNum];
num[ranNum] = temp;
//返回数字
return num[limit - time];
}
}
点击运行,成功生成独数
已连接到目标 VM, 地址: ''127.0.0.1:51558',传输: '套接字''
4 1 10 2 6 8 9 3 5 7
10 7 9 8 3 2 5 4 6 1
6 3 2 1 10 5 7 8 4 9
8 4 5 7 2 10 6 9 1 3
5 9 1 4 8 3 10 7 2 6
3 6 7 9 1 4 2 10 8 5
9 2 4 10 5 1 3 6 7 8
7 8 3 5 9 6 4 1 10 2
1 5 6 3 4 7 8 2 9 10
2 10 8 6 7 9 1 5 3 4
与目标 VM 断开连接, 地址为: ''127.0.0.1:51558',传输: '套接字''
进程已结束,退出代码为 0