SHIROのIchigoJam日記

マイコン「IchigoJam」(イチゴジャム)の電子工作とプログラミングをメインに

三目並べ通信対戦

IchigoJam+MixJuice(Wi-fiボード)の環境で、2台で通信対戦する三目並べです。
以前に公開したチャットシステムの応用で、プログラミング教室での教材を想定しています。

f:id:shiro0922:20210905110548j:plain

f:id:shiro0922:20210905131252p:plain

★注意★ 簡単なプログラムなのでセキュリティを一切考えていません。教室を行う時だけサイトを設置して、終わったら削除や移動をするようにしてください。サイトを置きっぱなしにすると、悪意のある人にアクセスされてデータベースを破壊されたり乗っ取られたりする危険性があります。

上記の乗っ取りなどを防ぐために、教室内にサーバーPCとWi-fiルーターを置いて、ローカルネット環境で動かすことをお勧めします。

準備

■Webサーバー

PHPMySQLが動くWebサーバーを用意します。
新規に作るならXAMPPなどを利用すると良いでしょう。

MySQLのデータベース、テーブル

phpMyAdminなどを使って、チャットのデータを記録するデータベース(例「xy」)を新規に作ります。
その中に「xy」テーブルを作成して、「time」列(datetime型)、「userid」列(text型)、「x」列(text型)、「y」列(text型)、「readsw」列(int型)を作ります。

time userid x y readsw

■ページの設置

www.example.jp/dir/(サイトのアドレス)内に、以下のWebページファイルを設置します。

db_login.php

ログイン情報を入れるファイルです。
dbnameはデータベース名、usernameはデータベースにアクセスするユーザー名、passwordはそのユーザーのパスワードを記述します。

<?php
$db_host='localhost';
$db_database='dbname';
$db_username='username';
$db_password='password';
?>
send.php

IchigoJam+MixJuiceから送られてきた手のデータを、データベースに書き込むWebページです。
「receive.log」にアクセスログが出力されます。もしデータベース接続エラーなどが出た場合は、このログを参照してください。

<?php

// ログイン情報のインクルード
include('db_login.php');

// データ受信

if (isset($_GET['ID'])) {

	$strParas = $_GET['ID'];
	
	$strPara = explode(",", $strParas);
	$strID = $strPara[0];
	$strX = $strPara[1];
	$strY = $strPara[2];

	// ログファイルの相対パス
	$strDataFilePath = 'receive.log';

	// ログファイルを追記モードでオープン
	$fp = fopen($strDataFilePath, "a");

	// 日付、時刻を取得
	date_default_timezone_set('Asia/Tokyo');
	$dt = new DateTime();
	$strDateTime = $dt->format('Y-m-d H:i:s');

	// 受信した値をログファイルに書き込み
	fwrite($fp, $strDateTime . ',Send,ID=' . $strID . ',X=' . $strX . ',Y=' . $strY . "\r\n");

	// データベースサーバーへ接続
	$connection = mysqli_connect($db_host, $db_username, $db_password, $db_database);
	if (!$connection) {
		fwrite($fp, "DB接続エラー\r\n");
	}

	// === xyテーブルを更新 ===

	// データ更新クエリを作成
	$query = "INSERT INTO xy SET time='$strDateTime', userid='$strID', x='$strX', y='$strY', readsw='0'";
	
	// クエリを実行
	$result = mysqli_query($connection, $query);
	if (!$result) {
		fwrite($fp, "データ更新エラー\r\n");
	}

	// === 終了処理 ===

	// データベース接続を閉じる
	mysqli_close($connection);

	// ログファイルポインタをクローズ
	fclose($fp);

}

?>
read.php

IchigoJamからのリクエストに応じて、データベースから手の文字列を出力するWebページです。
「receive.log」にアクセスログが出力されます。もしデータベース接続エラーなどが出た場合は、このログを参照してください。

<?php

// ログイン情報のインクルード
include('db_login.php');

// データ受信

