はじめに
こんにちは。
株式会社オプティマインドにて,GISエンジニアをしている@tkmbnです.
Qiitaでの記事発信は前回のアドベントカレンダー以来です。。(もっと書かなきゃ。。)
今回は、私個人の趣味であるモトクロスにちなんだ話です。
数年前までは、全日本モトクロス選手権などに出場しておりましたが、ここ最近は殆どがイベントのスタッフをしております。
初心者の方向けの走行会や、公式戦・草レースの集計をしています。
そんな中で開発をしたくなったのがレース集計アプリです。
最初にまとめ
- Claude Code Proプランを使って、Webアプリを開発した。
- 大体2週間位で開発できた。
- AppはGCPのCloudRunへデプロイ、DBはCloudSQLを利用。
- ライダー・観戦者含めて50人くらいの草レースでは、全員が見ても落ちることなくサービスが稼働できた。
開発経緯
まずは、モトクロスのレースのルールから説明します。
基本ルール
オフロードバイクで決められたコースを周回して順位を決めます。
スプリントレースの場合、横一線に並んでスタートし、決められた時間または周回数を周りきるまでをレースとしています。
スタート位置は違えどマリカーみたいな感じが一番想像しやすいかもしれません。
大体のレースが2ヒート(2本レースをする)という枠組みとなっています。
各ヒートの結果に対して、1位から順番にポイントが割り振られ、2ヒートの総合結果が最終的な結果となります。
集計方法
MYLAPS
公式戦では、センサーを用いた計測方法が取られることが殆どになりました。
MYLAPSというシステムを採用しており、コースのフィニッシュラインにはセンサーが埋め込まれ、各マシンにもセンサーを取り付ることで、フィニッシュラインを通過したタイミングを記録します。
MYLAPS側でしっかりとした集計ソフトウェアがあるため、基本的には見ているだけで集計ができます。
(もちろん、レース中のアクシデントや機器の不具合などは発生しうるので、全く気は抜けないです)
手集計
草レースでは、基本的には人の手での集計がされています。
フィニッシュラインを通過したライダーのゼッケンを紙にずらずら書き連ねていく感じです。
レース終了後それを集計し、順位とします。
スタート直後など、ライダーが固まって来られると手がもう追いつきません。
極稀にですが、草レースということもありマシンのゼッケンがついていない・読めない・見にくいという方がいらっしゃいます。
そういった方々には、朝の公式練習後に修正をお願いしたりしています。
エクセルでの集計(手集計の進化版)
ガッチガチに組まれたエクセルのVBAを使うという方法も、私のお手伝いしているレースでは存在します。
該当のセルにただひたすらにゼッケン番号をテンキーで打ち込んでエンターを押すというものになります。
自動で集計され、ヒート順位・総合順位もしっかり出るので、手集計のみよりも格段に利便性があがりました。
とはいえ、どうしても入力ミスやあとからの修正に若干の弱さがありました。
あと、シンプルに砂埃が尋常じゃない場所でPCやプリンターは良くないよね。。っていうのもあります。
例えばの話
地方選手権の話をすると、クラスの一覧はこれだけあります。
- IO (国際A級(IA)+国際B級(IB))
- NA(国内A級)
- NB(国内B級)
- JX(ジュニアクラス)
- K65(キッズ65ccクラス)
- K50(キッズ50ccクラス)
- エンジョイ(ライセンス不要のクラス)
1日のタイムスケジュールはだいたい、こんな感じ
上記の7クラス前後を合計で3回走ることになります。
よって、21クラス分の集計をする必要があります。
MYLAPSでは事前に選手表やクラス、レースの設定を登録してあるので、タイムスケジュールに則って集計の作業をこなしていくだけです。
草レースの場合、同等のクラス数があると仮定すると、この量を手で集計する必要があります。
入力ミスを減らして簡単に集計できるシステムが作りたい!
そんなこんなで、いかに簡単に集計ができるかを軸にWebアプリをつくろうと思いました。
でも基本インフラとかコアアルゴリズムとかばっかやっているのでWebアプリわからん。。となったわけです。
1、2年前からこういったアプリを作りたいと思っていましたが、手を出せずにいました。
だったら、AIに頼ればいけるやろ!と開発を始めました。
開発の流れ
前準備
業務でClaudeCodeを利用していた経験があったので、即採用しました。
個人でProプランを契約しました。
開発
全くといっていいほどフロントエンドの経験がないので、基本的にはClaudeにおまかせするスタイルでいきました。
完全におまかせするスタイルだとどうしても4時間のリミットひっかかりながらも、爆速でアプリを書いてもらいました。
実現したいこととしては、現地でPCなくとも結果が集計でき、エントラントの皆様に結果を共有するためのPDFを出力できるということを主としてやってもらいました。
モトクロスなどのレースにおける細々したルールや作業についても概ねできるようにしてくれました。
ほぼほぼおまかせしていたので、苦労した話とかは特にないんですが、唯一あるとしたらClaudeの4時間リミットに引っかかってしまうというのくらいですかね。。笑
テストデータやテストに関しても、ほとんど書いてくれたので、安心して開発できました。
ローカルでの動作確認
テストデータを突っ込んでイベントを作成、ラップ計測などをして確認してみました。

ヒート結果
ペナルティなどの入力が考えられるため、順位の降格やラップの減算をできるようにしました。
PCだとドラッグ&ドロップで順位移動をできるんですが、タブレットだと不可能だったので、物理ボタンを配置しました。

総合結果
ヒートの合計ポイントで順位をつけるんですが、同点だったときなどに何を優先するかは一応ロジックとして入れましたが、対応しきれないパターンも考え、マニュアルで順位をいじれるようにはしました。
PCだとドラッグ&ドロップで順位移動をできるんですが、タブレットだと不可能だったので、物理ボタンを配置しました。
デプロイ
ClaudeにTerraformコードも書かせていたので、Cloud Run・ArtifactRegistryとCloudSQLをすんなり作成。
CloudRunへデプロイするためのシェルスクリプトの書いてくれたので、それを動作させてデプロイしました。
動作テスト
いろいろと調整を加えながら迎えた当日。
ゆるーいレースだったので、午後から1本だけ耐久レースというスケジュール。
午前の間でもアプリを微調整して、練習走行中に簡単な実地テストを実施。
うまくデータ取れてそうで一安心しました!
本番は、午後の90分耐久レース。
現地の写真は取り忘れましたが、iPad mini (6th) + Bluetoothテンキーでテストしました。
レース中のゼッケン変更やら登録ミスの修正、ライダーの追加など、いろいろな事態が起きてくれたお陰で、しっかりテストできました。
ゲストアカウントの共有もエントラントの皆様に行い、レースの状況をリアルタイムに見れるようにもしました。
当時のメトリクスを見ても、問題なく処理できているようで安心しました。
(もうちょっとマシンスペックを下げられるかもなーとも思いました笑)
今後
GCPのリソースを使っているので、どうしてもお金はかかってしまいますが、今後もこのアプリで集計業務をしていきたいなと思っています。
実地テストを踏まえてまだ改善したいところが出てきたので、忘れないうちに直してもらおうと思います(Claudeに)
最後に
長々と文章を書いてしまいました。すみません。
Webアプリの開発経験がほとんどなくてもここまでのものを作れるってすごいな。と感じました。
生成AIの進歩ってすごいですね。
こういったツールたちをもっと使いこなせるように、いろいろと手を広げていきたいなと思います!
ここまで読んでくださりありがとうございました!






