お絵描きゲーム

今は携帯全盛ですが、一昔前までは通勤電車で「お絵描きゲーム」に夢中になっている方を良く見かけたものです。
それほど面白く多くの人に親しまれていたドットで絵を描く「Logic Puzzle」を JavaScript で作成します。
次のリンクをクリックすると β版のページ 「いちご」のパズルが楽しめます。

ゲームの概要

  1. Win32 API で作成したページ先頭の画像を見て下さい。
    縦横に15個のマスが並んでいます。
    マスの上には、縦方向にマークする数字が、マスの左には横方向にマークする数字が表示されています。
    指定された数のマスを塗りつぶしてドット絵を完成させるゲームです。
  2. Logic Puzzle の最も基本的なマークの方法に付いて説明します。
    例として15個の列に9個マークする場合を考えます。
    9個マークを左詰めで格納すると次のようになります。
    ■■■■■■■■■・・・・・・     左に詰めたとき
    
    次にマークを右詰めで格納します。
    ■■■■■■■■■・・・・・・     左に詰めたとき
    ・・・・・・■■■■■■■■■     右に詰めたとき
    
    このとき中央の重なった3個のマークが確定できます。
    ■■■■■■■■■・・・・・・     左に詰めたとき
    ・・・・・・■■■■■■■■■     右に詰めたとき
    ・・・・・・★★★・・・・・・     マークが確定
    
  3. 最も基本的なマークが確定したら、そこからは思考を凝らして進めて行きます。
    難問を解くには数時間(数日)かかることもあるようです。