if (isset($_GET['ID'])) {

	$strID = $_GET['ID'];
	
	// ログファイルの相対パス
	$strDataFilePath = 'receive.log';

	// ログファイルを追記モードでオープン
	$fp = fopen($strDataFilePath, "a");

	// 日付、時刻を取得
	date_default_timezone_set('Asia/Tokyo');
	$dt = new DateTime();
	$strDateTime = $dt->format('Y-m-d H:i:s');

	// 受信した値をログファイルに書き込み
	fwrite($fp, $strDateTime . ',Request,ID=' . $strID . "\r\n");

	// データベースサーバーへ接続
	$connection = mysqli_connect($db_host, $db_username, $db_password, $db_database);
	if (!$connection) {
		fwrite($fp, "DB接続エラー\r\n");
	}

	// === xyテーブルから読み取り ===

	// データ読み取りクエリを作成
	$query = "SELECT * FROM xy WHERE userid='$strID' AND readsw='0' ORDER BY time LIMIT 1";

	// クエリを実行
	$result = mysqli_query($connection, $query);
	if (!$result) {
		fwrite($fp, "データ読み取りエラー\r\n");
	}

	foreach ($result as $row) {
		if ($row['readsw'] == "0") {
			
			echo $row['x'] . $row['y'];
			$query = "UPDATE xy SET readsw='1' WHERE userid='$strID' AND readsw='0' ORDER BY time LIMIT 1";
			$result = mysqli_query($connection, $query);
			if (!$result) {
				fwrite($fp, "データ変更エラー\r\n");
			} else {
				fwrite($fp, $strDateTime . ',Update,ID=' . $strID . ',ReadSW=1' . "\r\n");
			}
			
		}
	}

	// === 終了処理 ===

	// データベース接続を閉じる
	mysqli_close($connection);

	// ログファイルをクローズ
	fclose($fp);

}

?>
index.php

データの一覧表を表示するWebページです。5秒ごとに表示が自動更新されます。動作テストの時に使います。

<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf8">
<title>Ichigo XY</title>
<link rel="stylesheet" href="styles.css" type="text/css" />
<meta http-equiv="refresh" content="5; URL=">
</head>

<body>
<h1>Ichigo XY</h1>

<?php

// ログイン情報のインクルード
include('db_login.php');

// データベースサーバーへ接続
$connection = mysqli_connect($db_host, $db_username, $db_password, $db_database);
if (!$connection) {
	die ("DB接続エラー<br />". mysql_error());
}

$strSort = "0";
if (isset($_GET['SORT'])) {
	$strSort = $_GET['SORT'];
}

// === xyテーブルから一覧表 ===

// クエリを作成
$query = "SELECT * FROM xy ORDER BY time";

// クエリを実行
$result = mysqli_query($connection, $query);
if (!$result) {
	die ("DBクエリエラー<br />". mysql_error());
}

// 結果から一覧表を表示
echo "<table>\r\n";
echo "<tr><th class='time'>Time</th><th class='userid'>UserID</th><th>X</th><th>Y</th><th>ReadSW</th></tr>\r\n";

foreach ($result as $row) {
	echo "<tr><td>" . $row['time'] . "</td><td>" . $row['userid'] . "</td><td>" . $row['x'] . "</td><td>" . $row['y'] . "</td>";
	if ($row['readsw']=="0") {
		echo "<td>未読</td>";
	} else {
		echo "<td>既読</td>";
	}
	echo "</tr>\r\n";
}

echo "</table>\r\n";

// === 終了処理 ===

// データベース接続を閉じる
mysqli_close($connection);

?>

</body>
</html>
styles.css

一覧表ページの見栄えを設定するスタイルシートです。お好みで改造してください。

html {
background-color: #FFFFFF;
font-family: sans-serif;
}

body {
margin: 20px auto 10px auto;
width: 920px;
text-align: center;
font-size: middle;
line-height: 1.3em;
color: #000000;
}

h1 {
height: 40px;
margin: 0px;
padding-left: 10px;
font-size: 18pt;
line-height: 40px;
color: #000000;
}

table {
margin: 10px auto 10px auto;
border-style: solid;
border: 2px solid #8888ff;
}

th {
text-align: center;
font-size: 14pt;
padding: 2px;
border: 1px solid #8888ff;
}

td {
font-size: 14pt;
padding: 2px;
border: 1px solid #8888ff;
}

■ページの動作テスト

