スクリーンショット_2019-12-19_20

栄冠ナイン攻略の為にセイバーメトリクスを持ち込みたくてデータベースアプリを作った話

この記事は「個人開発 Advent Calendar 2019」20日目の記事および「ひとり開発 Advent Calendar 2019」11日目の記事です。ひとり開発の11日目がぽっかり空いてたので急遽差し込みました。 余計なお世話だったらごめんね。

はじめに

ここ1ヶ月くらいDjangoで個人的にアプリを作ってる非エンジニアの人です。なんとかこの日に間に合いました。

作ったアプリについて

パワプロ2016、2018の栄冠ナインというゲームモードで利用できる、選手の個人記録データベース+一部のセイバーメトリクスを自動で計算できるDjangoアプリを開発しました。

https://github.com/shimayu22/Eikan-Database

環境

Python 3.7.4
Django 2.2.6
SQLite3(Djangoのデフォルトをそのまま使用)
Bootstrap4

なぜ作ったか

突然ですが、私は実況パワフルプロ野球のモードの一つである「栄冠ナイン」にどハマりしています。
特にパワプロ2016(PS3版)は購入してから栄冠ナインしかやってません。

元々はパワプロシリーズ自体が好きでご多分にもれずサクセスが好きだったのですが、学生から社会人となり、激務のため[1]8年くらいブランクがあったからか全然打てなくなってました。特にチェンジアップ打てない。魔球やこれ。

全盛期(パワプロ5~パワプロ12くらいの時期)は3打数5安打は当り前[2]レベルに打てていた時から比べると感覚が取り戻せず、ここが引き際と思い引退を決意し、高校野球の監督になりました。※ゲームの話です。

栄冠ナインとは、高校野球の監督としてプレイするモードで、他のモードのように選手自身を操作することはできません。練習の指示やチーム作り、試合での選手交代や一部の攻撃・守備時の指示だけが可能な中で甲子園優勝を目指します。基本的に運ゲーと評されることが多い。

そんな癖のあるモードですが、パワプロ2016版では49代表全てで甲子園優勝を目指し、2度達成しました。今3週目やってます。

2度の全国での全国制覇を達成するためにゲーム内の年数で250年くらいかかったのですが、もっと短縮できないかと思いました。
というのも、最初の1週目で得た育成や戦略のノウハウを2週目は最初から適用して挑戦しましたが、むしろ1年目より年数がかかり、こりゃ運ゲーだわと思っていました。
1イニング被満塁弾×2からの4者連続ホームラン最後はサヨナラホームランとかいうバカ試合も枚挙に遑がない。

画像1

セイバーメトリクスにハマりました

一方その頃、とあるきっかけで「マネーボール」や「ビックデータベースボール」、「セイバーメトリクスの落とし穴」などを読み始め、セイバーメトリクスに惹かれました。「マネーボール」はやきう好きなら読むといいよ読み物として面白いし。映画にもなりましたね。

2018年から独学でPythonを勉強してたし野球分析やってみたいなーと思っていたのですが、世の中には既に実際のNPBのデータを収集したり分析したりしている猛者がいて独自にシステムを作っていたりしていたので、自分のスキルレベルと照らし合わせるといきなりそこの土俵にはいけないしこれ挫折するだろうなーと思っていました。

そこで、一時は「もうこんな運ゲーやらんでいいわあほくさ」と思いましたが、セイバーメトリクスの感覚を掴むための練習台として、セイバーメトリクスの考えを取り入れて栄冠ナインをプレイしてみようという発想に至りました。前振りが長い。

まずはスプレッドシートでやってみた

そもそも250年くらいプレイして、「選手の活躍は能力に比例しない」という感触がありました。天才とかOBとか関係なく、なんとなくその選手が活躍する、活躍しないがある程度内部で決まってるのかな?というのが散見され、画面で表示されている打率、打点、HR数はそこまで当てにならないなぁと思っていました。

そこで「マネーボール」と同様にOPS[3]を基に打順を組んだら勝ちやすくなるのではないか、という仮説を立てて検証しました。セイバーメトリクス初心者なのでまずは「かんたんなセイバーメトリクス」からやっていきます。
ちなみにOPSと打順を組む際の考え方としては、「セイバーメトリクスの落とし穴」によると、

①長打率が最高の打者を3番に置く
②残りでOPSが最高の選手を4番に置く
③残りで出塁率が最高の2人を1、2番に置く
 (長打率が高い方を2番に置く)
④5番以降は残りをOPS順に並べる

というのがここ最近の基本線とのことです。
OBとか天才とかチームにいるとまずは3、4番に入れたくなりますが、情も思い込みも捨ててとにかく数字のみを見て毎試合打順を組み替えてみました。数値的に僅差であればその限りではありませんが。ここが監督の腕の見せ所さん!?

