情報学部 菅沼ホーム JavaScript 目次 索引

オセロ

  1. ステップ1: ゲームの枠組み

      対戦相手を人間またはコンピュータとするオセロを作成します.基本的に,「ゲーム枠の作成」で説明した方法とほぼ同じ方法で作成します.ただし,画面のサイズは変更しています.また,ゲームオーバーやゲームクリアの画面は存在しません.以下,各プログラムに対して,「ゲーム枠の作成」の場合との違いについて説明していきます.なお,作成手順としては,まず人間対人間のゲームを完成させ(ステップ4まで),その後,対戦相手をコンピュータにした場合に必要な機能を付加します(ステップ5).

    1. HTML ファイル

        「ゲーム枠の作成」における HTML ファイルと考え方は同じですが,「ゲームクリア」ボタンと「ゲームオーバー」ボタンを除くと共に,ゲーム方法を選択する 3 つのボタンと,システムからのメッセージを出力するためのテキストエリア( TEXTAREA 要素)が付加されています.また,ゲーム方法を選択するボタンをクリックすると,関数 gp_start を実行する前に,MainPanel オブジェクトのプロパティ mp.method の値を設定しています( 16 行目~ 18 行目).

      01	<!DOCTYPE HTML>
      02	<HTML>
      03	<HEAD>
      04		<TITLE>オセロ:ステップ1</TITLE>
      05		<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
      06		<META NAME=viewport CONTENT="width=device-width, initial-scale=1">
      07		<LINK REL="stylesheet" TYPE="text/css" HREF="../../../master.css">
      08		<SCRIPT TYPE="text/javascript" SRC="main/MainPanel.js"></SCRIPT>
      09		<SCRIPT TYPE="text/javascript" SRC="start/StartPanel.js"></SCRIPT>
      10		<SCRIPT TYPE="text/javascript" SRC="game/GamePanel.js"></SCRIPT>
      11	</HEAD>
      12	<BODY CLASS="eeffee" onLoad="mp_start()">
      13		<H1>オセロ:ステップ1</H1>
      14		<CANVAS ID="canvas_e" STYLE="background-color: #ffffff;" WIDTH="435" HEIGHT="435"></CANVAS><BR>
      15		<A HREF="method.htm" TARGET="method"><BUTTON ID="method" CLASS="std">遊び方</BUTTON></A>
      16		<BUTTON ID="g_method0" CLASS="std" onClick="JavaScript: mp.method=0; gp_start()">対人間</BUTTON>
      17		<BUTTON ID="g_method1" CLASS="std" onClick="JavaScript: mp.method=1; gp_start()">対コンピュータ(人先手)</BUTTON>
      18		<BUTTON ID="g_method2" CLASS="std" onClick="JavaScript: mp.method=2; gp_start()">対コンピュータ(人後手)</BUTTON>
      19		<TEXTAREA ID="ta" TYPE="text" NAME="ta" COLS="40" ROWS="5" CLASS="std"></TEXTAREA><BR>
      20		<BUTTON ID="first" CLASS="std" onClick="st_start()">再開</BUTTON>
      21		<BUTTON ID="finish" CLASS="std" onClick="mp.finish()">終了</BUTTON>
      22	</BODY>
      23	</HTML>
      				

    2. MainPanel

        「ゲーム枠の作成」における MainPanel とほぼ同じですが,ゲームオーバーやゲームクリアの状態,及び,ゲームレベルを無くし,MainPanel オブジェクトに対して,ゲーム方法を示すプロパティ method を追加しています.また,ボタン等の制御部分も多少異なっています.

      mp = null;   // MainPanel オブジェクト
      
      			//
      			// MainPanel の開始
      			//
      function mp_start()
      {
      					// キャンバス情報
      	let canvas = document.getElementById('canvas_e');   // キャンバス要素の取得
      	let ctx    = canvas.getContext('2d');   // キャンバスからコンテキストを取得
      					// MainPanel オブジェクト
      	mp = new MainPanel(canvas, ctx);
      					// StartPanel の表示
      	st_start();
      }
      			//
      			// MainPanel オブジェクト(プロパティ)
      			//
      function MainPanel(canvas, ctx)
      {
      	this.canvas = canvas;   // キャンバス要素
      	this.ctx    = ctx;   // キャンバスのコンテキスト
      	this.method = 0;   // ゲーム方法(0:対人間,1:対PC(先手),2:対PC(後手))
      	return this;
      }
      			//
      			// MainPanel オブジェクト(メソッド)
      			//
      MainPanel.prototype.finish = function()
      {
      					// キャンバスのクリア
      	mp.ctx.clearRect(0, 0, mp.canvas.width, mp.canvas.height);
      					// ボタンを非表示
      	document.getElementById('method').style.display = "none";
      	document.getElementById('g_method0').style.display = "none";
      	document.getElementById('g_method1').style.display = "none";
      	document.getElementById('g_method2').style.display = "none";
      	document.getElementById('ta').style.display = "none";
      	document.getElementById('first').style.display = "none";
      	document.getElementById('finish').style.display = "none";
      }
      				

    3. StartPanel

        「ゲーム枠の作成」における StartPanel とほとんど同じです.ボタン等の制御部分が異なっているだけです.当然のことながら,ゲームタイトル及び「遊び方」の内容を変更しています.

      			//
      			// StartPanel の開始
      			//
      function st_start()
      {
      	mp.level = 1;   // ゲームレベルの設定
      					// キャンバスのクリア
      	mp.ctx.clearRect(0, 0, mp.canvas.width, mp.canvas.height);
      					// ゲームタイトルの表示
      	mp.ctx.font = "40px 'MS ゴシック'";
      	mp.ctx.textBaseline = "middle";
      	mp.ctx.textAlign = "center";
      	mp.ctx.fillStyle = "rgb(0, 0, 0)";
      	mp.ctx.fillText("オセロ", mp.canvas.width/2, mp.canvas.height/2);
      					// ボタンの表示制御
      	document.getElementById('method').style.display = "";
      	document.getElementById('g_method0').style.display = "";
      	document.getElementById('g_method1').style.display = "";
      	document.getElementById('g_method2').style.display = "";
      	document.getElementById('ta').style.display = "none";
      	document.getElementById('first').style.display = "none";
      	document.getElementById('finish').style.display = "none";
      }
      				

    4. GamePanel

        GamePanel は,実際のゲームを実現するプログラムです.従って,「ゲーム枠の作成」における GamePanel とは,ゲームの種類によってその内容は大きく異なります.今後,このプログラムを完成させていくことになりますが,ここでは,オセロを実行する盤を表示しています.

      01	gp = null;   // GamePanel オブジェクト
      02	
      03				//
      04				// GamePanel の開始
      05				//
      06	function gp_start()
      07	{
      08						// GamePanel オブジェクト
      09		gp = new GamePanel();
      10						// 描画
      11		gp.draw();
      12						// ボタンの表示制御
      13		document.getElementById('method').style.display = "none";
      14		document.getElementById('g_method0').style.display = "none";
      15		document.getElementById('g_method1').style.display = "none";
      16		document.getElementById('g_method2').style.display = "none";
      17		document.getElementById('ta').style.display = "";
      18		document.getElementById('ta').style.color = "black";
      19		document.getElementById('ta').innerHTML = "黒の番です.";
      20		document.getElementById('first').style.display = "";
      21		document.getElementById('finish').style.display = "";
      22	}
      23				//
      24				// GamePanel オブジェクト(プロパティ)
      25				//
      26	function GamePanel()
      27	{
      28		this.sz = 51;   // マス目の大きさ
      29		this.gap = 3;   // マス目間のギャップ
      30		return this;
      31	}
      32				//
      33				// GamePanel オブジェクト(メソッド draw)
      34				//
      35	GamePanel.prototype.draw = function()
      36	{
      37						// キャンバスのクリア
      38		mp.ctx.clearRect(0, 0, mp.canvas.width, mp.canvas.height);
      39						// 描画
      40		mp.ctx.beginPath();
      41		mp.ctx.fillStyle = "rgb(165, 42, 42)";
      42		mp.ctx.fillRect(0, 0, mp.canvas.width, mp.canvas.height);
      43		mp.ctx.fill();
      44	
      45		for (let i1 = 0; i1 < 8; i1++) {
      46			for (let i2 = 0; i2 < 8; i2++) {
      47				let x = gp.gap + i2 * (gp.sz + gp.gap);
      48				let y = gp.gap + i1 * (gp.sz + gp.gap);
      49				mp.ctx.beginPath();
      50				mp.ctx.fillStyle = "rgb(0, 255, 0)";
      51				mp.ctx.fillRect(x, y, gp.sz, gp.sz);
      52				mp.ctx.fill();
      53			}
      54		}
      55	}
      				
      09 行目( gp_start 関数)

        GamePanel オブジェクトを生成し,その結果をグローバル変数 gp( 01 行目)に代入しています.具体的には,26 行目~ 31 行目に記述された GamePanel 関数が実行されます.

      11 行目( gp_start 関数)

        GamePanel オブジェクトのメソッド draw( 35 行目~ 55 行目)によって描画しています.

      17 行目~ 21 行目( gp_start 関数)

        テキストエリア,「再開」ボタン,及び,「終了」ボタンを表示しています.

      35 行目~ 55 行目( draw メソッド)

        オセロ盤を描画するためのメソッド draw の定義です.画面をクリア( 38 行目)した後,背景を描き( 40 行目~ 43 行目),コマを置くマス目を描画( 45 行目~ 54 行目)しています.

  2. ステップ2: 初期状態の表示

      ここでは,初期状態におけるコマの配置を表示しています.修正するプログラムは,GamePanel の GamePanel 関数と draw メソッドです.

    01	gp = null;   // GamePanel オブジェクト
    02	
    03				//
    04				// GamePanel の開始
    05				//
    06	function gp_start()
    07	{
    08						// GamePanel オブジェクト
    09		gp = new GamePanel();
    10						// 描画
    11		gp.draw();
    12						// ボタンの表示制御
    13		document.getElementById('method').style.display = "none";
    14		document.getElementById('g_method0').style.display = "none";
    15		document.getElementById('g_method1').style.display = "none";
    16		document.getElementById('g_method2').style.display = "none";
    17		document.getElementById('ta').style.display = "";
    18		document.getElementById('ta').style.color = "black";
    19		document.getElementById('ta').innerHTML = "黒の番です.";
    20		document.getElementById('first').style.display = "";
    21		document.getElementById('finish').style.display = "";
    22	}
    23				//
    24				// GamePanel オブジェクト(プロパティ)
    25				//
    26	function GamePanel()
    27	{
    28		this.sz = 51;   // マス目の大きさ
    29		this.gap = 3;   // マス目間のギャップ
    30		this.st = new Array();   // 盤面の状態(0:コマが置かれてない,-1:黒,1:白)
    31		this.st[0] = new Array(0, 0, 0, 0, 0, 0, 0, 0);
    32		this.st[1] = new Array(0, 0, 0, 0, 0, 0, 0, 0);
    33		this.st[2] = new Array(0, 0, 0, 0, 0, 0, 0, 0);
    34		this.st[3] = new Array(0, 0, 0, 1, -1, 0, 0, 0);
    35		this.st[4] = new Array(0, 0, 0, -1, 1, 0, 0, 0);
    36		this.st[5] = new Array(0, 0, 0, 0, 0, 0, 0, 0);
    37		this.st[6] = new Array(0, 0, 0, 0, 0, 0, 0, 0);
    38		this.st[7] = new Array(0, 0, 0, 0, 0, 0, 0, 0);
    39		return this;
    40	}
    41				//
    42				// GamePanel オブジェクト(メソッド draw)
    43				//
    44	GamePanel.prototype.draw = function()
    45	{
    46						// キャンバスのクリア
    47		mp.ctx.clearRect(0, 0, mp.canvas.width, mp.canvas.height);
    48						// 描画
    49		mp.ctx.beginPath();
    50		mp.ctx.fillStyle = "rgb(165, 42, 42)";
    51		mp.ctx.fillRect(0, 0, mp.canvas.width, mp.canvas.height);
    52		mp.ctx.fill();
    53	
    54		for (let i1 = 0; i1 < 8; i1++) {
    55			for (let i2 = 0; i2 < 8; i2++) {
    56				let x = gp.gap + i2 * (gp.sz + gp.gap);
    57				let y = gp.gap + i1 * (gp.sz + gp.gap);
    58				mp.ctx.beginPath();
    59				mp.ctx.fillStyle = "rgb(0, 255, 0)";
    60				mp.ctx.fillRect(x, y, gp.sz, gp.sz);
    61				mp.ctx.fill();
    62				if (gp.st[i1][i2] != 0) {
    63					x += Math.floor(gp.sz / 2);
    64					y += Math.floor(gp.sz / 2);
    65					mp.ctx.beginPath();
    66					if (gp.st[i1][i2] < 0)
    67						mp.ctx.fillStyle = "rgb(0, 0, 0)";
    68					else
    69						mp.ctx.fillStyle = "rgb(255, 255, 255)";
    70					mp.ctx.arc(x, y, Math.floor(gp.sz/2)-2, 0, 2*Math.PI);
    71					mp.ctx.fill();
    72				}
    73			}
    74		}
    75	}
    			
    30 行目~ 38 行目( GamePanel 関数)

      オセロ盤の状態を示すプロパティ st( 8 行 8 列の 2 次元配列)を定義し,その初期設定を行っています.0 の場合はコマが置かれてない,-1 の場合は黒コマが置かれている,また,1 の場合は白コマが置かれていることを示します.ここで示すように,2 次元配列は,まず配列を定義し( 30 行目),その配列の各要素を再び配列として定義する( 31 行目~ 38 行目)ことによって可能です.

      一般に,配列の各要素を配列として定義することによって,多次元配列を定義することが可能です.以下に示すのは 2 行 3 列の 2 次元配列の例です.
    	let a = new Array(2);   // let a = new Array(); でも可
    	for (let i1 = 0; i1 < 2; i1++)
    		a[i1] = new Array(3);				
    初期設定も同時に行いたい場合は,例えば,以下のようにして行います.
    	let a = new Array(2);   // let a = new Array(); でも可
    	a[0] = new Array(1, 2, 3);
    	a[1] = new Array(4, 5, 6);				
    62 行目~ 72 行目( draw メソッド)

      コマが存在する場所に,対応するコマを描画しています.

  3. ステップ3: コマを置く

      ここでは,人間対人間の対戦において,コマを置く動作を実現しています.GamePanel の gp_start 関数,及び,GamePanel 関数を修正すると共に,マウスのクリックイベントを処理するメソッド mouseClick,反転できるコマ探すメソッド r_check,コマの操作を行うメソッド set,及び,コマを反転するメソッド reverse を GamePanel オブジェクトに追加しています.

    001	gp = null;   // GamePanel オブジェクト
    002	
    003				//
    004				// GamePanel の開始
    005				//
    006	function gp_start()
    007	{
    008						// GamePanel オブジェクト
    009		gp = new GamePanel();
    010						// 描画
    011		gp.draw();
    012						// マウスクリックに対するイベントリスナ
    013		mp.canvas.addEventListener("click", gp.mouseClick);
    014						// ボタンの表示制御
    015		document.getElementById('method').style.display = "none";
    016		document.getElementById('g_method0').style.display = "none";
    017		document.getElementById('g_method1').style.display = "none";
    018		document.getElementById('g_method2').style.display = "none";
    019		document.getElementById('ta').style.display = "";
    020		document.getElementById('ta').style.color = "black";
    021		document.getElementById('ta').innerHTML = "黒の番です.";
    022		document.getElementById('first').style.display = "";
    023		document.getElementById('finish').style.display = "";
    024	}
    025				//
    026				// GamePanel オブジェクト(プロパティ)
    027				//
    028	function GamePanel()
    029	{
    030		this.sz = 51;   // マス目の大きさ
    031		this.gap = 3;   // マス目間のギャップ
    032		this.b_w = -1;   // -1:黒の手番,1:白の手番
    033		this.st = new Array();   // 盤面の状態(0:コマが置かれてない,-1:黒,1:白)
    034		this.st[0] = new Array(0, 0, 0, 0, 0, 0, 0, 0);
    035		this.st[1] = new Array(0, 0, 0, 0, 0, 0, 0, 0);
    036		this.st[2] = new Array(0, 0, 0, 0, 0, 0, 0, 0);
    037		this.st[3] = new Array(0, 0, 0, 1, -1, 0, 0, 0);
    038		this.st[4] = new Array(0, 0, 0, -1, 1, 0, 0, 0);
    039		this.st[5] = new Array(0, 0, 0, 0, 0, 0, 0, 0);
    040		this.st[6] = new Array(0, 0, 0, 0, 0, 0, 0, 0);
    041		this.st[7] = new Array(0, 0, 0, 0, 0, 0, 0, 0);
    042		this.n = new Array();   // 指定された位置の各方向に対する反転できるコマの数
    043		                        //    [0] : 上方向
    044		                        //    [1] : 斜め右上方向
    045		                        //    [2] : 右方向
    046		                        //    [3] : 斜め右下方向
    047		                        //    [4] : 下方向
    048		                        //    [5] : 斜め左下方向
    049		                        //    [6] : 左方向
    050		                        //    [7] : 斜め左上方向
    051		                        //    [8] : 全体
    052		return this;
    053	}
    054				//
    055				// GamePanel オブジェクト(メソッド mouseClick)
    056				//
    057	GamePanel.prototype.mouseClick = function(event)
    058	{
    059		let x_base  = mp.canvas.offsetLeft;   // キャンバスの左上のx座標
    060		let y_base  = mp.canvas.offsetTop;   // キャンバスの左上のy座標
    061		let x       = event.pageX - x_base;    // キャンバス内のクリックされた位置(x座標)
    062		let y       = event.pageY - y_base;    // キャンバス内のクリックされた位置(y座標)
    063						// クリックされたマス目を特定
    064		let k = new Array(-1, -1);
    065		for (let i1 = 0; i1 < 8; i1++) {
    066			if (y >= gp.gap+i1*(gp.gap+gp.sz) && y <= (i1+1)*(gp.gap+gp.sz)) {
    067				k[0] = i1;
    068				break;
    069			}
    070		}
    071		for (let i1 = 0; i1 < 8; i1++) {
    072			if (x >= gp.gap+i1*(gp.gap+gp.sz) && x <= (i1+1)*(gp.gap+gp.sz)) {
    073				k[1] = i1;
    074				break;
    075			}
    076		}
    077						// 反転できるコマを探す
    078		gp.r_check(k);
    079								// 反転するコマがない場合
    080		if (gp.n[8] <= 0) {
    081			document.getElementById('ta').style.color = "red";
    082			let str = "の番ですが,\nそこへはコマを置けません.";
    083			if (gp.b_w < 0)
    084				document.getElementById('ta').innerHTML = "黒" + str;
    085			else
    086				document.getElementById('ta').innerHTML = "白" + str;
    087		}
    088								// 反転するコマがある場合
    089		else
    090			gp.set(k);
    091	}
    092				//
    093				// k[0] 行 k[1] 列に黒または白( b_w )のコマを置いた場合,反転できるコマを探す( GamePanel オブジェクトのメソッド r_check )
    094				//
    095	GamePanel.prototype.r_check = function(k)
    096	{
    097		let d = new Array();
    098		d[0] = new Array(-1, 0);
    099		d[1] = new Array(-1, 1);
    100		d[2] = new Array(0, 1);
    101		d[3] = new Array(1, 1);
    102		d[4] = new Array(1, 0);
    103		d[5] = new Array(1, -1);
    104		d[6] = new Array(0, -1);
    105		d[7] = new Array(-1, -1);
    106		gp.n[8] = 0;
    107		if (k[0] >= 0 && k[1] >= 0 && gp.st[k[0]][k[1]] == 0) {
    108			for (let i1 = 0; i1 < 8; i1++) {
    109				let m1   = k[0];
    110				let m2   = k[1];
    111				gp.n[i1] = 0;
    112				let s    = 0;   // 0:開始,1:カウント,2:カウント終了,3:反転不可能
    113				let ct   = 0;
    114				while (s < 2) {
    115					m1 += d[i1][0];
    116					m2 += d[i1][1];
    117					if (m1 >= 0 && m1 < 8 && m2 >= 0 && m2 < 8) {
    118						if (gp.st[m1][m2] == 0)
    119							s = 3;
    120						else if (gp.st[m1][m2] == gp.b_w) {
    121							if (s == 1)
    122								s = 2;
    123							else
    124								s = 3;
    125						}
    126						else {
    127							s = 1;
    128							ct++;
    129						}
    130					}
    131					else
    132						s = 3;
    133				}
    134				if (s == 2) {
    135					gp.n[8]  += ct;
    136					gp.n[i1]  = ct;
    137				}
    138			}
    139		}
    140	}
    141				//
    142				// コマの操作( GamePanel オブジェクトのメソッド set )
    143				//
    144	GamePanel.prototype.set = function(k)
    145	{
    146						// 反転
    147		gp.reverse(k);
    148		gp.b_w = -gp.b_w;
    149		document.getElementById('ta').style.color = "black";
    150		if (gp.b_w < 0)
    151			document.getElementById('ta').innerHTML = "黒の番です.";
    152		else
    153			document.getElementById('ta').innerHTML = "白の番です.";
    154	}
    155				//
    156				// k[0] 行 k[1] 列に黒または白( b_w )のコマを置いた場合におけるコマの反転( GamePanel オブジェクトのメソッド reverse )
    157				//
    158	GamePanel.prototype.reverse = function(k)
    159	{
    160		let d = new Array();
    161		d[0] = new Array(-1, 0);
    162		d[1] = new Array(-1, 1);
    163		d[2] = new Array(0, 1);
    164		d[3] = new Array(1, 1);
    165		d[4] = new Array(1, 0);
    166		d[5] = new Array(1, -1);
    167		d[6] = new Array(0, -1);
    168		d[7] = new Array(-1, -1);
    169		for (let i1 = 0; i1 < 8; i1++) {
    170			let m1   = k[0];
    171			let m2   = k[1];
    172			for (let i2 = 0; i2 < gp.n[i1]; i2++) {
    173				m1 += d[i1][0];
    174				m2 += d[i1][1];
    175				gp.st[m1][m2] = gp.b_w;
    176			}
    177		}
    178		gp.st[k[0]][k[1]] = gp.b_w;
    179						// 描画
    180		gp.draw();
    181	}
    182				//
    183				// GamePanel オブジェクト(メソッド draw)
    184				//
    185	GamePanel.prototype.draw = function()
    186	{
    187						// キャンバスのクリア
    188		mp.ctx.clearRect(0, 0, mp.canvas.width, mp.canvas.height);
    189						// 描画
    190		mp.ctx.beginPath();
    191		mp.ctx.fillStyle = "rgb(165, 42, 42)";
    192		mp.ctx.fillRect(0, 0, mp.canvas.width, mp.canvas.height);
    193		mp.ctx.fill();
    194	
    195		for (let i1 = 0; i1 < 8; i1++) {
    196			for (let i2 = 0; i2 < 8; i2++) {
    197				let x = gp.gap + i2 * (gp.sz + gp.gap);
    198				let y = gp.gap + i1 * (gp.sz + gp.gap);
    199				mp.ctx.beginPath();
    200				mp.ctx.fillStyle = "rgb(0, 255, 0)";
    201				mp.ctx.fillRect(x, y, gp.sz, gp.sz);
    202				mp.ctx.fill();
    203				if (gp.st[i1][i2] != 0) {
    204					x += Math.floor(gp.sz / 2);
    205					y += Math.floor(gp.sz / 2);
    206					mp.ctx.beginPath();
    207					if (gp.st[i1][i2] < 0)
    208						mp.ctx.fillStyle = "rgb(0, 0, 0)";
    209					else
    210						mp.ctx.fillStyle = "rgb(255, 255, 255)";
    211					mp.ctx.arc(x, y, Math.floor(gp.sz/2)-2, 0, 2*Math.PI);
    212					mp.ctx.fill();
    213				}
    214			}
    215		}
    216	}
    			
    013 行目( gp_start 関数)

      マウスのクリックに対応するイベントリスナを追加します.クリックされた時の具体的な処理は,GamePanel オブジェクトのメソッド mouseClick( 057 行目~ 091 行目)で行われます.

    032 行目( GamePanel 関数)

      次にどちらの番かを示すプロパティ b_w を定義し,その初期設定を行っています.この値が -1 の場合は黒,また,1 の場合は白の番であることを示します.

    042 行目( GamePanel 関数)

      指定されたボタンにコマを置いた場合,斜め右上,右,斜め右下,下,斜め左下,左,及び,斜め左上方向の挟んで反転できるコマの数を設定するためのプロパティです.n[8] にはそれらの数の和が設定されます.従って,n[8] が 0 となるような場所にはコマを置けないことになります.

    064 行目~ 076 行目( mouseClick メソッド)

      クリックされたマス目を特定し,その行番号を k[0],列番号を k[1] に代入しています.

    078 行目( mouseClick メソッド)

      k[0] 行 k[1] 列にコマを置いた場合に反転できるコマを探すため,GamePanel オブジェクトのメソッド r_check を呼んでいます.その結果,n[0] ~ n[8] に値が設定されます.メソッドにおける処理内容は,095 行目~ 140 行目に記載されています.

    081 行目~ 086 行目( mouseClick メソッド)

      上の処理の結果,反転するコマが存在しない場合は,テキストエリアにメッセージを出力しています.

    090 行目( mouseClick メソッド)

      コマを反転し,その後の処理を行う GamePanel オブジェクトのメソッド set を呼んでいます.メソッドの内容は,144 行目~ 154 行目に記載されています.

    097 行目~ 105 行目( r_check メソッド)

      反転できるコマを探す方向をセットしています.例えば,(-1, 0) は,行番号が 1 だけ減り列番号が同じ方向,つまり,上方向を表しています.

    108 行目~ 138 行目( r_check メソッド)

      k[0] 行 k[1] 列 を基点とした 8 つの方向に対して,反転させることができるコマの数を数えています.

    147 行目( set メソッド)

      n[0] ~ n[8] に設定された内容に基づき,k[0] 行 k[1] 列にコマを置いた時の反転処理を行う GamePanel オブジェクトのメソッド reverse を呼んでいます.メソッドにおける処理内容は,158 行目~ 181 行目に記載されています.

    148 行目~ 153 行目( set メソッド)

      手番を変更した( 148 行目)後,テキストエリアにメッセージを出力しています.

    169 行目~ 178 行目( reverse メソッド)

      k[0] 行 k[1] 列にコマを置いた時,8 つの方向に対して,挟まれているコマを反転した後,178 行目において,置いたコマに対する処理を行っています.

    180 行目( reverse メソッド)

      再描画しています.

  4. ステップ4: 勝敗とスキップ

      ここでは,勝敗を決定する操作,及び,コマを置く場所が存在しない場合スキップする操作を追加します.ここまでの処理によって,人間対人間の対戦は完成となります.修正するプログラムは,GamePanel のメソッド set だけです.

    001	gp = null;   // GamePanel オブジェクト
    002	
    003				//
    004				// GamePanel の開始
    005				//
    006	function gp_start()
    007	{
    008						// GamePanel オブジェクト
    009		gp = new GamePanel();
    010						// 描画
    011		gp.draw();
    012						// マウスクリックに対するイベントリスナ
    013		mp.canvas.addEventListener("click", gp.mouseClick);
    014						// ボタンの表示制御
    015		document.getElementById('method').style.display = "none";
    016		document.getElementById('g_method0').style.display = "none";
    017		document.getElementById('g_method1').style.display = "none";
    018		document.getElementById('g_method2').style.display = "none";
    019		document.getElementById('ta').style.display = "";
    020		document.getElementById('ta').style.color = "black";
    021		document.getElementById('ta').innerHTML = "黒の番です.";
    022		document.getElementById('first').style.display = "";
    023		document.getElementById('finish').style.display = "";
    024	}
    025				//
    026				// GamePanel オブジェクト(プロパティ)
    027				//
    028	function GamePanel()
    029	{
    030		this.sz = 51;   // マス目の大きさ
    031		this.gap = 3;   // マス目間のギャップ
    032		this.b_w = -1;   // -1:黒の手番,1:白の手番
    033		this.st = new Array();   // 盤面の状態(0:コマが置かれてない,-1:黒,1:白)
    034		this.st[0] = new Array(0, 0, 0, 0, 0, 0, 0, 0);
    035		this.st[1] = new Array(0, 0, 0, 0, 0, 0, 0, 0);
    036		this.st[2] = new Array(0, 0, 0, 0, 0, 0, 0, 0);
    037		this.st[3] = new Array(0, 0, 0, 1, -1, 0, 0, 0);
    038		this.st[4] = new Array(0, 0, 0, -1, 1, 0, 0, 0);
    039		this.st[5] = new Array(0, 0, 0, 0, 0, 0, 0, 0);
    040		this.st[6] = new Array(0, 0, 0, 0, 0, 0, 0, 0);
    041		this.st[7] = new Array(0, 0, 0, 0, 0, 0, 0, 0);
    042		this.n = new Array();   // 指定された位置の各方向に対する反転できるコマの数
    043		                        //    [0] : 上方向
    044		                        //    [1] : 斜め右上方向
    045		                        //    [2] : 右方向
    046		                        //    [3] : 斜め右下方向
    047		                        //    [4] : 下方向
    048		                        //    [5] : 斜め左下方向
    049		                        //    [6] : 左方向
    050		                        //    [7] : 斜め左上方向
    051		                        //    [8] : 全体
    052		return this;
    053	}
    054				//
    055				// GamePanel オブジェクト(メソッド mouseClick)
    056				//
    057	GamePanel.prototype.mouseClick = function(event)
    058	{
    059		let x_base  = mp.canvas.offsetLeft;   // キャンバスの左上のx座標
    060		let y_base  = mp.canvas.offsetTop;   // キャンバスの左上のy座標
    061		let x       = event.pageX - x_base;    // キャンバス内のクリックされた位置(x座標)
    062		let y       = event.pageY - y_base;    // キャンバス内のクリックされた位置(y座標)
    063						// クリックされたマス目を特定
    064		let k = new Array(-1, -1);
    065		for (let i1 = 0; i1 < 8; i1++) {
    066			if (y >= gp.gap+i1*(gp.gap+gp.sz) && y <= (i1+1)*(gp.gap+gp.sz)) {
    067				k[0] = i1;
    068				break;
    069			}
    070		}
    071		for (let i1 = 0; i1 < 8; i1++) {
    072			if (x >= gp.gap+i1*(gp.gap+gp.sz) && x <= (i1+1)*(gp.gap+gp.sz)) {
    073				k[1] = i1;
    074				break;
    075			}
    076		}
    077						// 反転できるコマを探す
    078		gp.r_check(k);
    079								// 反転するコマがない場合
    080		if (gp.n[8] <= 0) {
    081			document.getElementById('ta').style.color = "red";
    082			let str = "の番ですが,\nそこへはコマを置けません.";
    083			if (gp.b_w < 0)
    084				document.getElementById('ta').innerHTML = "黒" + str;
    085			else
    086				document.getElementById('ta').innerHTML = "白" + str;
    087		}
    088								// 反転するコマがある場合
    089		else
    090			gp.set(k);
    091	}
    092				//
    093				// k[0] 行 k[1] 列に黒または白( b_w )のコマを置いた場合,反転できるコマを探す( GamePanel オブジェクトのメソッド r_check )
    094				//
    095	GamePanel.prototype.r_check = function(k)
    096	{
    097		let d = new Array();
    098		d[0] = new Array(-1, 0);
    099		d[1] = new Array(-1, 1);
    100		d[2] = new Array(0, 1);
    101		d[3] = new Array(1, 1);
    102		d[4] = new Array(1, 0);
    103		d[5] = new Array(1, -1);
    104		d[6] = new Array(0, -1);
    105		d[7] = new Array(-1, -1);
    106		gp.n[8] = 0;
    107		if (k[0] >= 0 && k[1] >= 0 && gp.st[k[0]][k[1]] == 0) {
    108			for (let i1 = 0; i1 < 8; i1++) {
    109				let m1   = k[0];
    110				let m2   = k[1];
    111				gp.n[i1] = 0;
    112				let s    = 0;   // 0:開始,1:カウント,2:カウント終了,3:反転不可能
    113				let ct   = 0;
    114				while (s < 2) {
    115					m1 += d[i1][0];
    116					m2 += d[i1][1];
    117					if (m1 >= 0 && m1 < 8 && m2 >= 0 && m2 < 8) {
    118						if (gp.st[m1][m2] == 0)
    119							s = 3;
    120						else if (gp.st[m1][m2] == gp.b_w) {
    121							if (s == 1)
    122								s = 2;
    123							else
    124								s = 3;
    125						}
    126						else {
    127							s = 1;
    128							ct++;
    129						}
    130					}
    131					else
    132						s = 3;
    133				}
    134				if (s == 2) {
    135					gp.n[8]  += ct;
    136					gp.n[i1]  = ct;
    137				}
    138			}
    139		}
    140	}
    141				//
    142				// コマの操作( GamePanel オブジェクトのメソッド set )
    143				//
    144	GamePanel.prototype.set = function(k)
    145	{
    146						// 反転
    147		gp.reverse(k);
    148		gp.b_w = -gp.b_w;
    149						// コマの数を数え,勝敗決定のチェック
    150		let b = 0;
    151		let w = 0;
    152		let total = 0;
    153		for (let i1 = 0; i1 < 8; i1++) {
    154			for (let i2 = 0; i2 < 8; i2++) {
    155				if (gp.st[i1][i2] != 0) {
    156					total++;
    157					if (gp.st[i1][i2] < 0)
    158						b++;
    159					else
    160						w++;
    161				}
    162			}
    163		}
    164						// 勝敗決定
    165		if (total == 64) {
    166			document.getElementById('ta').style.color = "black";
    167			let str = "黒 " + b + " 個, 白 " + w + " 個\n";
    168			if (b > w)
    169				document.getElementById('ta').innerHTML = str + "黒の勝ちです.";
    170			else if (b == w)
    171				document.getElementById('ta').innerHTML = str + "引き分けです.";
    172			else
    173				document.getElementById('ta').innerHTML = str + "白の勝ちです.";
    174			mp.canvas.removeEventListener("click", gp.mouseClick);   // リスのの除去
    175		}
    176						// 勝負継続
    177		else {
    178			document.getElementById('ta').style.color = "black";
    179			let str = "黒 " + b + " 個, 白 " + w + " 個\n";
    180								// スキップのチェック
    181			let sw = false;
    182			for (let i1 = 0; i1 < 8 && !sw; i1++) {
    183				for (let i2 = 0; i2 < 8 && !sw; i2++) {
    184					k[0] = i1;
    185					k[1] = i2;
    186					gp.r_check(k);
    187					if (gp.n[8] > 0)
    188						sw = true;
    189				}
    190			}
    191								// スキップの場合
    192			if (!sw) {
    193				gp.b_w = -gp.b_w;
    194				str += "コマを置けないため,スキップし,\n";
    195			}
    196								// 次の手
    197			if (gp.b_w < 0)
    198				document.getElementById('ta').innerHTML = str + "黒の番です.";
    199			else
    200				document.getElementById('ta').innerHTML = str + "白の番です.";
    201		}
    202	}
    203				//
    204				// k[0] 行 k[1] 列に黒または白( b_w )のコマを置いた場合におけるコマの反転( GamePanel オブジェクトのメソッド reverse )
    205				//
    206	GamePanel.prototype.reverse = function(k)
    207	{
    208		let d = new Array();
    209		d[0] = new Array(-1, 0);
    210		d[1] = new Array(-1, 1);
    211		d[2] = new Array(0, 1);
    212		d[3] = new Array(1, 1);
    213		d[4] = new Array(1, 0);
    214		d[5] = new Array(1, -1);
    215		d[6] = new Array(0, -1);
    216		d[7] = new Array(-1, -1);
    217		for (let i1 = 0; i1 < 8; i1++) {
    218			let m1   = k[0];
    219			let m2   = k[1];
    220			for (let i2 = 0; i2 < gp.n[i1]; i2++) {
    221				m1 += d[i1][0];
    222				m2 += d[i1][1];
    223				gp.st[m1][m2] = gp.b_w;
    224			}
    225		}
    226		gp.st[k[0]][k[1]] = gp.b_w;
    227						// 描画
    228		gp.draw();
    229	}
    230				//
    231				// GamePanel オブジェクト(メソッド draw)
    232				//
    233	GamePanel.prototype.draw = function()
    234	{
    235						// キャンバスのクリア
    236		mp.ctx.clearRect(0, 0, mp.canvas.width, mp.canvas.height);
    237						// 描画
    238		mp.ctx.beginPath();
    239		mp.ctx.fillStyle = "rgb(165, 42, 42)";
    240		mp.ctx.fillRect(0, 0, mp.canvas.width, mp.canvas.height);
    241		mp.ctx.fill();
    242	
    243		for (let i1 = 0; i1 < 8; i1++) {
    244			for (let i2 = 0; i2 < 8; i2++) {
    245				let x = gp.gap + i2 * (gp.sz + gp.gap);
    246				let y = gp.gap + i1 * (gp.sz + gp.gap);
    247				mp.ctx.beginPath();
    248				mp.ctx.fillStyle = "rgb(0, 255, 0)";
    249				mp.ctx.fillRect(x, y, gp.sz, gp.sz);
    250				mp.ctx.fill();
    251				if (gp.st[i1][i2] != 0) {
    252					x += Math.floor(gp.sz / 2);
    253					y += Math.floor(gp.sz / 2);
    254					mp.ctx.beginPath();
    255					if (gp.st[i1][i2] < 0)
    256						mp.ctx.fillStyle = "rgb(0, 0, 0)";
    257					else
    258						mp.ctx.fillStyle = "rgb(255, 255, 255)";
    259					mp.ctx.arc(x, y, Math.floor(gp.sz/2)-2, 0, 2*Math.PI);
    260					mp.ctx.fill();
    261				}
    262			}
    263		}
    264	}
    			
    149 行目~ 163 行目

      黒及び白のコマを数えています.

    165 行目~ 175 行目

      勝敗が決定した場合の処理です.テキストエリアにメッセージを出力した後,オセロ盤上のマス目をクリックしても反応しないようにしています.

    178,179 行目

      テキストエリアに,現時点における黒及び白のコマの数を表示しています.

    181 行目~ 190 行目

      GamePanel オブジェクトのメソッド r_check を利用して,コマを置ける場所が存在するか否かを調べています.

    192 行目~ 195 行目

      コマを置ける場所が存在しない場合は,テキストエリアにメッセージを出力し,手番を変更しています.

  5. ステップ5: 完成

      ここでは,コンピュータがコマを置く場所を決定する処理を加え,ゲームを完成します.コンピュータのアルゴリズムを強化すれば強いオセロになりますが,今回は,最も多くのコマを反転できる場所を選択するようにしています.GamePanel の gp_start 関数,mouseClick メソッド,及び,set メソッドを修正すると共に,コンピュータがコマを置く場所を決定するメソッド computer を GamePanel オブジェクトに追加しています.

    001	gp = null;   // GamePanel オブジェクト
    002	
    003				//
    004				// GamePanel の開始
    005				//
    006	function gp_start()
    007	{
    008						// GamePanel オブジェクト
    009		gp = new GamePanel();
    010						// 描画
    011		gp.draw();
    012						// マウスクリックに対するイベントリスナ
    013		mp.canvas.addEventListener("click", gp.mouseClick);
    014						// ボタンの表示制御
    015		document.getElementById('method').style.display = "none";
    016		document.getElementById('g_method0').style.display = "none";
    017		document.getElementById('g_method1').style.display = "none";
    018		document.getElementById('g_method2').style.display = "none";
    019		document.getElementById('ta').style.display = "";
    020		document.getElementById('ta').style.color = "black";
    021		if (mp.method == 0)
    022			document.getElementById('ta').innerHTML = "黒の番です.";
    023		else if (mp.method == 1)
    024			document.getElementById('ta').innerHTML = "あなた(黒)の番です.";
    025		else
    026			document.getElementById('ta').innerHTML = "コンピュータの番です.";
    027		document.getElementById('first').style.display = "";
    028		document.getElementById('finish').style.display = "";
    029						// コンピュータの操作
    030		if (mp.method == 2) {
    031			let k = gp.computer();   // コマを置く場所の決定
    032			gp.set(k);   // コマを置く
    033		}
    034	}
    035				//
    036				// GamePanel オブジェクト(プロパティ)
    037				//
    038	function GamePanel()
    039	{
    040		this.sz = 51;   // マス目の大きさ
    041		this.gap = 3;   // マス目間のギャップ
    042		this.b_w = -1;   // -1:黒の手番,1:白の手番
    043		this.st = new Array();   // 盤面の状態(0:コマが置かれてない,-1:黒,1:白)
    044		this.st[0] = new Array(0, 0, 0, 0, 0, 0, 0, 0);
    045		this.st[1] = new Array(0, 0, 0, 0, 0, 0, 0, 0);
    046		this.st[2] = new Array(0, 0, 0, 0, 0, 0, 0, 0);
    047		this.st[3] = new Array(0, 0, 0, 1, -1, 0, 0, 0);
    048		this.st[4] = new Array(0, 0, 0, -1, 1, 0, 0, 0);
    049		this.st[5] = new Array(0, 0, 0, 0, 0, 0, 0, 0);
    050		this.st[6] = new Array(0, 0, 0, 0, 0, 0, 0, 0);
    051		this.st[7] = new Array(0, 0, 0, 0, 0, 0, 0, 0);
    052		this.n = new Array();   // 指定された位置の各方向に対する反転できるコマの数
    053		                        //    [0] : 上方向
    054		                        //    [1] : 斜め右上方向
    055		                        //    [2] : 右方向
    056		                        //    [3] : 斜め右下方向
    057		                        //    [4] : 下方向
    058		                        //    [5] : 斜め左下方向
    059		                        //    [6] : 左方向
    060		                        //    [7] : 斜め左上方向
    061		                        //    [8] : 全体
    062		return this;
    063	}
    064				//
    065				// GamePanel オブジェクト(メソッド mouseClick)
    066				//
    067	GamePanel.prototype.mouseClick = function(event)
    068	{
    069		let x_base  = mp.canvas.offsetLeft;   // キャンバスの左上のx座標
    070		let y_base  = mp.canvas.offsetTop;   // キャンバスの左上のy座標
    071		let x       = event.pageX - x_base;    // キャンバス内のクリックされた位置(x座標)
    072		let y       = event.pageY - y_base;    // キャンバス内のクリックされた位置(y座標)
    073						// クリックされたマス目を特定
    074		let k = new Array(-1, -1);
    075		for (let i1 = 0; i1 < 8; i1++) {
    076			if (y >= gp.gap+i1*(gp.gap+gp.sz) && y <= (i1+1)*(gp.gap+gp.sz)) {
    077				k[0] = i1;
    078				break;
    079			}
    080		}
    081		for (let i1 = 0; i1 < 8; i1++) {
    082			if (x >= gp.gap+i1*(gp.gap+gp.sz) && x <= (i1+1)*(gp.gap+gp.sz)) {
    083				k[1] = i1;
    084				break;
    085			}
    086		}
    087						// 反転できるコマを探す
    088		gp.r_check(k);
    089								// 反転するコマがない場合
    090		if (gp.n[8] <= 0) {
    091			document.getElementById('ta').style.color = "red";
    092			let str = "の番ですが,\nそこへはコマを置けません.";
    093			if (mp.method > 0)
    094				document.getElementById('ta').innerHTML = "あなた" + str;
    095			else {
    096				if (gp.b_w < 0)
    097					document.getElementById('ta').innerHTML = "黒" + str;
    098				else
    099					document.getElementById('ta').innerHTML = "白" + str;
    100			}
    101		}
    102								// 反転するコマがある場合
    103		else
    104			gp.set(k);
    105	}
    106				//
    107				// k[0] 行 k[1] 列に黒または白( b_w )のコマを置いた場合,反転できるコマを探す( GamePanel オブジェクトのメソッド r_check )
    108				//
    109	GamePanel.prototype.r_check = function(k)
    110	{
    111		let d = new Array();
    112		d[0] = new Array(-1, 0);
    113		d[1] = new Array(-1, 1);
    114		d[2] = new Array(0, 1);
    115		d[3] = new Array(1, 1);
    116		d[4] = new Array(1, 0);
    117		d[5] = new Array(1, -1);
    118		d[6] = new Array(0, -1);
    119		d[7] = new Array(-1, -1);
    120		gp.n[8] = 0;
    121		if (k[0] >= 0 && k[1] >= 0 && gp.st[k[0]][k[1]] == 0) {
    122			for (let i1 = 0; i1 < 8; i1++) {
    123				let m1   = k[0];
    124				let m2   = k[1];
    125				gp.n[i1] = 0;
    126				let s    = 0;   // 0:開始,1:カウント,2:カウント終了,3:反転不可能
    127				let ct   = 0;
    128				while (s < 2) {
    129					m1 += d[i1][0];
    130					m2 += d[i1][1];
    131					if (m1 >= 0 && m1 < 8 && m2 >= 0 && m2 < 8) {
    132						if (gp.st[m1][m2] == 0)
    133							s = 3;
    134						else if (gp.st[m1][m2] == gp.b_w) {
    135							if (s == 1)
    136								s = 2;
    137							else
    138								s = 3;
    139						}
    140						else {
    141							s = 1;
    142							ct++;
    143						}
    144					}
    145					else
    146						s = 3;
    147				}
    148				if (s == 2) {
    149					gp.n[8]  += ct;
    150					gp.n[i1]  = ct;
    151				}
    152			}
    153		}
    154	}
    155				//
    156				// コマの操作( GamePanel オブジェクトのメソッド set )
    157				//
    158	GamePanel.prototype.set = function(k)
    159	{
    160						// 反転
    161		gp.reverse(k);
    162		gp.b_w = -gp.b_w;
    163						// コマの数を数え,勝敗決定のチェック
    164		let b = 0;
    165		let w = 0;
    166		let total = 0;
    167		for (let i1 = 0; i1 < 8; i1++) {
    168			for (let i2 = 0; i2 < 8; i2++) {
    169				if (gp.st[i1][i2] != 0) {
    170					total++;
    171					if (gp.st[i1][i2] < 0)
    172						b++;
    173					else
    174						w++;
    175				}
    176			}
    177		}
    178						// 勝敗決定
    179		if (total == 64) {
    180			document.getElementById('ta').style.color = "black";
    181			let str = "黒 " + b + " 個, 白 " + w + " 個\n";
    182			if (mp.method > 0) {
    183				if (b == w)
    184					document.getElementById('ta').innerHTML = str + "引き分けです.";
    185				else if (b > w && mp.method == 1 || b < w && mp.method == 2)
    186					document.getElementById('ta').innerHTML = str + "あなたの勝ちです.";
    187				else
    188					document.getElementById('ta').innerHTML = str + "コンピュータの勝ちです.";
    189			}
    190			else {
    191				if (b > w)
    192					document.getElementById('ta').innerHTML = str + "黒の勝ちです.";
    193				else if (b == w)
    194					document.getElementById('ta').innerHTML = str + "引き分けです.";
    195				else
    196					document.getElementById('ta').innerHTML = str + "白の勝ちです.";
    197			}
    198			mp.canvas.removeEventListener("click", gp.mouseClick);   // リスナの除去
    199		}
    200						// 勝負継続
    201		else {
    202			document.getElementById('ta').style.color = "black";
    203			let str = "黒 " + b + " 個, 白 " + w + " 個\n";
    204								// スキップのチェック
    205			let sw = false;
    206			for (let i1 = 0; i1 < 8 && !sw; i1++) {
    207				for (let i2 = 0; i2 < 8 && !sw; i2++) {
    208					k[0] = i1;
    209					k[1] = i2;
    210					gp.r_check(k);
    211					if (gp.n[8] > 0)
    212						sw = true;
    213				}
    214			}
    215								// 対コンピュータ
    216			if (mp.method > 0) {
    217										// スキップの場合
    218				if (!sw) {
    219					gp.b_w = -gp.b_w;
    220					str += "コマを置けないため,スキップし,\n";
    221					if (mp.method == 1 && gp.b_w < 0)
    222						document.getElementById('ta').innerHTML = str + "あなた(黒)の番です.";
    223					else if (mp.method == 2 && gp.b_w > 0)
    224						document.getElementById('ta').innerHTML = str + "あなた(白)の番です.";
    225					else {
    226						document.getElementById('ta').innerHTML = str + "コンピュータの番です.";
    227						k = gp.computer();   // コマを置く場所の決定
    228						gp.set(k);   // コマを置く
    229					}
    230				}
    231									// 次の手
    232				else {
    233					if (mp.method == 1 && gp.b_w < 0)
    234						document.getElementById('ta').innerHTML = str + "あなた(黒)の番です.";
    235					else if (mp.method == 2 && gp.b_w > 0)
    236						document.getElementById('ta').innerHTML = str + "あなた(白)の番です.";
    237					else {
    238						document.getElementById('ta').innerHTML = str + "コンピュータの番です.";
    239						k = gp.computer();   // コマを置く場所の決定
    240						gp.set(k);   // コマを置く
    241					}
    242				}
    243			}
    244								// 対人間
    245			else {
    246										// スキップの場合
    247				if (!sw) {
    248					gp.b_w = -gp.b_w;
    249					str += "コマを置けないため,スキップし,\n";
    250				}
    251										// 次の手
    252				if (gp.b_w < 0)
    253					document.getElementById('ta').innerHTML = str + "黒の番です.";
    254				else
    255					document.getElementById('ta').innerHTML = str + "白の番です.";
    256			}
    257		}
    258	}
    259				//
    260				// k[0] 行 k[1] 列に黒または白( b_w )のコマを置いた場合におけるコマの反転( GamePanel オブジェクトのメソッド reverse )
    261				//
    262	GamePanel.prototype.reverse = function(k)
    263	{
    264		let d = new Array();
    265		d[0] = new Array(-1, 0);
    266		d[1] = new Array(-1, 1);
    267		d[2] = new Array(0, 1);
    268		d[3] = new Array(1, 1);
    269		d[4] = new Array(1, 0);
    270		d[5] = new Array(1, -1);
    271		d[6] = new Array(0, -1);
    272		d[7] = new Array(-1, -1);
    273		for (let i1 = 0; i1 < 8; i1++) {
    274			let m1   = k[0];
    275			let m2   = k[1];
    276			for (let i2 = 0; i2 < gp.n[i1]; i2++) {
    277				m1 += d[i1][0];
    278				m2 += d[i1][1];
    279				gp.st[m1][m2] = gp.b_w;
    280			}
    281		}
    282		gp.st[k[0]][k[1]] = gp.b_w;
    283						// 描画
    284		gp.draw();
    285	}
    286				//
    287				// コンピュータが置くコマの場所を決定( GamePanel オブジェクトのメソッド computer )
    288				//
    289	GamePanel.prototype.computer = function()
    290	{
    291		let k = new Array();
    292		let kk = new Array();
    293		let mx = new Array();
    294		mx[8] = 0;
    295		for (let i1 = 0; i1 < 8; i1++) {
    296			for (let i2 = 0; i2 < 8; i2++) {
    297				kk[0] = i1;
    298				kk[1] = i2;
    299				gp.r_check(kk);
    300				if (gp.n[8] > mx[8]) {
    301					k[0] = kk[0];
    302					k[1] = kk[1];
    303					for (let i3 = 0; i3 < 9; i3++)
    304						mx[i3] = gp.n[i3];
    305				}
    306			}
    307		}
    308		for (let i1 = 0; i1 < 9; i1++)
    309			gp.n[i1] = mx[i1];
    310		return k;
    311	}
    312				//
    313				// GamePanel オブジェクト(メソッド draw)
    314				//
    315	GamePanel.prototype.draw = function()
    316	{
    317						// キャンバスのクリア
    318		mp.ctx.clearRect(0, 0, mp.canvas.width, mp.canvas.height);
    319						// 描画
    320		mp.ctx.beginPath();
    321		mp.ctx.fillStyle = "rgb(165, 42, 42)";
    322		mp.ctx.fillRect(0, 0, mp.canvas.width, mp.canvas.height);
    323		mp.ctx.fill();
    324	
    325		for (let i1 = 0; i1 < 8; i1++) {
    326			for (let i2 = 0; i2 < 8; i2++) {
    327				let x = gp.gap + i2 * (gp.sz + gp.gap);
    328				let y = gp.gap + i1 * (gp.sz + gp.gap);
    329				mp.ctx.beginPath();
    330				mp.ctx.fillStyle = "rgb(0, 255, 0)";
    331				mp.ctx.fillRect(x, y, gp.sz, gp.sz);
    332				mp.ctx.fill();
    333				if (gp.st[i1][i2] != 0) {
    334					x += Math.floor(gp.sz / 2);
    335					y += Math.floor(gp.sz / 2);
    336					mp.ctx.beginPath();
    337					if (gp.st[i1][i2] < 0)
    338						mp.ctx.fillStyle = "rgb(0, 0, 0)";
    339					else
    340						mp.ctx.fillStyle = "rgb(255, 255, 255)";
    341					mp.ctx.arc(x, y, Math.floor(gp.sz/2)-2, 0, 2*Math.PI);
    342					mp.ctx.fill();
    343				}
    344			}
    345		}
    346	}
    			
    021 行目~ 026 行目( gp_start 関数)

      テキストエリアへ出力するメッセージを変更しています.

    030 行目~ 033 行目( gp_start 関数)

      コンピュータが先手の場合,コンピュータがコマを置く場所を決定する GamePanel オブジェクトのメソッド computer を呼んだ( 031 行目)後,コマを置いた後の処理( 032 行目)を行っています.メソッド computer の内容は,289 行目~ 311 行目に記述してあります.

    093 行目~ 100 行目( mouseClick メソッド)

      テキストエリアへ出力するメッセージを変更しています.

    182 行目~ 197 行目( set メソッド)

      テキストエリアへ出力するメッセージを変更しています.

    216 行目~ 256 行目( set メソッド)

      対戦相手がコンピュータの場合,テキストエリアへ出力するメッセージを変更すると共に,人間がスキップする場合( 226 行目~ 228 行目),または,人間がコマを置いた場合はその処理を終了した後( 238 行目~ 240 行目),コンピュータによる処理を行っています.

    289 行目~ 311 行目( computer メソッド)

      コンピュータがコマを置く場所を決定するための処理を行っています.ここでは,最も多くコマを反転できる場所を選択し,その位置を配列として返しています.

情報学部 菅沼ホーム JavaScript 目次 索引