小中高生向けロボコンWROの得点集計システムを決勝大会まで持ち込んだお話【WRO Scoring System】

# 目次

| 章 | タイトル | 内容 |
|:-:|:-:|:-:|
| 1 | [はじめに](#1-はじめに) | 自己紹介および本記事について |
| 2 | [WROとは?](#2-wroとは) | WROについての説明 |
| 3 | [昨年のシステム](#3-昨年のシステム) | 昨年のシステムのおさらいとメリット・デメリット |
| 4 | [システム要件](#4-システム要件) | システムに必要な事項のまとめ |
| 5 | [完成したシステム](#5-完成したシステム) | スクショを交えながらシステムを紹介 |
| 6 | [今年の開発過程](#6-今年の開発過程) | 時系列に沿ってシステムの開発過程を記します |
| 7 | [ハマったところ](#7-ハマったところ) | 開発中に躓いた点のまとめ |
| 8 | [今後の方針](#8-今後の方針) | 来年以降の方針について |

:::note warn
本記事は長編記事ですので、是非**いいね・ストック**等して頂き、時間のあるときにゆっくりお読みください!!
:::

# 1. はじめに

改めまして自己紹介をさせて頂きます。
私は現在某大学にて電気電子情報分野を学んでいる大学生です。

中学・高校時代より、クラブ活動でロボットの研究を行っており、主に **`WRO(World Robot Olympiad)`** という大会に参加しておりました。
そのWROに現在は運営側として関わっており、本年は**公認京都予選会**の**技術委員長**、および**Japan決勝大会**の**RoboMission エレメンタリー部門 チーフジャッジ**としてお仕事をさせて頂きました。

詳しくは以下のページをご覧ください👇

https://wro-association.org/

https://www.wroj.org/

https://sites.google.com/view/kyotorobot/%E3%83%9B%E3%83%BC%E3%83%A0?authuser=0

## 今回のお話

昨年、私は以下の記事を投稿させて頂きました。

https://qiita.com/koushiro/items/bb6814092ad3a1a99e1a

内容としては、WROで用いる**得点集計システム**を開発し、京都予選会にて使用したというものでした。

今年、得点集計システムはパワーアップを遂げ、**2つの地方予選会、さらにJapan決勝大会**で用いることとなりました。
本記事は、その開発の経緯、および簡単なシステムの説明、そして今後の展望を記すものです。

:::note info
昨年の記事も是非お読みください！2章と3章は今年にも通じる話となっています。
:::

# 2. WROとは?

はじめに、そもそもWROとはどういった大会かを記したいと思います。

## 全体概要

WRO(World Robot Olympiad)とは、LEGO社のMindstorms EV3 および SPIKE Prime 等を使用して参加するロボットコンテストです。

![EV3&SPIKE.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/b3477b8d-9f4a-836a-5218-cc221adce678.png)

日本全国で公認予選会が開かれており、それらの優秀チームがJapan決勝大会で戦います。
さらに決勝大会の上位チームは、国際大会に出場することが出来ます。

2022年より区分分け(名前)が変わり、現在は **「ROBO MISSION」「FUTURE INNOVATORS」「ROBO SPORTS」「FUTURE ENGINEERS」** の4つの大きなカテゴリがあります。このうち、私が携わっているのは **「ROBO MISSION」** になります。

![competitions.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/280e8161-f30c-90b3-f96d-11e3f19cb3c6.png)

## ROBO MISSION の概要

ROBO MISSIONでは2~3人1組のチームを組み、課されるミッションをこなすロボットを製作します。

![DSCN3311.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/1f009f22-3710-0efa-83d0-6c7ff5a98e91.jpeg)

(WRO Japan 2023 公認 京都予選会 での選手の調整所「ピット」の様子)

![DSCN3334.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/a17bfb71-54aa-70e3-32fa-ff776364640a.jpeg)

(WRO Japan 2023 公認 京都予選会 での競技コートの様子)

参加できるのは主に小中高生で、8~12歳の**エレメンタリーカテゴリ**、11~15歳の**ジュニアカテゴリ**、14~19歳の**シニアカテゴリ**と3つの年齢区分があります。

またJapanでは、中・上級者向けの**エキスパート競技**と初級者向けの**ミドル競技**に分かれており、**計6カテゴリ**が展開されています。

尚、京都予選会では初参加の小学生向けの**エレメンタリーベーシック**も開催しており、計7カテゴリを実施しております。

**毎年更新されるルール** は、その年のテーマ（国際大会開催国の特徴を表したもの）に沿ったものとなっています。ただし本質的に問われていることは同じで、以下のような技術が問われます。
  
- 正確なロボットの走行
- オブジェクトの操作・運搬
- オブジェクトの認識や色読み
- 指定された通りの手順（アルゴリズム）

ちなみに2023年の国際大会はパナマ 🇵🇦 で、主に **海(港湾都市)** をテーマにしたルールとなっています。

ルール等については👇こちらから

https://wro-association.org/competition/2023-season/

# 3. 昨年のシステム

本年のシステムを説明する前に、昨年のシステムをおさらいしておきます。

:::note warn
昨年よりも前の経緯については昨年の記事に記しておりますので、そちらをご覧ください。

[小中高生向けロボコンWROの運営に携わり得点集計システムを運用した件 / 3. 背景・経緯](https://qiita.com/koushiro/items/bb6814092ad3a1a99e1a#3-%E8%83%8C%E6%99%AF%E7%B5%8C%E7%B7%AF)
（3章がそれにあたります）
:::

昨年のシステムは以下のような構成となっていました。

![2022_システム構成図_間略図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/411852c2-5ae9-4716-4baa-b7c4e55be355.png)


フロントエンドとして、フリーで使えるHTMLサーバー「Xfree」を用いて、その上にHTMLファイルを置きました。
主な機能としては、採点結果を送信するための **「フォーム」** と、採点結果を閲覧するための **「ランキング」** に分かれます。

サーバーには以下の画像のような**ポータルサイト**が置かれており、そこから各カテゴリに遷移する形となっています。

![2022_審判用ポータル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/28a7ae36-1baf-3460-7b6c-a0758e4831ac.png)

ただし、「フォーム」にアクセスすることが出来るのは**審判のみ**であり、選手・観客は「ランキング」にしかアクセスすることが出来ません。これを分けるために、同一サーバー内に二つのドメインを登録し、動線を分けています。

データベースには**Google SpreadSheet**を用いており、各カテゴリごとに一つのブックを用意しています。

そしてデータベースとフロントを結びつけるためにバックエンドとして動いているのが5つの**Google Apps Scripts**のスクリプトです。

## フォーム画面

フォームはHTML/CSS/JavaScriptで書かれており、**チーム名**や**ラウンド**、**各ミッションの成功数**、**タイム等**必要な情報を入力していきます。

![2022_SeniorEx_Form.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/42927be6-abc2-5629-feda-ccac6eead5c2.png)

## ランキング画面

ランキング画面も同じくHTML/CSS/JavaScriptで書かれており、フォームから送信された情報をバックエンド側で解析し、算出したランキングを表示しています。
さらに、**Check**ボタンを押すことで、そのチームの詳細結果も閲覧する事が出来ます。

![2022_SeniorEx_Ranking.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/4babab69-7715-571a-8bad-71eb5fa42915.png)

## 詳細結果画面の画像

各チーム・各ラウンドの詳細な結果を閲覧することが出来る画面です。

![2022_Result_GAS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/2f496144-2b38-4790-9185-c0c9231b4b6f.png)

## スプレッドシート

SpreadSheetの1つのブック内には、以下の4つのシートが用意されています。

| シート名 | 用途 |
|:-:|:-:|
| Base | 送信データをそのまま保存 |
| Total | 各チームごとにデータを整理 |
| Rank | ランキングを生成 |
| Order | 出走順を記録 |

![2022_SpreadSheet_Base.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/02a124d6-7fcf-5de8-6796-f398787e2b18.png)

![2022_SpreadSheet_Total.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/d2c90097-4e1f-ab64-79f8-bf5300d6e4bf.png)

![2022_SpreadSheet_Rank.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/cc6c596c-bc88-7466-c34c-14d2e47d947d.png)

## 昨年までのシステムの良かったところ

### 大会時間の短縮

京都予選会では2018年まで紙の採点シートで得点を集計していました。
しかし、チーム数の増加に伴い、その集計作業に非常に長い時間を要していました。
(1時間程度はざらにかかっていた…)

これを解決するべく採点システムを導入し、**集計にかかる時間を大幅に短縮**しました。
そこから改良を重ね、昨年時点で既に**リアルタイムでの得点の公表**まで出来るようになっています。

### 無料で運用できる

先述の3つのサービスは全て無料で利用することが出来ます。
したがって、**システム全体を完全無料で保守・運用**することが出来ていました。
これは財政面で余裕の無い予選会、および開発者(つまり私)にとって非常に良いことです。

## 本システム最大の欠点

昨年投稿した記事の最後にも記しましたが、本システムには大きな欠点がありました。

ざっくり言えば、**GASとGoogle SpreadSheetを用いたシステムに限界を迎えている**という事です。

まずGASによるSpreadSheetの読み書きですが、一つのセルの読み書きには数秒の時間がかかります。
特に **「書き」** はすごく時間がかかります。
読み書きは一カ所では済まず十数箇所に及ぶため、**一つの送信当たり十数秒から長くて数十秒ほどかかっていました。**
選手や審判はその送信が完了するまで待たなければなりません。

そしてもう一つ、こちらの方がより致命的ですが、SpreadSheetへの書き込みが同時に2件以上発生すると、**スプレッドシートのフォーマットが崩れてしまう**懸念がある点です。
MySQLに代表されるようなリレーショナルデータベースには **「占有ロック」** や **「共有ロック」** といった、一つの処理にのみ読み書きの権限が与えられるロック機構が備わっています。
これにより、データの不整合を防いでいます。

一方、SpreadSheetには基本的にそのような機能はありません。
(自分でそういう機構を作れば出来るかもだけど…)

そのため、セルの書き込みの過程でシート上のフォーマットを崩してしまうことがありました。
実際に昨年の大会ではそのような事例が何件か発生し、大会中にシートを修正する必要が出てしまいました。

これでは、本来の目的である大会の円滑な運営に貢献するどころか、むしろ支障をきたす可能性がある状態となります。
従って、**GASとSpreadSheetによるシステムを廃止しよう**と決めました。

# 4. システム要件

ここまでの背景を踏まえた上で、今年作成するシステムに必要な事項を整理したいと思います。

- 競技の採点をWeb上で行う
- アプリケーションはブラウザ上で動作し、入力にはタブレット端末(主にiPad)を想定する
- 競技結果を自動集計
- 予選会用システムでは最高点の算出を行い、ランキングの作成・表示までをリアルタイムに行う
- 観客用ページを用意し、リアルタイムランキングを閲覧可能にする
- 同ページから各走行の詳細結果(ミッションの成功個数など)を閲覧可能にする
- 【修正点】リレーショナルデータベースシステムを用い、堅牢なシステムを構築する
- 【修正点】ログイン認証などを備えたセキュリティ面も保たれたシステムを構築する
- 【新機能】チーム呼び出し機能を設ける
    - スクリーンにチーム番号を表示する
    - 採点フォームから簡単に呼び出せるようにする

### Webアプリケーションにする

まず、これまで同様、競技の採点結果を**Web**から行う事とします。
Webブラウザで実行する形にすれば、OSの違いによる影響を受けにくいからです。
予選会としては全ての審判の方に端末を用意する余裕は無く、基本的に審判が持参する端末で入力していただく形になるので、どんな端末・OSでも動くというのは重要なポイントです。

### 入力端末はiPadを想定

どんな端末でも…と言いつつ、主に使う端末としてはiPadを想定しています。
これは画面領域の広さ、操作のしやすさ、ブラウザの安定性等、様々なことを考慮した結果です。
どんなハード・ソフトでも動くことを目指しますが、最優先はiPadでの動作とします。

### 集計

送信した競技結果は自動集計し、各チームごとにまとめ、ランキングの作成まで行えるものとします。
順位のつけ方には大会ごとに様々な方式がありますが、予選会段階では旧来の **「2回の走行うち高い方の点数を採用する方式」** とします。

### リアルタイムランキング

昨年度までのシステムと同様、審判のみがアクセスできるページとは別に、選手・観客でもアクセスできるサイトを用意し、リアルタイムで競技結果・順位の閲覧が出来るようにします。
競技結果ではそのチームの各走行で、**どのミッションを、どれだけ成功できたか**まで閲覧出来るようにします。

### リレーショナルデータベースシステム

ここからは昨年からの修正点です。

SpreadSheetをデータベースとして代用する方式は廃止し、**SQL文により操作するリレーショナルデータベースを導入**します。

### セキュリティ面

昨年のシステムはログイン認証などの機能はなく、データ送信時にフォームにパスワードを入力するのみでした。
本年のシステムでは、フォームに遷移する以前にログイン認証をかけることとし、セキュリティ面を向上させます。

### チーム呼び出し機能

さらに、フォーム上から**次に出走するチームを呼び出すことが出来る機能**を新たに追加します。
昨年度のシステムでも既に、フォーム画面で**チームの出走順**を閲覧することが出来ていました。
しかし、審判は基本的に競技コートから離れることが出来ず、次のチームをピット(競技コートから離れた調整所)まで呼びに行くことは不可能です。

実際に、昨年度大会では選手の呼び出し面が問題となり、結果的には大会委員長がマイクで1チームずつ呼び出すということになりました。
これを**画面 及び 音**を使って呼び出そうという計画です。

## システム構成

以上を踏まえて、今回作成したシステムの構成を以下に記します。

- 実行環境 : Linuxサーバー
  - 予選会 : さくらVPSサーバー (OS: CentOS9)
  - 決勝大会 : 決勝大会用のLinuxサーバー
- エンジン : Node.js v20.0.0
- Webフレームワーク : Express
- WebSocket通信 : Socket.io
- 開発言語
  - バックエンド : javascript
  - フロントエンド : HTML / CSS / javascript

初めに、システムを動かすエンジンとして**Node.js**を採用しました。
これは後ほど出てきますが、協力を依頼した私の後輩がNode.jsでの開発に慣れていたのが選択した理由です。
私としては、別件でPythonのDjangoを触っていたので、それとどちらにしようか悩みましたが、新しい環境を触ってみたいなと思い、Node.jsで開発することを決めました。

さて、Node.jsはあくまでエンジン(実行環境)であり、Webアプリを開発するにはそのためのフレームワークが必要です。
Node.jsのWebアプリフレームワークといえば、やはり**Express**ですね。
本システムにおいても、Expressを使いWebアプリを実現していきます。

さらに、前項にて選手呼び出し機能を実現したいと書きましたが、呼び出しボタンを押した瞬間に画面に表示される、もしくは音が流れる、といったような機能が必要だと感じました。すなわち、常時繋がっているリアルタイム通信が必要です。
そのため、WebSocket通信が行えるフレームワーク、**Socket.io**も導入しました。

以上より、本システムは**Node.js + Express + Socket.io**の構成で成り立っています。

次にこれらを動かすマシンですが、全てを統括するLinuxサーバーが必要です。
今回は予選会用にはさくらのVPSサーバーをレンタルし、CentOS9を載せて運用しました。
又、後ほど出てきますが、決勝大会用には主催者提供のLinuxサーバーを用いました。

開発言語についてですが、バックエンドについてはエンジンがNode.jsですので、言うまでもなくjavascriptです。
フロントについても特にこだわることなく、 HTML + CSS + javascript で構築しました。

![構成図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/9ba2466b-df1b-6406-2f08-d03cf17f9ccf.png)

# 5. 完成したシステム

それでは、作成したシステムをスクリーンショットを交えながら紹介していきます。

尚、今回のQiitaの記事用にデモンストレーション用アカウント・大会を用意しました。
是非こちらも体験してみてください!!

アクセスはこちら👇から

http://wro-kyoto.com/wro_calc/home

:::note info

【Qiita用アカウント】
ID: Qiita_demo
Pass: qiita2023
:::

## 審判用ページ

### ホーム

審判用ページの始めの画面です。

![2023_home.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/88368e3c-7ee1-5421-96fd-02b0bf8eebe2.png)

赤〇で囲んだ「ログイン」ボタンを押し、ログイン認証をします。

![2023_login.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/2dd701be-4453-a043-0f33-aa04ebd8a57a.png)

ログイン認証に成功するとホーム画面に戻り、自分がアクセス可能な大会が選択できるようになります。
(選択ボタンが黄色になり押せるようになる。)

システム管理者の場合👇

![2023_home2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/88f94288-06bf-a8a4-0f68-30b138bde4cb.png)

審判アカウントの場合👇

![2023_home3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/96d94bca-26f7-f090-f5f8-ed6d8f847ea6.png)

アカウントごとにアクセス出来る大会を制御出来るのが本システムのポイントです。

中央に配置されている「選手用ホーム」は、選手・観客用ページへ遷移するためのリンクです。

その他、ホーム画面には各種機能にアクセスするためのボタンが配置されています。

主な機能は以下の通りです。

| 機能 | 内容 | アクセス権限 |
|:-:|:-:|:-:|
| パスワード変更 | ログイン時に必要なパスワードを変更 | 審判アカウント |
| エントリーページ | 大会へのチームのエントリー | 管理者アカウント |
| ユーザー登録 | 新しいアカウントを作成 | 管理者アカウント |
| ユーザー管理 | 作成済みアカウントの閲覧・削除が可能 | 管理者アカウント |
| レコード管理 | 全ての競技結果データの閲覧・削除が可能 | 管理者アカウント |
| ログビュー | どのアカウントが、何の作業を行ったかの確認が可能 | 管理者アカウント |

### カテゴリ選択

ホームにて大会を選択すると、次に以下のようなカテゴリ選択画面に移ります。

![2023_select.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/361b014b-fe42-8b66-746a-1cb724171eaf.png)

カテゴリ選択画面ではWRO Japanで実施される6つのカテゴリ(+京都予選会用の小学校ベーシック)が表示されており、実施されるカテゴリのみ「選択」ボタンがアクティブになります。

各カテゴリの列には「チーム」「結果」「選択」の3つのボタンが配置されています。

#### チーム

「チーム」ボタンを押すと「エントリービュー」が開き、そのカテゴリにエントリーしているチームの詳細情報が閲覧出来ます。

![2023_entry_view.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/270dfdb3-4a45-0dd1-5e81-c8cb40635fea.png)

#### 結果

「結果」ボタンを押すと「レコードビュー」が開き、そのカテゴリで送信された競技結果データが閲覧出来ます。
ランキングになる前のデータで、いつ、誰が、どのような内容のデータを送ったが全て確認できます。

![2023_record_view.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/8b8e0d3d-2363-31e9-367f-4997bb90cb86.png)

#### 選択

「選択」ボタンを押すと、そのカテゴリの採点フォームに遷移します。
採点フォームについては次の小見出し以降で詳しく説明します。

### 採点フォーム

本システムの胆である、競技結果を入力し送信する採点フォームです。

![2023_form_ja1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/b80519e6-9623-11a9-6c43-4dfd29438f56.png)

沢山の機能があるので、昨年の記事同様に番号を振って説明します。
ただし、昨年の記事で既に扱った機能も多くあるので、新機能をメインに説明していきます。

:::note info
既にある機能については👇昨年の記事で詳しく説明しております。
[昨年の記事 / 5.成果物の紹介 / Formページ](https://qiita.com/koushiro/items/bb6814092ad3a1a99e1a#form%E3%83%9A%E3%83%BC%E3%82%B8)
:::

#### ➀ 出走順表示 【アップデート】

ヘッダー部分の一番左に配置した三本線の丸ボタンを押すと、左からナビゲーションウィンドウがせり出し、各コートごとのチームの出走順が表示されます。

![2023_orderlist.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/6f5f8c5d-d09c-57e5-0f07-b5c7033b5497.png)

今年度はこの画面に、 **「チーム呼び出し機能」** を追加しました。

出走順リストには各チームごとに、「競技コート」「出走順」「チーム名」 **「呼び出しボタン」** が配置されています。
この「呼び出しボタン」を押すことで、会場に設置された **「呼び出し画面」** にチーム名等が表示されます。

![2023_call.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/eb899bae-5a2c-5be4-d5cc-784991baa0d5.png)

又、チーム名の表示と共に、**合成音声によるチーム名の読み上げ**も行われます。

<iframe width="560" height="315" src="https://www.youtube.com/embed/3UdvpLD9bzc?si=I8T4Zfu0APQI5VdI" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

これらの機能は上述のとおり、**Socket.io**を用いてWebSocket通信により行っています。
これにより、リアルタイムでの呼び出しが可能となっています。

#### (i) 言語切り替え機能 【新機能】

ヘッダーに新たに **「言語切り替えトグルボタン」** を搭載しました。
このトグルボタンのON/OFFを切り替えることで、本文を日本語から英語に切り替えることが可能です。

![2023_forn_en.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/f35356a6-8c50-c211-8f4e-22687cb09a16.png)

この機能について、基本的に採点時は私が翻訳した日本語文により行いますが、これは正式な文ではありません。
あくまで、採点の効率化を考え日本語文を掲載しています。

ところが、翻訳したことで元の分のニュアンスが消えてしまっていることがあります。
例えば、「オブジェクトが〇〇に入っている」というのは、接地面なのか投影面なのかといったことです。
そうした際はこの機能により、英語に切り替えて(つまり元の原文に戻し)、原文のニュアンスに沿って判定するといったことを可能にしています。

もちろん、英語話者の方が審判を行う、あるいは競技そのものを英語で行うことを可能にしていることは言うまでもありません。

#### ➁ ストップウォッチ機能

これまで同様、フォーム最上部にストップウォッチの機能を搭載しています。
しかしながら、ブラウザによって遅延具合に差が生じたりするため、実運用はしていません。
実際には別でストップウォッチを持ち、そちらでタイムを計測しています。

#### ➂ チーム名入力

チーム名をプルダウンから選択します。
リストについてはデータベースから引き出してきます。

#### ➃ ラウンド選択

何回目のチャレンジかを選択します。
車検違反によりエキシビジョンとなった場合は、その下にあるエキシビジョンのチェックボックスにもチェック☑を入れます。
エキシビジョンのチーム(競技結果)は、自動的にランキング生成から除外されます。

#### ➄ 各ミッションの採点

それぞれのミッションの成功の有無、もしくはその成功個数を記録していきます。

#### (ii)選択テーブル 【アップデート】

今まで、判定結果のラジオボタンは縦に並んでいました。
しかし、これではフォームが縦に長くなるばかりで、見栄えが良くないと感じていました。

![radio_button.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/c5fd9c18-a5c4-c53f-8b9a-8e7d91162bcb.png)

そこでUIを改良し、そのミッションごとに**横並び**に出来るようにしました。
さらに、`YES`や`NO`、`0`,`1`,`2`,`3`など判定状況の部分は色をつけて見やすくしています。

#### ➆ タイム入力

上述のとおり、ストップウォッチで計測したタイムをこの欄に打ち込みます。
タイムは**秒**で打ち込むこととしており、小数点以下の打ち込みも可能です。

京都予選会においては小数第一位まで入力することとしました。

(Ex. 1分41秒55であれば、`101.55`と入力する。)

#### ➇ 入力データ確認

審判がすべてのデータを入力した後、選手はその入力項目に間違いが無いか確認する必要があります。
その際に、ページをスクロールせずともデータを確認できるように、表に一覧表示しています。
**各項目で何を選択したか** 、 **それによる点数** 、 **合計点** 、 **タイム** 、さらに **選択エラー** (あり得ない選択をしていないか)といったことを処理しており、それらの結果がこの表に現れます。

👇 **入力エラーが発生した時の例**

![2023_form_error.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/2b9d2cf6-693b-ab04-d5d0-5acf7bdab2f3.png)

#### ➈ 選手による確認ボタン

選手は採点結果に間違いがないことを確認したあと、採点シートに署名をする必要があります。
これは紙の採点シートでの話ですが、これをデジタル上でも行う必要があります。

WROの規定上、デジタルで採点を行う場合、署名に代わりチェック出来るものがあれば良いとされています。
そのため本システムでは、最下部にチェックボックスを配置し、選手の署名の代わりとしています。
このチェックボックスにチェックを入れたことにより、選手は採点結果に同意したものとみなします。

### 大会選択のその他機能

カテゴリ選択画面にてアクセス可能な他の機能について記します。

#### 公開設定

公開設定機能では、選手・観客用ページで閲覧できる各カテゴリごとのランキングについて、公開・非公開を切り替えることが出来ます。
例えば、表彰式での順位発表前に、一時的にランキング画面を閉鎖するといったことが可能となっています。

![2023_setting.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/da96be84-9f49-6f54-db48-546787857bab.png)

#### 呼び出し確認

➀ 出走順表示 のパートでお伝えした、「チーム呼び出し画面」にアクセスするためのリンクです。

#### 会場アナウンス

チーム呼び出しで使用している合成音声の機能だけを切り出し、任意のテキストを読み上げることが出来る機能です。

![2023_anoune.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/07446379-e995-a016-e6af-700c839b6e20.png)

テキストボックスに文章を打ち込み、「放送」ボタンを押すことで合成音声が文章を読み上げます。
今年度の大会では出番はありませんでしたが、汎用ツールとして搭載しています。

#### 結果LIVE

これは主に配信用ツールなのですが、その大会内で一番最後に送られた競技結果データを表示する機能です。
これもSocket.ioを用いたリアルタイム通信となっており、👇の画像のように競技風景に重ねるようにテロップを表示することが出来ます。

【京都予選会のYouTubeライブのスクリーンショット】

![youtube_live.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/3d4ac758-c2d0-9a3c-274c-9ec6dc4b7791.png)


## 選手・観客用ページ

ここからは、選手や観客でもアクセスできるページについて紹介していきます。

### ホーム

選手・観客用ページの始めの画面です。

![2023_audience_home.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/66fb02c7-4bac-33a6-0110-0aba7b71d3e9.png)

こちらのページにはログイン認証等はなく、登録されている大会が全て表示されています。

大会名横の「選択」ボタンを押すと、審判用ページと同様にカテゴリ選択画面に移ります。

### カテゴリ選択

選手・観客用ページのカテゴリ選択画面では「選択」ボタンのみが配置されており、押下することでそのカテゴリのランキング画面に遷移します。

![2023_audience_select.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/2f0b39fb-fe47-76af-0413-8982df16fbc5.png)

### ランキング画面

カテゴリを選択すると、そのカテゴリのランキング、およびラウンドごとの得点が表示されます。

![2023_audience_rank.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/11a519e3-307f-8053-239f-f1a705fb50a3.png)

上述のとおり、京都予選会では「全ての走行のうち最も良い得点を採用する方式」を取っております。
そのため、システムが各チームの最高得点を判断し、その得点をもとに降順でソートをかけています。

尚、得点が同点の場合はタイムが早い方が順位が上なります。

ランキングテーブルの下には、各ラウンドごとの得点が走行順に表示されています。

ランキングテーブルの一番右側の列、「詳細」の「チェック」リンクを押すと、そのチームの競技結果の詳細情報が閲覧できます。

### 競技結果詳細画面

![2023_audience_check.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/09ef37b4-0c29-86d4-f6b8-8723de40cf7e.png)

詳細画面では、審判用ページの確認表のようなテーブル上に、ミッション項目、点数、各ラウンドでのデータが表示されます。
本機能にて、全てのチームの競技結果を閲覧することが可能となっています。

選手は振り返り作業に役立てることが出来る他、観客も観戦しているチームがどれだけミッションをこなせたかを確認することが出来ます。

又、このページについてもヘッダーのトグルボタンを切り替えることで日本語と英語の言語切り替えが可能です。

# 6. 今年の開発過程

本年1月のルール発表から、8月末のJapan決勝大会までの開発の流れを記したいと思います。

## 1月

1月初旬に、2023年のルールが発表されました。
これを受け、**昨年度の反省を活かした新たなシステムを京都予選会に導入**する計画をたてました。

## 2月

2月末、**共同開発者として中高時代の後輩を誘います。**
現在、彼もまたWRO Japan 公認福岡予選会の技術委員として運営に携わっています。

昨年までのシステムを廃止し新たなシステムを構築することから、Webアプリケーション開発の知識が必要なほか、システムを実装するためのマンパワーも必要でした。
少し前から、彼が趣味でWebアプリケーションを製作していること、さらに福岡予選会に所属していることを聞いていたので、ちょうど良いと思い彼を誘いました。
結果的には、システムのコーディングの9割方を彼が担うことになりました。

## 3月

各カテゴリのフォーム(レギュラーチャレンジ)の製作が完了しました。
京都予選会では全てのカテゴリを実施するため、私の方で全ルールに目を通し、実装を行いました。
上述のとおり、フォーム部分でのUIの変更はいくつかありましたが、基本的には昨年までのもを踏襲しているためそこまで難しい作業ではありません。
(作業量はハンパないけど…)

同時期に、後輩君がシステムの外側部分の試作版を作製してくれました。

👇この時点で出来上がっていた機能

- ログイン認証
- 大会一覧画面
- カテゴリ選択
- エントリー登録画面
- エントリーの一覧
- 送信されたレコードの一覧
- ユーザー登録画面
- ユーザー一覧

## 4月

カテゴリ選択画面から各カテゴリのフォームへの遷移が出来るようになりました。
フォーム部分の製作は私、それ以外は後輩君といった役割分担だったため、ここでこの2つが繋がることとなります。

同時期に、「次チーム呼び出し機能」の試作版を私の方で作製しました。
この時点では、GASでURLクエリ付きのGETを受け取り、クエリに応じてスプレッドシートにチーム番号を書き込む方式を採用して、なんとなくの動きを再現しています。

<iframe width="560" height="315" src="https://www.youtube.com/embed/srfOWicFZMs?si=jtVkUdk9_lPx2BUw" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

ただ今回は**GASからの卒業**がある種テーマですので、Node.jsにより実現できないか探っていました。
そこで`Socket.io`を見つけたので、これを使って次チーム呼び出しが実現できないか、後輩君に打診しました。

尚、この月の月末に、正式に**福岡予選会でも採点システムを使用することが決定**しました。

## 5月

本番用のVPSサーバを契約し、オンラインでの試験を開始しました。

同時期、以下の各種機能を後輩君が追加しました。

- レコード管理機能
- ログビューの追加
- ランキング画面の追加
  - 順位の表示
  - 各チームの集計結果も表示できるように

ここまでで、システムの大枠はほぼ完成したと言えます。

(尚、6月は特にこれといった動きはありませんでした。)

## 7月

7月上旬、追加機能について検討を行いました。

- ランキング・集計結果の公開・非公開設定
- ユーザーのパスワード変更機能

その後すぐこれらの機能は実装されました。

7月中旬、この頃から本番想定でデバッグを行っていましたが、あるバグが多発します
それが、 **「一定時間でログインが抜けてしまう問題」** と **「存在しないレコードの引き出し」** のバグです。
これらが同時に発生し、**システムがダウン**するといったことが発生しました。
大会中のシステムダウンなどあってはならないので、そのバグの解消に向けて取り組みました。
(これについては後ほど述べます)

同時期、後輩君が**Socket.ioによる次チーム呼び出し機能の実装**に成功しました。

又、エキシビジョンとなった競技への対応も完了しました。具体的には以下のような処理が行われることになりました。

- エキシビジョンの結果は総合順位に反映されないように
- 得点・タイムにはカッコ()が付き、判別されるように

そして、これが今季最大のニュースですが、7月下旬、**WRO Japanより「得点集計システムを使用したい」との連絡**を頂きました。
こんなにも早く話が広がると思っていなかったため、非常に驚きました。

しかし、この時点では旧ルールにしか対応しておらず、**エクストラチャレンジを用いる新ルール用にシステム改修を行う必要**がありました。
さらに、エクストラチャレンジ用の採点フォームを製作する必要がありますが、ルールは基本的に技術委員長のみ知っているため、誰が作るのかといった問題も協議する必要がありました。

その後すぐ、Japan決勝大会 運営副委員長、RoboMission 競技委員長、私で会議を行い、Japan 決勝大会での使用が正式決定しました。
これにあたり、Japan 決勝大会専用カスタムバージョンをRM競技委員長と私で作製することも合わせて決定しました。

## 7月30日 京都予選会 / 福岡予選会 開催日

地方予選会の開催日は統一されているわけではありませんが、たまたま京都と福岡の開催日は同じでした。

### 京都予選会

まず、呼び出し機能により円滑な競技進行が可能になりました。午前中競技に至っては、スケジュールに対して巻いてしまうほどのスピーディーさでした。
京都予選会では102チーム、204走行分のデータを自動集計し、リアルタイムでのランキング表示もしっかり動作しました。

しかしながら、上述の「ログイン抜け」の症状が治っておらず、15走行分のデータを技術委員長(私)が打ち直すことになりました。
又、京都用のサーバーで2度クラッシュが発生しました。すぐに気付き対処したため、運営に支障はありませんでした。

### 福岡予選会

福岡予選会ではシニアエキスパート/シニアミドル競技に14チームが出場し、計28走行分のデータを自動集計しました。
こちらも、リアルタイムでのランキング表示までしっかり動作しました。
福岡予選会においても、数件データの打ち直しがありましたが、運営には大きな支障はきたしませんでした。

## 8月上旬

地方予選会が終わりひと段落した8月上旬、Japanカスタム製作に向けてのミーティングを私と後輩君で行いました。
ここでは、**レギュラーチャレンジとエクストラチャレンジをどのように分岐させるか**について協議しました。

結果的には、システム内に「レギュラーチャレンジ用の大会」と「エクストラチャレンジ用の大会」の二つを登録し、それぞれに割り振られるIDに応じて表示するフォームを変えることで対処しました。

同時期、私はJapan 決勝大会 エレメンタリーカテゴリ(主に小学生対象)のチーフジャッジに就任することが決定しました。
尚、後輩君も集計担当スタッフ(システム管理者)としてJapan決勝大会に参加することとなりました。

さて、この頃からシステムの改修は私のみが担当するようになりました。
これは、当日その時まで発表されないエクストラチャレンジルールが流出してしまうことを防ぐ狙いです。
この時点で、既に私はチーフジャッジとしてエクストラチャレンジのルールを把握していましたので、私がフォームを作製すれば問題ないと思い、そうした次第です。

## 8月中旬

8月中旬、エクストラチャレンジへの(応急的な)対応が完了しました。
上述の方針のとおり、選択する大会(レギュラー・エクストラday1・エクストラday2)に応じて表示するフォームが変わるようにしました。

![japan_home.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/296b2027-a7d6-5a27-c536-59ecb8623fe9.png)

又、一つのユーザーアカウントで、複数の大会にアクセスすることが出来るようにしました。
同様に一つのチームIDで、複数の大会にアクセスすることが出来るようにしたかったのですが、当初のシステム構想には無い処理となり短期間での実装が難しかったため、レギュラー用のIDとエクストラ用のIDの2つを用意することで対処しました。

さらに、エクストラチャレンジのルールをギリギリまで伏せるため、**大会の公開・非公開設定**を実装しました。

同時期、長らくバグとして抱えていた「ログイン抜け」の問題がようやく解消しました。
どうやらCookieの期限が再ログイン時に延長されるようになっていなかったようで、それが延長されるように修正しました。

一方、別のバグが発生し始めました。
Japan決勝大会用のサーバーを起動して、デバッグをしていたところ、iOS端末のみログイン出来ない現象が発生しました。
他のOS(WindowsやAndroid)では問題なくログイン出来たため、iOSのウェブエンジン(WebKit)に依存する問題だと考え、原因を探りました。
本システムはログイン時にCookieを発行しているため、恐らくiOSのみなんらかの原因でCookieが発行されないのだろうと推測出来ました。

結果的には、決勝大会用のサーバーの時間設定が狂っていた事が判明し、これを正しい時間に設定することでiOSでもログインできるようになりました。
このことから、iOSのブラウザエンジンWebkitのCookieに対するセキュリティが他のブラウザエンジンより高いことがわかりました。

ここまでで、決勝大会前の実装・修正が全て完了しました。

## 8月26-27日 WRO 2023 Japan 決勝大会

RoboMission競技は、26(土)にミドル競技、27(日)にエキスパート競技を開催しました。
採点システムは想定通り動作し、システムによる致命的な不具合は一切ありませんでした。

1日目は 64チーム、128走行分、2日目は 73チーム、146走行分、2日間の合計で137チーム、274走行分のデータを自動集計しました。

Japan決勝大会は、エクストラチャレンジが導入された新ルールで、レギュラーチャレンジとエクストラチャレンジの合計点により競われるルールとなっています。
この計算方式をシステムに導入することは出来なかったので、システムからCSVでデータを吐き出せるようにして、計算自体は外部のPythonスクリプトにより行うこととしました。

そのJapan決勝大会用突貫Pythonスクリプトにより、合計点の算出まで一瞬で行えるようになりました。
ソートに関してはPythonで行うとかえってややこしそうだったので、Excelで作業することにしました。
それでも順位算出まで3分以内で行えるようになり、**集計作業の高速化**、**オンタイムでの表彰式・閉会式実施**へ貢献しました。

以上の決勝大会の終了をもち、今年度用の開発は終了しました。

ただし、修正すべきポイント、追加したい機能、コードの清書などやることは沢山あるため、オフシーズンも開発を継続する予定となっています。
詳しい今後の方針については後の章で記したいと思います。

# 7. ハマったところ

この8か月の開発中、いくつか躓いたところがありました。
それについてここで列挙したいと思います。
詳しい解決方法等については、別の記事に書く方針です。

- ログインが急に抜ける
  - 再ログイン時にリセットがかかっていなかった
- 存在しないレコードをSQLで引き出すと、レコードの中身が無くアプリ全体が死んでしまう
  - 重要な部分にはtry-catchを実装した
- iOSでのみログインが出来ない
  - サーバーの時間がおかしかった
  - iOSのWebkitのみCookieが発行されなかった

【解決方法についての記事】

現在執筆中…

# 8. 今後の方針

最後に、本システムの改善点および今後の方針について記し、この記事を締めたいと思います。

## 改善点

- エクストラチャレンジへの正式対応
- 汎用UIの開発
  - ルール変更のたびにフォームを作り直していては効率が落ちる
  - DBに登録するだけでフォームを生成できるようにしたい
- レスポンシブUI
  - 今はPCやタブレット端末を想定してUIを作成している
  - 幅広く使ってもらうためにはスマホへの対応も必要

### エクストラチャレンジ対応

まず、エクストラチャレンジへの対応は絶対に行わなければならないポイントです。
本年度は、京都予選会・福岡予選会ともに、エクストラチャレンジの導入は見送りました。
そのため、システム設計段階でそもそもエクストラチャレンジのことを想定していませんでした。
しかし、Japan決勝大会への導入が決まり、このエクストラに対応していない点がネックとなってしまいました。
来年に向けて、本格的に実装していきたいと思います。

### 汎用UIの開発

次にフォームについての変更です。
これまで、その年のルールに合わせて、私がHTMLをベタ打ちで作製していました。
しかし、これでは効率が非常に悪く、又エクストラルールのような追加ルールにも対応できないため、データベース等に登録したルールを自動的に参照し、フォームを生成する方式が必要だなと感じました。

### レスポンシブUI

最後に、レスポンシブUIについてです。
レスポンシブUIとは、一つのサイトを閲覧するときに、どんな端末からアクセスしてもちゃんと見やすくなるように表示されるUIのことです。
現在、採点システムの大枠は(大体)レスポンシブUI対応となっていますが、フォーム部分に関しては完全に非対応です。
(気持ち、UIが変化するくらい)
これを、本格的にレスポンシブUIに対応させようという方針です。

今回はどの大会でもシステム製作者が現場にいるので、操作についてのサポートはその場で行うことができましたが、我々のサポートがなくとも、誰でも簡単にシステムを使えるようにしたいという狙いから、そのような方針を立てています。

システムの都合で使える端末が限られるというのは、利用者側からすると非常に不便な点であり、システム提供側からしても、提供機会を減らすことに繋がります。
これらの理由から、レスポンシブUIへの対応を考えています。

## 今後の戦略的な方針

昨年の記事でもお伝えした通り、私は2019年の京都予選会からシステムを開発しています。
以前より、システムを他の予選会にも広めていけたらな…とは考えていました。

今年は私の方から声をかけ、福岡予選会にも導入することができ、2つの予選会で運用することとなりました。
これだけでも私としては進歩だと感じていたのですが、まさかのJapan決勝大会でも用いることとなり、とても前に進んだ年だなと感じております。
今回の契機を活かし、ますます他の予選会にも広めていきたいと考えております。

Japan決勝大会でも、各審判の方(我々と同じように地方予選を主催している方々)に沢山のお褒めの言葉を頂きました。
「是非、うちの予選会でも導入したい」との声も頂いたので、その声に応えられるよう現在調整中です。

**より汎用的に**、**より使いやすく**、そして**より堅牢なシステム**を目指し、今後も開発をしていきたいと考えております。

以上、ここまで長らくお読み頂きありがとうございました。

p.s. 
各予選会、およびJapan決勝大会でご協力頂いた全てのスタッフの皆様に感謝申し上げます、ありがとうございました。😊