とはいえ栄冠ナインに対してOPS始め、どの指標が戦績に影響あるかがわからないし、別の指標を計算するために周回プレイするのは拷問に等しい[3]ので、スプレッドシートに成績入力欄とOPS以外にも栄冠ナインで表示される項目から計算できる指標用の欄を作って、20年分ほどプレイしてみました。
その結果がこちら。

元SIerとしてのスキルが遺憾なく発揮されてますね!ただしExcel台帳滅ぶべし慈悲はない。

前回の20年目まで[4]の優勝回数が6回なのと比べると、20年目までに12代表で甲子園優勝(13回優勝)と、ずいぶんいい感じな進捗具合です。やマN。

スプレッドシートにも問題が

じゃあわざわざ開発しないでもこのままスプレッドシートでやっていきゃいいじゃん?って思うかもしれませんが、このスプレッドシートにはいくつか問題がありました。

1.めちゃくちゃ入力し辛い
スプレッドシートを見てもらえばわかりますが、めちゃくちゃ入力し辛いです・・・。
まず、入力欄には「+4」みたいな感じで今までの成績を足していくので単純に入力が大変だったり、入力をミスるとそのセルの値が全部消えます。(10敗)無慈悲。
また、普段はOPSでソートしているので、1,2番はちょっと下の方、3,4番は一番上と目線が動きやすいし、代打で出した選手がたまたまHR打つと、ずっと一番上に表示されたりします。
ちなみに卒業した選手は行を非表示にしたり、優勝したらセルに色を付けたり、定期的な細かい手作業がいくつかあります。

2.試合ごとの成績がわからない
トータルの成績はわかりますが、選手一人ひとりの試合ごとだったり年度ごとの成績がわかりません。選手によっては2年生がピークだったんだけど、なかなかOPSが落ちず4番に座り続けたりするので、もうちょっと細かく成績を見たいなと思っていました。

3.計算式を定期的に修正しなければならない
特にチーム打率、OPS、防御率、DERは、半期ごとに所属している選手(夏なら1~3年、秋なら1,2年)の成績から計算したいので、チームが変わるごとに参照元セルを変更しています。時間もかかるし、基本的に眠い目をこすりながら夜中にプレイしているのでオペミスが発生しやすいです。ダブルチェックに付き合ってくれる人もいません。

ということでDjangoアプリ、はじめました

打順を組む際にOPSを参考[5]にすると運ゲーが多少マシになることがわかりましたので、アプリ開発に移ります。

Djangoを選んだ理由

以前SwiftでiOSアプリを作成したり、Railsチュートリアルを完走したりしましたが、今回はDjangoを選びました。

1. Pythonで書ける
PaizaでPythonを学んだり、事務仕事で使えるPythonスクリプトを作ったりしていたので、自分としてはPythonが今のところコスト低めに開発ができるかな、という算段がありました。

2. 管理画面からデータを登録できる
Djangoの特性として、Modelクラスを書くだけでデータ入力画面も作られます。
厳密に言えば多少コード書きますし、ログイン機能付きの管理画面内に登録画面があるので、誰でも触れるようにしたい場合はその限りではないですが、フロント側でフォーム画面を作成したり、登録・更新・削除処理を作ったりするよりは、はるかに少ない労力で作れます。
手前味噌ですがこちらの記事を作成するにあたり作ったアプリも、Modelだけで作りました。Modelだけでこんな感じの画面になるので、アプリの方向性によってはずいぶんサクッと作れます。

3. 仮想環境でサクッと動かせる
今回のアプリはその特性から、みんなが使えるWebアプリとして公開しようとはハナから思っていませんでした。
そのため、venv(サーバーを用意しなくていいという文脈)でサクッと動作するということも一つの理由となりました。厳密にはPython3の機能の一つ?

完成までの道のり

まず2週間くらいかけて「公式チュートリアル」や「こちらの記事」を基にDjangoについて学びました。
だいたい感覚がつかめてきたところで、要件定義を行います。Scrapboxを使ってこんな感じでやってました。

画像2

こうやって書いておかないとね、自分でもどうするか忘れるからね(健忘)ある程度要件定義したら作り始め、検討が足りなかったところがあれば追記したり、もっといい方法を思いついたら変更したりしていました。

開発期間としては1か月程度です。だいたい平日の夜、家事を終えて[6]奥さんと娘を寝かしつけてからなので早ければ22時から24時、時には2時くらいまでゴリゴリ書いてました。身体的には辛いですがすごーいたのしー!ってやってました。Github見るとそれまでの砂漠具合が嘘のように10月後半からの茂り方がすごい。

こだわりポイント

