この記事はクソアプリ Advent Calendar 2021の24日目の記事です。
はじめに
モンティ・ホール問題というものをご存知でしょうか。
モンティ・ホール(英語版)(Monty Hall, 本名:Monte Halperin)が司会者を務めるアメリカのゲームショー番組、「Let's make a deal(英語版)[注釈 1]」の中で行われたゲームに関する論争に由来する。一種の心理トリックになっており、確率論から導かれる結果を説明されても、なお納得しない者が少なくないことから、本項~プロブレムの他、~ジレンマあるいは~パラドックスとも称される。「直感で正しいと思える解答と、論理的に正しい解答が異なる問題」の適例とされる。
とのこと。
投稿された相談
プレーヤーの前に閉じた3つのドアがあって、1つのドアの後ろには景品の新車が、2つのドアの後ろには、はずれを意味するヤギがいる。プレーヤーは新車のドアを当てると新車がもらえる。プレーヤーが1つのドアを選択した後、司会のモンティが残りのドアのうちヤギがいるドアを開けてヤギを見せる。
ここでプレーヤーは、最初に選んだドアを、残っている開けられていないドアに変更してもよいと言われる。
ここでプレーヤーはドアを変更すべきだろうか?
この相談に対して、マリリン・ボス・サヴァントは「正解は『ドアを変更する』である。なぜなら、ドアを変更した場合には景品を当てる確率が2倍になるからだ」と回答。
この回答に対するさまざまな反論が出現し、騒動になったとされています。
例えばこんな意見。
それでも私は1/2だと思う、、超面白い!モンティ・ホール問題
なるほど、確かにそんな気もしてきた....
数学的分からないなら、実際何度も試行してみればいいのだ!
ただ、ひとりでは何度も試行するのは面倒だし、偏りがあるとも言える。
ということで、アプリ「みんなで解くモンティ・ホール問題」を開発。
アプリだけ触りたい方はこちら
=> みんなで解くモンティ・ホール問題
#開発
Flutterを勉強し始めましたが、まだWebアプリは作ったことがないので、
Flutterで作ってみることに。
下準備
1. Firebaseプロジェクトから新しいプロジェクトを作成
Firestore Databaseを使う予定なので、作成。
リージョンは asia-northeast1
(Tokyo) で。
ルールはあとで。
2. Terminalからプロジェクトを紐づける
$ firebase login
$ firebase init # FirestoreとHostingを選択
:
:
=== Firestore Setup
Firestore Security Rules allow you to define how and when to allow
requests. You can keep these rules in your project directory
and publish them with firebase deploy.
? What file should be used for Firestore Rules? firestore.rules
Firestore indexes allow you to perform complex queries while
maintaining performance that scales with the size of the result
set. You can keep index definitions in your project directory
and publish them with firebase deploy.
? What file should be used for Firestore indexes? firestore.indexes.json
=== Hosting Setup
Your public directory is the folder (relative to your project directory) that
will contain Hosting assets to be uploaded with firebase deploy. If you
have a build process for your assets, use your build's output directory.
? What do you want to use as your public directory? public
? Configure as a single-page app (rewrite all urls to /index.html)? Yes
? Set up automatic builds and deploys with GitHub? No
✔ Wrote public/index.html
:
:
設定は大体デフォルトにしておき、後から変更することに。
3. Flutterプロジェクトを作成
$ flutter create monty_hall_problem
firebase.json
の中身の hosting > public
を flutter のビルドディレクトリに変更
{
"firestore": {
"rules": "firestore.rules",
"indexes": "firestore.indexes.json"
},
"hosting": {
"public": "monty_hall_problem/build/web", <-- ここ
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
]
}
}
ゲームの流れ
- 扉が3枚出る
- その中から一枚選ぶ(クリック)
- 残りの2枚から不正解の方をランダムでモンティさんが開けてくれる
- それを見て、最初に選んでいた扉から変えるかどうかを考える。
- 最終的に選んだ方を開ける
ひとりで解くモンティ・ホール問題
試行回数32回でも、扉を変えた時の方が正解率が2倍程度高い結果に...!!
みんなで解くモンティ・ホール問題
この状態でもクソアプリとしては完成でいいのですが、"みんなで" 解けるようにしたいのでWebアプリとしてデプロイしDBを使って、試行結果を保存するようにします。
- デプロイ先: Firebase Hosting
- DB: Firebase Firestore
Flutter web × Firebase
エラー発生
"FirebaseOptions cannot be null when creating the default app."
main.dart
で初期化する際にFirebaseOptions
を追加した。
"自分の値"
の部分はFirebase Consoleからコピーしてくる。
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: const FirebaseOptions(
apiKey: "自分の値",
appId: "自分の値",
messagingSenderId: "自分の値",
projectId: "自分の値"
),
);
runApp(const MyApp());
}
Android Studioのプルダウンメニューから Chrome (web)
を選択し Run => ok.
$ flutter build web
$ firebase deploy
実際のアプリ
皆さんのデータが反映されますので、ぜひ遊んでみてください。
URL: https://montyhallproblem-a7b4a.web.app
遊び方
4. 結果が表示されます。下のボタンを押せば再度試行できます。
5. みんなの
というタブを押すと、これまで試行されてきた全てのデータが表示されます。
本当に理論値通り、変えた時の方が良いのか確かめてみてください!!
最後に
開発に関して
Flutter × Firebaseは慣れてくると、考えた順番そのままでアプリを作っていける感じがします。
まずドアが三つあって、選択可能にして、選択したら指のポインタ出して、あ、ここら辺にボタン差し込むか、、、
というように思考と同期して開発できる感がすごく、とても気持ちいいです。
途中で色々な壁にぶつかりましたが、それでもこのような開発体験なのはすごい。
何個か作って慣れてくると、何かを思いついたらすぐ実装して公開する、というハードルはとてつもなく下がる気がします。
モンティ・ホール問題に関して
試行回数少ないですが、それでもやはり変えた時の方が正解率が高い結果になりました。
皆さんの協力をお待ちしています。
試行回数1000回くらいを目指して、、、
ここまで読んでいただき、ありがとうございました。