用JavaScript写的数独算法

<!--*******************************************************
*	基本就是按照自己平时解题的思路写下去的
*	运行效果可以参考:http://jameschn.weebly.com
********************************************************-->
<style type="text/css">



<!--

.num_input_white {

width:30px;

height:30px;

align:middle;

valign:middle;

background-color:ffffff;

text-align: center;

font-size: 20px;

font: bold;

color: bule;

}



.num_input_blue {

width:30px;

height:30px;

align:middle;

valign:middle;

background-color:#ccffff;

text-align: center;

font-size: 20px;

font: bold;

color: bule;

}

--></style><SCRIPT language=JavaScript>

<!--

var puzzle = new Array();			//用于存储数独的数组

var stock_puzzle = new Array();		//猜测结果时存放状态的堆栈

var stock_fill = new Array();			//猜测时存放可能结果的堆栈

var pop_fill = new Array();			//读出堆栈的数独状态时临时存放位置



/***************************************************************

*

*	唯一法:

*	通过判断相应位置的行,列,九宫格里已经填入的数字

*	当有唯一值则填入

*	当多于一个值的时候则返回准备下一轮填写

*	无法填入任何值则返回准备回溯

*

****************************************************************/



function get_unique(i,j)

{



	num_enable = new Array();		//可填入的数字

	num_exist = new String();		//行,列,九宫格中已经填入的数字

	

	for(k=0;k<9;k++)

	{//查看行,列

		if (puzzle[i][k] != "")

		{//查看行

			if(num_exist.indexOf(puzzle[i][k]) == -1)

			{//如果未加入存在字符串则添加进去

				num_exist = num_exist + puzzle[i][k].toString();

			}	

		}

		

		if (puzzle[k][j] != "")

		{//查看列

			if(num_exist.indexOf(puzzle[k][j]) == -1)

			{//同上

				num_exist = num_exist + puzzle[k][j].toString();

			}

		}

	}

	

	for(p=(Math.floor(i/3)*3);p<(Math.floor(i/3)*3)+3;p++)

	{//查看九宫格

		for(q=(Math.floor(j/3)*3);q<(Math.floor(j/3)*3)+3;q++)

		{

			if (puzzle[p][q] != "")

			{

				if(num_exist.indexOf(puzzle[p][q]) == -1)

				{

					num_exist = num_exist + puzzle[p][q].toString();

				}

			}	

		}

	}

	

	if (num_exist.length > 8)

	{//当该位置其他的行,列,九宫格上已经填入所有的数字,表示该位置已经无法再填写数字

		return -1;		//返回-1准备回溯

	}



	for(k=1;k<10;k++)

	{//开始判断该位置可以填写的数字

		if(num_exist.indexOf(k) == -1)

		{//如果可填写则添加到num_enable数组中

			num_enable.push(k);

		}		

	}



	if(num_enable.length != 1)

	{//如果该数组不是唯一值,则待定

		return 0;		//返回0表示下一轮再尝试填写

	}

	

	puzzle[i][j] = num_enable[0];	//当判断到唯一值的时候填写进去

	return 1;				//并返回1表示填写成功

	

}



/***************************************************************

*

*	覆盖法:

*	根据已经填写的数字,覆盖该数字相应的行,列,九宫格

*	再判断各行,列,九宫格里如果只有一个位置未覆盖,则填写该数字

*

****************************************************************/



function get_cover(num)