1. なるべく入力が楽になるようにした
例えばなるべくデフォルト値を設定したり、選手の試合結果を入力する画面では選択できる選手を絞って、上の世代が出てこないようにしました。
また、入力時は打順(またはリザルト画面の表示順)で入力できるようにしてあるので、あとはなるべくTabで移動しながら数字を入れるだけにして、入力時間の短縮を図りました。入力に時間かけるのは本分ではなく、あくまで優勝する為なので。

2. 管理画面を活用した
試合結果を入力する画面では、野手は9行、投手は1行がデフォルトで表示されますが、もちろんそれ以上の人数が出場する場合があります。
Djangoの管理画面では、JavaScriptとか書かなくても行の追加、削除処理が可能です。助かる。
そのため、データ入力は管理画面でやる、と割り切ってずいぶん開発期間が短縮できました。まぁ多人数でいじる類のものではないのでいいよね。割り切り大事。

3. もちろん指標は自動計算
試合情報の登録ボタンを押すことで、指標を計算する→指標用のテーブルに登録するというところまでやってくれるようにしました。多少SQLというかDBというか、DjangoのORMで苦労しましたが、やりたいことは実現できました。いやーやっぱり必要に迫られると習得できますね。ただクラス設計はじめ、これでいいのかは自信がない。

4. 後の拡張性
とりあえずVer.1.0.0ってことで、ある程度ざっくりした集計をしていますが、選手ごと、試合ごとの成績を個別に持っているので、今後少しずつ細かく集計していこうと思います。詳しく、楽にデータが取れるようになって気付くこともありそうですが、あんまり細かすぎてもただの自己満足でしかないので、仮説検証しながらになるかなぁ。

こだわらなかったポイント

1. 新規で学ぶ必要があることを最小限に抑える
「venv?Dockerは?」と思った方もいるかもしれませんが、自分としては現状使ったことがなかったし、Djangoの習得で精一杯だったので、今回は見送りました。
あれもこれも習得したいですが、手を出しすぎると本編が進まないので次回への課題として積んでおきます。

2. 最初にゴールを決めた
個人開発と言えば、特に締め切りもなく急かされることもないので、開発中に「あ、こんな機能もあるといいな!」とひらめいてしまうと、延々と開発してしまいます。通称エターなる。
そのため、まず最初に想定している機能やひらめいた機能を書き出して、その中から「Ver1.0.0として最低限必要な機能」というのをピックアップしました。
今回のアプリで言えば、

・チーム、選手、試合結果を登録することができる
・ 試合結果を登録したら、それを元にセイバーメトリクス(これも検討して算出する指標を絞った)の計算をしてDBに保存する
・フロント側は現在のチーム情報と選手、チーム結果一覧が表示させるだけ

くらいです。なのでフロント側は貧相です。とりま表示されるからいいかの精神で、今後の課題としています。Vue.jsとか使ってみたい。

3. Bootstrapに頼った
個人開発玄人の方々の間では「Bootstrap臭」と言われ始めていますが、こちとら素人なのでガンガン頼ります。
正直最初は使わないようにしようかなと思いましたが、軽く作った時点でWeb1.0を感じたので頼ることにしました。

こ ん な 感 じ

画像3

もっとサクッと開発できるようになってからそういう所にこだわり始めればいいんじゃないかな?

4. テストを書かなかった
TDD全盛(?)ですが、今回はテスト書きませんでした。これも上記と同様に、とにかく形にするので精一杯だったのでまず形にして世に出すことを優先しました。
いや、もちろん書いた方がより良いですが、個人開発初心者は(ある程度の最低限度はありますが)とにかく一回リリースすることを目標にするのが良いかなと思います。
無事リリースできたので、この後少しずつテストを書いたりDocker使ってみたりしながら色々勉強したいと思います。

5. masterにコミットし続けた
gitでバージョン管理をする際は、git-flowという手法を用いて開発する方法がありますが、今回はひたすらmaster一本でやりました。

なぜならGithubに草が生えるからです。(重要)

孤独な個人開発では目に見えるものが心の支えになります。Githubに草が生えた様子を見ていると、今日も頑張ろうという意欲がわきますが、Githubの仕様上masterにコミットしないと草が生えません。

以前作ったiOSアプリではなんちゃってgit-flowで開発していましたが、developで開発していると完成時にmasterにマージするまで草が生えないため、モチベを保つのに苦労しました。
そのため、個人で開発しているのであれば、Ver.1.0.0まではmasterだけでいいかなと思います。(ちょっと処理を試す為にブランチ切ったりしましたが)
で、今回リリースしたので、今後改修する場合はgit-flow風にやっていく予定です。