PCのブラウザで「www.example.jp/dir/index.php」を開くと、一覧表ページが表示されます。
ブラウザの別ウインドウで、書き換えページへ以下のようにアクセスすると、メッセージを送信できます。

www.example.jp/dir/send.php?ID=UEDA01,0,0

「UEDA01」はユーザーID、「0,0」は手のx,y座標です。
データを送信した後、一覧表ページで受信されていることを確認してください。

教室での使い方

(1)IchigoJam+MixJuiceを動かして、Wi-fiアクセスポイントに接続します。

?”MJ APC ssid password”

ssidWi-fiアクセスポイントのSSID、passwordはパスワードです。ちゃんと接続するまで1分ほど待ってください。
(一度接続するとその設定が記憶され、次回は入力しなくても自動接続されます)

(2)教室内で、通信対戦するペアを決めます。

(3)以下の三目並べプログラムを入力して、ペアの2台で実行します。

10 '*3MOKU
20 CLV:CLS:UART 1,1
30 L=3:M=L-1
40 FOR A=1 TO L
50 FOR B=1 TO L:?".";:NEXT:?
60 NEXT
70 CLK:LC 0,L+1:?"(YOU.)"
80 K=INKEY()
90 X=X-(K=28)*(X>0)+(K=29)*(X<M)
100 Y=Y-(K=30)*(Y>0)+(K=31)*(Y<M)
110 LC X,Y,1:WAIT 5
120 IF K=10 GOTO 190
130 IF K!=32 OR SCR(X,Y)!=46 GOTO 80
140 LC X,Y:?"O":S=S+1:BEEP
150 LC 0,-1
160 ?"MJ GET www.example.jp/dir/SEND.PHP?ID=UEDA01";
170 ?",";CHR$(X+48);",";CHR$(Y+48)
180 IF S=L*L GOTO 270
190 CLK:LC 0,L+1:?"(READ)"
200 WAIT 60:LC 0,-1
210 ?"MJ GET www.example.jp/dir/READ.PHP?ID=UEDA02"
220 WAIT 60:X=INKEY():IF !X GOTO 200
230 Y=INKEY():IF !Y CONT
240 X=X-48:Y=Y-48
250 LC X,Y:?"X":S=S+1:BEEP 30
260 IF S<L*L GOTO 70
270 BEEP 10,30
280 LC 0,L+2

160行の「UEDA01」は自分のユーザーID、210行の「UEDA02」はペア相手のユーザーIDです。それぞれのIchigoJamで別のIDにしてください。

(遊び方)

2台でプログラムを起動すると、3×3のます目が表示されます。どちらも自分(YOU.)の手番になるので、後手側はEnterキーを押してパスしてください。(READ)と表示されて、相手の手を待ちます。

先手側 後手側
f:id:shiro0922:20210905171011p:plain f:id:shiro0922:20210905171025p:plain


自分(YOU.)の手番では、上下左右の矢印キーでカーソルを移動して、スペースキーで打ってください。自分の手は「O」(マル)で表示されます。相手へ手のデータが転送されて、そちら側では「X」(バツ)で表示されます。

先手側 後手側
f:id:shiro0922:20210905171615p:plain f:id:shiro0922:20210905171626p:plain


手番を交替して、くり返し打っていきます。

先手側 後手側
f:id:shiro0922:20210905171654p:plain f:id:shiro0922:20210905171706p:plain


どちらかの盤面で、縦・横・斜めのどこかで「○」が三目そろうと、そのプレイヤーの勝利です。どちらもそろわずに9手が終わった場合は引き分けです。勝敗判定は人間がやってください。

先手側 後手側
f:id:shiro0922:20210905171736p:plain f:id:shiro0922:20210905171747p:plain

(4)プログラムの改造

30 L=3:M=L-1

30行の「L=3」は盤面のサイズです。「L=5」にすると盤面を5×5、「L=10」にすると10×10に広げられます(最大20×20まで)。

  • 5×5の盤面

f:id:shiro0922:20210905172254p:plain

  • 10×10の盤面

f:id:shiro0922:20210905172332p:plain
勝敗判定は人間がするので、例えば盤面を20×20に広げて、五目並べで勝負してもいいでしょう。