数独游戏求解程序

写一个数独游戏的求解程序

代码如下欢迎交流

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();

	}

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值