{

	var cover_state = new Array();		//存储覆盖状态

	var row = new Array();		//初始化多维数组临时行数组

	result = false;			//初始化覆盖结果

	

	for(i=0;i<9;i++)

	{//初始化覆盖状态为0

		row = Array();

		for(j=0;j<9;j++)

		{

			row[j] = 0;	

		}

		cover_state[i] = row;

	}

	

	for(i=0;i<9;i++)

	{//已经填写数字的位置都设为1

		for(j=0;j<9;j++)

		{

			if (puzzle[i][j] != "")

			{

				cover_state[i][j] = 1;

			}

		}

	}

	

	for(i=0;i<9;i++)

	{

		for(j=0;j<9;j++)

		{

			if (puzzle[i][j] == num)

			{

				for(k=0;k<9;k++)

				{//设置行,列的覆盖状态

					cover_state[i][k] = 1;

					cover_state[k][j] = 1;

				}

				

				for(p=(Math.floor(i/3)*3);p<(Math.floor(i/3)*3)+3;p++)

				{//设置九宫格的覆盖状态

					for(q=(Math.floor(j/3)*3);q<(Math.floor(j/3)*3)+3;q++)

					{	

						cover_state[p][q] = 1;

					}

				}

			}	

		}

	}

	

	for(i=0;i<9;i++)

	{//查看行,列中未被覆盖的位置个数

		countX = 0;		//初始化行未被覆盖的个数

		countY = 0;		//初始化列为被覆盖的个数

		

		for(j=0;j<9;j++)

		{

			if (cover_state[i][j] == 0)

			{

				countX++;

			}

			if (cover_state[j][i] == 0)

			{

				countY++;

			}

		}

		

		if (countX == 1)

		{//如果行里只有一个未被覆盖的位置

			for(j=0;j<9;j++)

			{//则查找该位置填入相应数字

				if (cover_state[i][j] == 0)

				{

					puzzle[i][j] = num;

					result = true;	//并设置填写结果,表明该轮已经填入过数字

				}

			}

		}

		

		if (countY == 1)

		{//同上,查看列

			for(j=0;j<9;j++)

			{

				if (cover_state[j][i] == 0)

				{

					puzzle[j][i] = num;

					result = true;

				}

			}

		}

	}

	

	for(i=0;i<9;i+=3)

	{//同上,查看九宫格

		for(j=0;j<9;j+=3)

		{

			countZ = 0;

			

			for(p=i;p<i+3;p++)

			{

				for(q=j;q<j+3;q++)

				{

					if (cover_state[p][q] == 0)

					{

						countZ++;

					}

				}

			}

			

			if (countZ == 1)

			{

				for(p=i;p<i+3;p++)

				{

					for(q=j;q<j+3;q++)

					{

						if (cover_state[p][q] == 0)

						{

							puzzle[p][q] = num;

							

							result = true;

						}

					}

				}

			}

		}

	}

	

	return result;	

}





/***************************************************************

*

*	当通过以上两种算法未能得到最终解的时候

*	通过猜测继续进行解题

*	猜测前先把当前的题目跟可填入数字进行压栈处理

*

****************************************************************/



function push_filled()

{

	var num_exist = new String();		//当前位置相应的行,列,九宫格中已经填入的数字字符串



	for(i=0;i<9;i++)

	{

		for(j=0;j<9;j++)

		{

			if (puzzle[i][j] == "")

			{//查找第一个还未填写数字的位置			

				//获取该位置相应的行,列,九宫格中已经填入的数字

				for(k=0;k<9;k++)

				{//行,列

					if (puzzle[i][k] != "")

					{

						if(num_exist.indexOf(puzzle[i][k]) == -1)

						{

							num_exist = num_exist + puzzle[i][k].toString();

						}	

					}

					

					if (puzzle[k][j] != "")

					{

						if(num_exist.indexOf(puzzle[k][j]) == -1)

						{

							num_exist = num_exist + puzzle[k][j].toString();

						}

					}

				}

				

				for(p=(Math.floor(i/3)*3);p<(Math.floor(i/3)*3)+3;p++)

				{//九宫格

					for(q=(Math.floor(j/3)*3);q<(Math.floor(j/3)*3)+3;q++)

					{

						if (puzzle[p][q] != "")

						{

							if(num_exist.indexOf(puzzle[p][q]) == -1)

							{

								num_exist = num_exist + puzzle[p][q].toString();

							}

						}	

					}

				}	

				

				for(k=1;k<10;k++)

				{//获取所有可能的数字

					if(num_exist.indexOf(k) == -1)

					{//将可填入数字的位置,数字及当前题目状态进行压栈

						stock_fill.push(i+","+j+","+k);

						stock_puzzle.push(puzzle.toString());

					}		

				}

				return true;	//表明已经有数据入栈

			}

	

		}

	}

	

	return false;		//一直没有数据入栈,即表示所有题目已经答完

}



