<!--******************************************************* * 基本就是按照自己平时解题的思路写下去的 * 运行效果可以参考: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>