ナンプレの基本インターフェイスを前回構築したんですが、やはり自動回答と自動問題作成機能を作らないとチャンとしたゲームとは言えないでしょう。
そこで、今回は問題を自動で回答する、機能に挑戦してみました。
最初に行っておきますが、ナンプレには、レベルがあって、初級、中級、上級とあり、今回は初級問題にのみ対応できるプログラムになっています。
前回のおさらい
前回は、ナンプレの基本表示部分と、入力処理、回答を入力した後の正解チェック機能を作ってます。
基本的にjavascriptだけで動作する事を目的にしてますが、問題読み込み機能でajaxを使っているので、ファイル表示では動作しないので、読み込み機能を使うときは仮想環境か、サーバーに配置して使ってください。
今回の機能概要
「初級の自動回答機能」として、以下の処理を実現してます。
1. 空欄の箇所に入る可能性のある数値を仮登録
2. 縦、横、3x3の箱でのユニーク値チェック
3. チェックを複数回繰り返す反復処理
ソースコード
今回の変更点は「numberplace.js」のみだけですが、とりあえず全てのソースコードを載せておきます。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<title>NumberPlace</title>
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache">
<meta http-equiv="Expires" content="Thu, 01 Dec 1994 16:00:00 GMT">
<link type='text/css' rel='stylesheet' href='css/numberplace.css' />
<script type='text/javascript' src='js/lib.js'></script>
<script type='text/javascript' src='js/numberplace.js'></script>
</head>
<body class='design_black' data-transition='scroll_stop'>
<h1>NumberPlace</h1>
<hr>
<div id='game'>
<table class="numberplace">
<tr><td></td><td></td><td></td> <td></td><td></td><td></td> <td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td> <td></td><td></td><td></td> <td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td> <td></td><td></td><td></td> <td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td> <td></td><td></td><td></td> <td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td> <td></td><td></td><td></td> <td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td> <td></td><td></td><td></td> <td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td> <td></td><td></td><td></td> <td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td> <td></td><td></td><td></td> <td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td> <td></td><td></td><td></td> <td></td><td></td><td></td></tr>
</table>
</div>
<div id="key">
<table class="numberKey">
<tr>
<td data-key="1">1</td>
<td data-key="2">2</td>
<td data-key="3">3</td>
</tr>
<tr>
<td data-key="4">4</td>
<td data-key="5">5</td>
<td data-key="6">6</td>
</tr>
<tr>
<td data-key="7">7</td>
<td data-key="8">8</td>
<td data-key="9">9</td>
</tr>
<tr>
<td class="clear" data-key="" colspan="3">clear</td>
</tr>
</table>
</div>
<hr>
<div>
<button id="clear">Clear</button>
<button id="solve">Solve</button>
<button id="finish">Finish</button>
</div>
<div>
<button id="load">Load</button>
<button id="save">Save</button>
</div>
<!-- <div>
<button id="programSave">Program-Save</button>
<button id="programLoad">Program-Load</button>
</div> -->
<hr>
<ol id="lists">
</ol>
</body>
</html>
body,html{
width:100%;
height:100%;
}
body{
text-align:center;
}
#game{
display:inline-block;
box-shadow:4px 4px 4px rgba(0,0,0,0.4);
margin:auto auto;
}
table{
border-collapse:collapse;
}
td{
padding:0;
margin:0;
}
/*numberPlace*/
.numberplace td{
width:32px;
height:32px;
border:1px solid #666;
cursor:pointer;
text-align:center;
vertical-align:middle;
background-color:white;
font-size:20px;
font-weight:bold;
}
.numberplace td:hover{
background-color:#DDD;
}
.numberplace tr:nth-child(1){
border-top:2px solid #000;
}
.numberplace tr:nth-child(3){
border-bottom:2px solid #000;
}
.numberplace tr:nth-child(6){
border-bottom:2px solid #000;
}
.numberplace tr:nth-child(9){
border-bottom:2px solid #000;
}
.numberplace td:nth-child(1){
border-left:2px solid #000;
}
.numberplace td:nth-child(3){
border-right:2px solid #000;
}
.numberplace td:nth-child(6){
border-right:2px solid #000;
}
.numberplace td:nth-child(9){
border-right:2px solid #000;
}
/*action*/
#game .numberplace td{
background-color:#FFF;
}
#game .numberplace td[data-enable="false"]{
background-color:#EEE;
}
#game .numberplace td[data-enable="active"]{
background-color:#FEE;
}
#game .numberplace td[data-enable="target"]{
background-color:#FCC;
}
#game .numberplace td[data-enable="bad"]{
background-color:#CCF;
}
#game .numberplace td[data-enable="complete"]{
background-color:#FFC;
}
/*numberKey*/
#key{
position:absolute;
display:none;
box-shadow:10px 10px 10px rgba(0,0,0,0.4);
margin:8px;
}
.numberKey td{
width:40px;
height:40px;
background-color:blue;
color:white;
cont-weight:bold;
text-align:center;
vertical-align:middle;
font-size:32px;
border:1px solid white;
cursor:pointer;
}
.numberKey td.clear{
width:auto;
background-color:#666;
font-size:24px;
}
.numberKey td:hover{
background-color:red;
}
.numberKey td:active{
background-color:black;
}
/*etc*/
button{
margin:8px;
font-size:12px;
font-weight:bold;
cursor:pointer;
border:1px solid #CCC;
border-radius:4px;
padding:8px;
}
button:hover{
opacity:0.5;
}
#lists li{
text-align:left;
cursor:pointer;
font-size:24px;
}
!(function(){
var $$={};
/**
* Library ---------------------
*/
/**
* Event-Set
* param @ t : Target-element
* param @ m : mode ["onload"->"load" , "onclick"->"click"]
* param @ f : function
**/
$$.eventAdd=function(t, m, f){
//other Browser
if (t.addEventListener){t.addEventListener(m, f, false)}
//IE
else{
if(m=='load'){
var body = document.body;
if(typeof(body)!='undefined'){body = w;}
if((typeof(onload)!='undefined' && typeof(body.onload)!='undefined' && onload == body.onload) || typeof(eval(onload))=='object'){
t.attachEvent('on' + m, function() { f.call(t , window.event); });
}
else{f.call(t, w.event)}
}
else{t.attachEvent('on' + m, function() { f.call(t , window.event); })}
}
};
/**
* Get URL-property
* return @ [url , domain , querys{}];
**/
$$.urlProperty=function(url){
if(!url){url=location.href}
var res = {};
var urls = url.split("?");
res.url = urls[0];
res.domain = urls[0].split("/")[2];
res.querys={};
if(urls[1]){
var querys = urls[1].split("&");
for(var i=0;i<querys.length;i++){
var keyValue = querys[i].split("=");
if(keyValue.length!=2||keyValue[0]===""){continue}
res.querys[keyValue[0]] = keyValue[1];
}
}
return res;
};
/**
* Ajax
* $$.ajax.set({
* url:"**",
* method:"POST",
* async:true,
* query:{},
* querys:[],
* onSuccess:function(){}
* });
**/
$$.ajax = {
createHttpRequest:function(){
//Win ie用
if(window.ActiveXObject){
//MSXML2以降用;
try{return new ActiveXObject("Msxml2.XMLHTTP")}
catch(e){
//旧MSXML用;
try{return new ActiveXObject("Microsoft.XMLHTTP")}
catch(e2){return null}
}
}
//Win ie以外のXMLHttpRequestオブジェクト実装ブラウザ用;
else if(window.XMLHttpRequest){return new XMLHttpRequest()}
else{return null}
},
//XMLHttpRequestオブジェクト生成
set:function(options){
if(!options){return}
var httpoj = new $$.ajax.createHttpRequest();
if(!httpoj){return;}
//open メソッド;
option = $$.ajax.setOption(options);
httpoj.open( option.method , option.url , option.async );
//type
//httpoj.setRequestHeader('Content-Type', option.type);
if(typeof option.type != "undefined"){
httpoj.setRequestHeader('Content-Type', option.type);
}
else{
httpoj.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
}
//onload-check
// httpoj.onreadystatechange = this.readystate(httpoj,option);
httpoj.onreadystatechange = function(){
//readyState値は4で受信完了;
if (httpoj.readyState==4){
//コールバック
option.onSuccess(httpoj.responseText);
}
};
//query整形
var data = $$.ajax.setQuery(option);
//send メソッド
if(data.length){
httpoj.send(data.join("&"));
}
else{
httpoj.send();
}
},
dataOption:{
url:"",
query:{}, // same-key Nothing
querys:[], // same-key OK
data:{}, // ETC-data event受渡用
async:"true", // [trye:非同期 false:同期]
method:"POST", // [POST / GET]
type:"application/x-www-form-urlencoded", // [text/javascript]...
//call-back
onSuccess:function(res){console.log("Success:"+res)},
onError:function(res){console.log("Error:"+res)}
},
setOption:function(options){
var option = {};
for(var i in $$.ajax.dataOption){
if(typeof options[i] != "undefined"){
option[i] = options[i];
}
else{
option[i] = $$.ajax.dataOption[i];
}
}
return option;
},
setQuery:function(option){
var data = [];
if(typeof option.query != "undefined"){
for(var i in option.query){
data.push(i+"="+encodeURIComponent(option.query[i]));
}
}
if(typeof option.querys != "undefined"){
for(var i=0;i<option.querys.length;i++){
if(typeof option.querys[i] == "Array"){
data.push(option.querys[i][0]+"="+encodeURIComponent(option.querys[i][1]));
}
else{
var sp = option.querys[i].split("=");
data.push(sp[0]+"="+encodeURIComponent(sp[1]));
}
}
}
return data;
},
_:0
};
//path-info Ex):p=location.href
$$.pathinfo = function(p){
var basename="",
dirname=[],
filename=[],
ext="";
var p2 = p.split("?");
var urls = p2[0].split("/");
for(var i=0; i<urls.length-1; i++){
dirname.push(urls[i]);
}
basename = urls[urls.length-1];
var basenames = basename.split(".");
for(var i=0;i<basenames.length-1;i++){
filename.push(basenames[i]);
}
ext = basenames[basenames.length-1];
return {
"hostname":urls[2],
"basename":basename,
"dirname":dirname.join("/"),
"filename":filename.join("."),
"extension":ext,
"query":(p2[1])?p2[1]:"",
"path":p2[0]
};
};
$$.urlinfo=function(uri){
if(!uri){uri = location.href}
var url = uri;
//URLとクエリ分離分解;
var query={};
// set-query
if(uri.indexOf("?")!=-1){
var sp1 = uri.split("?");
url = sp1[0];
query = $$.getQuery(sp1[1],"&","=");
}
// semi-colon-split
else if(uri.indexOf(";")!=-1){
var sp = uri.split(";");
url = sp[0];
query = $$.getQuery(sp1[1],";","=");
}
//基本情報取得;
var sp = url.split("/");
var selfpath = "";
for(var i=3;i<sp.length;i++){
//selfpaths.push(sp[i]);
selfpath += "/"+sp[i];
}
var data={
url:url,
dirname:this.pathinfo(url).dirname,
domain:sp[2],
protocol:sp[0].replace(":",""),
selfpath:selfpath,
query:query
};
return data;
};
// ex) $$.getQuery("a=1&b=2&c=3","&","=");
$$.getQuery = function(data, splitValue, keyValueSplit){
var query = {};
var sp = data.split(splitValue);
for(var i=0; i<sp.length; i++){
var sp2 = sp[i].split(keyValueSplit);
query[sp2[0]] = sp2[1];
}
return query;
};
//cookie
$$.cookie = {
//init-data
options:{
name : 'temporary_cookie',
day : 0,
hour : 0,
min : 1,
sec : 0
},
//expires
date : function(add) {
if(!add){add = 0}
var exp = new Date();
if(add){
exp.setTime(exp.getTime()+ add);
}
else{
exp.setTime(exp.getTime()
+ (this.options.day * 1000 * 60 * 60 * 24)
+ (this.options.hour * 1000 * 60 * 60)
+ (this.options.min * 1000 * 60)
+ (this.options.sec * 1000));
}
return exp.toGMTString();
},
//secure-check
checkSecure : function() {
if (location.href.match(/^https:/)) {return true}
else {return false}
},
set : function(name, val, addTime) {
if(!addTime){addTime = 3600;}
if(!name){name = this.options.name}
val = this.encode(val);
if (this.checkSecure()) {
document.cookie = name + "=" + val + ";expires=" + this.date(addTime) + ";secure";
}
else {
document.cookie = name + "=" + val + ";expires=" + this.date(addTime);
}
},
del : function(name){
if(!name){name = this.options.name}
var exp = new Date();
exp.setTime(exp.getTime()-1);
var d = exp.toGMTString();
if (this.checkSecure()) {
document.cookie = name + "='';expires=" + d + ";secure";
}
else {
document.cookie = name + "='';expires=" + d;
}
},
get : function(name){
return this.val(name);
},
val : function(name) {
var ck0 = document.cookie.split(" ").join("");
var ck1 = ck0.split(";");
for ( var i = 0; i < ck1.length; i++) {
var ck2 = ck1[i].split("=");
if (ck2[0] == name) {
ck2[1] = this.encode(ck2[1]);
return ck2[1];
}
}
return '';
},
encode:function(val){
if (!val) {return ""}
val = val.split("¥r") .join("");
val = val.split("¥n") .join("");
val = val.split("<") .join("-");
val = val.split("%3c").join("-");
val = val.split("%3C").join("-");
val = val.split(">") .join("-");
val = val.split("%3e").join("-");
val = val.split("%3E").join("-");
return val;
}
};
/**
// set-value -> element [ex) $$.getElement("id","#sample")]
// type @ [id , class , querySelector]
// caution issue return multi-element
**/
$$.getElement = function(type , str , num){
//single
if(type == "id"){
return document.getElementById(str);
}
//multi
var elements;
if(type == "class"){
elements = document.getElementsByClassName(str);
}
else if(type == "name"){
elements = document.getElementsByName(str);
}
else if(type == "querySelector"){
elements = document.querySelector(str);
}
// return--
if(num == "multi"){
return elements;
}
else if(num == "first"){
return elements[0];
}
};
$$.getScriptTag = function(){
var protechScript = document.getElementById("ProtechScript");
if(protechScript == null){return null}
return __PROTECH_COMMON.urlinfo(protechScript.src);
};
$$.getServiceData = function(service , srcInfo){
if(typeof(__PROTECH_INFO)=="undeifned" || typeof(__PROTECH_INFO.services)=="undeifned"){return null}
var data = null;
for(var i=0; i<__PROTECH_INFO.services.length; i++){
if(typeof __PROTECH_INFO.services[i] == "undefined"){continue}
if(service && service != __PROTECH_INFO.services[i].api){continue}
// solid-id
if(typeof srcInfo.query.p != "undefined"){
if(typeof __PROTECH_INFO.services[i].pid == "undefined"){continue}
if(srcInfo.query.p == __PROTECH_INFO.services[i].pid){
data = __PROTECH_INFO.services[i];
break;
}
else{continue}
}
// url-match
if(typeof __PROTECH_INFO.services[i]["url"] == "undefined"){continue}
if(__PROTECH_INFO.services[i]["url"] == location.href){
data = __PROTECH_INFO.services[i];
break;
}
}
return data;
};
/**
* Servide Use Function
**/
$$.getCookie = function(name){
if(!name
|| typeof __PROTECH != "undefined"
|| typeof __PROTECH.cookieName != "undefined"
){name = __PROTECH.cookieName}
var cookieData = $$.cookie.get(name);
if(!cookieData){
return {"pv":"","uu":"","su":""};
}
else{
var sp = cookieData.split(".");
return {"uu":sp[0],"su":sp[1],"pv":sp[2]};
}
}
/**
* Log write
*/
$$.logWrite = function(data){
var uidCookie = $$.getCookie();
var q = [
'mode=' + 'log',
'd=' + escape(__PROTECH[service].uKey),
'pv=' + escape(uidCookie["pv"]),
'su=' + escape(uidCookie["su"]),
'uu=' + escape(uidCookie["uu"]),
'data=' + escape(data)
];
var sc = document.createElement('script');
sc.src = __PROTECH[service].scriptPath + 'load.php'+'?t='+ (+new Date()) + "&" +q.join("&");
sc.type = 'text/javascript';
sc.async = true;
document.body.appendChild(sc);
console.log(sc.src);
}
/**
* 62進数
**/
$$.hex62 = {
chars:function(){
var str = "";
str += "0123456789";
str += "abcdefghijklmnopqrstuvwxyz";
str += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
return str;
},
encode:function(num){
var chars = this.chars();
var cn = chars.length;
var str = [];
var a1 , a2;
while (num != 0) {
a1 = parseInt(num / cn);
a2 = num - (a1 * cn);
str.unshift(chars.substr(a2,1));
num = a1;
}
var res = str.join("");
res = (!res)?"0":res;
return res;
},
decode:function(num){
var chars = this.chars();
var char2 = {};
var cn = chars.length;
for (var i=0; i< cn; i++) {
char2[chars[i]] = i;
}
var str = 0;
for (var i=0; i<num.toString().length; i++) {
str += char2[num.substr((i+1)*-1, 1)] * Math.pow(cn, i);
}
return str;
}
};
/**
* 100進数
**/
$$.digit100 = {
chars:function(){
var str = "";
str += "0123456789";
str += "abcdefghijklmnopqrstuvwxyz";
str += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// -+*/@_?,.;:^!#$%&'()[]{}<>=~|`¥
//str += "!";
return str;
},
encode:function(num){
var chars = this.chars();
var cn = chars.length;
var str = [];
var a1 , a2;
while (num != 0) {
a1 = parseInt(num / cn);
a2 = num - (a1 * cn);
str.unshift(chars.substr(a2,1));
num = a1;
}
var res = str.join("");
res = (!res)?"0":res;
return res;
},
decode:function(num){
var chars = this.chars();
var char2 = {};
var cn = chars.length;
for (var i=0; i< cn; i++) {
char2[chars[i]] = i;
}
var str = 0;
for (var i=0; i<num.toString().length; i++) {
str += char2[num.substr((i+1)*-1, 1)] * Math.pow(cn, i);
}
return str;
}
};
// Transformation
$$.getPos = function(elm){
//エレメント確認処理
if(!elm){return;}
//途中指定のエレメントチェック(指定がない場合はbody)
var target = document.body;
//デフォルト座標
var pos={x:0,y:0};
do{
//指定エレメントでストップする。
if(elm == target){break}
//対象エレメントが存在しない場合はその辞典で終了
if(typeof(elm)=='undefined' || elm==null){break}
//座標を足し込む
pos.x += elm.offsetLeft;
pos.y += elm.offsetTop;
}
//上位エレメントを参照する
while(elm = elm.offsetParent);
//最終座標を返す
return pos;
};
//targetの中心座標にelmの中心座標を移動する。
$$.getPosCenter = function(elm,target){
var pos1 = $$.getPos(target);
var size1 = $$.getSize(target);
var size2 = $$.getSize(elm);
return {
x:(pos1.x+(size1.x/2)-(size2.x/2)),
y:(pos1.y+(size1.y/2)-(size2.y/2))
};
};
$$.getSize = function(elm){
//対象element
if(typeof(elm)=='undefined'){
if (navigator.userAgent.match("MSIE")&&document.compatMode!='BackCompat'){
elm = document.documentElement;
}
else{
elm = document.getElementsByTagName("body")[0];
}
}
//サイズ取得;
var size={
x:elm.offsetWidth,
y:elm.offsetHeight
};
//子階層依存※下に1つのみの子を持つ場合サイズチェックを行う;
if(elm.childNodes.length==1 && elm.tagName=='A'){
var chk ={
x:elm.childNodes[0].offsetWidth,
y:elm.childNodes[0].offsetHeight
};
if(chk.x > size.x){
size.x = chk.x;
}
if(chk.y > size.y){
size.y = chk.y;
}
}
return size;
};
//Emveronment
$$.getWindowSize = function(){
var d={x:0,y:0};
var e;
if(window.innerWidth){
document.x = window.innerWidth;
document.y = window.innerHeight;
}
else if(navigator.userAgent.indexOf("MSIE")!=-1&&document.compatMode=='BackCompat'){
document.x = document.body.clientWidth;
document.y = document.body.clientHeight;
}
else{
document.x = document.documentElement.clientWidth;
document.y = document.documentElement.clientHeight;
}
return d;
};
//mouse
$$.getMouse = {
pos:{x:0,y:0},
proc:function(e){
//IE以外のブラウザ;
if(e){
this.pos={
x:e.clientX,
y:e.clientY
};
}
//IE処理;
else{
this.pos={
x:event.x,
y:event.y
};
}
}
};
window.$$LIB = $$;
})();
!(function(){
$$={};
$$.data = {
game:null,
key :null
};
$$.datas = [];
$$.targetElm = null;
$$.__construct = function(){
// numberplace
$$.data.game = document.getElementById("game");
if($$.data.game===null){return}
var table = $$.getNumberPlace();
if(table.className !== "numberplace"){return}
$$.setClassName(table);
$$.setInputEvent(table);
// key
$$.data.key = document.getElementById("key");
if(key===null){return}
var keyTables = $$.data.key.getElementsByTagName("table");
if(!keyTables.length){return}
$$.setKeyEvent(keyTables[0]);
// Button
$$.setButtonLoad();
$$.setButtonSave();
$$.setButtonProgramSave();
$$.setButtonProgramLoad();
$$.setButtonClear();
$$.setButtonFinish();
$$.setButtonSolve();
//load-sample
$$.loadSample();
//$$.getCache();
};
$$.setClassName = function(table){
//cells
var td = table.getElementsByTagName("td");
// set-array
for(var i=0; i<td.length; i++){
td[i].setAttribute("data-num" , i);
var classes = [];
var row = parseInt(i/9 , 10);
classes.push("row-" + row);
var col = (i%9);
classes.push("col-" + col);
var box = Number(parseInt(i/27)*3 ,10) + Number(parseInt(parseInt(i%9 ,10)/3 ,10));
classes.push("box-" + box);
td[i].className = classes.join(" ");
td[i].setAttribute("data-row" , row);
td[i].setAttribute("data-col" , col);
td[i].setAttribute("data-box" , box);
}
};
// Button
$$.setButtonClear = function(){
var elm = document.getElementById("clear");
if(elm===null){return}
elm.onclick = function(){
$$.clearPazzle();
};
};
$$.setButtonLoad = function(){
var elm = document.getElementById("load");
if(elm===null){return}
elm.onclick = function(){
//$$.setLoad();
$$.getCache();
};
};
$$.setButtonSave = function(){
var elm = document.getElementById("save");
if(elm===null){return}
elm.onclick = function(){
$$.setSave();
};
};
$$.setButtonProgramSave = function(){
var elm = document.getElementById("programSave");
if(elm===null){return}
elm.onclick = function(){
$$.setProgramSave();
};
};
$$.setButtonProgramLoad = function(){
var elm = document.getElementById("programLoad");
if(elm===null){return}
elm.onclick = function(){
$$.setProgramLoad();
};
};
$$.clearPazzle = function(){
var table = $$.getNumberPlace();
var td = table.getElementsByTagName("td");
for(var i=0; i<td.length; i++){
td[i].innerHTML = "";
td[i].setAttribute("data-enable" , "");
}
};
$$.setComplete = function(){
var table = $$.getNumberPlace();
var td = table.getElementsByTagName("td");
for(var i=0; i<td.length; i++){
td[i].setAttribute("data-enable" , "complete");
}
};
$$.setSave = function(){
var table = $$.getNumberPlace();
var td = table.getElementsByTagName("td");
var data = [];
var emptyFlg = 0;
for(var i=0; i<td.length; i++){
var num = td[i].innerHTML;
if(num === ""){
data[i] = "-";
}
else{
data[i] = Number(num);
}
if(td[i].innerHTML!==""){emptyFlg++;}
}
if(emptyFlg > 0){
var str = $$.getSave_arr2str(data);
localStorage.setItem("numberplace", str);
}
else{
localStorage.removeItem("numberplace");
}
};
$$.setProgramSave = function(){
var table = $$.getNumberPlace();
var td = table.getElementsByTagName("td");
var data = [];
var emptyFlg = 0;
for(var i=0; i<td.length; i++){
var num = td[i].innerHTML;
if(num === ""){
data[i] = "-";
}
else{
data[i] = Number(num);
}
if(td[i].innerHTML!==""){emptyFlg++;}
}
if(emptyFlg > 0){
var str = $$.getSave_arr2str(data);
localStorage.setItem("numberplace_program", str);
}
else{
localStorage.removeItem("numberplace_program");
}
};
$$.setProgramLoad = function(){
var table = $$.getNumberPlace();
var td = table.getElementsByTagName("td");
var ls = localStorage.getItem("numberplace_program");
if(!ls){return}
var data = $$.getSave_str2arr(ls);
for(var i=0; i<td.length; i++){
//if(!data[i] || !data[i].match(/[1-9]/)){data[i] = ""}
if(!data[i].toString().match(/[1-9]/)){data[i] = ""}
td[i].innerHTML = data[i];
}
};
$$.getCache = function(){
var table = $$.getNumberPlace();
var td = table.getElementsByTagName("td");
var ls = localStorage.getItem("numberplace");
if(!ls){return}
var data = $$.getSave_str2arr(ls);
for(var i=0; i<td.length; i++){
// if(data[i] === 0){data[i] = ""}
// if(data[i] === "-"){data[i] = ""}
if(!data[i].toString().match(/[1-9]/)){data[i] = ""}
td[i].innerHTML = data[i];
}
};
$$.getProgramData = function(){
var ls = localStorage.getItem("numberplace_program");
if(!ls){return ""}
return $$.getSave_str2arr(ls);
};
/**
* LocalStorage-Save Value
* condition : Numeric (1-digit)
*/
$$.getSave_arr2str = function(arr){
var str="";
for(var i=0; i<arr.length; i++){
str += arr[i].toString();
}
return str;
};
$$.getSave_str2arr = function(str){
str = str.replace(/\"/g , '');
var arr=[];
for(var i=0; i<str.length; i++){
arr.push(Number(str.charAt(i)));
}
return arr;
};
$$.loadSample = function(){
$$LIB.ajax.set({
url:"./data/sample.json",
method:"GET",
async:"true",
//type:"text/javascript",
//query:{},
onSuccess:function(res){
if(!res){return}
var json = JSON.parse(res);
var lists = document.getElementById("lists");
for(var i=0; i<json.length; i++){
var li = document.createElement("li");
li.innerHTML = json[i].name;
li.setAttribute("data-np" , json[i].data);
li.onclick = $$.clickDataLists;
lists.appendChild(li);
}
}
});
};
$$.clickDataLists = function(event){
var elm = event.target;
var data = elm.getAttribute("data-np");
if(!data){return}
$$.setData_list2view(data);
}
$$.setData_list2view = function(data_np){
if(!data_np){return}
var table = $$.getNumberPlace();
var td = table.getElementsByTagName("td");
var data = $$.getSave_str2arr(data_np);
for(var i=0; i<td.length; i++){
if(data[i].toString().match(/[1-9]/)){
td[i].innerHTML = data[i];
td[i].setAttribute("data-enable","false");
}
else{
td[i].innerHTML = "";
td[i].setAttribute("data-enable","true");
}
}
// cache
localStorage.setItem("numberplace_program" , data_np);
};
/**
* Input
*/
$$.setInputEvent = function(table){
var td = table.getElementsByTagName("td");
for(var i=0; i<td.length; i++){
td[i].onclick = $$.viewKeyElement;
}
};
$$.viewKeyElement = function(event){
var elm = event.target;
if(elm.getAttribute("data-enable") === "false"){return}
$$.setCellsColorOn(elm);
$$.targetElm = elm;
var key = document.getElementById("key");
$$.setKeyPosition(key , elm);
};
$$.setKeyPosition = function(key , elm){
var win = $$LIB.getWindowSize();
var pos = $$LIB.getPos(elm);
if(pos.x < win.x/2){
key.style.setProperty("right","0","");
key.style.setProperty("left","auto","");
}
else{
key.style.setProperty("right","auto","");
key.style.setProperty("left","16px","");
}
key.style.setProperty("display","block","");
};
$$.setKeyEvent = function(table){
var td = table.getElementsByTagName("td");
for(var i=0; i<td.length; i++){
td[i].onclick = $$.clickKey;
}
};
$$.clickKey = function(event){
if($$.targetElm === null){return}
//$$.cancelSolveError();
$$.cancelPazzleCheck();
var elm = event.target;
var key = document.getElementById("key");
key.style.setProperty("display","none","");
$$.targetElm.innerHTML = elm.getAttribute("data-key");
$$.setCellsColorOff($$.targetElm);
$$.targetElm = null;
};
$$.setCellsColorOn = function(elm){
if($$.targetElm !== null){
$$.setCellsColorOff($$.targetElm);
}
// cross
var row = elm.getAttribute("data-row");
var rows = $$.data.game.getElementsByClassName("row-"+row);
for(var i=0; i<rows.length; i++){
if(rows[i].getAttribute("data-enable") === "false"){continue}
if(rows[i] === elm){continue}
rows[i].setAttribute("data-enable" , "active");
}
var col = elm.getAttribute("data-col");
var cols = $$.data.game.getElementsByClassName("col-"+col);
for(var i=0; i<cols.length; i++){
if(cols[i].getAttribute("data-enable") === "false"){continue}
if(cols[i] === elm){continue}
cols[i].setAttribute("data-enable" , "active");
}
//target
elm.setAttribute("data-enable" , "target");
};
$$.setCellsColorOff = function(elm){
//cross + target
var row = elm.getAttribute("data-row");
var rows = $$.data.game.getElementsByClassName("row-"+row);
for(var i=0; i<rows.length; i++){
if(rows[i].getAttribute("data-enable") === "false"){continue}
if(rows[i] === elm){continue}
rows[i].setAttribute("data-enable" , "true");
}
var col = elm.getAttribute("data-col");
var cols = $$.data.game.getElementsByClassName("col-"+col);
for(var i=0; i<cols.length; i++){
if(cols[i].getAttribute("data-enable") === "false"){continue}
if(cols[i] === elm){continue}
cols[i].setAttribute("data-enable" , "true");
}
//target
elm.setAttribute("data-enable" , "true");
};
/**
* Finish
*/
$$.setButtonFinish = function(){
var elm = document.getElementById("finish");
if(elm===null){return}
elm.onclick = function(){
if(!$$.checkPazzle()){
$$.setComplete();
//alert("complete");
}
else{
//alert("not fix");
//$$.checkSolve();
}
};
};
// return error-count
$$.checkPazzle = function(){
var table = $$.getNumberPlace();
//flg
var flg = 0;
for(var i=0; i<9; i++){
//check-row
var rows = table.getElementsByClassName("row-"+i);
var arrRow = [];
for(var j=0; j<rows.length; j++){
if(rows[i].getAttribute("data-enable") === "false"){continue}
var num = rows[j].innerHTML;
if(num===""){
flg++;
continue;
}
if(arrRow.indexOf(num)!==-1){
flg++;
}
arrRow.push(num);
}
//overlap
arrRow = arrRow.filter(function (x, i, self) {
return self.indexOf(x) === i && i !== self.lastIndexOf(x);
});
for(var j=0; j<rows.length; j++){
var val = rows[j].innerHTML;
if(val === ""){
rows[j].setAttribute("data-enable" , "bad");
}
else if(arrRow.indexOf(val) != -1){
rows[j].setAttribute("data-enable" , "bad");
}
}
//check-col
var cols = table.getElementsByClassName("col-"+i);
var arrCol = [];
for(var j=0; j<cols.length; j++){
if(cols[i].getAttribute("data-enable") === "false"){continue}
var num = cols[j].innerHTML;
if(num===""){
flg++;
continue;
}
if(arrCol.indexOf(num)!==-1){
flg++;
}
arrCol.push(num);
}
//overlap
arrCol = arrCol.filter(function (x, i, self) {
return self.indexOf(x) === i && i !== self.lastIndexOf(x);
});
for(var j=0; j<cols.length; j++){
var val = cols[j].innerHTML;
if(val === ""){
cols[j].setAttribute("data-enable" , "bad");
}
else if(arrCol.indexOf(val) !== -1){
cols[j].setAttribute("data-enable" , "bad");
}
}
//check-box
var boxs = table.getElementsByClassName("box-"+i);
var arrBox = [];
for(var j=0; j<boxs.length; j++){
if(boxs[i].getAttribute("data-enable") === "false"){continue}
var num = boxs[j].innerHTML;
if(num===""){
flg++;
continue;
}
if(arrBox.indexOf(num)!==-1){
flg++;
}
arrBox.push(num);
}
//overlap
arrBox = arrBox.filter(function (x, i, self) {
return self.indexOf(x) === i && i !== self.lastIndexOf(x);
});
for(var j=0; j<boxs.length; j++){
var val = boxs[j].innerHTML;
if(val === ""){
boxs[j].setAttribute("data-enable" , "bad");
}
else if(arrBox.indexOf(val) !== -1){
boxs[j].setAttribute("data-enable" , "bad");
}
}
}
return flg;
};
$$.cancelPazzleCheck = function(){
var table = $$.getNumberPlace();
var td = table.getElementsByTagName("td");
for(var i=0; i<td.length; i++){
if(td[i].getAttribute("data-enable")!==null){
td[i].removeAttribute("data-enable");
}
}
};
/**
* Solve
*/
$$.setButtonSolve = function(){
var elm = document.getElementById("solve");
//elm.onclick = $$.solve.set;
elm.onclick = $$.solve.action;
};
$$.solve = {
action:function(){
// Empty-Check
if($$.solve.checkAllEmpty()===true){
alert("All empty !!!");
return false;
}
// First-set
$$.solve.setDataTemp();
// Loop-Check
var cnt = $$.solve.loop();
console.log("level :" + cnt );
// PazzleFinishCheck
if(!$$.checkPazzle()){
$$.setComplete();
}
},
// Inition-only
setDataTemp:function(){
var table = $$.getNumberPlace();
var td = table.getElementsByTagName("td");
// set 9.length
for(var i=0; i<td.length; i++){
if(td.innerHTML !== ""){
td[i].setAttribute("data-temp","123456789");
}
}
// temp-data-remove
$$.solve.checkFirstAll();
},
checkAllEmpty:function(){
var table = $$.getNumberPlace();
var td = table.getElementsByTagName("td");
var empty = 0;
for(var i=0; i<td.length; i++){
if(td[i].innerHTML!==""){empty++}
}
if(empty===0){return true}else{return false}
},
loop:function(){
var num=1;
console.log("start");
//$$.solve.check();
while($$.solve.check()!==0){
console.log(num);
num++;
}
return num;
},
check:function(){
$$.solve.checkFirstAll();
$$.solve.checkUniqueGroupAll();
var cnt = 0;
cnt += $$.solve.checkUnique();
return cnt;
},
checkFirstAll:function(){
$$.solve.checkFirst("row");
$$.solve.checkFirst("col");
$$.solve.checkFirst("box");
},
checkFirst:function(key){
var table = $$.getNumberPlace();
for(var i=0; i<9; i++){
var tempValues = $$.solve.getGroupValues(key,i);
//console.log(key+"/"+i+"/"+temp);
$$.solve.setTemp(key,i,tempValues);
}
//$$.solve.checkFirstAll();
},
checkUniqueGroupAll:function(){
$$.solve.checkUniqueGroup("row");
$$.solve.checkUniqueGroup("col");
$$.solve.checkUniqueGroup("box");
},
checkUniqueGroup:function(key){
var table = $$.getNumberPlace();
for(var cnt=0; cnt<9; cnt++){
var cells = table.getElementsByClassName(key+"-"+cnt);
// Search for single numerical value.(単一数字を探す)
for(var num=1; num<=9; num++){
var flg = 0;
var elm = null;
var targetValue = "";
for(var i=0; i<cells.length; i++){
if(cells[i].innerHTML!==""){continue}
var tempValue = cells[i].getAttribute("data-temp");
if(tempValue===null){continue}
if(tempValue.indexOf(num)!==-1){
flg++;
elm = cells[i];
targetValue = num;
}
}
if(flg!==1 || elm===null || targetValue===""){continue}
for(var i=0; i<cells.length; i++){
if(cells[i].innerHTML!==""){continue}
var tempValue = cells[i].getAttribute("data-temp");
if(tempValue===null){continue}
if(cells[i]===elm){
cells[i].setAttribute("data-temp" , targetValue);
}
else{
var newValue = tempValue.split(targetValue).join("");
cells[i].setAttribute("data-temp" , newValue);
}
}
}
}
},
checkUnique:function(){
var cnt = 0;
var table = $$.getNumberPlace();
var td = table.getElementsByTagName("td");
for(var i=0; i<td.length; i++){
if(td[i].innerHTML!==""){continue}
var temp = td[i].getAttribute("data-temp");
if(temp === null){continue}
if(temp && temp.length === 1){
td[i].innerHTML = temp;
td[i].removeAttribute("data-temp");
cnt++;
}
}
return cnt;
},
getGroupValues:function(key,num){
var table = $$.getNumberPlace();
var cells = table.getElementsByClassName(key+"-"+num);
var values = "";
for(var i=0; i<cells.length; i++){
var str = cells[i].innerHTML;
if(!str){continue}
values += str;
}
values = $$.getStrUnique(values);
return values;
},
setTemp:function(key,num,values){
var table = $$.getNumberPlace();
var cells = table.getElementsByClassName(key+"-"+num);
for(var i=0; i<cells.length; i++){
var str = cells[i].innerHTML;
if(str){
$$.solve.removeElementTempData(cells[i]);
}
else{
$$.solve.setSharpen(cells[i],values);
}
}
},
removeElementTempData:function(elm){
elm.removeAttribute("data-temp");
},
setSharpen:function(elm,delValue){
if(elm.innerHTML!==""){return}
var currentValue = elm.getAttribute("data-temp");
if(currentValue===null){return}
var newValue = "";
for(var i=0; i<currentValue.length; i++){
var char = currentValue.charAt(i);
if(delValue.indexOf(char)!==-1){continue}
newValue += char;
}
newValue = $$.getStrUnique(newValue);
//console.log(newValue+"/"+currentValue+"/"+delValue);
elm.setAttribute("data-temp" , newValue);
}
};
/**
* Common
*/
$$.getNumberPlace = function(){
var tables = $$.data.game.getElementsByTagName("table");
return tables[0];
};
$$.getData = function(){
var table = $$.getNumberPlace();
var td = table.getElementsByTagName("td");
var data = [];
for(var i=0; i<td.length; i++){
var num = td[i].innerHTML;
if(num === ""){
data[i] = "-";
}
else{
data[i] = Number(num);
}
}
return $$.getSave_arr2str(data);
};
$$.getStrUnique = function(str){
if(str==="" || str===null || str==="undefined" || typeof str !== "string"){return ""}
var newStr=[];
for(var i=0; i<str.length; i++){
var char = str.charAt(i);
if(newStr.indexOf(char)===-1){
newStr.push(char);
}
}
//sort
newStr = newStr.sort(function(a,b){
if( a < b ) return -1;
if( a > b ) return 1;
return 0;
});
return newStr.join("");
};
$$.getArrayUnique = function(arr){
var unique = [];
for(var i=0; i<arr.length; i++){
unique[i] = "";
if(arr[i]===""){continue}
// currentStr
var currentStr = arr[i];
var otherStr = (function(arr,num){
var str = "";
for(var i=0; i<arr.length; i++){
if(num == i){continue}
str += arr[i];
}
return str;
})(arr,i);
for(var j=0; j<currentStr.length; j++){
//var flg = 0;
var char = currentStr.charAt(j);
if(otherStr.indexOf(char)==-1){
unique[i] += char;
}
}
}
return unique;
};
$$.getRowStr = function(lineNumber){//console.log(lineNumber);
var table = $$.getNumberPlace();
var rows = table.getElementsByClassName("row-"+lineNumber);
var data = "";
for(var i=0; i<rows.length; i++){
var str = rows[i].innerHTML;
if(str!==""){data += str;}
}
return data;
};
$$LIB.eventAdd(window , "load" , $$.__construct);
})();
[
{
"name":"sample-1",
"data":"--7---2-----6-4---4----2--8-----1--52---5--1---6-8--7--8-------1--59-8-372-4-----"
},
{
"name":"sample-2",
"data":"--1---3-----9-1--423---7-69--8-6--71---------19----------8-9--6---3---4-42-------"
},
{
"name":"sample-3",
"data":"--2---6-----3-895-7-8--5-------56--8-7--9--2--8----5-----92----5-3----------431--"
},
{
"name":"sample-4",
"data":"--4---3---9---867-12---9--8------725--------49---2-------5----7----6-94-2-8-1--3-"
},
{
"name":"sample-5",
"data":"--2---5---86---------5--71-89--5---2--4-8--3-2--------4----2---7---4--8---9--826-"
},
{
"name":"sample-6",
"data":"--7---3--8------4956------12-3-9-----7---3--6--5--1----8-1--5----4----9-71-2-----"
},
{
"name":"sample-7",
"data":"--9---6--4--2--9------------754--------9-2-8-6------25-4----1979---3-----1--8----"
},
{
"name":"sample-8",
"data":"--6---1--4--1-8-597--2------5-9--4-------6391-67-4-2------7---81------7----4-----"
},
{
"name":"sample-9",
"data":"--6---5--3-1-8--699----5-1-5--6--8----8---1---6-87---------1953---496----1------2"
},
{
"name":"sample-10",
"data":"--9---6--61-----2--5--3-1---7-5-826--62--4--------14-52---6--5-18-----9-9----5---"
},
{
"name":"sample-11",
"data":"6--4-----5----7-9--1--8-3----27----4-5-----6-1----95----9-7--4--8-3----2-----6--3"
}
]
解説
index.htmlに解凍ボタンを付け加えています。その影響でJS側でボタンを押したイベントを追加してますが、大した処理でないので、ここは解説カットします。
numberplace.jsの中の"$$.solve"という関数が今回のポイントですが、少し大きなプログラムになってしまったので、大まかなフローは下記のとおりです。
1. 解凍ボタンを押した時に処理を実行
2. 空欄に対して1~9の数字を仮登録
3. 仮登録した数字の縦、横、3x3の箱、の部分に重複のある数値を仮登録の数値から除外する
4. 縦、横、3x3箱の中で重複する数値の内値を拾って確定数値にする(この時点では仮登録するだけ)
5. 仮登録されている数値のうち、1つしかないものを確定数値として、反映させる。(この時仮登録は削除する)
6. 完了していない場合、3番に戻ってさらに処理をすすめる。
この手順で、初級レベルの解凍はできます。
もちろん、すこしレベルの高い問題になると、空欄を残してプログラムが終了してしまうので、この点は次回以降に対応する予定なので、認識しておいてください。
ポイント
解説の4番について、すこし分かりにくいので、図を用意しておきました。
分かりにくいですが、どうしてもわからない場合は、メールかコメントください。
別途解説したいと思います。
サンプル問題
横列を例にします
入れられる数値を全て書き出す
1が一つしかないので確定
これを繰り返す
上記の様な処理を繰り返し行うことで、初級レベルは空欄がどんどん埋まっていきます。
上級レベルに対しての課題
これでも解答できない問題は、もう少し別の判定を行わないといけません。
少し書いておくと、3x3マスの縦と横を1つのユニーク値として、他のブロックに対して優先順位を付けていき、不要判定を行なって、仮登録値を削除していくことで、確定数字を割り出すという内容です。
数独好きの人は、次回をお楽しみに・・・
0 件のコメント:
コメントを投稿