プログラムの開発手順

  1. Canvas にマスを描きます。(dot_line.html)
    ソースコードを掲載していない場合は、html を実行して右クリックから「ソースの表示」で確認することが出来ます。
    Canvas にマスを描く をクリックしてみて下さい。
    <html>
    <head>
    <meta charset=utf-8>
    <link rel="stylesheet" href="javascript.css" type="text/css">
    <title>お絵描き</title>
    </head>
    
    <body>
    <canvas id="mycanvas" width="240" height="240"></canvas>
    <style>
    canvas
    {   border: 1px solid silver;  }
    </style>
    
    <script>
    var canvas = document.getElementById('mycanvas');
    c = canvas.getContext('2d');
    
        // 線の色と太さ
        mode= 15;
        c.strokeStyle = 'gray';
        c.lineWidth = 2;
        c.beginPath();
        for(var i=0; i<mode+1; i++)
        {   c.moveTo(0, i*13);
            c.lineTo(mode*13, i*13);
            c.moveTo(i*13, 0);
            c.lineTo(i*13, mode*13);
        }
        c.stroke();
    </script>
    
    </body>
    </html>
    
  2. c.moveTo() と c.lineTo() で横線と縦線を引いてマスを描画します。
    Canvas のプログラムは Canvas を定義線を描画 を参照して下さい。

  3. マスの上と左に Counter Class を使ってパズルの数字を表示します。(dot_num.html)
    パズルの数字を表示 をクリックしてみて下さい。
    <html>
    <head>
    <meta charset=utf-8>
    <title>お絵描き</title>
    <script>
    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);
        }
    }
    </script>
    </head>
    
    <body bgcolor=#e0d8d0>
    <canvas id="mycanvas" width="360" height="360"></canvas>
    <style>
    canvas
    {   border: 1px solid silver;  }
    </style>
    
    <script>
    var canvas = document.getElementById('mycanvas');
    c = canvas.getContext('2d');
    
        mode= 15;
        cor= 'black';
        // 線の色と太さ
        c.strokeStyle = 'gray';
        c.lineWidth = 2;
        c.beginPath();
        for(var i=0; i<mode+1; i++)
        {   c.moveTo(0+70, i*16+70);
            c.lineTo(mode*16+70, i*16+70);
            c.moveTo(i*16+70, 70);
            c.lineTo(i*16+70, mode*16+70);
        }
        c.stroke();
    
        var xt = [[2],[4,2],[7,2],[2,6],[3,6],[2,1,5],[6,5],[1,4,3],[4,3,4],[3,5,2],[7,3,1],[2,2,3,3],[7,3],[1,2,4],[7]];
        var yt = [[6],[8,1],[4,3,3],[3,3,5],[2,9,1],[2,2,2,3],[4,9],[4,2,1,1],[5,6],[5,1,1],[6,3],[7,1],[2,7],[2,2],[1]];
    
        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+10, i*16+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+80, j*12+10);
    </script>
    
    </body>
    </html>
    
  4. このゲームに使用する数字の画像(numm.gif)を作成しました。

    画像でカウンターを表示するプログラムは カウンタークラス を参照して下さい。
    お絵描きパズルでは、マスに2桁の数字が対応する場合があり、2桁のときは詰めて描画しています。

  5. クリックでマスを塗りつぶします。(dot_black.html)
    クリックで塗りつぶす
    <script>
      document.onmousedown =
        function(e)
        {   if (!e)  e= window.event;
            //window.alert("X:" + e.clientX + "  Y:" + e.clientY);
            var xp = Math.floor((e.clientX - 10)/16)*16+7;
            var yp = Math.floor((e.clientY - 10)/16)*16+7;
            //window.alert("XP:" + xp + "  YP:" + yp + "  cor:" + cor);
    
            c.fillStyle = 'black';
            c.fillRect(xp, yp, 14, 14);
        }
    
  6. クリックされた座標からマスの座標を計算して、マスを黒く塗りつぶします。

  7. セルのマーク&消去を設定します。(dot_mark.html)
    カラー&消去を設定
      document.onmousedown =
        function(e)
        {   if (!e)  e= window.event;
            if (e.clientY>380 && e.clientY<420)
            {   if (e.clientX<50)       cor= 'black';
                else if (e.clientX<100) cor= 'red';
                else if (e.clientX<150) cor= 'green';
                else if (e.clientX<200) cor= 'blue';
                else if (e.clientX<250) cor= 'yellow';
                else if (e.clientX<290) cor= 'white';
                else cor= 'null';
                return;
            } 
            var xp = Math.floor((e.clientX - 10)/16)*16+7;
            var yp = Math.floor((e.clientY - 10)/16)*16+7;
    
            c.fillStyle = cor;
            if (cor=='black' || cor=='white')
            {   c.fillRect(xp, yp, 14, 14);
                return;
            }
            if (cor=='null')
            {   c.clearRect(xp, yp, 14, 14);
                return;
            }
            c.beginPath();
            if (cor=='red') c.arc(xp+4, yp+4, 3, 0, 2 * Math.PI, false);
            else if (cor=='green')  c.arc(xp+10, yp+4, 3, 0, 2 * Math.PI, false);
            else if (cor=='blue')   c.arc(xp+4, yp+10, 3, 0, 2 * Math.PI, false);
            else c.arc(xp+10, yp+10, 3, 0, 2 * Math.PI, false);
            c.fill();
        }
    
        ・・・
    
    </script>
    <p>
      <div>黑  赤  緑  青  黄  白  消去</div><br>
    </p>
    
  8. お絵描きゲームでは、マスに印を付けたり、黒く塗りつぶしたり、取り消したりと試行錯誤を繰り返します。
    黑, 赤, 緑, 青, 黄, 白, 消去をクリックすると、マークの色と種類が設定されます。
    これで一応ゲームをプレイ出来るレベルになります。

  9. マークの基本手順をサポートしてα版の完成です。(dot_alpha.html)
    α版の完成
    function Cross(num, data)
    {   var ary= new Array();
        var i;
        window.alert("data:" + data);
        for(i=0; i<data.length; i++)
        {   for(j=0; j<data[i]; j++)    ary.push(i);
            if (ary.length<num) ary.push(-1);
        }
        var bk= new Array();
        for(i=data.length-1; i>=0; i--)
        {   for(j=0; j<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])  ary[i]= 1;
            else   ary[i]= 2;  
        }
        return ary;
    }
    </script>
    </head>
    
    <script>
        var xt = [[2],[4,2],[7,2],[2,6],[3,6],[2,1,5],[6,5],[1,4,3],[4,3,4],[3,5,2],[7,3,1],[2,2,3,3],[7,3],[1,2,4],[7]];
        var yt = [[6],[8,1],[4,3,3],[3,3,5],[2,9,1],[2,2,2,3],[4,9],[4,2,1,1],[5,6],[5,1,1],[6,3],[7,1],[2,7],[2,2],[1]];
        xn= yt.length;  // 横方向のマス
        yn= xt.length;  // 縦方向のマス
    
      document.onmousedown =
        function(e)
        {   if (!e)  e= window.event;
            var xp = Math.floor((e.clientX-75)/16);
            var yp = Math.floor((e.clientY-75)/16);
            //window.alert("XP:" + xp + "  YP:" + yp + "  cor:" + cor);
    
            if (yp>yn+1)
            {   if (e.clientX<50)       cor= 'black';
                else if (e.clientX<120) cor= 'white';
                else if (e.clientX<170) cor= 'red';
                else if (e.clientX<220) cor= 'green';
                else if (e.clientX<270) cor= 'blue';
                else if (e.clientX<320) cor= 'yellow';
                else cor= 'null';
                return;
            } 
    
            var xw = xp*16+71;
            var yw = yp*16+71;
    
            // 行のクロスを調べる
            if (xp>=xn && yp<yn)
            {   var ans= Cross(xn, xt[yp]);
                c.fillStyle = 'black';
                for(var i=0; i<xn; i++)     
                {   if (ans[i]==1)  c.fillRect(i*16+71, yw, 14, 14);
                    else   c.clearRect(i*16+71, yw, 14, 14);
                }
                c.fill();
                return;
            }
            // 列のクロスを調べる
            if (yp>=yn && xp<xn)
            {   var ans= Cross(yn, yt[xp]);
                c.fillStyle = 'black';
                for(var i=0; i<yn; i++)     
                {   if (ans[i]==1)  c.fillRect(xw, i*16+71, 14, 14);
                    else   c.clearRect(xw, i*16+71, 14, 14);
                }
                c.fill();
                return;
            }
            if (xp>=xn || yp>=yn)   return;
    
            c.fillStyle = cor;
            if (cor=='black' || cor=='white')
            {   c.fillRect(xw, yw, 14, 14);
                return;
            }
            if (cor=='null')
            {   c.clearRect(xw, yw, 14, 14);
                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();
        }
    
        var canvas = document.getElementById('mycanvas');
        c = canvas.getContext('2d');
    
        cor= 'black';
        // 線の色と太さ
        c.strokeStyle = 'gray';
        c.lineWidth = 2;
        c.beginPath();
        // 横線
        for(var i=0; i<yn+1; i++)
        {   c.moveTo(70, i*16+70);
            c.lineTo(xn*16+70, i*16+70);
        }
        // 縦線
        for(var i=0; i<xn+1; i++)
        {   c.moveTo(i*16+70, 70);
            c.lineTo(i*16+70, yn*16+70);
        }
        for(var i=0; i<yn+1; i=i+5)
        {   c.moveTo(0, i*16+70);
            c.lineTo(70, i*16+70);
        }
        for(var i=0; i<xn+1; i=i+5)
        {   c.moveTo(i*16+70, 0);
            c.lineTo(i*16+70, 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+10, i*16+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+80, j*12+10);
    </script>
    <p>
      <div>黑  白   赤  緑  青  黄   消去</div><br>
    </p>
    
  10. 行または列の重なるマスを黒く塗りつぶす Cross() 関数を組み込みます。
    行の右(または 列の下)をクリックすると、その行または列の重なるマスが塗りつぶされます。
    これで決まり切った面倒な操作をコンピュータに任せることが出来ます。

公開ゲーム

  1. ホームページで公開する「お絵描きゲーム」を作成します。
    パズルのデータを直接プログラム内で定義するので、共通部分を JavaScript File(dotalpha.js) に記述して組み込みます。
    dotalpha.js のソースコードです。
    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);
        }
    }
    
    // マークゼロの行(列)を調べます(2:白)
    function Cross(num, data)
    {   var ary= new Array();
        var i;
        window.alert("data:" + data);
        if (data[0]==0)
        {   for(i=0; i<num; i++)    ary[i]= 2;
            return ary;
        }
        for(i=0; i<data.length; i++)
        {   for(j=0; j<data[i]; j++)    ary.push(i);
            if (ary.length<num) ary.push(-1);
        }
        var bk= new Array();
        for(i=data.length-1; i>=0; i--)
        {   for(j=0; j<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);
        }
        //window.alert("array:" + ary);
        //window.alert("back:" + bk);
        for(i=0; i<num; i++)
        {   if (ary[i]!=-1 && ary[i]==bk[num-i-1])  ary[i]= 1;
            else   ary[i]= 0;  
        }
        return ary;
    }
    
    // マスにマークを一個描画する
    function Mark(cor, xp, yp)
    {   if (xp>=xn || yp>=yn || xp<0 || yp<0)   return;
        Mark2(cor, xp, yp);
    }
    function Mark2(cor, xp, yp)
    {   var xw = xp*16+base+71;
        var yw = yp*16+base+71;
        c.fillStyle = cor;
        if (cor=='black' || cor=='white')
        {   c.fillRect(xw, yw, 14, 14);
            return;
        }
        if (cor=='null')
        {   c.clearRect(xw, yw, 14, 14);
            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 View_Line()
    {   // 線の色と太さ
        c.strokeStyle = 'gray';
        c.lineWidth = 2;
        c.beginPath();
        // 横線
        for(var i=0; i<yn+1; i++)
        {   c.moveTo(base+70, i*16+base+70);
            c.lineTo(xn*16+base+70, i*16+base+70);
        }
        // 縦線
        for(var i=0; i<xn+1; i++)
        {   c.moveTo(i*16+base+70, base+70);
            c.lineTo(i*16+base+70, yn*16+base+70);
        }
        c.moveTo(base+1, base+1);
        c.lineTo(xn*16+base+70, base+1);
        c.moveTo(base+1, base+1);
        c.lineTo(base+1, yn*16+base+70);
        for(var i=0; i<yn+1; i=i+5)
        {   c.moveTo(base, i*16+base+70);
            c.lineTo(base+70, i*16+base+70);
        }
        for(var i=0; i<xn+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);
    }
    
  2. Counter() は、画像で数字を描画する Class です。
    Cross() は、行(列)を解析して確定するセルを調べます。
    Mark(), Mark2() は、セルにマーク(黑, 白, 削除)などを一個描画します。
    セルの罫線は base を基点に引かれています。
    71 は、行/列の表示を考慮した補正値です。
    View_Line() でセルの罫線を描画します。
    base はマスの罫線を描画する基点です。
  3. いちごの「お絵描きゲーム」をプレイする dot_ichigo.html です。
    <html>
    <head>
    <meta charset=utf-8>
    <title>いちご</title>
    <script src="dotalpha.js">
    </script>
    </head>
    
    <body bgcolor=#e0d8d0>
    <canvas id="mycanvas" width="340" height="340"></canvas>
    <style>
    canvas
    {   border: 1px solid silver;  }
    </style>
    
    <script>
        xt = [[2],[4,2],[7,2],[2,6],[3,6],[2,1,5],[6,5],[1,4,3],[4,3,4],[3,5,2],[7,3,1],[2,2,3,3],[7,3],[1,2,4],[7]];
        yt = [[6],[8,1],[4,3,3],[3,3,5],[2,9,1],[2,2,2,3],[4,9],[4,2,1,1],[5,6],[5,1,1],[6,3],[7,1],[2,7],[2,2],[1]];
        xn= yt.length;  // 横方向のマス
        yn= xt.length;  // 縦方向のマス
        cor= 'black';
        base= 16;       // マスの基点
    
      document.onmousedown =
        function(e)
        {   if (!e)  e= window.event;
            //window.alert("X:" + e.clientX + "  Y:" + e.clientY);
            var xp = Math.floor((e.clientX-base-75)/16);
            var yp = Math.floor((e.clientY-base-75)/16);
            //window.alert("XP:" + xp + "  YP:" + yp + "  cor:" + cor);
    
            // マスのクリック
            if (xp>=0 && xp<xn && yp>=0 && yp<yn)
            {   Mark(cor, xp, yp);
                return;
            }
            // 行のクロスを調べる
            if (xp<-4 && yp<yn)
            {   var ans= Cross(xn, xt[yp]);
                for(var i=0; i<xn; i++)     
                {   if (ans[i]==1)          Mark('black', i, yp);
                    else  if (ans[i]==2)    Mark('white', i, yp);
                    else                    Mark('null', i, yp);
                }
                return;
            }
            // 列のクロスを調べる
            if (yp<-4 && xp<xn)
            {   var ans= Cross(yn, yt[xp]);
                for(var i=0; i<yn; i++)     
                {   if (ans[i]==1)          Mark('black', xp, i);
                    else  if (ans[i]==2)    Mark('white', xp, i);
                    else                    Mark('null', xp, i);
                }
                return;
            }
            // 色の選択
            if (yp>yn+1)
            {   if (e.clientX<50)       cor= 'black';
                else if (e.clientX<120) cor= 'white';
                else if (e.clientX<170) cor= 'red';
                else if (e.clientX<220) cor= 'green';
                else if (e.clientX<270) cor= 'blue';
                else if (e.clientX<320) cor= 'yellow';
                else cor= 'null';
                return;
            }
        }
    
        var canvas = document.getElementById('mycanvas');
        c = canvas.getContext('2d');
        View_Line();
    </script>
    <p>
      <div>黑  白   赤  緑  青  黄   消去</div><br>
    </p>
    
    </body>
    </html>
    
  4. 他のパズルをプレイするときは xt と yt を書き換えて下さい。
    行または列の重なるマスを黒く塗りつぶす Cross() 関数を組み込んでいます。
    矩形の左(または上)をクリックすると、その行または列のヒントが表示されます。
    行の右, 列の下では間違ってクリックすることが良くあり、左(または上)に変更しました。
    誰でも簡単に起動できるので「お絵描きゲーム」を楽しんで下さい。

  5. 本来ならお絵描きゲームのデータはファイルから入力するのが本筋でしょう。
    所が Javascript でファイルからデータを入力すると、Canvas のページから新しいページに切り変わってしまいます。
    そこで、データを入力するページとゲームを操作するページを分けて作成します。
    そのとき問題となるのがデータのサイズが大きく POST で渡さなければならないことです。
    GET と POST の説明は GET パラメータを取得 POST で送信 を参照して下さい。
    dot_data.html でデータファイルを入力して dot_game.php を呼び出します。
  6. データファイルを入力して dot_game.php を呼び出す dot_data.html のソースコードです。
    Javascript のファイル入力は Read Text File を参照して下さい。
    改行コード(\r\n)を「;」に置き換えて渡します。
    PHP のプログラムでは、パソコンからビルトインサーバーを起動して呼び出しています。('http://localhost:8000/dot_game.php')
    テストが終わった段階で、PHP をサポートしているサーバーにアップロードします。
    <html>
    <head>
    <meta charset=utf-8>
    <title>お絵描き</title>
    </head>
    
    <body bgcolor=#e0d8d0>
    <h1>お絵描きパズル</h1>
    データファイルを選択して下さい。<br><br>
    <form name="test">
    <input type="file" id="selfile" /><br/>
    </form>
    
    <script>
    function postForm(value)
    {   var form = document.createElement('form');
        var request = document.createElement('input');
     
        form.method = 'POST';
        form.action = 'http://localhost:8000/dot_game.php';
     
        request.name = 'data';
        request.value = value;
     
        form.appendChild(request);
        document.body.appendChild(form);
     
        form.submit();
    }
    
        var obj1 = document.getElementById("selfile");
        //ダイアログでファイルが選択された時
        obj1.addEventListener("change",function(evt)
        {   var file = evt.target.files;
            var reader = new FileReader();
            reader.readAsText(file[0]);
      
            //読込終了後の処理
            reader.onload = function(ev)
            {   var str= reader.result;
                str= str.replace(/\n/g, ';');
                postForm(str);
            }
        },false);
    </script>
    
    </body>
    </html>
    
  7. ファイルからデータを入力する「お絵描きゲーム」を PHP にバトンを渡して完成させます。
    この先は PHP の「お絵描きパズル」を参照して下さい。

前田稔の超初心者のプログラム入門
超初心者のプログラム入門(JavaScript)