【PHP】【初心者向け】ぼっちっちは誰だゲームを作ってみた

この記事は[2019新卒 エンジニア Advent Calendar 2019](https://qiita.com/advent-calendar/2019/2019-graduates)の10日目の記事です。

19新卒！というわけで参加させていただきました。が，バリバリ初心者ゆえ，記事には期待しないでください…

##自分について

- 2019年，文学部を卒業
- プログラミングまったくの未経験で，システム開発の部署に
- HTML・CSS・JS・PHPを学び今に至る

#本題
PHP(とMySQLとJS)を用いて，ぼっちっちは誰だゲームができるWEBアプリを開発しました。
(※実際に作ったのは10月頃です)

##ぼっちっちは誰だゲームって？
関ジャニ∞クロニクル　という番組で実施された，多人数で遊ぶゲームです。

> お題がかかれているカードを１人ずつにランダムに振り分け、かかれている単語について話し合う。５枚の内１枚だけ違うお題がかかれているのだが、１人だけ違うカードを持っている人、つまり「ぼっちちっちが誰なのか」を最も早く見破ったメンバーが勝利するというもの。

引用：https://www.fujitv.co.jp/fujitv/news/20195531.html

ワードウルフと大部分は共通しています。どっちかというとワードウルフのほうが有名かもしれません。
もちろんワードウルフでも遊べます。

##イメージを考える

###完成イメージ：
遊ぶメンバーで集まる
⇒.phpファイルにアクセスする
⇒スタートボタンを押す(ほかの人は画面を見てはいけない)
⇒ブラウザにお題が表示される
⇒ボタンを押したらお題が非表示になる
⇒確認したら次の人にスマホを渡す
⇒…
⇒人数分スマホを回したらゲームスタート。

人狼ゲームのアプリのイメージです。

##できたやつのスクショをどうぞ

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513757/79df42b6-13a5-0a96-9ad7-75bb2ea4d2f1.jpeg" width=40%>
1. 人数を設定してスタートボタンを押す
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513757/b63924bf-dd5e-11ef-64b1-619e190d3f5a.jpeg" width=40%>
2.　スタートボタンを押した直後，一人目のお題表示
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513757/10c15092-7048-ccc8-8355-da87c5c363d4.jpeg" width=40%>
3.　隠すボタンを押してお題を隠し，次の人にスマホを回す
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513757/1ef18d9e-62cc-3b29-a99c-1c5ab86bb8f8.jpeg" width=40%>
4.　次の人は進むボタンを押すと，次のお題が表示される　確認したら隠す　これを繰り返す
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513757/90402e66-03c1-05ae-d56a-3d48e37f921e.jpeg" width=40%>
5.　どこかでお題が1度だけ変わる
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513757/ff153d7d-ec2c-bbdb-51fe-294afc74b1f3.jpeg" width=40%>
6. 5回表示したので，ゲームスタート！


###プログラムを考えていく
5人で遊ぶ場合を考えて

* 進むボタンを押すたびに数字が増える変数を設定する　これを \$count とする
* 1~5からランダムな数字を一つ決定する　これを \$botti として
* if (\$count === \$botti)　の場合に，違うお題を表示
* お題は多次元配列で管理， \$data[\$key]　とする
    * 進むボタンをただの更新ボタンにし，\$count・\$botti・\$keyをCookieで保持すればできるのでは。

##というわけでまず書いてみた

```php
<?php
$data1 = [];
$data1[0] = [];
$data1[1] = [];
$data1[0][0] = '東京';
$data1[0][1] = '富士山';

$data1[1][0] = '横山';
$data1[1][1] = '村上';

$data1[2][0] = '富士山';
$data1[2][1] = '東京';

$data1[3][0] = '村上';
$data1[3][1] = '横山';

//お題を選ぶ
if(isset($_COOKIE['key'])){
	$key = $_COOKIE['key'];
}else{
	$key = rand(0,3);
}

//ぼっちは何番目～
if(isset($_COOKIE['botti'])){
	$botti = $_COOKIE['botti'];
}else{
	$botti = rand(1,5);
}

//カウント情報があるか判定
if(isset($_COOKIE['count'])){
	$count = $_COOKIE['count'];
	$count++;
}else{
	$count = 1;
}

//cookieに保存する
setcookie('count',$count);
setcookie('botti',$botti);
setcookie('key',$key);

//リセットされたときcookie削除
if(isset($_POST['reset'])){
	setcookie('botti',$botti, time()-3600);
	setcookie('count',$count, time()-3600);
	setcookie('key',$key, time()-3600);
}
?>
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <title>ぼっち</title>
    </head>
    <body>
        <p>あなたのお題は：</p>
        <?php if($count == $botti){ ?>
            <p><?php echo $data1[$key][0]; ?></p>
        <?php }else{ ?>
            <p><?php echo $data1[$key][1]; ?></p>
        <?php } ?>
        <form method='post'>
            <input type='submit' value='実行'>
        </form>
        <form method="post">
            <input type='hidden' name='reset' value='reset'>
            <input type='submit' value='リセット'>
        </form>
        <?php if(isset($_POST['reset'])){ ?>
            <div>リセットされました</div>
        <?php }?>
    </body>
</html>
```

Q.お題の意味はなんですか
A.番組をみたらわかります

(一番最初に書いたやつをほぼそのまま持ってきたので変数名とかひどいです)
とりあえず期待していた動きはできました。しかし，遊べるレベルではありません

* 人数設定ができない(ファイルを直接いじる必要がある)
* 非表示ボタンがない
* 表示されるお題は2つのうちどちらか，しかも二重登録する必要がある
    * 例えば果物をお題にする場合，現状「りんご」「バナナ」で \$data1[0][0]/[1] とすると，「りんご」が必ず多数派になります。したがって，「バナナ」「りんご」の順でもお題登録をしなければいけません。
    * そもそも，「りんご」「バナナ」「さくらんぼ」「メロン」…など複数のお題から多数派/少数派を選ぶ仕組みのほうが，ランダム性もあり楽しいはずです。

* したがって、「どのお題が選ばれたか」「そのうちの何番目と何番目の要素が多数派/少数派として選ばれたか」「何番目の人間がぼっちか」をCookieに持つ必要があります。また、遊ぶ人数もCookieに持っておいたほうがよいでしょう。


##改善してみた
```php
<?php

$data = [];

//テンプレ：$data[] = array();
$data[0] = array('大野智','二宮和也','櫻井翔','松本潤','相葉雅紀');
$data[1] = array('国分太一','松岡昌宏','長瀬智也','城島茂');
$data[2] = array('坂本昌行','長野博','井ノ原快彦','森田剛','三宅健');
$data[3] = array('横山裕','村上信五','丸山隆平','安田章大','大倉忠義');
$data[4] = array('山田涼介','知念侑李','中島裕翔','有岡大貴','高木雄也','伊野尾慧','八乙女光','薮宏太','岡本圭人');
$data[5] = array('中島健人','菊池風磨','佐藤勝利','松島聡','マリウス葉');
$data[6] = array('亀梨和也','上田竜也','中丸雄一');
$data[7] = array('加藤シゲアキ','小山慶一郎','手越祐也','増田貴久');

//人数が送信された場合
if(isset($_POST['num'])){
	$person = intval($_POST['num']);

	//自然数か判定する
	if($person > 0){

		//関数呼び出し
		$cookieArr = setValue($data, $person);

		$group = $cookieArr[0];
		$key1 = $cookieArr[1];
		$key2 = $cookieArr[2];
		$botti = $cookieArr[3];
		$count = $cookieArr[4];

		$cookieArr[] = $person;

		$cookieValue = implode(',',$cookieArr);
		setcookie('cookie',$cookieValue);

	}else{
		$error = '数字は1以上で入力してください。';
	}
}

//Cookieが存在する場合
if(isset($_COOKIE['cookie'])){
	$cookieArr = explode(',',$_COOKIE['cookie']);

	$group = $cookieArr[0];
	$key1 = $cookieArr[1];
	$key2 = $cookieArr[2];
	$botti = $cookieArr[3];
	$count = $cookieArr[4]+1;
	$person = $cookieArr[5];

	$cookieArr[4]++;

	//再びsetcookie
	$cookieValue = implode(',',$cookieArr);
	setcookie('cookie',$cookieValue);

	//リセットされた場合
	if(isset($_POST['reset'])){
		setcookie('cookie', $cookieValue, time()-3600);
	}
}

function setValue($data,$person){ //2回目アクセスしか発生しない。

	//group = $dataのどれを選ぶか
	$group = rand(0,(count($data))-1);

	//keys = $dataの多数派と少数派を決める
	$keys = array_rand($data[$group], 2);
	var_dump($data[$group]);
	shuffle($keys);

	$key1 = $keys[0];
	$key2 = $keys[1];

	$botti = rand(1,$person);

	$count = 1;

	return array($group, $key1, $key2, $botti, $count);
}
?>
<!doctype html>
<html>
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width,initial-scale=1">
		<title>ぼっちっちゲーム(仮)</title>
        <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
	</head>
	<body>
		<div class='container'>
			<p>☆リセット→人数入力→スタートを押すようにしてください☆</p>
			<form method='post'>
				<p><input type='number' name='num' style='width:50px;'>人でプレイ！
				<input type='submit' value='スタート'></p>
			</form>
			<p>あなたのお題は：</p>
			<?php if(isset($_COOKIE['cookie']) || isset($_POST['num'])){  ?>
				<?php if($count == $botti){ ?>
					<p id='answer1'><?php echo $data[$group][$key1]; ?></p>
				<?php }elseif(intval($count) > intval($person)){ ?>			
					<p>人数分表示しました。</p>
				<?php }else{ ?>
					<p id='answer2'><?php echo $data[$group][$key2]; ?></p>
				<?php } ?>
				<form>
					<input type='submit' value='進む'>
				</form>
			<?php } ?>
			<input type='button' onclick="hidden1();" value='隠す'>
			<form method="post">
				<input type='hidden' name='reset' value='reset'>
				<input type='submit' value='リセット'>
			</form>
			<?php if(isset($_POST['reset'])){ ?>
				<div>リセットされました</div>
			<?php }?>
			<?php if(isset($error) && empty($_COOKIE['cookie'])){ ?>
				<div>数字は1以上で入力してください。</div>
			<?php }?>
		</div>
		<script>
			function hidden1(){
				if(document.getElementById('answer1') != null){
					var ans1 = document.getElementById('answer1');
					ans1.style.display='none';
				}else{
					var ans2 = document.getElementById('answer2');
					ans2.style.display='none';
				}
			}
		</script>
	</body>
</html>
```

Q. ジャニオタなの？
A. ジャニオタではない

これで，3つ以上の要素のあるお題配列からランダムに2つお題として選ばれる要素が決定され，表示させることができました。
しかし，やはりお題をファイルの中に組み入れているのが気になります。プログラムを書いた人が有利になってしまう。参加する人がみんなお題登録できるべきでしょう。

上記では配列でお題を持っていますが，カンマ区切りで文字列としてお題を登録して，そいつをexplodeすればよいのでは！？

##お題登録ページを作る

というわけで，データベースと連携してブラウザからもお題登録できるようにします。
お題を登録するデータベースをまず作成します。

ID 　　　int(11)   　　　　 not null 　　　auto_increment
DATA　varchar(1000) 　　not null

ぶっちゃけカラムは1つあればよいのですが，念のためIDカラムも作成します。

そして，お題登録ページを作成します。遊ぶページとは別にしたかったので，以下のようなページ構成になりました

top.html ―― create.php　　…お題登録ページ
　　　　　｜
　　　　　―― play.php   　　…今まで作ってきたページ

##現在の完成形を以下に載せます(top.htmlは省略)

```create.php
<?php
$dsn = 'mysql:dbname=***;host=***;charset=utf8;';
$user = '***';
$pass = '***';

try{
	$pdo = new PDO($dsn,$user,$pass,
		[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,
		PDO::ATTR_DEFAULT_FETCH_MODE=>PDO::FETCH_ASSOC]
	);

	if(isset($_POST['inputs'])){
		$input = $_POST['inputs'];
		if(preg_match('/.+,.+/',$input)){
			$query = 'INSERT INTO botti(DATA) VALUES(:input);';
			$stmt = $pdo -> prepare($query);
			$stmt -> bindValue(':input', $input, PDO::PARAM_STR);
			$stmt -> execute();
			$message = '登録されました。';
		}else{
			$message = '正しくない入力です！';
		}
	}

}catch(PDOExpection $e){
	exit($e->getMessage());
}
?>

<!doctype html>
<html>
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width,initial-scale=1">
		<title>お題登録</title>
		<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
		<script src='js/bootstrap.bundle.js'></script>
		<link rel='stylesheet' href='css/bootstrap.css'>
	</head>
	<body>
		<div class='container'>
			<p>お題をカンマ区切りで入力してください。カンマは半角でお願いします。</p>
			<p>例：りんご,バナナ,メロン,さくらんぼ</p>
			<form method='post' name="myform">
				<input type='text' name='inputs'>
				<input type="button" class='register' value="登録" onclick='confirmFunc();'>
			</form>
			<?php if(isset($message)){ ?>
				<div class='mt-2'><?php echo $message; ?></div>
			<?php } ?>
			<a href='top.html'>戻る</a>
		</div>
		<script>
			function confirmFunc(){
				var val = confirm('登録します。よろしいですか？');
				if (val == true){
					document.myform.submit();
				}
			}
		</script>
	</body>
</html>

```


```play.php
<?php

$dsn = 'mysql:dbname=***;host=***;charset=utf8;';
$user = '***';
$pass = '***';

try{
	$pdo = new PDO($dsn,$user,$pass,
		[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION,
		PDO::ATTR_DEFAULT_FETCH_MODE=>PDO::FETCH_ASSOC]
	);

	$stmt = $pdo->query('select DATA from botti');
	$rows = $stmt->fetchAll(PDO::FETCH_COLUMN);

}catch(PDOExpection $e){
	exit($e->getMessage());
}

//人数が送信された場合
if(isset($_POST['num'])){
	$person = intval($_POST['num']);

	//自然数か判定する
	if($person > 0){

		//関数呼び出し
		$cookieArr = setValue($rows, $person);

		$group = $cookieArr[0];
		$key0 = $cookieArr[1];
		$key1 = $cookieArr[2];
		$botti = $cookieArr[3];
		$count = $cookieArr[4];

		$cookieArr[] = $person;

		$data = explode(',', $rows[$group]);

		$cookieValue = implode(',',$cookieArr);
		setcookie('cookie',$cookieValue);

	}else{
		$error = '数字は1以上で入力してください。';
	}
}

//Cookieが存在する場合
if(isset($_COOKIE['cookie'])){
	$cookieArr = explode(',',$_COOKIE['cookie']);

	$group = $cookieArr[0];
	$key0 = $cookieArr[1];
	$key1 = $cookieArr[2];
	$botti = $cookieArr[3];
	$count = $cookieArr[4]+1;
	$person = $cookieArr[5];

	$cookieArr[4]++;

	$data = explode(',', $rows[$group]);

	//再びsetcookie
	$cookieValue = implode(',',$cookieArr);
	setcookie('cookie',$cookieValue);

	//リセットされた場合
	if(isset($_POST['reset'])){
		setcookie('cookie', $cookieValue, time()-3600);
	}
}

function setValue($rows,$person){ //2回目アクセスしか発生しない。

	//group = $dataのどれを選ぶか
	$group = rand(0,(count($rows))-1); //int

	$data = explode(',',$rows[$group]); //str→array

	//keys = $dataの多数派と少数派を決める
	$keys = array_rand($data, 2);
	shuffle($keys);

	$key0 = $keys[0];
	$key1 = $keys[1];

	$botti = rand(1,$person);

	$count = 1;

	return array($group, $key0, $key1, $botti, $count);
}


function h($str)
{
    return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
}
?>

<!doctype html>
<html>
	<head>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width,initial-scale=1">
		<title>ぼっちっちゲーム(仮)</title>
		<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
		<script src='js/bootstrap.bundle.js'></script>
		<link rel='stylesheet' href='css/bootstrap.css'>
	</head>
	<body>
		<div class='container'>
			<p></p>
			<p>☆リセット→人数入力→スタートを押すようにしてください☆</p>
			<form method='post'>
				<p><input type='number' name='num' style='width:50px;'>人でプレイ！
				<input type='submit' value='スタート'></p>
			</form>
			<p></p>
			<p>あなたのお題は：</p>
			<?php if(isset($_COOKIE['cookie']) || isset($_POST['num'])){  ?>
				<?php if($count == $botti){ ?>
					<p id='answer1'><?php echo h($data[$key0]); ?></p>
				<?php }elseif(intval($count) > intval($person)){ ?>			
					<p>人数分表示しました。</p>
				<?php }else{ ?>
					<p id='answer2'><?php echo h($data[$key1]); ?></p>
				<?php } ?>
				<form>
					<input type='submit' value='進む'>
				</form>
			<?php } ?>
			<p></p>
			<p></p>
			<input type='button' onclick="hideAns();" value='隠す'>
			<p></p>
			<form method="post">
				<input type='hidden' name='reset' value='reset'>
				<input type='submit' value='リセット'>
			</form>
			<?php if(isset($_POST['reset'])){ ?>
				<div>リセットされました</div>
			<?php }?>
			<?php if(isset($error) && empty($_COOKIE['cookie'])){ ?>
				<div>数字は1以上で入力してください。</div>
			<?php }?>
			<p></p>
			<p></p>
			<a href='top.html'>戻る</a>
		</div>
		<script>
			function hideAns(){
				if(document.getElementById('answer1') != null){
					var ans1 = document.getElementById('answer1');
					ans1.style.display='none';
				}else{
					var ans2 = document.getElementById('answer2');
					ans2.style.display='none';
				}
			}
		</script>
	</body>
</html>

```
Q.やっぱり変数名ひどくない？
A.返す言葉もございません。

Q.なんでHTMLタグの属性，シングルクォーテーションなの？
A.この頃の癖です。今はダブルにしてます。

Q.Bootstrap使ってなくない？
A.見た目考えるのめんどくさかっ(ry

それはともかく，誰でもお題が登録できるようになりました！これでプログラム作成者もお題のすべては知りません！！

##実際に遊んでみた
このプログラムを使って実際に友達と遊びました。事前にお題登録はお願いしていたのですが，なんと100を超えるお題が登録されておりました！

**楽しかったです！！**
とても盛り上がりました。

##そのほか作ってみた感想

* PHP,HTML,JS,Cookie,データベースといった色んな要素を組み合わせて作ったので学んだことの復習にもなりました。
* ソースコードはまだまだ稚拙なものなので，また書き直したいです。とりあえず毎回テーブルを全件取得してるのはよろしくないので，SELECTの段階で1レコードに絞り込みたいですね。また、idの値で自分がぼっちか分かってしまいます。Cookieはもう仕方ない。あとはオブジェクト指向をマスターしてからかな…
* そして，この記事を書いてみて，アウトプットの難しさを痛感しました\_(:3 」∠)_うへー


ここまでお読みくださりありがとうございました！
初心者のみなさまお互い頑張りましょう。