javascript的数独自动填充算法代码

  数独游戏的一段代码,忘记了用的是深度优先还是广度优先的搜索算法,使用了些概率上的算法改进,share下,怕过几年不小心删除了, g.js 貌似另外一篇博文中有,这里就不贴了。
  
  当初这段代码颇有些缘由,古人有曰:山不在高有仙则名,水不在深有龙则灵。编程语言本无类,不要抱怨某些语言如何如何,关键的问题还是在人。这段代码比很多native code要快,不信各位可自行验证

  本来不想继续写了,回想下还是做些笔记吧,以免时间长了自己都忘记了,备注下这段代码使用的技巧:


1.js代码使用CloneNode(true)克隆DOM节点(包含子节点)创建多个九宫格,并用CSS将其渲染成不同的效果;

  

2.面向对象的设计结构;mvc分层设计


3.推断的时候使用可能值排除法,当无法明确推断的时候,寻找可能值个数最少的节点开始(这个是重点),先压栈保存状态,然后尝试填充,继续推断或猜测,直到得到答案,或者出错回滚排除错误值后向另一个方向继续


<!-- copy all right , barenx@163.com -->


<html><head><meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<meta http-equiv="Description" content="there is one shoudu online demo">
<meta http-equiv="Keywords" content="shoudu;javascript;css;web design;dom">
<meta http-equiv="Auther" content="barenx">
<title>sodu demo--PowerBy Barenx</title>
<script language="javascript" type="text/javascript" src="g.js"></script>
<style type="text/css">
body{
	text-align:center;
	margin:5px;
}
/*big display number block*/
#tb td, #hx td{
	width:47px;
	height:47px;
	font-size:17px; 
	font-family:Verdana, Arial, Helvetica, sans-serif; 
	vertical-align:middle; 
	text-align:center; 
	work-break:break-all;
	border:1px #FFFFFF solid;
}
#tb td{
	border:#ffffff dotted 1px;
	font-weight:bold;
}
#hx td{
	cursor:pointer;
	background:#99FFFF;
}

/*main div block*/
#lp1{
	width:auto;
	height:auto;
	float:left;
	border:1px #00CC33 solid;
}
#lp1 table{
	margin:2px auto
}
#lp1 hr{
	width:480px;
}

/*information div block*/
#rp1{
	display:block;
	width:510px;
	height:auto;
	float:left;
	border:none;
	margin:auto 5px;
	padding:3px;
}
#rp1 td {
	width:14px;
	height:14px;
	font-size:11px; 
	font-family:Verdana, Arial, Helvetica, sans-serif; 
	vertical-align:middle; 
	text-align:center; 
	work-break:break-all;
	float:none;
}
#rp1 table{
	table-layout:fixed;
	border:1px #CC0033 solid;
	margin:2px;
	float:left;
}

/*debug div block*/
#debugWin{
	width:100%;
	height:60px;
	margin:3px;
	display:block;
	padding-bottom:15px;
	text-align:left;
}

#debugWin div{
	width:100%;
	margin:0 40px 1px 1px;
	padding:0 20px 0 12px;
	border:1px solid #000099;
	height:50px;
	overflow-y:scroll;
	text-align:left;
	word-break:break-all;
	font-size:10px;
}

#debugWin input{
	width:85px;
	height:auto;
	font:Verdana, Arial, Helvetica, sans-serif;
	font-size:1.75ex;
}

</style>
</head>
<body>
<div id=debugWin></div>
<div id=lp1></div>
<div id=rp1></div>
</body>
<script language="javascript" type="text/javascript">
//Copyright(C) 2008 BAREN Productions. All rights reserved.
var ihx={
	//choiced number
	val:0,
	//nine pane, td block object [1-9] 
	O:[],
	//td block onclick callback function 
	click:function(id){
		if(id==this.val)return;
		if(this.O[this.val]){
			with(this.O[this.val].style){
				background="#99ffff";
				color="#000";
				fontWeight="";		
			}
		}
		var y=this.O[id];
		if(!y)return false;
		with(y.style){
			background="#ffff99";
			color="#a11";
			fontWeight="bold";
		}
		this.val=id;
	},
	//initialization function ---create events' function to change css style
	Create:function(id){
		var tbcs=_F.$('hx').rows[0].cells,o;
		this.O[0]=0;
		for(var i=0;i<tbcs[_L];i++){
			o=tbcs[i];
			o.v=i+1;
			o.οnclick=function(){ihx.click(this.v)}
			o.οnmοuseenter=function(){this.style.border="#000000 dotted 1px"}
			o.οnmοuseleave=function(){this.style.border="#ffffff dotted 1px"}
			this.O.push(o);
		}
		//set default value
		this.click(1);
	}
},