/***************************************************************

*

*	题目状态是以字符串进行压栈

*	该函数将字符串题目状态还原

*

****************************************************************/



function strToPuzzle(str)

{

	arr = str.split(",");

	

	for(i=0;i<9;i++)

	{

		for(j=0;j<9;j++)

		{

			puzzle[i][j] = arr[i*9+j];

		}

	}	

}



/***************************************************************

*

*	进行答题

*	当最先两种算法无法完成题目时进行猜测

*	猜测时如果遇到某一个位置无法填入任何数字时

*	则进行出栈处理,进行回溯继续答题

*

****************************************************************/



function answer()

{

	var filled = true;			//表示一轮循环中已经填入了至少一个数字

	var pop_puzzle = new String();		//存储从堆栈里读取的题目状态

	

	while (filled)

	{//如果填入过数字则继续答题	

		filled = false;

		

		for(i=0;i<9;i++)

		{

			for(j=0;j<9;j++)

			{

				if (puzzle[i][j] == "")

				{//对各个为填入数字的地方用唯一法进行答题

					result = get_unique(i,j);

					if (result == -1)

					{//如果某个位置无法填入任何值,则进行回溯

						if (stock_fill.length > 0)

						{//堆栈不为空则可继续进行回溯答题

							pop_puzzle = stock_puzzle.pop();		//题目状态出栈

							strToPuzzle(pop_puzzle);			//还原题目

							get_fill = stock_fill.pop();			//可能值出栈

							pop_fill = get_fill.split(",");			

							puzzle[pop_fill[0]][pop_fill[1]] = pop_fill[2];	//填入可能值

							answer();					//继续答题

						}

						else

						{//堆栈以空,表明无法继续进行答题

							return false;

						}

					}

					else if (result == 1)

					{//表明该位置已经通过唯一法填入了某一个数字

						filled = true;

					}

				}	

			}			

		}

		

		for(z=1;z<9;z++)

		{//以覆盖法进行答题

			result = get_cover(z);

			

			if (result == 1)

			{

				filled = true;

			}

		}

	}

		

	if (push_filled())

	{//题目还未打完,则表示要进行猜测了,出栈操作同上			

		pop_puzzle = stock_puzzle.pop();

		strToPuzzle(pop_puzzle);

		get_fill = stock_fill.pop();

		pop_fill = get_fill.split(",");

		puzzle[pop_fill[0]][pop_fill[1]] = pop_fill[2];

		answer();

	}

	else

	{//题目已经答完

		return true;

	}

		

}



/***************************************************************

*

*	查看题目是否有解

*	对题目中某一个数字进行行,列,九宫格对照

*	如果其中有重复的值则表明该题目无解

*

****************************************************************/



function check_puzzle()

{

	for(i=0;i<9;i++)

	{

		for(j=0;j<9;j++)

		{

			if(puzzle[i][j] != "")

			{

			

				for(k=0;k<9;k++)

				{//查看行,列

					if (puzzle[i][k] == puzzle[i][j] && k != j)

					{

						return false;	//无解

					}

					

					if (puzzle[k][j] == puzzle[i][j] && k != i)

					{

						return false;	//无解

					}

				}

				

				for(p=(Math.floor(i/3)*3);p<(Math.floor(i/3)*3)+3;p++)

				{//查看九宫格

					for(q=(Math.floor(j/3)*3);q<(Math.floor(j/3)*3)+3;q++)

					{

						if (puzzle[p][q] == puzzle[i][j] && p != i && q != j)

						{

							return false;	//无解

						}	

					}

				}

					

			}			

		}

	}

	

	return true;		//有解	

}





