【腐食杯】大会運営を支える”集計システム”にGASを導入して半自動化してみた
TECH BLOG 2026/3/10 スコール

【腐食杯】大会運営を支える”集計システム”にGASを導入して半自動化してみた

#腐食杯 #テックログ #非公式大会
SHARE

はじめに

 どうもこんにちは、スコールと申します。タイトルの「腐食杯」にて集計システム作成/集計情報統括・送信を担当させていただきました。

 いきなりですが皆さん、集計システムって何?と疑問に思われたことでしょう。そこで、この記事では  「集計システムの主な仕事」  「GASを導入して自動化」  の大きく2つのセクションに分けて、大会における集計システムについてお話ししていこうと思います。

集計システムの主な仕事

 まず、「腐食杯」の試合ルールについて軽くおさらいしておきましょう。

・腐食 vs 参加者 の構図に基づき、「腐食より失点数が少ない状態を維持し続ける」ことを目指してプレイする

・参加者には初期ライフが2つあり、腐食より失点数が多かった場合、ライフを1つ失う。

・ライフが0になった参加者は脱落となる

・特殊ルール:チョウハツ 各曲で可否を問い、行った人数に応じて腐食の失点数が軽減される(ガード)

・特殊ルールその2:ガード チョウハツの人数・残りプレイヤー人数に応じて、本来の失点からn%減少させる

 以上のルールを踏まえ、試合を動作させるためのシステムを作っていくものとします。

さて、この時、どれだけの量の値を計算して、保持しなければならないでしょうか。

・プレイヤーごとのライフ(最大24人分)

・プレイヤーごとの失点数(最大24人分、PERFECT~MISSの5値)

・腐食の失点数(PERFECT~MISSの5値)

・残りプレイヤーのうち、チョウハツを行ったプレイヤーの割合

・残りプレイヤーの人数

・ガードの割合(%)

・本来の失点から、ガードの割合だけ減少させた値

計153個(本当はもっとある)の数値を保持したり、時には計算をしたりせねばなりません。

そこで、このデータの保持と計算を、表計算ソフトにやってもらうようにしたものが今回の集計システムです。

今回の場合はそこに配信ソフトウェアのOBS Studioと連携する用のデータや公式サイトに試合結果を適宜送信する機能を盛り込んだものを作成しました。

作っていく流れ

 まず、人間が入力するエリアを先に決めておきます。 今回は各プレイヤーのリザルトを入力してもらう必要があるので、腐食含む25人のリザルトを入力するゾーンに枠線を引いたり色をつけたりして見た目を軽く整えておきます。ついでに、各プレイヤー名の横に「チョウハツしたかどうか」を管理するチェックボックスも置いときましょうか。 する or しない の二値化ができているものはチェックボックスで管理するのが手っ取り早いです。

プレイヤー1人あたりのリザルト入力エリアはこのような感じになりました

これを25人分用意します

ここでルールを改めて見返すと、リザルトの入力以外は計算または値の参照でいけそうな感じがします。

・ライフの管理と減少 → それぞれの失点数を参照して、腐食の失点数より多い場合、ライフを1つ減らす

・残りプレイヤーの人数 → ライフが1以上残っているプレイヤーをCOUNTIF関数で数える

・チョウハツを行ったプレイヤーの割合 → TRUEになっているチェックボックスをCOUNTIF関数で数え、残りプレイヤーの人数で割る

・ガードの割合→ 「残りプレイヤーの人数がa人以下になったとき、n%加算する」「チョウハツ割合がb%を超えた場合、さらにn%加算する」ことをまとめた表を作成して、それを参照して割合を計算する

このように、目的と手段が全て繋がっていることが確認できたので、あとはひたすら数式を打ち込んでいきます。 たまにデバッグ作業として自分がプレイしたリザルトを入力してみたりしながら、上記の仕様をつぎ込んでいきます。

数式がすべて打ち終わったら、システムの基礎になるものは完成です。ルール(仕様書)通りの挙動をするのでここで完成!解散!といきたい所ですが、気になる箇所が何か所かあります。

自動化

 ここまでで、大会に必要な機能がすべて備わったシステムが完成しましたが、気になる箇所が1つあります。

ライフの管理と減少 → それぞれの失点数を参照して、腐食の失点数より多い場合、ライフを1つ減らす

 現状のシステムでは、ライフを管理しているエリアに毎回移動して、ライフが2なら1に、1なら0にする処理を人数分行わなければいけません。 私がこれを超スピードで行えるハイスピード人間ならこのままで問題ないのですが、あいにく私はハイスピード人間でもないし、数の打ち間違えが起こる可能性もあります。

 そこで登場するのが、Google Apps Script、通称GASです。

GASについて少し説明すると、Googleが提供するアプリケーションサービス(GoogleスプレッドシートやGoogleドキュメントなど)で使えるスクリプトを作成/使用できる機能のことです。このGASに、望んだ動作をすることを祈りながらスクリプトを記述していくことで、「キミだけの最強の便利機能を作ろう!」ということができます。

 今回はこのGASを使用して、次の機能をそれぞれワンボタンで済むようにしてみました。