matrixs={
	//O td :--y rowNum[1-9] , --x cellIndex[1-9] 	:--matrix [1-9]*[1-9]
	O:[],
	//dump info table tr td :--matrix [1-9]*[1-9]*[1-9]
	DumpDev:[],
	//mark if true dump information 
	Ready:true,
	//set one pane
	set:function(y,x,v,iw){
		var i,o=this.O,c=o[y][x];
		if(c.isFix)return true;
		//debug.printTitle(p.P[v],v);
		if(c.P[v]!=v)return false;
		for(i=0;i<20;i++) c.Na[i].P[v]='';
		//debug.print(c.Na[_L]);
		for(i=1;i<=9;i++) c.P[i]='';
		c.P[v]=v;
		c.innerHTML=v;
		if(iw)c.style.color='green';
		this.dump();
		return c.isFix=true;
	},
	//save data to string
	save:function(){
		var o=matrixs.O,v=[],y,x;
		for(y=1;y<=9;y++){
			for(x=1;x<=9;x++)v.push(o[y][x].isFix?o[y][x].innerHTML:0);
		}
		return v.join('');
		//debug.stop();
	},
	//Load data from string
	load:function(s,m){
		s=(s||'').replace(/\D+/g,'');
		if(s[_L]!=81)return debug.print('error data input,9*9 panes numbers needed!\n');
		m=m||s;
		this.Ready=false;
		this.reset();
		var i,x,y,a;
		for(i=0;i<81;i++){
			y=Math.floor(i/9)+1;
			x=i%9+1;
			a=s.charAt(i);
			if(a>0&&a<=9)this.set(y,x,a,(a!=m.charAt(i)));
		}
		this.Ready=true;
		this.dump();
	},
	//get point value
	getPointVal:function(y,x){return this.O[y][x].P.join('')},
	// rational value check
	isError:function(){
		var i,j,o=this.O;
		for(i=1;i<=9;i++){
			for(j=1;j<=9;j++){
				if(this.O[i][j].P.join('')[_L]<=0) return {y:i,x:j};
			}
		}
		return false;
	},
	//check wheather the table is full filled 
	isFull:function(){
		var i,j,o=this.O;
		for(i=1;i<=9;i++){
			for(j=1;j<=9;j++){
				if(!o[i][j].isFix) return false;
			}
		}
		return true;
	},
	//reset user data & display 
	reset:function(){
		var y,x,o=this.O,oy,oyx;
		for(y=1;y<=9;y++){
			oy=o[y];
			for(x=1;x<=9;x++){
				oyx=oy[x];
				oyx.isFix=false;
				oyx.innerHTML=" ";
				oyx.style.color="#000";
				oyx.P=['',1,2,3,4,5,6,7,8,9];
			}
		}
		this.dump();
	},
	//dump funciton to show matrix status
	dump:function(){
		if(!this.Ready)return;
		var d=this.DumpDev,o=this.O,oy,dv,dvy;
		var v,y,x,a,b;
		for(v=1;v<=9;v++){ dv=d[v];
			for(y=1;y<=9;y++){ dvy=dv[y];oy=o[y];
				for(x=1;x<=9;x++){
					a=oy[x].P[v];b=dvy[x];
					if(a!=b.innerHTML)b.innerHTML=a;
				}
			}
		}
	},
	setNerb:function(y,x,o){
		var i,j,c=o[y][x];
		for(j=1;j<=9;j++) if(j!=y)c.Ny.push(o[j][x]);
		for(i=1;i<=9;i++) if(i!=x)c.Nx.push(o[y][i]); 
		var bx=Math.floor((x-1)/3)*3+1;
		var by=Math.floor((y-1)/3)*3+1;
		c.Na=c.Na.concat(c.Ny,c.Nx);
		//if (x==1 && y==1)debug.stop();
		for(j=by;j<by+3;j++){
			for(i=bx;i<bx+3;i++){
				if(i!=x || j!=y) c.Nb.push(o[j][i]);
				if(i!=x && j!=y) c.Na.push(o[j][i]);
			}
		}
	},
	//initialization function set variants' value,fomate matrix array
	Create:function(id,de)
	{
		var tbrs=_F.$(id).rows,tbcs,cell;
		var i,j,k,o=[0];
		for(i=1;i<=9;i++){
			o[i]=[0];
			tbcs=tbrs[i-1].cells;
			for(j=0;j<tbcs[_L];j++){
				cell=tbcs[j];
				cell.y=i;
				cell.x=j+1;
				cell.Ny=[];
				cell.Nx=[];
				cell.Nb=[];
				cell.Na=[];
				cell.P=['',1,2,3,4,5,6,7,8,9];
				cell.οnclick=function(){matrixs.set(this.y,this.x,ihx.val)}
				cell.οnmοuseenter=function(){this.style.border="#000000 dotted 1px";debug.printTitle(matrixs.getPointVal(this.y,this.x))}
				cell.οnmοuseleave=function(){this.style.border="#ffffff dotted 1px"}
				o[i].push(cell);
			}
		}
		for(i=1;i<=9;i++){
			for(j=1;j<=9;j++) this.setNerb(i,j,o);
		}
		delete this.setNerb;
		this.O=o;o=0;

		var d=[0],dv,dvy;
		for(i=1;i<=9;i++){
			tbrs=_F.$(de+i).rows;
			dv=[0];
			for(j=0;j<9;j++){
				tbcs=tbrs[j].cells;
				dvy=[0];
				for(k=0;k<9;k++)dvy.push(tbcs[k]);
				dv.push(dvy);
			}
			d.push(dv);
		}
		//debug.stop();
		this.DumpDev=d;
		d=0;dv=0;dvy=0;
		tbcs=0;tbrs=0;cell=0;
		
		debug.f.push(
			{
				n:"save",
				f:function(){
					debug.println(matrixs.save());
				}
			},
			{
				n:"load",
				f:function(){
					matrixs.load(debug.get("input your data",""));
				}
			},
			{
				n:"reset",
				f:function(){
					matrixs.reset();
					intelligence.reset();
				}
			},
			{
				n:"intelligence",
				f:function(){
					intelligence.start();
				}
			},
			{
				n:"check",
				f:function(){
					var rlt=matrixs.isError();
					debug.println(rlt?['point(',rlt.y,",",rlt.x,') has no choice!']:'check ok!');
				}
			}
		);
	}
},
//intelligence functions can guess the right number in the cell be filled
intelligence={
	org:'',
	buf:[],
	lastMin:1,
	timer:0,
	//reset program clear buf
	reset:function(){
		this.buf=[];
		this.org='';
		this.lastMin=1;
	},
	//get point is the only possibility, return the value or zero
	checkPoint:function(y,x,c){
		var i,j,v,s,vs=matrixs.getPointVal(y,x);
		if (vs[_L]==1)return vs;
		for(i=0;i<vs[_L];i++){
			v=vs.charAt(i);
			for(s=0,j=0;j<8;j++){
				if(c.Ny[j].P[v])s++;
				if(s>0)break;
			}
			if(0==s)return v;
			for(s=0,j=0;j<8;j++){
				if(c.Nx[j].P[v])s++;
				if(s>1)break;
			}
			if(0==s)return v;
			for(s=0,j=0;j<8;j++){
				if(c.Nb[j].P[v])s++;
				if(s>0)break;
			}
			if(0==s)return v;
		}
		return 0
	},
	//infer values
	infer:function(){
		var y,x,v,c,o=matrixs.O;
		for(y=1;y<=9;y++){
			for(x=1;x<=9;x++){
				c=o[y][x];
				if(c.isFix)continue;
				v=this.checkPoint(y,x,c);
				if(0!=v){
					debug.print(["point(",y,",",x,")=",v,"\t"].join(''));
					return matrixs.set(y,x,v,1);
				}
			}
		}
		return 0;
	},
	doGuessFirst:function(){
		//guess value struct {(y,x),v}
		var y,x,v,l,minX,minY,minL=10,Lm=this.lastMin,o=matrixs.O,c;
		for(y=1;y<=9;y++){
			for(x=1;x<=9;x++){
				//if isFix continue
				c=o[y][x];
				if(c.isFix)continue;
				//get point value
				v=c.P.join(''); l=v[_L];
				//find min value length Point
				if(l<minL){minX=x; minY=y; minL=l}
				if(Lm==l)break;
			}
			if(Lm==l)break;
		}
		this.lastMin=l;
		c=o[minY][minX];

		var k,s,i,vn=[];minVs=c.P.join(''),minVn=99,Pointer=-1;
		//calculate each value's probability--- vn, & find the min value point
		for(k=0;k<minVs[_L];k++){
			//get a value
			v=minVs.charAt(k);
			//calculat its nerb count
			for(s=0,i=0;i<20;i++) if(c.Na[i].P[v])s++;
			//save it
			vn[k]=s;
			//find the min value
			if(s<minVn){minVn=s; Pointer=k}
		}
		
		//return a guess point object
		return {
			x:minX,		//point x
			y:minY,		//point y
			v:minVs.charAt(Pointer),//i guess value//this is the max probability
			i:Pointer,	//i guess value pointer
			vn:vn,		//all point values nerb count
			av:minVs,	//all point values
			r:matrixs.save() // save matrixs status
		}
	},
	doGuessNext:function(gP){
		//disable last guess point value
		gP.vn[gP.i]=99;
		//init value
		var s,gv={i:-1,vn:99},minVn=99,Pointer=-1;
		//find next value
		for(var k=0;k<gP.av[_L];k++){
			s=gP.vn[k];
			if(s<minVn){minVn=s; Pointer=k}
		}
		//no found return null
		if(-1==Pointer) return null;
		//update guess point value
		gP.v=gP.av.charAt(Pointer);
		gP.i=Pointer;
		return gP;
	},
	//try to guess point value
	guess:function(gP){
		//debug.printTitle('guess tree deep ==>',this.buf[_L]);
		//if exist guess point try next value
		if(gP){
			//change guess point clean the error value
			gP=this.doGuessNext(gP);
			//if no value left null retrun ,do roll back 
			if(null==gP){
				//when error guess ,roll data back
				if(this.buf[_L]>0){
					return this.guess(this.buf.pop());
				}
				//no data to go back ,print error
				else{
					debug.println("the input value is corrupted!");
					return false;
				}
			}
			matrixs.load(gP.r,this.org);
		}
		//create a guess point
		else gP=this.doGuessFirst();
		this.buf.push(gP);
		debug.print(["Guess(",gP.y,",",gP.x,")=",gP.v,"\t"].join(''));
		matrixs.set(gP.y,gP.x,gP.v,1);
		setTimeout(function(){intelligence.run()},10);
		//debug.stop();
	},
	//start function
	run:function(){
		//check if the table is full filled 
		if(matrixs.isFull()){
			return debug.println("well done! ="+(new Date()-this.timer));
		}
		//still some panes' value is unknown
		//hide the fellow logic stuct , the 'else' case is not necessary 
		//else{
		//check if any pane value is error
		if(matrixs.isError()){
			//when error guess ,roll data back
			if(this.buf[_L]>0) return this.guess(this.buf.pop());
			//no data to go back ,print error
			else return debug.println("the input value is corrupted!");
		}
		//save curent status ,try to give one simple guess
		else{
			//if infer valu is legal try to infer the next point value
			if(this.infer()) return setTimeout(function(){intelligence.run()},10);
			//can not infer any point value
			else return this.guess();
		}
	},
	start:function(){
		this.timer=new Date();
		this.reset();
		this.org=matrixs.save();
		this.run();
	}
},
//debug functions
debug={
	//screen output device
	dev:null,
	//debug functions define here , init function will create button for these functions
	f:[],
	//initialization function , id - output device container id
	init:function(id){
		this.dev=_F.$c('div');
		_F.$a(_F.$(id),this.dev);
		for(var i=0;i<this.f[_L];i++)_F.$a(_F.$(id),_F.$c('input',{type:'button',value:this.f[i].n,onclick:this.f[i].f}));
		_F.$a(_F.$(id),_F.$c('input',{type:'button',value:'clear',onclick:function(){debug.clear()}}));
	},
	//print information to debuger device 
	print:function(){
		_F.$a(this.dev,_F.$t(1==arguments[_L]?arguments[0]:Array.apply([],arguments)));
		this.dev.scrollTop+=200;
	},
	//print information to debuger device end with crlf
	println:function(){
		_F.$a(this.dev,_F.$t(1==arguments[_L]?arguments[0]:Array.apply([],arguments)));
		_F.$a(this.dev,_F.$c('br'));
		this.dev.scrollTop+=200;
	},
	//print information to top document title
	printTitle:function(){top.document.title=(Array.apply([],arguments)).join(',').replace(/\s+/g,' ');},
	//get input from user
	get:function(){return prompt(arguments[0],arguments[1])},
	//clear debuge device ouput
	clear:function(){this.dev.innerHTML='';},
	//stop running script by calling the native debuger if available, else do nothing
	stop:function(){debugger}
}
/*************************************************************/
/*	this function draw all panes in the special id
/*	con1	container 1 id	--left panes layer
/*	con2	container 2	id	--right panes layer
/*	id1 	choice table id --in left layer
/*	id2 	main table id   --contain ninety-nine panes 
/*	id3 	information table id string mark
/*************************************************************/
function DrawTables(con1,con2,id1,id2,id3){
	var cont,tb,row,i,j,cell;
	cont=_F.$(con1);
	tb=_F.$c('table',{id:id1});
	row=tb.insertRow(0);
	for(i=0;i<9;i++){row.insertCell(i).innerHTML=i+1}
	_F.$a(cont,tb);
	
	_F.$a(cont,_F.$c('hr'));
	tb=_F.$c('table',{id:id2});
	for(i=0;i<9;i++){
		row=tb.insertRow(i);
		for(j=0;j<9;j++){
			cell=row.insertCell(j);
			cell.innerHTML=" ";
			cell.bgColor =((i>2&&i<6)^(j>2&&j<6))?"#ffffcc":"#ccffff";
		}
	}
	_F.$a(cont,tb);
	cont.onselectstart=_F.f;
	
	cont=_F.$(con2);
	for(i=1;i<=9;i++){
		tb=tb.cloneNode(true);
		tb.id=id3+i;
		_F.$a(cont,tb);
	}
	cont.onselectstart=_F.f;
	_F.$a(cont,_F.$c('div',{innerHTML:'<b>Copyright(C) 2008 BAREN Productions. <br />All rights reserved.</b>'}));
}
// global initialization funtion, create each object on document's Ready 
(function init(){
	DrawTables('lp1','rp1','hx','tb',"de");delete DarwTables;
	ihx.Create('hx');delete ihx.Create;
	matrixs.Create('tb',"de");delete matrixs.Create;
	debug.init('debugWin');delete debug.init;
	
	_F.$l(document,function(){
		var k=event.keyCode-48;
		if(k>0&&k<=9)ihx.click(k);
		//if(event.ctrlKey)debug.printTitle(matrixs.getCurPointInfo());
		//debug.print(k);
	},"keydown");
	
	setTimeout(function(){
		_F.$h(_F.$('rp1'));
		matrixs.dump();
		_F.$s(_F.$('rp1'));
	},10);
})();
//forbiden user select opration
//document.onselectstart=_F.f;

