三目並べをCanvasとjQueryで作る

#はじめに
三目並べは小規模ながら簡単なルールを持つボードゲームであるため，プログラミング入門として良く作られる。実際，HTML上で動く三目並べは，JavaScript，Java，Ruby　で多く作られている [^1] [^2] [^3] [^4] [^5]。中でも JavaScript は初心者向きであり，多くの人が最初に取り組もうとすると思われる。一方，HTML5 でサポートされた Canvas は，美しい図形を容易に描くことができ，位置を座標で指定できるため，リバーシや囲碁のような大きな盤面にも容易に拡張できる。そこで，三目並べの作成に Canvas を使いたいと思うのは自然であろう。

JavaScript のボタンやテーブルを使うときは，マウスボタンのクリックイベントに対して，関数の引数にオブジェクトを取得することができ，そのオブジェクトに対する処理を順次記述していくことになる。それに対して，HTML5 Canvas を使うときは，マウスボタンのクリックイベントに対して，jQuery のカスタム trigger を発行してそれを受信した時，ユーザの処理を記述する手順が必要となる。ここでは，この手順について解説する。実際に動いているプログラムは，[ここを参照されたい](http://waves.upper.jp/Computer/TicTacToe/TicTacToe01.html)。プログラムも置いてある [^6]。

完成後にプログラムを見直したところ，わざわざ，カスタム trigger を使わなくても良いことがわかった。しかし，カスタム trigger の使い方としては役立つので，初版としてそのまま残すことにした。三目並べに関しては，より簡潔なコード改訂版として，改めて提示することにした[^6]。

実を言えば，HTML5 Canvas と jQuery を使った囲碁の対局サイトがある[^7]。但し，そのプログラムの解説はなく，開発日誌[^8] が見られるだけなので詳細が判らない。そのため，ここに自分なりに作成したプログラムを紹介して，ご批判を仰ぎたい。

#Canvas による画面の作成
Canvas を利用すると，美しい図形を容易に描くことができる。作成した三目並べの初期画面を，下図に示す。

![三目並べの初期画面](http://waves.upper.jp/Computer/TicTacToe/image01.jpg "三目並べの初期画面")

この画面を表示するための JavaScript は，下に示すように，簡単である。

``` Javascript
function boardset(){
    ctx.fillStyle = 'rgb(0, 160, 80)';
	ctx.rect(60, 20, 180, 180);
	ctx.fill();
	ctx.strokeStyle = 'black';
	ctx.lineWidth = 2;
	ctx.beginPath();
	for (var i = 0; i <= 3; i++) {
		ctx.moveTo(60, 20+60*i);
		ctx.lineTo(240,20+60*i);
		ctx.stroke();
	}
	for (var j = 0; j <= 3; j++) {
		ctx.moveTo(60+60*j, 20);
		ctx.lineTo(60+60*j,200);
		ctx.stroke();
	}
    message("あなたの番です");
    r2message("再度挑戦　   終了");
    drawsq(dx,dy,dw,dh,dr,dcolor);
    drawsq(dx+110,dy,dw-30,dh,dr,dcolor);
}
```

#jQuery カスタム trigger の利用方法
先に述べたように，マウスボタンのクリックイベントに対して，jQuery のカスタム trigger を発行してそれを受信した時，ユーザの処理を記述する手順が必要となる。その主要部分を示すと，下記のようになる。

```Javascript
    // ユーザーの一手
    // user カスタムイベントを作成・受信
    $(document).on('user', function() {
        console.log('user カスタムイベントが実行されました');
        if (value[p] != 0) {
            message("そこは置けません");
        }
        else if(value[p] == 0) {
            value[p] = 1;
        	circle(p);
            turn++;
            if (5 <= turn) r = judge();
            if ( r == 0 ) {
                // cpu にカスタムイベントを送る
                message("CPU の番です");
                $(document).trigger('cpu');
            }
        }
    });

    // マウスボタンのクリックイベントに対する処理
    $('#board').on('click', function(e) {
    	var m = e.target.getBoundingClientRect();
        x = e.clientX - m.left;
    	y = e.clientY - m.top;
    	if ( (60 <= x && x < 240)  &&  (20 <= y && y < 200 )) {
        	if ( 60 <= x && x < 240 ) {
        		if( 20 <= y && y < 80 ) {
        			if( x < 120 ) p = 0;
        			else if( x < 180 ) p = 1;
        			else if( x < 240 ) p = 2; }
        		...
            }
            // user にカスタムイベントを送る
            $(document).trigger('user');
            return;
        }
```

上記で大事な点は，\$(document).trigger('user') {}，すなわち，user にカスタムイベントを送る命令の前に，それを受信する命令 \$(document).on('user', function() {} ) を作成しておくことである。マウスクリックイベントを受信すると，ここに制御が渡ってくるので，ユーザーの一手を記述しておく。ユーザーはその後で，cpu にカスタムイベントを送ることになる。当然ながら，このカスタムイベントを送る命令の前に，これを受信する命令を記述しておかなければならない。このように考えると，ゲームを進める構造が見えてくる。

#trigger を省略したコード改訂版について
上記のプログラムを見直したところ，わざわざ，カスタム trigger を使わなくても良いことがわかった。trigger を使わない簡潔なコードは，下記のようになる。

```Javascript
    // マウスボタンのクリックイベントに対する処理
    $('#board').on('click', function(e) {
    	var m = e.target.getBoundingClientRect();
        x = e.clientX - m.left;
    	y = e.clientY - m.top;
    	if ( (60 <= x && x < 240)  &&  (20 <= y && y < 200 )) {
        	if ( 60 <= x && x < 240 ) {
        		if( 20 <= y && y < 80 ) {
        			if( x < 120 ) p = 0;
        			else if( x < 180 ) p = 1;
        			else if( x < 240 ) p = 2; }
        		...
            }
            // ユーザーの一手
            if (value[p] != 0) {
                message("そこは置けません");
            }
            else if(value[p] == 0) {
                value[p] = 1;
            	circle(p);
                turn++;
                if (5 <= turn) r = judge();
                if ( r == 0 ) {
                    message("CPU の番です");
                    // コンピュータの一手
        	...
```

初版で，\$(document).trigger('user') {}，すなわち，user にカスタムイベントを送る命令を書いた部分に，それを受信する命令 \$(document).on('user', function() {} ) の中で書いたコード部分を直接書くことによって，コードが簡潔になることがわかった。

#CPU の一手と終局の判定方法
三目並べの対局途中画面を，下図に示す。左側の図にみられるように，〇印はユーザーの手を示し，✖印は cpu の手を示す。現在，5 手まで進んだ局面である。

![三目並べの対局途中画面](http://waves.upper.jp/Computer/TicTacToe/image02.jpg "三目並べの対局途中画面")

cpu の一手は，ランダムに決められる。すなわち，三目並べの枠 0 - 8 の数値を乱数で発生させて，対応する枠がすでに使われている場合は，再度試行する。9 回繰り返しても，空きが見つからない場合は，0 番から順に検索して，最初の空きに入れる。

ここで，枠内に描く図形と枠内を表す値は，対応関係さえあれば良い。そこで，終局の判定をしやすい値を用いた。上図の右側に示したように，ユーザーの手は 1 ，cpu の手は 10 を対応させる。これによって，縦横斜めいずれかの枠内合計値が 3 のときユーザーの勝ち，合計値が 30 のとき cpu の勝ちと判定できる。合計する枠内に相手の手が入っていても，この判定で良いことを確かめられたい。

従って，判定プログラムは，下記のように簡単になる。

```Javascript
function judge() {
    // 勝ち
    if ((value[0]+value[1]+value[2]) == 3 ||
        (value[3]+value[4]+value[5]) == 3 ||
        (value[6]+value[7]+value[8]) == 3 ||
        (value[0]+value[3]+value[6]) == 3 ||
        (value[1]+value[4]+value[7]) == 3 ||
        (value[2]+value[5]+value[8]) == 3 ||
        (value[0]+value[4]+value[8]) == 3 ||
        (value[2]+value[4]+value[6]) == 3 ) {
            message("あなたの勝ちです");
            return 1;
    }
    ...
}
```

#おわりに
三目並べを作るときに，HTML5 Canvas を利用する方法について述べた。本文で示したように，プログラムの可読性は良いと考えている。頭書に示した URL から，プログラム HTML と JavaScript ファイル[^6] をダウンロードして実行しながら見れば，より理解しやすいと思われる。

[^1]: [JavaScriptで作るかんたんアプリケーション](http://programming-blues.hatenablog.com/entry/ThreeBlocksApp)

[^2]: [jQueryで三目並べ（○×ゲーム）を作る過程と結果](http://www.arts-net.co.jp/team/staff_blog/04/12596.html)

[^3]: [作って遊ぼうJava(2) 三目並べの盤のクラス](http://nobukit.cocolog-nifty.com/blog/2011/06/java2-c9ce.html)

[^4]: [三目並べで学ぶミニマックス法](https://postd.cc/tic-tac-toe-understanding-the-minimax-algorithm/)

[^5]: [三目並べの全探索と評価関数](https://qiita.com/kaityo256/items/dfc93258692b38da64bf)

[^6]: [三目並べ プログラム HTML JavaScript](http://waves.upper.jp/Computer/tictactoe.html)

[^7]: [囲碁ブラウザゲーム COSUMI - 無料！](https://www.cosumi.net/)

[^8]: [「囲碁ブラウザゲーム COSUMI」開発日誌](http://www.perfectsky.net/blog/?cat=25)