① 各プレイヤーのライフを減らしたりする

② 各曲の結果を別シートに転写する

 それぞれの機能をスクリプトにするまでの道筋を、端的に紹介していきます。

① 各プレイヤーのライフを減らしたりする

 まず、仕様通りのシステムを作った段階で、「腐食の失点数と各プレイヤーの失点数を比較する」という数式がシート内に埋め込まれています。これを使います。

現在の数式では、「(腐食より)失点数が少なかったら”勝利”、失点数が多かったら”敗北”」と表示するようにしているのですが、この”勝利”と”敗北”をそれぞれ0と1に置き換えます。これをライフの減少量として扱います。

各プレイヤーのライフは縦一列に並べて管理してあるので、上記の0または1をライフの右隣に表示されるようにします。

プレイヤー名失点数ライフ減少量
腐食-13
例1-2121
例2-520

このように、それぞれの値が保持されている

ここから、GASの出番です。for文でプレイヤー全員を対象に、mathメソッドで(ライフ) - (減少量) の減算を行うようにすれば、あとはワンボタンで全員のライフを、腐食に勝利したプレイヤーのライフは0減少(つまり、減らない)、敗北したプレイヤーのライフは1減少させることができます。 使用したシステム内では、この機能をdecrementLife()としています。

② 各曲の結果を別シートに転写する

 この機能は、各曲の集計結果を公式サイトのリアルタイムリザルト確認ページに反映するために必要になっていました。ついでに、配信画面の「TRACK 〇曲目」の曲数もこの別シートのデータ数+1で管理していました。

 現在のシステムでは、最大25人分の失点を別シートに手打ちする必要があるのですが、さすがにそんなことをしていられないので、GASを使います。

 下準備として、楽曲名と各プレイヤーの失点数を参照するセルを横一列に並べておきます。GASでは、「セルの値を取得する」「特定のセルに値を格納する」という機能(getRange, getValues, setValues)が用意されています。これをなるべく短いコードで記述したいので、下準備としてデータを並べています。

 あとは、データのあるシートから値を持ってきて、別シートに格納するように書けば9割方完成です。

 最後に、別シートに格納するデータが「既に格納されたデータの1つ下の行に保存されるようにする」ために「格納予定のエリアがすべて空白である行を上から順にサーチする」機能を足したりして、この機能も完成です。

 大会本番では、各曲の集計が終了し、次の曲に移るまでの間にこの機能が働いていました。当初はこのコード内で集計班が入力したリザルトを消去する機能も追加してwriteRecordAndDelete()としていましたが、配信画面に内部精度が表示されないミスを発見したため、急遽削除することになってしまいました。

 このような機能がワンボタンで起動できるのが、GASの強みであり使う理由です。むしろ使わない手はない、とまで言えます。

 ここで本当は実際に使用したコードを載せてやろうかな、と思ったのですが、色々と漏洩すると怖いのでやめました。ChatGPTにこの記事読ませたら似たようなコード書いてくれると思います。

その他にGASを使用した部分

 GASを使用して自動化した部分は上記のライフ減少とリザルト転写と、もう一つあります。それは集計データをOBSに送る、という作業です。

 詳しくは、Googleスプレッドシート → APIサーバー → OBS という流れのうち、スプレッドシート → APIサーバー の部分の半自動化を行いました。

以下はコードの構造説明になります。

 この作業では、3つの機能を組み合わせて半自動化を行っていました。

① シート”ID対応表”にまとめてあるフェーズ(試合進行を数値化したもの)・セル番地・固有IDのデータを参照し、それぞれのセルの値を取得する

② ①で取得したデータを元に、データを集約した文字列を構築する

③ ②で構築した文字列をAPIサーバーに送り付ける

 この3つをそれぞれgetIdMappings(), buildDataArray(), sendSongData()と名付けて、これもほぼワンボタンでできるようにしていました。これらの機能のおかげで、離れ離れの場所から打ち込んだリザルトを迅速に配信スタジオのOBSまで届けることができていました。

総括

 このような手順で、腐食杯の集計システムを作らせていただきました。個人的にはまだまだ詰めの甘い箇所や使用感の確認不足もありましたが、集計班の方々には概ね好評だったようで、非常にありがたいお話でした。

 なかなか他の大会にはないゲームルールだったこともあり、新たな学びや発見を多く得られた企画だったな〜と振り返って感じています。もし次「腐食杯2」的なものがあるなら、OBSの画面レイアウトを動的に変更できるような何かを盛り込んだパーフェクト集計システムくんを構築しに赴きたいと思います。

 以上、集計システム作成/集計情報統括・送信担当のスコールでした。ここまで読んでいただきありがとうございました。

あとがき

 私自身プロセカの大会や企画に携わったのが初だったこともあり、数年ぶりにプロセカをダウンロードしてデータ復旧に失敗して、課題曲を楽曲ショップで購入するところからちまちまとやっていたわけなんですが、はぐって曲めちゃくちゃ良くないですか???????非終点判定遊戯地力しか無いのでAPは出せませんが…