6. 動くと思うからリリースした
原文:「Done is better than perfect」
Google翻訳だと「完了は完璧よりも優れています」と出ますが、えんじにゃーの方々には「多分動くと思うからリリースしようぜ」でおなじみですね。

エターならないための最大の策は「リリースすること」です。とんちかな?こだわりは尽きませんが、こだわり過ぎると寿命が尽きます。
もちろん最低限のセキュリティやバグ、クラウド破産しないか、使い勝手なんかを検証する必要はありますが、世の中に出しちゃえばフィードバックももらえるし、こうして記事にもできますし、達成感も味わえます。酒がうめぇ。(早速直したいところが見えてきた)

今後の展望

まずは自分が一番の利用者なので、これ使って楽しみたいと思います。
まぁ、PS4買えない[7]のでね、PS3版2016ですが。おちんぎんアップしたい。

また、今回は主にOPSを主眼に打順を決めることでより点数を稼いで勝率をあげよう、というまさに20年ほど前のアスレチックスのような戦略でしたが、データを取ることで他にも攻略に有用な要素を見つけられたらと思います。
例えば
・野手の守備力をあげれば失点が減るのか
・逆に下限の守備力はどれくらいか
・投手に覚えさせるべき変化球は何か
・どの特殊能力を取得できれば勝ちやすくなるか
などなど、まだまだできることはあると思います。その為のデータ収集?その為のデータ分析?
ただ栄冠ナインだと取れるデータの粒度にも限界があるし(あとはゴロフライ率とか?)、何より画面みながらの手入力が辛い。なんとかPS4から取得できんのか。API叩けばデータが取得できる未来はよ。

おわりに

個人開発 Advent Calendar投稿日に間に合わせるために、ここ2週間は特に頑張りました。実は当初はひとり開発 Advent Calendarの方かなと思ってましたが、その頃は全部埋まってたのでね・・・。
いい機会になりましたありがとうございます。そして自分で自分を褒めてやりたい。これで一旦開発は減速して、年末年始は「セイバーメトリクス入門」とか「なぜ日本人メジャーリーガーにはパ出身者が多いのか」を読むぞー。インプットの時間だああああああああああ。

ちなみに

試用版としてHerokuにデプロイしています。
ちょろっと触ってみようかな、という奇特な方はこちらへ。(初回アクセス時に少し待ち時間があるかもしれません)

管理画面のユーザー名:testuser01
     パスワード:eikan-app4

このユーザーはアプリ用テーブルの閲覧、追加、変更が可能です。ダミーデータが入っていますが、好き勝手追加してもらって構いません。自分が使っている環境は別にあるので。

こっちは実際に使っているやつ↓
https://endb.shimay.uno/
コード的にもガンガン更新しています。

俺も使ってみたいよ、という方はGithubからDLして環境作って動かしてみてください。READMEに使い方を書いています。コンテナとかVPSとかHerokuとかにデプロイしたい方はご自身の責任で対応をお願いします。

いや、本当はWebアプリとしてリリースしたかったけどさ、ログイン機能作ったり、ユーザーのチームごとに集計できるようにしたりとか面倒だったから・・・。あとせいぜい3人[8]くらいしか使わなそう(内1人は自分)だったし・・・リリース優先ってことで・・・。


-----

注釈:

「セイバーメトリクス」:参考:「30分で理解するセイバーメトリクスの教科書 - 野球を統計的に楽しもう
「OPS」:出塁率と長打率を足した数値。セイバーメトリクスの指標のひとつ。元々は1980年代に提唱されてはいたが、2000年代にアスレチックスがOPSを基にした選手運用を取り入れ、「マネーボール」により徐々にMLB全体に普及した。

[1]「激務のため」:うつ病になるくらいのレベル。こちらとか参照(ダイマ)
[2]「3打数5安打は当り前」:やきうスラングの「全盛期のイチロー伝説」より
[3]「別の指標を計算するために周回プレイするのは拷問に等しい」:栄冠ナインのプレイ時間は、ゲーム内の1年で1~3時間くらいかかります。試合に勝てば勝つほどプレイ時間が伸びる。ちなみに49代表制覇には仕事しながらだと現実の時間で半年前後かかります。
[4]「前回の20年目までの~」:前回までは1年ごとに要約してメモに残していた
[5]「OPSを参考」:あくまで参考
[6]「家事を終えて」:共働きで時短中の兼業主夫です。洗濯以外の家事はだいたい私が担当。
[7]「PS4買えない」:セールで一番下のグレードが2万円か・・・悩む・・・
[8]「3人」:やきうスラングで「オリックスファン3人説」のこと。後に当時のオリックス監督が本拠地動員数170万人を170人と言い間違えたことで、最近は170人に増えている。

サポート、私の好きな言葉です。