`
yiminghe
  • 浏览: 1431447 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

编程之美:javascript的数独实现

阅读更多

书中没有给出具体实现,但是算法1也不难,自己实现玩玩用来测智商吧。

 

规则:

 

一个由3个3*3的子矩阵组成的9*9矩阵,其中每个3*3矩阵都由1-9这9个数字组成,且数独矩阵中每行每列都没有重复数字。

 

3*3子矩阵数字各不相同

 

效果图:


演示@google code

 

 

 

代码: (可copy直接运行,或 附件

 

1.0 (2009-07-22 16:54)

 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh-CN" dir="ltr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>数独游戏</title>

<script type="text/javascript">

//<![CDATA[

 /***
	
		产生一个 9*9 的数独矩阵,满足数独规则 :
		
		1.一个由9个3*3的子矩阵组成的9*9矩阵,其中每个3*3矩阵都由1-9这9个数字组成,
		
		2.且数独矩阵中每行每列都没有重复数字。
		
		
		关键方法:
		深度搜索,记下每个单元格对应的可选数序列,当没有路线时清空自己的可选数序列,
		利用回朔,改变上个单元格已选泽的值
		
		
	
	
	****/
	
	
	
	
	
	
	
	
	if(!Array.prototype.indexOf) {  
	   Array.prototype.indexOf = function(v){  
	        for(var i=0;i<this.length;i++)  
	            if(this[i] === v) return i;  
	        return -1;  
	    }  
	}  
//http://blog.stevenlevithan.com/archives/faster-trim-javascript
//fast !
	if(!String.prototype.trim) { 
			String.prototype.trim=function() {
	                      var	str = this.replace(/^\s\s*/, ''),
		              ws = /\s/,
		               i = str.length;
	                       while (ws.test(str.charAt(--i)));
	                       return str.slice(0, i + 1);
                          }
	}
	
	
       
	/*
		*********************************************************************
		start : 数组随机函数组
	
		floy 算法对数组进行重排序
		http://yiminghe.iteye.com/blog/409039
	*/

  function randIt(l,u){  
       return l+Math.floor(Math.random()*(u-l+1));  
  }
  
  
  /* 
       1 - n 中随机取m个数组成序列 
   */  
   function randomList(m,n) {  
       var start=n-m+1;  
       var holder=[];  
         
       for(var i=start;i<=n;i++) {  
           //random 1~i not 1~i-1  
           var cur=randIt(1,i);  
           //trick tick  
           var position=holder.indexOf(cur)+1;       
           var insert=position?i:cur;  
           holder.splice(position,0,insert);                 
       }  
         
       return holder;  
    }
   
   
   /**
   	arr 数组元素随机打乱
   **/
   function randomArray(arr) {
  		var rIndex=randomList(arr.length,arr.length);
  		var newArr=[];
  		for(var i=0;i<rIndex.length;i++) {
  			newArr[i]=arr[rIndex[i]-1];
  		}
  		return newArr;
  		
   }
   
/*
	end : 数组随机函数组
	********************************************************************************
*/   
   
   
 
	/*
		数独 core 对象 ,其实就是对2维数组的封装
	*/ 
	function Sudoku(){	
	
	}  


   
       

	/*
		得到当前单元格的一个可选值,-1 表示没有可选值了,要向前回朔
	*/
	Sudoku.prototype.getNextRandom = function(currentCell){		
		
		var currentX=currentCell%9; //col
		var currentY=Math.floor(currentCell/9); //row
		var currentSubMaxtrixX=Math.floor(currentX/3); //sub this.matrix col
		var currentSubMaxtrixY=Math.floor(currentY/3); //sub this.matrix row
		var index=0;
		
		//初始可选数字
		var avails=[1,2,3,4,5,6,7,8,9];		
		
		//没有计算过,计算可选序列,用于回朔枚举
		if(!this.matrix[currentY][currentX]) {			
			
			/*
				根据数独规则进行过滤
			*/
			
			//同一行不能重复
			for(var i=0;i<currentX;i++) {
				if(avails.indexOf(this.matrix[currentY][i].value)!=-1)
					avails.splice(avails.indexOf(this.matrix[currentY][i].value),1);
			}
			
			//同一列不能重复
			for(var i=0;i<currentY;i++) {
				if(avails.indexOf(this.matrix[i][currentX].value)!=-1)
					avails.splice(avails.indexOf(this.matrix[i][currentX].value),1);
			}
			
			//3*3 小矩阵不能重复
			outer:for(var j=currentSubMaxtrixY*3;j<currentSubMaxtrixY*3+3;j++) {		
				for(var i=currentSubMaxtrixX*3;i<currentSubMaxtrixX*3+3;i++) {
					
					//小矩阵验证到当前单元格就行了
					if(j==currentY && i==currentX) break outer;			
					
					if(avails.indexOf(this.matrix[j][i].value)!=-1)
						avails.splice(avails.indexOf(this.matrix[j][i].value),1);
				}
			}
			
			//没有选择了
			if(avails.length==0) return  -1;
			
			//avails 最好随机打乱,每次生成不同的数独
			avails=randomArray(avails);
			
		} else {
			
			index=this.matrix[currentY][currentX].index;
			
			//枚举完毕,仍然不行,清除计算状态,
			if(index == this.matrix[currentY][currentX].availList.length-1) {
				this.matrix[currentY][currentX]=null;
				return -1;
			}
			
			//回朔到这里了,当前数字不行,那么在可选序列中选中下一个可选数字
			++index;
			avails=this.matrix[currentY][currentX].availList;
				
		}
		
		//返回数独单元的结构表示
		return {
			//当前单元格选择的值的index
			index:index,
			//记下产生的可选序列,回朔时用于枚举下一个值
			availList:avails,
			value:avails[index]
		};
		
	}
	
	
	/*
		指定编号的 Cell 设置数值
	*/
	Sudoku.prototype.setValueOfMatrix = function(currentCell,val) {
		var currentX=Math.floor(currentCell%9); //col
		var currentY=Math.floor(currentCell/9); //row
		this.matrix[currentY][currentX]=val;
	}
	
	
	/*
		静态方法:验证是否符合数独规则
	*/
	Sudoku.validate = function (matrix){
		var cache={};
		
		for(var i=0;i<9;i++) {
			cache={};
			for(var j=0;j<9;j++) {
				if(cache[matrix[i][j]]) {
					
					return "row "+(i+1)+"  error";	
				}		
				cache[matrix[i][j]] = 1;
			}
		}	
		
		
		for(var i=0;i<9;i++) {
			cache={};
			for(var j=0;j<9;j++) {
				if(cache[matrix[j][i]]) {
					
					return "col "+(j+1)+"  error";
				}	
				cache[matrix[j][i]] = 1;
			}
		}	
		
		
		for(var i=0;i<3;i++) {
			
			for(var j=0;j<3;j++) {
				
				cache={};
				
				for(var subi=i*3;subi<i*3+3;subi++) {
					
					for(var subj=j*3;subj<j*3+3;subj++) {
						
						if(cache[[matrix[subi][subj]]]) {
							
							return "submatrix "+(i*3+j)+"error";
						}
						cache[matrix[subi][subj]] = 1;
				
					}	
					
				
				}	
					
			}
		}	
		return null;		
	}
	
	
	/*
		重要,生成符合数独规则的矩阵
	*/
	Sudoku.prototype.generate = function (space) {
		this.matrix=[];
		
		for(var i=0;i<9;i++) 
			this.matrix.push([]);			
		
		var currentCell=0;
		
		//按照行编号 0~80 ,共 9*9=81 个单元格
		while(true) {
			var nextValue=this.getNextRandom(currentCell);			
			if(nextValue!=-1) {
				this.setValueOfMatrix(currentCell,nextValue);
				++currentCell;
			} else {
				//无值可选了,回朔
				--currentCell;	
			}
			
			//9*9 全部完成
			if(currentCell==81) break;
		}
		
		
		
		/*
			矩阵已经搞好了--------------------------------------------
		*/ 
					
		var holes=randomList(space,81);
		
		for(var i=0;i<holes.length;i++) {
			var currentX=Math.floor((holes[i]-1)%9); //col
			var currentY=Math.floor((holes[i]-1)/9); //row
			this.matrix[currentY][currentX]=null;
		}
		
		return this.matrix;		
		
	}
	 //]]>

</script>





<style type="text/css">
	table {
		border-collapse: collapse;
		width: 80%;
		padding-left: 5%;
		table-layout: fixed;
		margin: 20px;
	}
	
	div {
		margin: 20px;
		padding-left: 5%;
	}
	
	input#space {
		margin-right: 10px;
	}
	
	td {
		padding: 5px;
		border: 1px solid black;
	}
	
	input.tableCell {
		width: 80%;
	}
</style>
</head>
<body>
	<table cellspacing="0" cellpadding="0">
		<caption>我的数独</caption>
		<tbody id="dataTable">
			<tr>
				<td>1</td>
				<td>1</td>
				<td>1</td>
				<td>1</td>
				<td>1</td>
				<td>1</td>
				<td>1</td>
				<td>1</td>
				<td>1</td>
			</tr>
		</tbody>
	
	</table>
	<div>
		<label for="space">空格数:</label> 
		<input type="text" id="space"	size="2" value="2" /> 
		<input type="button" value="生成数独" id="run" /> 
		<input type="button" value="我要验证" id="validate"	/>
		
	</div>
	<script type="text/javascript">
		//<![CDATA[	
	
		function collectData(tableEl){
			var matrix=[];
			for(var i=0;i<tableEl.childNodes.length;i++) {
				
				var tr=tableEl.childNodes[i].childNodes;
				var row=[];
				for(var j=0;j<tr.length;j++) {
					var td=tr[j];
					
					var ti=0;
					
					while(td.childNodes[ti] && td.childNodes[ti].nodeType ==3 )ti++;
					
					if(td.childNodes[ti]) {
												
						if( ! /^[1-9]$/.test(td.childNodes[ti].value.trim())) {
							return "输入1-9之间";
						}				
						
						row.push(parseInt(td.childNodes[ti].value.trim()));
					}
					
					else {
						row.push(parseInt(td.innerHTML));
					}
					
				}
				
				matrix.push(row);
				
			}		
			
			return matrix;
		
		}
		
		
		
		function startValidate(){
			var dataTable=document.getElementById("dataTable");
			var newMatrix = collectData(dataTable);
			if(typeof newMatrix == "string") {
				alert(newMatrix);
				return;
			}
			
			var info=Sudoku.validate(newMatrix);
			if(info)
				alert(info);
			else
				alert("恭喜你,成功了");
		}
		
		
		
		/*
			*****************************************************
			启动函数来了:
			
		*/
		function main(){
		
			var space =parseInt(document.getElementById("space").value);
			
			if(isNaN(space))
				space=0;
			
			if(space>81 || space<0) {
				alert("空格数不合规范:(");
				return;
			}
			
			var sudoku = new Sudoku();
			var matrix= sudoku.generate(space);
			
			var dataTable=document.getElementById("dataTable");
			
			
			
			while (dataTable.childNodes[0]) {
				dataTable.removeChild(dataTable.childNodes[0]);
			}
			
			for(var i=0;i<9;i++) {
				var dataTableTr=document.createElement("tr");
				for(var j=0;j<9;j++) {
					var dataTableTd=document.createElement("td");
					
					if(matrix[i][j])
						dataTableTd.innerHTML=matrix[i][j].value;
					else
						dataTableTd.innerHTML="<input type='text' class='tableCell' />";
						
					dataTableTr.appendChild(dataTableTd);
					//document.writeln(matrix[i][j].value+"&nbsp;");
				}
				dataTable.appendChild(dataTableTr);
			}
			
			
		}
		main();
		
		document.getElementById("run").onclick=function(){
			main();
		};
		
		document.getElementById("validate").onclick=function(){
			startValidate();
		};
		//]]>
		 
	</script>
</body>
</html>
  • 大小: 7.6 KB
0
0
分享到:
评论

相关推荐

    数据结构课设-数独游戏

    请设计一个数独游戏,要求包括: 1, 基本要求:能按照不同难度级别设置随机的初始数独,允许用户在空格处填入数字完成数独游戏;在用户输入数字时,判断冲突,给...建议使用JavaScript/HTML/CSS编程,使用回溯算法。

    ngsudoku:数独的angularjs实现

    Sudoku为实现算法以解决9 x 9经典Sudoko矩阵中的空单元格提供了很好的编程挑战。 有许多站点提供解决方案策略的详细信息,但是对于新手而言,所需要做的就是耐心地坐下来并按逻辑进行组合直到达到最终目标。 我可能...

    solve-sudoku:构建数独游戏求解器

    所以我希望能够以编程方式解决数独谜题,理想情况下我想自己解决这个问题。 我在数独方面表现不错,所以我希望我有一半的机会来管理它。 策略 所以,我们将不得不实现董事会的代表,这很好,很花哨而且很容易。 我们...

    sudoku:生成数独,求解算法和穷举搜索的启发式算法

    实现的算法 生成数独 this . generate = function ( cellEmptyInput ) { this . refreshSudoku ( ) ; for ( var i = 0 ; i &lt; this . getRandomInt ( 1 , 9 ) ; i ++ ) { this . transposeRowBig ( this . ...

    fp-sudoku:数独作为函数式编程练习

    数独作为函数式编程练习 用 跑步: npm install node index 并在浏览器中打开localhost:3000 。 Docker化 docker run -it --rm --volume $(pwd):/app --publish 3000:3000 yanatan16/fp-sudoku 并在浏览器中打开...

    数独游戏matlab代码-James-P-D:詹姆斯·PD

    数独游戏m​​atlab代码詹姆斯·PD 以下是我的Github上每个存储库的快速概述。 所有项目都是原始资源(而不是其他用户创建的项目的分支)。 内容 -C#控制台应用程序,用于基于Forth的基于堆栈的语言 -教育编程语言...

    snake_game:使用HTML和编程语言JavaScript构建的老式“ NOKIA” Snake游戏

    数独 使用HTML和编程语言JavaScript构建的老式“ NOKIA” Snake游戏。 语言: 描述: Snake游戏的创建是为了练习javascript和HTML。 使用键盘上的箭头移动蛇。 尽可能多吃苹果。 不要咬自己! 演示: :hammer_and...

    Android程序设计基础

    作者: (美)Ed Burnette 译者: 张波 高朝勤 杨越 丛书名: 图灵程序设计丛书 出版社:人民邮电出版社 ISBN:9787115215369 上架时间:2009-11-6 出版日期:2009 年11月 开本:16开 页码:196 版次:1-1 ...

    sudoku:基于Python的Sudoku求解器

    同时,我在漫长的休息中选择了几种编程语言,包括python和javascript。 因此,我们开始-具有基于javascript的UI组件的基于python的数独求解器。 用法 基于终端的CLI 数独 基于Web的gui后端(为浏览器生成html) ...

    uber-sudoku:uber的代码示例

    超级数独 这是一个简单的Sudoku游戏实现,您可以输入数字并最终建立有效的完整Sudoku。 应用程序结构概述: -- index.html 主HTML文件 LIB 使用的javascript库 样式表CSS文件 js 这里所有JavaScript逻辑 图片将要...

    vambda:用漂亮的图形编写可视化的Lisp程序

    这张图片解决了数独问题。 不,确实如此! 用图形编写漂亮的程序。 Vambda是用于编写Lisp程序的视觉编辑器,重点在于美观和可视化逻辑结构。 您可以完全在浏览器中构建和运行程序(仅在Chrome中经过测试),无需...

    华为机试108题源码(题目&&解答)

    ├─037 数独问题 │ └─Debug ├─038 名字漂亮度 │ └─Source │ └─Debug ├─039 字符串截取 │ └─Source │ └─Debug ├─040 单链表删除数据 │ └─Source │ └─Debug ├─041 多线程 │ └─Source...

Global site tag (gtag.js) - Google Analytics