大家可以将代码复制拷贝到本地HTML页面上直接运行查看效果。 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Sudoku</title> <mce:style type="text/css"><!-- #main { margin-left: 20px; float: left; } #main #info span { display:-moz-inline-box; display:inline-block; width:50px; text-align: right; } #main .area { float: left; border: 1px solid black; } #main .area div { width: 60px; height: 60px; border: 1px solid blue; float: left; } #main .area #template { width: 60px; height: 60px; border: 0; font-size: 12px; } #main .area #template div { width: 20px; height: 17px; border: 0; color: white; text-align: center; padding-top: 3px; } #main .area div .val { padding: 5px; width: 50px; height: 50px; font-size: 45px; border: 0; text-align: center; } #main .area div .y { background-color: gray; } br { clear: both; } #button { float: left; } #button button { width: 100px; padding: 3px 0; display: block; margin-bottom: 12px; } #button label { display: block; margin-bottom: 5px; } --></mce:style><style type="text/css" mce_bogus="1">#main { margin-left: 20px; float: left; } #main #info span { display:-moz-inline-box; display:inline-block; width:50px; text-align: right; } #main .area { float: left; border: 1px solid black; } #main .area div { width: 60px; height: 60px; border: 1px solid blue; float: left; } #main .area #template { width: 60px; height: 60px; border: 0; font-size: 12px; } #main .area #template div { width: 20px; height: 17px; border: 0; color: white; text-align: center; padding-top: 3px; } #main .area div .val { padding: 5px; width: 50px; height: 50px; font-size: 45px; border: 0; text-align: center; } #main .area div .y { background-color: gray; } br { clear: both; } #button { float: left; } #button button { width: 100px; padding: 3px 0; display: block; margin-bottom: 12px; } #button label { display: block; margin-bottom: 5px; }</style> <mce:script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" mce_src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></mce:script> <mce:script type="text/javascript"><!-- /* * MAP对象,实现MAP功能 * written by danny zhou, 2005-04-15 * 接口: * size() 获取MAP元素个数 * isEmpty() 判断MAP是否为空 * clear() 删除MAP所有元素 * put(key, value) 向MAP中增加元素(key, value) * remove(key) 删除指定KEY的元素,成功返回True,失败返回False * get(key) 获取指定KEY的元素值VALUE,失败返回NULL * element(index) 获取指定索引的元素(使用element.key,element.value获取KEY和VALUE), 失败返回NULL * containsKey(key) 判断MAP中是否含有指定KEY的元素 * containsValue(value) 判断MAP中是否含有指定VALUE的元素 * values() 获取MAP中所有VALUE的数组(ARRAY) * keys() 获取MAP中所有KEY的数组(ARRAY) * * 例子: * var map = new Map(); * * map.put("key", "value"); * var val = map.get("key") * …… * */ function Map() { this.elements = []; // 获取MAP元素个数 this.size = function() { return this.elements.length; } // 判断MAP是否为空 this.isEmpty = function() { return (this.elements.length < 1); } // 删除MAP所有元素 this.clear = function() { this.elements = []; } // 向MAP中增加元素(key, value) this.put = function(_key, _value) { this.elements.push({ key : _key, value : _value }); } // 删除指定KEY的元素,成功返回True,失败返回False this.remove = function(_key) { var bln = false; try { for (var i = this.elements.length - 1; i >=0; i--) { if (this.elements[i].key == _key) { this.elements.splice(i, 1); return true; } } } catch (e) { bln = false; } return bln; } // 获取指定KEY的元素值VALUE,失败返回NULL this.get = function(_key) { try { for (var i = this.elements.length - 1; i >=0; i--) { if (this.elements[i].key == _key) { return this.elements[i].value; } } } catch (e) { return null; } } // 获取指定索引的元素(使用element.key,element.value获取KEY和VALUE),失败返回NULL this.element = function(_index) { if (_index < 0 || _index >= this.elements.length) { return null; } return this.elements[_index]; } // 判断MAP中是否含有指定KEY的元素 this.containsKey = function(_key) { var bln = false; try { for (var i = this.elements.length - 1; i >=0; i--) { if (this.elements[i].key == _key) { bln = true; } } } catch (e) { bln = false; } return bln; } // 判断MAP中是否含有指定VALUE的元素 this.containsValue = function(_value) { var bln = false; try { for (var i = this.elements.length - 1; i >=0; i--) { if (this.elements[i].value == _value) { bln = true; } } } catch (e) { bln = false; } return bln; } // 获取MAP中所有VALUE的数组(ARRAY) this.values = function() { var arr = new Array(); for (var i = this.elements.length - 1; i >=0; i--) { arr.push(this.elements[i].value); } return arr; } // 获取MAP中所有KEY的数组(ARRAY) this.keys = function() { var arr = new Array(); for (var i = this.elements.length - 1; i >=0; i--) { arr.push(this.elements[i].key); } return arr; } // 覆盖toString() this.toString = function() { var result = ""; for (var i = this.elements.length - 1; i >=0; i--) { result += ", " + this.elements[i].key + "=" + this.elements[i].value; } result = "[" + result.substring(1) + "]"; return result; } } // --></mce:script> <mce:script type="text/javascript"><!-- /** * 数独解法算法 * author: thomas_z * email: zhao_xshg47@126.com */ $(function() { var timer = schema = nodes = order = t = a = b = 0, pause = false; var loop, temp, prior = step = [], map = new Map(); var $exhaust = $('#main #info span.exhaust'); var $visited = $('#main #info span.visited'); var _candidate = function(position, value) { // position like 'r1 c3 b1' var all = [1, 2, 3, 4, 5, 6, 7, 8, 9]; var result = ""; $.each(position.split(' '), function() { $('.' + this + ' .val').each(function() { delete all[$(this).text() - 1]; }); }); for (var v in all) { result += all[v]; } if (value) { result += value; } return result; }; var _pick = function(candidate, pos) { if (!order) { // 由低到高 return candidate.charAt(pos - 1); } else { // 由高到低 return candidate.charAt(candidate.length - pos); } } var _opposite = function(position) { //算出对立位置,旋转时使用 var c = 10 - parseInt(position.charAt(4)); return (position.substring(0, 4) + c); } var _position = function(schema) { var position = null; switch (schema) { case 0: for (var i = 0; i < 8; i++) { if (prior[i]) { position = prior[i][0]; break; } } break; case 1: for (var i = 0; i < 8; i++) { if (prior[i]) { position = prior[i][parseInt(prior[i].length/2)]; break; } } break; case 2: for (var i = 0; i < 8; i++) { if (prior[i]) { position = prior[i][prior[i].length - 1]; break; } } break; case 3: position = map.element(0).key; break; case 4: position = map.element(parseInt(map.size()/2)).key; break; case 5: position = map.element(map.size() - 1).key; break; } return position; } var populate = function(times) { t = times; if (pause) { return false; } a = new Date().getTime(); $exhaust.text(a - b); $visited.text(nodes); do { loop = false; map.clear(); prior = []; $('#main .area div:empty').each(function() { var $this = $(this); var position = $this.attr('class'); var cd = _candidate(position); if (cd.length == 1) { nodes++; $this.html('<div class="val t' + times + '">' + cd + '</div>'); loop = true; } else if (cd.length > 1) { map.put(position, cd); //以每个空格的可填数排放 temp = cd.length - 2; if (!prior[temp]) { prior[temp] = []; } prior[temp].push(position); } }); } while (loop); var empty = $('#main .area div:empty').length; if (empty) { // 如果空格数大于0, 说明还未结束 times++; if (empty == map.size()) { // 如果空格数等于收集到的map数,说明暂时填入的数字还没有问题 var position = _position(schema); var value = map.get(position); // 尝试填入下一个空格 step.push(position); var pos = 0; for (var i = step.length - 1; i >= 0; i--) { if (step[i] == position) { // 获取该节点被访问的次数 pos++; } } if (pos <= value.length) { // 如果某空格上可填入的数字还没有试全,则尝试下一个数字 nodes++; $("div[class=" + position + "]") .html('<div class="val t' + times + '">' + _pick(value, pos) + '</div>'); } else { // 如果全部尝试完了,说明上面的某个空格填入了错误的数字, 需要退到上一被填空格处 for (var i = 0; i < pos; i++) { step.pop(); } if (!step.length) { // 如果step被弹光了,说明此题无解 alert('NO ANSWER!'); $('button:contains("PAUSE")').attr("disabled", true); $('button:contains("COMPUTE")').attr("disabled", false); $('button:contains("NEW GAME")').attr("disabled", false); $('button:contains("REPLAY")').attr("disabled", false); return false; } times--; $("#main .area div .t" + times).remove(); times--; } } else { // 说明填入的数错了,需要回退一步 times--; $("#main .area div .t" + times).remove(); times--; } setTimeout(function() { populate(times); }, timer); } else { // 结束 a = new Date().getTime(); $exhaust.text(a - b); $visited.text(nodes); $('button:contains("PAUSE")').attr("disabled", true); $('button:contains("COMPUTE")').attr("disabled", false); $('button:contains("NEW GAME")').attr("disabled", false); $('button:contains("REPLAY")').attr("disabled", false); return ture; } } $('button:contains("NEW GAME")').click(function() { if (confirm("Start A New Game?")) { step = []; $('#main .area > div').empty(); $('#main #info span.count').text(0); $exhaust.text(0); $visited.text(0); $('button:contains("EDIT")').attr("disabled", false); $('button:contains("COMPUTE")').attr("disabled", false); $('button:contains("ROTATE")').attr("disabled", false); $('button:contains("CONTINUE")').text("PAUSE").attr("disabled", true); } }); $('button:contains("ROTATE")').click(function() { var init_nodes_pos_arr = []; $('#main .area > div .y').each(function() { init_nodes_pos_arr.push($(this).parent().attr('class')); }); for (var i = 0; i < init_nodes_pos_arr.length; i++) { var opposite = _opposite(init_nodes_pos_arr[i]); // 如果对应位置有数字,则从init_nodes_pos_arr中除去 for (var j = i + 1; j < init_nodes_pos_arr.length; j++) { if (init_nodes_pos_arr[j].indexOf(opposite) > -1) { init_nodes_pos_arr.splice(j, 1); break; } } // 交换数据 var $opposite = $('div[class^=' + opposite + ']').children().remove(); $('div[class^=' + opposite + ']') .html($('div[class=' + init_nodes_pos_arr[i] + ']').children()); $('div[class=' + init_nodes_pos_arr[i] + ']').html($opposite); } }); $('button:contains("REPLAY")').click(function() { if (confirm("REPLAY?")) { step = []; $exhaust.text(0); $visited.text(0); $('#main .area > div .val').not('.y').remove(); $('button:contains("EDIT")').attr("disabled", false); $('button:contains("COMPUTE")').attr("disabled", false); $('button:contains("ROTATE")').attr("disabled", false); $('button:contains("CONTINUE")').text("PAUSE").attr("disabled", true); } }); $('button:contains("EDIT")').click(function() { var $this = $(this); if ($this.text() == "EDIT DONE") { $this.text("EDITING"); $('#main .area > div').click(function() { if (!$('#main #template').length) { var $this = $(this); var cd = _candidate($this.attr('class'), $this.text()); $this.empty().append($('#template').clone().show()); $.each(cd.split(''), function() { $('#main .area #template div:contains(' + this + ')') .css({'color': 'black', 'cursor': 'pointer'}) .hover(function() { $(this).css({'background-color': 'yellow'}); }, function() { $(this).css({'background-color': 'white'}); }) .click(function(event) { event.stopPropagation(); $this.html('<div class="val y">' + $(this).text() + '</div>'); }); }); } }); } else { // $(this).text() == "EDIT DONE" if ($('#main .area #template').length) { alert('NO'); return false; } step = []; $(this).text("EDIT DONE"); $('#main #info span.count').text($('#main .area > div .y').length); $('#main div').unbind('click'); } }); $('button:contains("COMPUTE")').click(function() { if (!$('button:contains("EDIT DONE")').length) { alert('Please Click EDITING Button'); return false; } b = new Date().getTime(); pause = false; nodes = t = 0; timer = $('#timer').val(); order = parseInt($('#order').val()); schema = parseInt($('#schema').val()); $exhaust.text(0); $(this).attr("disabled", true); $('button:contains("NEW GAME")').attr("disabled", true); $('button:contains("EDIT")').attr("disabled", true); $('button:contains("ROTATE")').attr("disabled", true); $('button:contains("REPLAY")').attr("disabled", true); $('button:contains("PAUSE")').attr("disabled", false); // recursive // populate the first time populate(t); }); $('#main #info span.count').text($('#main .area > div .y').length); $('#main .area > div').dblclick(function() { $(this).empty(); }); $('button:contains("PAUSE")').click(function() { if ($(this).text() == "PAUSE") { pause = true; $(this).text("CONTINUE"); $('button:contains("NEW GAME")').attr("disabled", false); $('button:contains("REPLAY")').attr("disabled", false); } else { // "CONTINUE" pause = false; $(this).text("PAUSE"); $('button:contains("NEW GAME")').attr("disabled", true); $('button:contains("EDIT")').attr("disabled", true); $('button:contains("REPLAY")').attr("disabled", true); populate(t); } }); }); // --></mce:script> </head> <body> <div id="button"> <button>NEW GAME</button> <button>EDIT DONE</button> <button>ROTATE</button> <button>REPLAY</button> <label for="timer">DELAY: <select id="timer" name="timer"> <option value="0">0</option> <option value="50">50</option> <option value="500">500</option> <option value="1000">1000</option> <option value="1500">1500</option> <option value="2000">2000</option> </select> ms </label> <label for="order">PICK ORDER: <select id="order" name="order"> <option value="0">ASC</option> <option value="1">DESC</option> </select> </label> <label for="schema">ENTRY: <select id="schema" name="schema"> <option value="0">TOP-LEFT(FAST)</option> <option value="1">CENTER(FAST)</option> <option value="2">BOTTOM-RIGHT(FAST)</option> <option value="3">TOP-LEFT(NORMAL)</option> <option value="4">CENTER(NORMAL)</option> <option value="5">BOTTOM-RIGHT(NORMAL)</option> </select> </label> <button>COMPUTE</button> <button disabled="disabled">PAUSE</button> </div> <div id="main"> <div id="info"> INITIAL NUMBERS: <span class="count"></span>, EXHAUST: <span class="exhaust">0</span>ms, VISITED: <span class="visited">0</span>nodes. </div> <div class="area"> <div class="r1 c1 b1"><div class="val y">7</div></div> <div class="r1 c2 b1"></div> <div class="r1 c3 b1"></div> <br> <div class="r2 c1 b1"></div> <div class="r2 c2 b1"><div class="val y">2</div></div> <div class="r2 c3 b1"></div> <br> <div class="r3 c1 b1"></div> <div class="r3 c2 b1"></div> <div class="r3 c3 b1"><div class="val y">6</div></div> </div> <div class="area"> <div class="r1 c4 b2"></div> <div class="r1 c5 b2"></div> <div class="r1 c6 b2"></div> <br> <div class="r2 c4 b2"><div class="val y">1</div></div> <div class="r2 c5 b2"></div> <div class="r2 c6 b2"></div> <br> <div class="r3 c4 b2"></div> <div class="r3 c5 b2"></div> <div class="r3 c6 b2"></div> </div> <div class="area"> <div class="r1 c7 b3"></div> <div class="r1 c8 b3"></div> <div class="r1 c9 b3"><div class="val y">3</div></div> <br> <div class="r2 c7 b3"></div> <div class="r2 c8 b3"><div class="val y">9</div></div> <div class="r2 c9 b3"></div> <br> <div class="r3 c7 b3"><div class="val y">8</div></div> <div class="r3 c8 b3"></div> <div class="r3 c9 b3"></div> </div> <br> <div class="area"> <div class="r4 c1 b4"></div> <div class="r4 c2 b4"><div class="val y">5</div></div> <div class="r4 c3 b4"></div> <br> <div class="r5 c1 b4"></div> <div class="r5 c2 b4"></div> <div class="r5 c3 b4"></div> <br> <div class="r6 c1 b4"></div> <div class="r6 c2 b4"></div> <div class="r6 c3 b4"></div> </div> <div class="area"> <div class="r4 c4 b5"><div class="val y">4</div></div> <div class="r4 c5 b5"></div> <div class="r4 c6 b5"><div class="val y">1</div></div> <br> <div class="r5 c4 b5"></div> <div class="r5 c5 b5"><div class="val y">6</div></div> <div class="r5 c6 b5"></div> <br> <div class="r6 c4 b5"><div class="val y">5</div></div> <div class="r6 c5 b5"></div> <div class="r6 c6 b5"><div class="val y">7</div></div> </div> <div class="area"> <div class="r4 c7 b6"></div> <div class="r4 c8 b6"></div> <div class="r4 c9 b6"></div> <br> <div class="r5 c7 b6"></div> <div class="r5 c8 b6"></div> <div class="r5 c9 b6"></div> <br> <div class="r6 c7 b6"></div> <div class="r6 c8 b6"><div class="val y">4</div></div> <div class="r6 c9 b6"></div> </div> <br> <div class="area"> <div class="r7 c1 b7"></div> <div class="r7 c2 b7"></div> <div class="r7 c3 b7"><div class="val y">8</div></div> <br> <div class="r8 c1 b7"></div> <div class="r8 c2 b7"><div class="val y">1</div></div> <div class="r8 c3 b7"></div> <br> <div class="r9 c1 b7"><div class="val y">3</div></div> <div class="r9 c2 b7"></div> <div class="r9 c3 b7"></div> </div> <div class="area"> <div class="r7 c4 b8"></div> <div class="r7 c5 b8"></div> <div class="r7 c6 b8"></div> <br> <div class="r8 c4 b8"></div> <div class="r8 c5 b8"></div> <div class="r8 c6 b8"><div class="val y">4</div></div> <br> <div class="r9 c4 b8"></div> <div class="r9 c5 b8"></div> <div class="r9 c6 b8"></div> </div> <div class="area"> <div class="r7 c7 b9"><div class="val y">7</div></div> <div class="r7 c8 b9"></div> <div class="r7 c9 b9"></div> <br> <div class="r8 c7 b9"></div> <div class="r8 c8 b9"><div class="val y">2</div></div> <div class="r8 c9 b9"></div> <br> <div class="r9 c7 b9"></div> <div class="r9 c8 b9"></div> <div class="r9 c9 b9"><div class="val y">6</div></div> </div> <br> </div> <div id="template" style="display: none;" mce_style="display: none;"> <div>1</div> <div>2</div> <div>3</div> <br/> <div>4</div> <div>5</div> <div>6</div> <br/> <div>7</div> <div>8</div> <div>9</div> <br/> </div> </body> </html>