/***************************************************************

*

*	填写表单

*	将结果填入到html表单中

*

****************************************************************/



function fill_input()

{

	for(i=0;i<9;i++)

	{

		for(j=0;j<9;j++)

		{

			document.getElementById("num_"+i+"_"+j).value = puzzle[i][j];			

		}

	}		

}





/***************************************************************

*

*	相应用户按键,进行答题

*

****************************************************************/



function get_answer()

{

	var row = new Array();

	for(i=0;i<9;i++)

	{//读取表单的数字,初始化题目

		row = Array();

		for(j=0;j<9;j++)

		{

			row[j] = document.getElementById("num_"+i+"_"+j).value;

			

			if(document.getElementById("num_"+i+"_"+j).value != "")

			{

				document.getElementById("num_"+i+"_"+j).style.color = "red";

			}

		}

		puzzle[i] = row;

	}

	

	if (check_puzzle())

	{//如果该题目有解,则进行答题

		answer();

		fill_input();

		alert("Finished!");

	}

	else

	{

		alert("No Answers!");

	}

}



//-->

</SCRIPT>

<h1>Sudoku Puzzle</h1>

<form action="test.php" method="post" name="num_form">

    <table cellspacing="0" cellpadding="0" border="0">

        <tbody>

            <tr>

                <td><input class="num_input_blue" maxlength="1" name="num_0_0" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_0_1" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_0_2" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_0_3" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_0_4" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_0_5" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_0_6" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_0_7" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_0_8" /></td>

            </tr>

            <tr>

                <td><input class="num_input_blue" maxlength="1" name="num_1_0" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_1_1" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_1_2" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_1_3" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_1_4" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_1_5" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_1_6" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_1_7" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_1_8" /></td>

            </tr>

            <tr>

                <td><input class="num_input_blue" maxlength="1" name="num_2_0" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_2_1" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_2_2" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_2_3" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_2_4" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_2_5" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_2_6" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_2_7" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_2_8" /></td>

            </tr>

            <tr>

                <td><input class="num_input_white" maxlength="1" name="num_3_0" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_3_1" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_3_2" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_3_3" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_3_4" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_3_5" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_3_6" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_3_7" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_3_8" /></td>

            </tr>

            <tr>

                <td><input class="num_input_white" maxlength="1" name="num_4_0" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_4_1" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_4_2" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_4_3" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_4_4" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_4_5" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_4_6" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_4_7" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_4_8" /></td>

            </tr>

            <tr>

                <td><input class="num_input_white" maxlength="1" name="num_5_0" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_5_1" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_5_2" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_5_3" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_5_4" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_5_5" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_5_6" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_5_7" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_5_8" /></td>

            </tr>

            <tr>

                <td><input class="num_input_blue" maxlength="1" name="num_6_0" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_6_1" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_6_2" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_6_3" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_6_4" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_6_5" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_6_6" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_6_7" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_6_8" /></td>

            </tr>

            <tr>

                <td><input class="num_input_blue" maxlength="1" name="num_7_0" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_7_1" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_7_2" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_7_3" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_7_4" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_7_5" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_7_6" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_7_7" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_7_8" /></td>

            </tr>

            <tr>

                <td><input class="num_input_blue" maxlength="1" name="num_8_0" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_8_1" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_8_2" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_8_3" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_8_4" /></td>

                <td><input class="num_input_white" maxlength="1" name="num_8_5" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_8_6" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_8_7" /></td>

                <td><input class="num_input_blue" maxlength="1" name="num_8_8" /></td>

            </tr>

            <tr>

                <td colspan="9" height="10"> </td>

            </tr>

            <tr>

                <td colspan="9"><input οnclick="javascript:get_answer();" type="button" value="    GET    " /> <input type="reset" value="    RESET    " /></td>

            </tr>

        </tbody>

    </table>

</form>
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值