</script>
</html>


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一个基于Python的数独挖洞算法示例代码: ```python import random def generate_puzzle(): """ 生成数独谜题 """ # 初始化一个空的9x9数独网格 puzzle = [[0 for x in range(9)] for y in range(9)] # 生成第一行 puzzle[0] = random.sample(range(1, 10), 9) # 逐行生成数独谜题 for row in range(1, 9): for col in range(9): # 根据已有数字生成当前行 available_nums = [i for i in range(1, 10) if i not in puzzle[row]] # 根据已有数字生成当前列 for i in range(row): if puzzle[i][col] in available_nums: available_nums.remove(puzzle[i][col]) # 根据已有数字生成当前九宫格 square_row = (row // 3) * 3 square_col = (col // 3) * 3 for i in range(square_row, square_row + 3): for j in range(square_col, square_col + 3): if puzzle[i][j] in available_nums: available_nums.remove(puzzle[i][j]) # 随机从可用数字中选择一个填入当前格 puzzle[row][col] = random.choice(available_nums) return puzzle def remove_numbers(puzzle, holes): """ 挖洞,移除数独中的数字 """ # 复制一份数独谜题 puzzle_copy = [row[:] for row in puzzle] # 初始化已挖洞的格子数量 holes_count = 0 # 随机选择格子挖洞,直到达到指定数量的洞 while holes_count < holes: # 随机选择一行和一列 row = random.randint(0, 8) col = random.randint(0, 8) # 如果当前格子未挖洞,将其挖洞 if puzzle_copy[row][col] != 0: puzzle_copy[row][col] = 0 holes_count += 1 return puzzle_copy ``` 使用示例: ```python # 生成一个数独谜题 puzzle = generate_puzzle() # 挖洞,移除30个数字 puzzle_with_holes = remove_numbers(puzzle, 30) # 输出数独谜题 for row in puzzle_with_holes: print(row) ``` 这个示例代码生成一个数独谜题,然后使用 `remove_numbers` 函数挖掉指定数量的数字。你可以根据需要修改 `generate_puzzle` 和 `remove_numbers` 函数中的参数来生成不同的数独谜题。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值