<html>
<head>
<meta charset="UTF-8">
<title>お絵描きパズル</title>
<script>
// Counter Class で数字を表示
function Counter(img, sw, sh)
{ this.Img= img; //Image File(0~9の画像)
this.Sw = sw; //Sprite の幅
this.Sh = sh; //Sprite の高さ
//「上, 右, 下, 左」の順
this.View_Num = function(num, x, y)
{ if (num>9)
{ var n= Math.floor(num/10);
var pos = n*this.Sw;
var s1= 'style="clip:rect(0px,' + (pos+this.Sw) + 'px,' + this.Sh + 'px,' + pos + 'px);';
var s2 = 'position:absolute;left:' + (x-pos-2) + 'px;top:' + y + 'px;';
var s = '<img src="' + this.Img + '"' + s1 + s2 + '">';
document.write(s);
var n= num%10;
var pos = n*this.Sw;
var s1= 'style="clip:rect(0px,' + (pos+this.Sw) + 'px,' + this.Sh + 'px,' + pos + 'px);';
var s2 = 'position:absolute;left:' + (x-pos+2) + 'px;top:' + y + 'px;';
var s = '<img src="' + this.Img + '"' + s1 + s2 + '">';
document.write(s);
return;
}
var pos = num*this.Sw;
var s1= 'style="clip:rect(0px,' + (pos+this.Sw) + 'px,' + this.Sh + 'px,' + pos + 'px);';
var s2 = 'position:absolute;left:' + (x-pos) + 'px;top:' + y + 'px;';
var s = '<img src="' + this.Img + '"' + s1 + s2 + '">';
document.write(s);
}
}
// num行(num+100列)を抽出→s_line[], s_no, s_data[]
function Select(num)
{ if (num<0 || (num>90 && num-100<0)) return;
s_line = [];
//選択マークの設定(赤⇔null)
if (s_no!=-1)
{ if (s_no<90) //行(枠の下をクリア)
{ Mark3("null", -1, s_no);
for(var i=0; i<xnum; i++) Mark3('null', i, ynum);
}
else //列(枠の右をクリア)
{ Mark3("null", s_no-100, -1);
for(var i=0; i<ynum; i++) Mark3('null', xnum, i);
}
}
if (num<90) Mark3("red", -1, num);
else Mark3("red", num-100, -1);
// num 行(列)を抽出
//window.alert("Select:" + num + " ynum:" + ynum + " xnum:" + xnum);
s_no= num;
if (num<90) // 行を抽出
{ for(var i=0; i<xnum; i++) s_line[i]= t[num][i];
s_data= xt[num];
}
else // 列を抽出
{ var nw= num-100;
for(var i=0; i<ynum; i++) s_line[i]= t[i][nw];
s_data= yt[nw];
}
Cross();
Set_Hint(num, s_line);
}
// 行・列のヒントを枠の右・下に表示
function Set_Hint(num, s_line)
{ //window.alert(s_line);
if (num<100) //抽出行を下に描画
{ for(var i=0; i<xnum; i++)
{ if (s_line[i]==1) Mark3("black", i, ynum);
else if(s_line[i]==2) Mark3("white", i, ynum);
else Mark3("null", i, ynum);
}
}
else //抽出列を右に描画
{ for(var i=0; i<ynum; i++)
{ if (s_line[i]==1) Mark3("black", xnum, i);
else if(s_line[i]==2) Mark3("white", xnum, i);
else Mark3("null", xnum, i);
}
}
SetMark("black");
}
// s_line→配列 t[][] に戻す
function Set(num)
{ //window.alert("NUM:" + num + " SEL:" + s_line + " ynum:" + ynum + " xnum:" + xnum);
if (num<100) //行を戻す(0~xnum, num)
{ for(var i=0; i<xnum; i++)
{ t[num][i]= s_line[i];
if (s_line[i]==1) Mark("black", i, num);
if (s_line[i]==2) Mark("white", i, num);
if (s_line[i]==0) Mark("null", i, num);
}
}
else //列を戻す(num-100, 0~ynum)
{ var nw= num-100;
for(var i=0; i<ynum; i++)
{ t[i][nw]= s_line[i];
if (s_line[i]==1) Mark("black", nw, i);
if (s_line[i]==2) Mark("white", nw, i);
if (s_line[i]==0) Mark("null", nw, i);
}
}
SetMark("black");
}
// s_line[] の解析(s_line[], s_no, s_data[]) は正しいとする
function Cross()
{ num= s_line.length;
var sum = 0; //s_data[] の合計
for(var i=0; i<s_data.length; i++)
{ sum += parseInt(s_data[i]); }
var c= 0; //Mark Count
var n= 0; //null Count
for(var i=0; i<num; i++)
{ if (s_line[i]==1) c++;
if (s_line[i]==0) n++;
}
//window.alert("sum:" + sum + " mark:" + c + " null:" + n);
if (c==sum) //マーク確定(残りは空白)
{ for(var i=0; i<num; i++)
if (s_line[i]!=1) s_line[i]= 2;
return;
}
if (c+n==sum) //残りの null にマークする
{ for(var i=0; i<num; i++)
if (s_line[i]==0) s_line[i]= 1;
return;
}
//重なるマークを調べる
var ary= new Array();
for(i=0; i<s_data.length; i++)
{ for(j=0; j<s_data[i]; j++) ary.push(i);
if (ary.length<num) ary.push(-1);
}
var bk= new Array();
for(i=s_data.length-1; i>=0; i--)
{ for(j=0; j<s_data[i]; j++) bk.push(i);
if (bk.length<num) bk.push(-1);
}
for(i=ary.length; i<num; i++)
{ ary.push(-1);
bk.push(-1);
}
for(i=0; i<num; i++)
{ if (ary[i]!=-1 && ary[i]==bk[num-i-1]) s_line[i]= 1; }
}
function Mark(cor, xp, yp)
{ if (xp>=xnum || yp>=ynum || xp<0 || yp<0) return;
Mark2(cor, xp, yp);
}
function Mark2(cor, xp, yp)
{ var xw = xp*16+88;
var yw = yp*16+88;
c.fillStyle = cor;
if (cor=='black' || cor=='white')
{ c.fillRect(xw, yw, 13, 13);
return;
}
if (cor=='null')
{ c.clearRect(xw, yw, 13, 13);
return;
}
c.beginPath();
if (cor=='red') c.arc(xw+4, yw+4, 3, 0, 2 * Math.PI, false);
else if (cor=='green') c.arc(xw+10, yw+4, 3, 0, 2 * Math.PI, false);
else if (cor=='blue') c.arc(xw+4, yw+10, 3, 0, 2 * Math.PI, false);
else c.arc(xw+10, yw+10, 3, 0, 2 * Math.PI, false);
c.fill();
}
function Mark3(cor, xp, yp)
{ var xw = xp*16+90;
var yw = yp*16+90;
c.fillStyle = cor;
if (cor=='black' || cor=='white')
{ c.fillRect(xw, yw, 10, 10);
return;
}
if (cor=='null')
{ c.clearRect(xw, yw, 10, 10);
return;
}
c.beginPath();
if (cor=='red') c.arc(xw+3, yw+3, 3, 0, 2 * Math.PI, false);
//else if (cor=='green') c.arc(xw+5, yw+3, 3, 0, 2 * Math.PI, false);
//else if (cor=='blue') c.arc(xw+3, yw+5, 3, 0, 2 * Math.PI, false);
//else c.arc(xw+5, yw+5, 3, 0, 2 * Math.PI, false);
c.fill();
}
// 左上隅にマークを描画
function SetMark(mk)
{ cor= mk;
c.clearRect(20, 20, 14, 14);
if (cor=='null') return;
c.fillStyle = cor;
if (cor=='black' || cor=='white')
{ c.fillRect(20, 20, 10, 10);
return;
}
c.beginPath();
if (cor=='red') c.arc(23, 23, 3, 0, 2 * Math.PI, false);
else if (cor=='green') c.arc(21, 21, 3, 0, 2 * Math.PI, false);
else if (cor=='blue') c.arc(21, 21, 3, 0, 2 * Math.PI, false);
else c.arc(23, 23, 3, 0, 2 * Math.PI, false);
c.fill();
}
// 完成チェック
function Fin()
{ SetMark("black");
for(var i=0; i<ynum; i++)
for(var j=0; j<xnum; j++)
if (t[i][j]==0)
{ window.alert("未完成です");
return;
}
for(var i=0; i<xt.length; i++)
{ var wk= xt[i];
var p= 0;
for(var j=0; j<wk.length; j++)
{ for(; p<xnum && t[i][p]!=1; p++);
for(var c=0; p<xnum && t[i][p]==1; c++, p++);
if (wk[j]!=c)
{ window.alert("Error 行:" + i);
return;
}
}
}
for(var i=0; i<yt.length; i++)
{ var wk= yt[i];
var p= 0;
for(var j=0; j<wk.length; j++)
{ for(; p<ynum && t[p][i]!=1; p++);
for(var c=0; p<ynum && t[p][i]==1; c++, p++);
if (wk[j]!=c)
{ window.alert("Error 列:" + i);
return;
}
}
}
window.alert("*完成です");
}
function scr()
{ xscr = document.body.scrollLeft;
yscr = document.body.scrollTop;
//xscr = document.documentElement.scrollLeft;
//yscr = document.documentElement.scrollTop;
//alert("横" + xscr + "px,縦" + yscr + "px");
}
// 罫線を描画する
function View_Line()
{ // 5セルの枠
c.strokeStyle = 'blue';
c.lineWidth = 1;
for(var i=0; i<xnum; i=i+5)
for(var j=0; j<ynum; j=j+5)
{ c.strokeRect(i*16+base+71, j*16+base+71, 80, 80); }
// 線の色と太さ
c.strokeStyle = 'gray';
c.lineWidth = 2;
c.beginPath();
// 横線
for(var i=0; i<=ynum; i++)
{ c.moveTo(base+70, i*16+base+70);
c.lineTo(xnum*16+base+70, i*16+base+70);
}
// 縦線
for(var i=0; i<=xnum; i++)
{ c.moveTo(i*16+base+70, base+70);
c.lineTo(i*16+base+70, ynum*16+base+70);
}
// 外枠
c.moveTo(base+1, base+1);
c.lineTo(xnum*16+base+70, base+1);
c.moveTo(base+1, base+1);
c.lineTo(base+1, ynum*16+base+70);
for(var i=0; i<ynum+1; i=i+5)
{ c.moveTo(base, i*16+base+70);
c.lineTo(base+70, i*16+base+70);
}
for(var i=0; i<xnum+1; i=i+5)
{ c.moveTo(i*16+base+70, base);
c.lineTo(i*16+base+70, base+70);
}
c.stroke();
// 数字の表示
var cls = new Counter("numm.gif", 16, 16);
for(var i=0; i<xt.length; i++)
for(var j=0; j<xt[i].length; j++)
cls.View_Num(xt[i][j], j*10+base+10, i*16+base+80);
for(var i=0; i<yt.length; i++)
for(var j=0; j<yt[i].length; j++)
cls.View_Num(yt[i][j], i*16+base+80, j*12+base+10);
//メニューの表示
document.write('<div onclick= Set(s_no) style="position:absolute;left:' + bs + 'px;top:140px;">設定</div>');
document.write('<div onclick= Fin() style="position:absolute;left:' + (bs+60) + 'px;top:140px;">完成?</div>');
document.write('<div onclick= SetMark("black") style="position:absolute;left:' + bs + 'px;top:180px;">黑</div>');
document.write('<div onclick= SetMark("white") style="position:absolute;left:' + bs + 'px;top:200px;">白</div>');
document.write('<div onclick= SetMark("null") style="position:absolute;left:' + bs + 'px;top:220px;">消去</div>');
document.write('<div onclick= SetMark("red") style="position:absolute;left:' + (bs+60) + 'px;top:180px;">赤</div>');
document.write('<div onclick= SetMark("green") style="position:absolute;left:' + (bs+60) + 'px;top:200px;">緑</div>');
document.write('<div onclick= SetMark("blue") style="position:absolute;left:' + (bs+60) + 'px;top:220px;">青</div>');
document.write('<div onclick= SetMark("yellow") style="position:absolute;left:' + (bs+60) + 'px;top:240px;">黄</div>');
}
</script>
<?php
function init($str)
{ global $xnum, $ynum, $xt, $yt, $name;
//error_log($str, 3, 'app.log');
$w1 = explode(';', $str);
$name= substr($w1[0],2); //パズル名
$xy= explode(' ', $w1[1]); //行数, 列数
//$xy= explode("/,| /", $w1[1]); //Error
$xnum= intval($xy[0]);
$ynum= intval($xy[1]);
//error_log("\nX num:$xnum Y num:$ynum\n", 3, 'app.log');
$c= 0;
for($p=3; $c<$xnum; $p++)
{ $wk= $w1[$p];
if (substr($wk,0,1)=="/") continue;
//error_log("\n$wk", 3, 'app.log');
$ww= explode(' ', $wk);
array_push($xt, $ww);
$c++;
}
for($i=0; $i<count($xt); $i++)
{ $wk= $xt[$i];
if (count($wk)>1 && $wk[count($wk)-1]==0) array_pop($xt[$i]);
}
$c= 0;
for($p++; $c<$ynum; $p++)
{ $wk= $w1[$p];
if (substr($wk,0,1)=="/") continue;
//error_log("\n$wk", 3, 'app.log');
$ww= explode(' ', $wk);
array_push($yt, $ww);
$c++;
}
for($i=0; $i<count($yt); $i++)
{ $wk= $yt[$i];
if (count($wk)>1 && $wk[count($wk)-1]==0) array_pop($yt[$i]);
}
}
?>
</head>
<body bgcolor=#e0d8d0>
<canvas id="mycanvas" width="800" height="600"></canvas>
<style>
canvas
{ border: 1px solid silver; }
</style>
<?php
$xnum= 0;
$ynum= 0;
$xt= array();
$yt= array();
$name= "いちご";
$data = $_POST["data"];
init($data);
$jsonXT = json_encode($xt);
$jsonYT = json_encode($yt);
?>
<script>
document.onmousedown =
function(e)
{ if (!e) e= window.event;
scr(); // Scrill 値を調べる
var xp = Math.floor((e.clientX-base-75)/16);
var yp = Math.floor((e.clientY-base-75)/16);
var click= e.clientX + "," + e.clientY;
document.getElementById("click").textContent= click;
var pos= xp + "," + yp;
document.getElementById("pos").textContent= pos;
// マスのクリック
if (xp>=0 && xp<xnum && yp>=0 && yp<ynum)
{ Mark(cor, xp, yp);
if (cor=='null') t[yp][xp]= 0;
if (cor=='black') t[yp][xp]= 1;
if (cor=='white') t[yp][xp]= 2;
return;
}
// 行を抽出する
if (xp<-4 && yp<ynum)
{ Select(yp);
return;
}
// 列を抽出する
if (yp<-4 && xp<xnum)
{ Select(xp+100);
return;
}
return;
}
xt = JSON.parse('<?php echo $jsonXT;?>');
yt = JSON.parse('<?php echo $jsonYT;?>');
//window.alert("XT: " + xt);
ynum= xt.length; // 縦方向のマスの数
xnum= yt.length; // 横方向のマスの数
//window.alert("縦のマス:" + ynum + " 横のマス:" + xnum);
xscr= 0; // ScrollX 値
yscr= 0; // ScrollY 値
cor= 'black';
base= 16; // マスの基点
bs= (xnum+2)*16+86; // メニューの表示座標
s_line= new Array(50); // 解析エリア(MAX 50)
s_no= -1; // 行(0~15),列(100~115)
s_data= [0];
t= new Array(ynum); // 0:未定, 1:マーク, 2:空白
for(var i=0; i<ynum; i++)
{ t[i]= new Array(xnum); }
for(var i=0; i<ynum; i++)
for(var j=0; j<xnum; j++)
t[i][j]= 0;
var canvas = document.getElementById('mycanvas');
c = canvas.getContext('2d');
View_Line();
SetMark("black");
</script>
<p>
<div id="click" style="position:absolute;left:26px;top:40px;">click</div><br>
<div id="pos" style="position:absolute;left:26px;top:55px;">pos</div><br>
<div style="position:absolute;left:26px;top:75px;"><?php echo $name;?></div>
</p>
</body>
</html>
|