写一个数独游戏的求解程序
代码如下欢迎交流
package shudu;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
//棋盘类
public class Qp {
ArrayList<Integer>[][] q = new ArrayList[9][9]; //棋格子,每各格子为ArrayList 存了1-9个数代表有9个取值的可能
int COUNT = 81; //棋盘格子数
String fullString = null; //类似toString 方法
Boolean ifRepetition = true; //是否有重复值,false 为出现重复着,若为false,后续的迭代过程中该棋盘会被舍弃
Boolean ifComplete = false; //是否完成,true为完成,完成代表代表该棋盘为正确解
ArrayList<Qp> qpList = new ArrayList<Qp>(); //存放下次迭代需要的 棋盘
public Qp(ArrayList<Integer>[][] qx) { //迭代过程中的构造函数
this.q = qx;
this.printQ(); //不止打印自己,还会初始化成员变量
System.out.println();
}
public Qp(int[][] iq) { //首次初始化的构造函数
for (int j = 0; j < iq.length; j++) {
for (int i = 0; i < iq[j].length; i++) {
if (iq[j][i] != 0) {
q[j][i] = new ArrayList<Integer>();
q[j][i].add(iq[j][i]);
} else {
q[j][i] = new ArrayList<Integer>(Arrays.asList(1, 2, 3, 4,
5, 6, 7, 8, 9));
}
}
}
this.printQ();
System.out.println();
}
public ArrayList<Integer>[][] setValue(int x, int y, int v) {
// 给棋盘某个格子设置固定值
System.out.println("设置固定值开始");
ArrayList<Integer>[][] qn = cloneQ();
qn[x][y] = new ArrayList<Integer>(Arrays.asList(v));
return qn;
}
public void printQ() {
int count = 0; // 统计确认值的格子,若 count = 81 说明棋盘得到解
String f = "";
for (ArrayList<Integer>[] i : this.q) {
for (ArrayList<Integer> k : i) {
if (k.size() == 1) {
count++;
f = f + k.get(0);
System.out.print(k.get(0));
} else {
f = f + "?";
System.out.print("?");
}
}
f = f + '\n';
System.out.println();
}
if (count == this.COUNT) {
this.ifComplete = true;
}
this.fullString = f;
}
public Qp checkQ() {
// 遍历棋盘没个格子,根据格子所在 列,行,宫,已出现的值,排除格子的取值范围
//直至取值范围为1,得到某个格子确定值
//每销去一个取值范围,需要检查棋盘会出现重复值,若出现该次遍历设为无效
ArrayList<Integer>[][] qn = cloneQ(); //克隆一个棋盘取值,用于废弃遍历时还原棋盘
for (int x = 0; x < q.length; x++) {
for (int y = 0; y < q[x].length; y++) {
ArrayList<Integer> tarList = getRLG(x, y);
for (int i : getRowSorList(tarList.get(0))) { //遍历行
if (q[x][y].indexOf(i) != -1 && q[x][y].size() > 1) {
q[x][y].remove(q[x][y].indexOf(i)); //销去格子的取值
if (!checkRepet()) { //检查若重复,返回原棋盘
q = qn;
Qp rq = new Qp(qn);
rq.ifRepetition = false;
return rq;
}
}
}
for (int i : getColumSorList(tarList.get(1))) { //遍历列
if (q[x][y].indexOf(i) != -1 && q[x][y].size() > 1) {
q[x][y].remove(q[x][y].indexOf(i)); //销去格子的取值
if (!checkRepet()) { //检查若重复,返回原棋盘
q = qn;
Qp rq = new Qp(qn);
rq.ifRepetition = false;
return rq;
}
}
}
for (int i : getGongSorList(tarList.get(2))) { //检查宫
if (q[x][y].indexOf(i) != -1 && q[x][y].size() > 1) {
q[x][y].remove(q[x][y].indexOf(i)); //销去格子的取值
if (!checkRepet()) { //检查若重复,返回原棋盘
q = qn;
Qp rq = new Qp(qn);
rq.ifRepetition = false;
return rq;
}
}
}
}
}
System.out.println("检查无重复元素");
return new Qp(q);
}
public Qp dealQqList() { //迭代处理,自己看吧,当 ifComplete 为true返回解,
if (!this.ifRepetition || this.ifComplete) { //中间需要设置可能取值,放置到 QpList中,同于下一次迭代处理
return null; //本方法就是迭代处理 QpList 直到获取棋盘的解
} //调了我一整天 -_-!
if (this.qpList == null || this.qpList.size() == 0) {
return null;
}
for (Qp q : this.qpList) {
if (q == null) {
continue;
}
Qp qq = q.ReCheck(q);
System.out.println("qq.ifComplete===========" + qq.ifComplete); //打印出是否完成
System.out.println("qq.ifRepetition=========" + qq.ifRepetition); //打印出是否重复
if (qq.ifComplete) {
return qq; //返回解
} else if (!qq.ifRepetition) {
continue;
} else {
qq.setQpList(qq.getMinQ()); //设置QpList
Qp qqq = qq.dealQqList(); //迭代处理
if (qqq == null) {
continue;
}
if (qqq.ifComplete) {
this.ifComplete = true;
// 只要有1解就终止
return qqq; //返回解
}
}
}
System.out.println("这个List什么也解不到,下一个");
return null;
}
public void setQpList(ArrayList<Integer> xy) { //设置qpList
int x = xy.get(0);
int y = xy.get(1);
for (int i : q[x][y]) {
this.qpList.add(new Qp(setValue(x, y, i)));
}
}
public ArrayList[][] cloneQ() { //克隆棋盘取值,防止迭代过程串值
ArrayList[][] qn = new ArrayList[9][9];
for (int x = 0; x < q.length; x++) {
for (int y = 0; y < q[x].length; y++) {
qn[x][y] = new ArrayList<Integer>();
for (int i : q[x][y]) {
qn[x][y].add(i);
}
}
}
return qn;
}
public ArrayList<Integer> getRowSorList(int i) { //遍历行,行的编号重0开始
ArrayList<Integer> sl = new ArrayList<Integer>();
for (ArrayList<Integer> rowL : this.q[i]) {
if (rowL.size() == 1) {
sl.add(rowL.get(0));
}
}
if (sl.size() == 0) {
// System.out.println("未填写的行");
return sl;
}
if (ifRepet(sl)) {
return sl;
} else {
this.ifRepetition = false;
System.out.println(sl);
System.out.println("第" + i + "行中出现重复数据");
return sl;
}
}
public ArrayList<Integer> getColumSorList(int i) { //遍历列,列的编号从0开始
ArrayList<Integer> sl = new ArrayList<Integer>();
for (ArrayList<Integer>[] columL : this.q) {
if (columL[i].size() == 1) {
sl.add(columL[i].get(0));
}
}
if (sl.size() == 0) {
// System.out.println("未填写的列");
return sl;
}
if (ifRepet(sl)) {
return sl;
} else {
this.ifRepetition = false;
System.out.println(sl);
System.out.println("第" + i + "列中出现重复数据");
return sl;
}
}
public ArrayList<Integer> getGongSorList(int i) { //遍历宫,注意宫的编号是从1开始的
ArrayList<Integer> sl = new ArrayList<Integer>();
int row = ((i - 1) / 3) * 3;
int colum = ((i - 1) % 3) * 3;
for (int j = 0; j < 3; j++) {
int tempR;
int tempC;
tempR = row + j;
for (int k = 0; k < 3; k++) {
tempC = colum + k;
if (q[tempR][tempC].size() == 1) {
sl.add(q[tempR][tempC].get(0));
}
}
}
if (sl.size() == 0) {
// System.out.println("未填写的宫");
return sl;
}
if (ifRepet(sl)) {
return sl;
} else {
this.ifRepetition = false;
System.out.println(sl);
System.out.println("第" + i + "宫中出现重复数据");
return sl;
}
}
public boolean checkRepet() { //检查所有 行,列,宫 是否有重复
for (int i = 0; i < 9; i++) {
if (!ifRepet(getRowSorList(i))) {
return false;
}
if (!ifRepet(getColumSorList(i))) {
return false;
}
}
for (int j = 1; j <= 9; j++) {
if (!ifRepet(getGongSorList(j))) {
return false;
}
}
return true;
}
public boolean ifRepet(ArrayList<Integer> ar) { //检查 ArrayList 中 是否有重复元素
if (new HashSet<Integer>(ar).size() < ar.size()) {
return false;
} else {
return true;
}
}
public ArrayList<Integer> getRLG(int x, int y) { //获取给定格子所在 行,列,宫 编号 方置 ArrayList中(放数组比较合理)
ArrayList<Integer> rlg = new ArrayList<Integer>();
int r = x / 3;
int c = y / 3;
int k = 1 + 3 * r + c;
rlg.add(x);
rlg.add(y);
rlg.add(k);
return rlg;
}
public ArrayList<Integer> getMinQ() { //获取执行取值格子坐标,后续放置于qpList中
ArrayList<Integer> reXY = new ArrayList<Integer>();
int minSize = 10;
for (int x = 0; x < this.q.length; x++) {
for (int y = 0; y < q[x].length; y++) {
if (q[x][y].size() > 1 && q[x][y].size() < minSize) {
minSize = q[x][y].size();
reXY.clear();
reXY.add(x);
reXY.add(y);
}
}
}
if (reXY.size() != 0) {
System.out.println("reXY最小数集合为 第:(" + reXY.get(0) + ","
+ reXY.get(1) + ")" + " 大小为:" + minSize);
System.out.println(q[reXY.get(0)][reXY.get(1)]);
} else {
System.out.println("无最小集");
}
return reXY;
}
public Qp ReCheck(Qp qp) { //迭代棋盘获取每个格子的最小取值范围的棋盘
Qp rqp = qp.checkQ();
if (qp.fullString != null && qp.fullString.equals(rqp.fullString)) {
return rqp;
} else {
return ReCheck(qp.checkQ());
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int[][] iq = new int[][] { { 0, 4, 7, 0, 0, 0, 8, 0, 0 },
{ 6, 0, 0, 0, 2, 8, 0, 0, 0 }, { 0, 0, 0, 0, 0, 6, 1, 0, 9 },
{ 0, 1, 0, 7, 0, 0, 0, 8, 4 }, { 2, 0, 0, 1, 0, 0, 0, 0, 7 },
{ 0, 0, 3, 6, 8, 0, 0, 5, 0 }, { 0, 0, 2, 5, 0, 0, 0, 0, 8 },
{ 0, 0, 0, 0, 6, 0, 3, 9, 0 }, { 5, 3, 0, 0, 0, 4, 0, 6, 0 } };
iq = new int[][] { { 2, 0, 0, 0, 3, 0, 0, 1, 0 },
{ 0, 0, 1, 0, 0, 6, 0, 7, 0 }, { 0, 0, 9, 7, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 4, 1, 0, 0 }, { 0, 1, 0, 0, 0, 0, 5, 4, 0 },
{ 0, 0, 4, 6, 0, 5, 0, 0, 0 }, { 4, 0, 0, 0, 6, 3, 0, 0, 1 },
{ 0, 6, 3, 1, 0, 0, 0, 8, 0 }, { 0, 0, 0, 0, 2, 0, 6, 0, 7 }, };
iq = new int[][] { { 0, 0, 9, 0, 0, 0, 1, 0, 6 },
{ 7, 0, 3, 0, 0, 8, 0, 0, 0 }, { 0, 0, 0, 0, 0, 6, 4, 3, 0 },
{ 0, 0, 8, 2, 9, 0, 0, 0, 4 }, { 9, 0, 0, 0, 3, 0, 0, 0, 0 },
{ 0, 7, 0, 0, 0, 0, 0, 2, 0 }, { 0, 3, 0, 0, 0, 4, 0, 0, 8 },
{ 0, 0, 0, 0, 5, 0, 6, 0, 0 }, { 2, 4, 0, 0, 0, 0, 0, 0, 0 }, };
Qp qq = new Qp(iq);
Qp qqq = qq.ReCheck(qq);
qqq.setQpList(qqq.getMinQ());
Qp qqqq = qqq.dealQqList();
System.out.println("结果为:");
qqqq.printQ();
}
}