高校の文化祭でWebアプリ作った！

今回は、自分たちが文化祭で作った「Casino Money Manager[^1]」こと、QRコード決済もどきの開発について話します。
はじめて記事を書くので至らない点が多いと思いますが温かい目で見守ってください！
![名市工文化祭の画像](https://www.instagram.com/p/CjJg-ukvXvr/media "Instagram @meishiko1936 文化祭の門の画像")

:::note alert
本記事の内容は、名古屋市並びに名古屋市立工業高等学校に非公式で公開しているものです。
本記事に関する問い合わせをこれらの機関へ行う行為は**慎んでいただくようお願いいたします**。
:::
[^1]: 名付け親の自分でも名前がダサすぎると思ったので、クラスには「QRコードのやつ」として流通させました。

# 記事を書いたきっかけ:pencil2:
@YumNumm さんの「[高校の文化祭でソフトウェア開発をしたお話](https://qiita.com/YumNumm/items/32ffcced7193e11930d9)」を読んで技術記事を書いてみたくなったからです。
この記事を参考にして作ったので、作りがバリ似てます。@YumNummさんごめんなさい...

# 自己紹介:frame_photo:
はじめまして。どきみきと申します。[名市工](https://www.nagoya-c.ed.jp/school/kogyo-th/index.html)[^2]2年生の17歳、OSSに貢献すること夢見てプログラムを勉強してる初心者プログラマーです。
[^2]: 名古屋市立工業高等学校の別名。YouTubeチャンネルもぜひ！ [名市工チャンネル - YouTube](https://www.youtube.com/channel/UCrYNqDQA5INOp68WCTbqH0Q)

合成音声(特にVOCALOID!!)が大好きなので、ボカロとかボイロとかボイボとか好きな人と仲良くしたいです。

# 文化祭でなにやったの?:school:
自分たちのクラスでは、教室でカジノをやりました。
お金を賭けてゲームをして、一定金額以上稼げたら景品!!みたいな出し物です。
ゲームは丁半、Eカード、ブラックジャック、High and Lowの四つを用意して、そこで遊んでもらう感じです。
今回自分はこの文化祭のお金の部分を回せるようなWebアプリをつくりました。

# Casino Money Managerの概要:slot_machine:
<dl>
    <dt>ゲームのbet管理</dt>
    <dd>ゲーム開始時、QRコードをお客さんに提示してもらい、コントロールパネルから掛け金、ゲーム結果を設定する。</dd>
    <dd>一気に複数人の掛け金、ゲーム結果を設定することもできる。</dd>
    <dt>お客さん用画面の表示</dt>
    <dd>QRコードを普通のQRコードリーダーで読み込んだ時は、「お客さん用画面」を表示するようにする。</dd>
    <dd>お客さん用画面では、所持金、ゲーム履歴が表示されるようにする。</dd>
    <dd>お客さん用画面で、自分のアカウントにニックネームを付けられるようにする。</dd>
    <dt>回数制限</dt>
    <dd>ゲームは合計で5回までしかできないようにする。</dd>
    <dt>終了処理</dt>
    <dd>出口でQRコードをお客さんから回収し、コントロールパネルから終了処理をする。終了処理をしたQRコードは、また使いまわせるようにする。</dd>
    <dt>ランキングの表示</dt>
    <dd>教室にモニターを設置して、そこにランキングを表示する</dd>
    <dt>ディーラー用画面のアクセス制限</dt>
    <dd>ディーラーは事前に登録処理をし、登録処理をしたスマホのみがディーラー用画面を操作できるようになる。</dd>
    <dd>ディーラーとして登録されていない場合はエラーを返す。</dd>
 
</dl>

![zu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851058/1216f8c5-cbb3-e552-6223-5a9af8e1726c.png)

## 実際の画面:iphone:
お金を賭ける画面(ディーラー側)
![bet_AdobeExpress.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851058/c5612d23-6779-d812-c4cc-0da2d742f10e.gif)
履歴を表示する画面(お客さん側)
![history_AdobeExpress.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851058/9112e7f1-371f-58d1-a18b-1edbc6d8f63e.gif)
終了処理の画面(ディーラー側)
![admin_endthegame_AdobeExpress.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851058/efc2cd07-8372-1050-d283-e600cc2e8f67.gif)
ランキングの画面
![スクリーンショット 2022-10-02 212939.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851058/58bdadde-977c-06b7-d7a4-25c66bbceb6a.png)

# 利用した言語や技術:gear:
|使ったところ|言語・技術|
|:-:|:-:|
|フロントエンド|HTML, CSS, JS|
|バックエンド|PHP|
|データベース|MySQL|
|3Dモデル編集|Blender|

## HTML, CSS
見えてる部分は大体これです。

実はHTML, CSSはほとんど友達に作ってもらいました！ありがとう！！

自分で作ったのはランキングの画面ぐらいです。なのであんまりわかりません。

あとは先人の力を借りて、[CSSをリセット](https://getbootstrap.com/docs/5.2/content/reboot/)したり、ディーラー画面の最後に[動くチェックマーク](https://bbbootstrap.com/snippets/animated-checkmark-50934051)をつけたりしました。


## JavaScript
ランキングのリアルタイム更新の実装やQRコードの読み取り、その他諸々に使いました。

JSを触るのは初めてでしたが、すごく使いやすくてすぐになれました。

QRコードの読み取りには[jsQR](https://github.com/cozmo/jsQR)を、ランキング画面の王冠とトロフィーを動かすのに[three.js](https://threejs.org/)を使いました。


## PHP
CasinoMoneyManagerとSQLの橋渡しと、ディーラー用画面のアクセス管理に使いました。

今回は不特定多数の人が使うプログラムなので、`GET`や`POST`で取得した値の検証に気を配ってプログラムしました。

## MySQL
お客さんデータ、ディーラー管理はすべてこれです。

テーブルはこんな感じです。

![データベース ER 図 (カラスの足記法).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851058/e6223f9e-a174-5f02-c445-b02405b2b6eb.png)
[LucidChart](https://www.lucidchart.com/pages/ja)を使って図を作成したら、自動でテーブル定義用のSQLまで用意してくれました。LucidChart神過ぎる....

## Blender
ランキングの1, 2, 3位のやつを編集するのに使いました。

[トロフィー](https://sketchfab.com/3d-models/a-cool-little-cup-just-for-fun-afd10a0435184da58cb5f391c0499b14)と[王冠](https://sketchfab.com/3d-models/fall-guys-crown-64e55ffd4f864a20a943710c581d194f)のモデルを借りて、#1~3を付けただけです。

3Dモデルを編集するのが難しすぎて頭がパンクしそうになりました。特にテクスチャあたりが難しすぎる...

# 開発:keyboard:
夏休みから頑張りました。
ふりかえると最初の方でちゃんと設計してればフレームワークの導入だったりでもっと楽に開発できた気がします...

## 最初の一週間目
愚かな自分は要件定義もなにもせずにいきなりSQLのテーブル設計に入りました。
この後プログラミングで不都合が出まくって後悔することも知らずに...

## たのしい二、三週間目
なんとかPHPを使って基本的なディーラーの操作ができるようになりました。

大体のデザイン案を完成させて、友達にCSSの作成を頼みました。忙しい中ありがとう！

ここでJavaScriptを使わないとクライアント側での値の検証(所持金以上に賭けられないようにするなど)ができないことに気づき始めてJavaScriptの勉強し始めます。

## 勉強の四週間目
友達からもらったCSSを自分のPHPに適応させつつ、JS部分を作っていきます。

最初の方に書いたJSはなんかわからんけど動いているという一番怖い状態でしたが、後半のほうになると結構きれいなJSを書けるようになってきました。

ここで初めて`map`関数と`reduce`関数に出会いました。配列といえば`for`一択だった自分にとって目から鱗でした。

## 地獄の二カ月目
一応Ver1.0が完成したのでクラスメイトに使ってもらいました...が、

>・ランキングとかあったらいいなぁ
・ニックネームとかつけれたらおもしろそう
・ディーラー画面で掛け金設定を一気に複数人できるようにしてほしい
・これディーラー画面お客さんからは動かせないようにした方がよくない?
etc...

などの意見が出てきたので追加機能を作る1カ月になりました。

よくよく考えれば最初に欲しい機能とか聞いとくべきだったよな...と思いながらプログラムしました。

ただ自分のコードが汚すぎて(特にJS...)新しい機能の実装がつらかったです...

特に設計もなんもなしに適当にツギハギしたプログラムに嫌気がさしてYoutubeとniconico無限周回してました。

ただ複数人掛け金設定できた時はバチクソうれしかったです。

## いやになる三か月目
この辺から文化祭のカウントダウンも始まり、もうそろそろ文化祭だな...っていう雰囲気が流れてきました。

とりあえず追加機能の実装を終えて実際にクラス全体で動かしてみました。

そしたらさらに改善点やバグが出まくりました。

>・掛け金設定の送信ボタンを連打で重複登録される
・ニックネームをユニークな値にしたい
・回数制限がほしい
・QRコード読み取り画面が重すぎて動かない
etc...

ここまでくると前に進むしかありません。

頭空っぽにしてとりあえずプログラムしました。

ただ最初の意見よりも機能追加がすくなくなってだんだんバグ修正が増えてきたので一応完成には近づいている...?

## 完成!
最終的に文化祭3日前に全部の機能の実装とテストが終わり、夏休みから作ってきた集大成を見せるときが来ました！
文化祭1日目も順調に(?)動いてくれて感動しました！

## これで終わるはずがなく...
文化祭1日目が終わったところでさらに改善点が出てきました！！！！！！プログラムたのしい！！！！！！！！
>・ランキング画面4位以下の人も表示してほしい
・QRコードが読み込みにくい
・掛け金設定の時にお客さんの残り回数を表示してほしい
etc...

やってやろうじゃねえかよこの野郎！！！！！！

この日に人生で初めてZONEなるエナジードリンクを飲みました。エナジードリンクを普段飲まないせいか気持ち悪くなりました。

結局上の機能も追加しました。
# 文化祭当日！:balloon:
2日間の文化祭！特に問題なく順調に動いた！...ならよかったんですけど、実際はそうはいきませんでした。

## 文化祭1日目に起きた問題
初日はシステムがうまく動くかどうか心配すぎて心臓バクバクでした。

### ランキング表示されない問題
解決方法: 表示する端末のDNSキャッシュのクリア

ストーリー:
文化祭が始まるまで残り1時間の場面。
モニターに学校のPCを接続してランキングの画面を表示しようとしたら、
>i-Filter「サーバーが存在しないか、接続拒否している可能性があります。」

え？
......え？？？？？？？？？？

死ぬほど焦りました。
焦りすぎて腕ブルッブルの足ガックガクでした。

とりあえずサーバーが生きてるかどうか確認。友達にサーバーにアクセスしてもらいました。
そしたら友達のスマホからはサーバーにアクセスできるそう

なら学校PCが悪い?

何度かF5で更新するも画面変わらず
前に一度動作チェックして動くことを確認したのになぜ当日に動かないのか。
動作チェック時から変わったところ...

変わったところ...

[ConoHa VPS](https://www.conoha.jp/vps/)のプランをチキって2Gプランから8Gプランに変えたこと?

プランを変えたならIPアドレスも変わる?

望みをかけてPCのDNSキャッシュを消してみることに。
Windowsコマンドプロンプトに`ipconfig /flushdns`をいれて実行。

そしたらすんなり動いてくれました！

## 文化祭2日目に起きた問題
さすがに1日目行けたし2日目は完璧やろ！...と当時の自分は本気で思ってました

### ディーラーがミスって賞金の倍率を2000倍にしちゃった問題
解決方法: HTMLの`input`タグに`max`属性を設定する

ストーリー:
余裕をぶっこいて学校祭を楽しむ自分。そこにLINEが...
> ![スクリーンショット 2022-10-02 232829.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851058/6ed35322-585b-7cef-c19d-8293a0f2257e.png)

とりあえず教室に戻ってみる。そしたらランキングに意味わからんほど多い金額。

なんで????????????????????

とりあえずphpMyAdminで該当ユーザーの履歴を覗き見る。

そしたら賞金の倍率2000倍とかいう異質なセル(通常は0~10倍程度)

どうやらディーラーが間違えて2000倍と入力したらしい。
~~PHPとかのバグじゃなくてヒューマンエラーかよ！焦らせやがって！~~
基本情報技術者試験[^3]で言っていたフールプルーフとはこのことか...と実感しつつ、HTMLの`input`タグに`max`属性を付けて対応した。
[^3]: [IPA](https://www.ipa.go.jp/)の実施する試験。国家資格がとれる。

## 悪いことばかりじゃない
お客さんが自分の作ったシステムを使ってくれていたり、
ランキング画面を見て喜んでいる人がいたり、
「やっぱり工業高校生はすごいな！」と先生やお客さんから褒めてもらえた。
それだけで夏休みから作ってきてよかったなって思えるし、これからもっとプログラムを勉強しようと思った。

# 感想:writing_hand:
まずは感謝です。HTML・CSSを書いてくれた友人、OSSを作って公開してくれたさいつよプログラマー様、コロナ禍の中で文化祭を開いてくれた先生、来てくれたお客さん、ゲームのディーラーや教室の装飾を頑張ってくれたクラスメイト、文化祭当日にQRコードを印刷してくれた友達へ！ありがとう！！！みんながいたからこそ成功させられた文化祭になったなと思います。

貴重な体験の場をいただいたことをうれしく思います。

やっぱり自分で作ったものを動かしていろんな人に使ってもらうことほどうれしいことはありませんね。
夏休みからずっと作り続けてきたプログラムの集大成がここで見れてよかったです。
脳汁ドバドバです。

プログラム面の感想ですが、やっぱり設計はちゃんとやらないといけませんね。
最初は適当にプログラムしていても特に問題は起きませんでしたが、
徐々にプログラムの規模が大きくなるにつれて何がどうなってるのか全く分からない状況になって初めて設計の大切さを学びました。
そういう状況になるともうプログラム書く気が起きないんですよね。1機能追加するだけで影響範囲が広すぎて3日ぐらいかかるとかざらにありました。

あと検証もちゃんとやらないといけませんね。
文化祭1日目が終わったあと、ランキング画面に1~12位の人の名前を表示する機能を付けたのですが、
全画面表示にすると画面がバグるという致命的なバグを見過ごしてしまい、文化祭2日目の朝に表示させてようやく気が付きました。
直す時間もなかったので、2日目はやむを得ずに全画面表示にせずに表示しましたが、これからは絶対に検証をしようと心に誓いました。

文化祭でサイトを公開したら悪い先輩が攻撃とか仕掛けてくるんじゃないかと思って片っ端からログを取って異常検知をしていましたが、案外何も来ずに拍子抜けしました。学校にスーパーハカーがいなくてよかった...
<br>
ということでここまで読んでくれた皆さん！ありがとうございました！
コメント、いいねお待ちしております！