より良い競プロ生活のためのDiscordBot制作

# 0. はじめに
名古屋工業大学のプログラミング部C0deに所属しています、いぬかきです。

2023年度の冬休みにC0deは、Pixivさんと協賛で部内ハッカソンを行いました！
みんなご存知、あのPixivですよ！！すごくない！？！？

https://x.com/pixiv_corp/status/1737646568633954469?s=20

このハッカソンにて、同級生二人と競プロ生活をより快適にするためのDiscordBotを共同開発しました。チーム名は「君の思いをAccept」です。
Pixivメンター賞と、学生メンター優秀賞をいただけてめちゃくちゃ嬉しかった♪

https://x.com/c0demattari/status/1750108314200068592?s=20

今回はその振り返りレポートを書いていこうと思います！

# 1. 制作のきっかけ
みなさんは競技プログラミングに取り組んでいるでしょうか？

**プログラムの書き方を学べる！
アルゴリズムを学べる！
ゲームのようにレート変動があり楽しい！**

と、いいこと尽くめの競技プログラミング。
プログラマを志すなら、やらない理由はない！！！

それなのに、、**C0deでは取り組んでいる人が少ない**（＞人＜；）

ただ部員に聞いてみると、どうやら競技プログラミングに興味はあるようです。
では、なぜ競プロに取り組まないのでしょうか、、、？

部員A「あぁ、今日ABCだったか、、、忘れてた、、、」
部員B「興味はあるんだけど、やる気が起こらなくて、、、」

![スクリーンショット 2024-01-28 175454.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1377150/18f26bc1-a378-b9dd-72b8-2562176bff82.png)

    
みんなやりたいという思いはあるけど、理由があって**しかたなく**出来ないと。
なるほど、競プロがしたいという思いはあるんですね。

それなら、、、


![スクリーンショット 2024-01-28 175716.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1377150/5595fa37-5b0c-e45a-8b07-1c9dad00cc23.png)


![スクリーンショット 2024-01-28 175600.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1377150/97a8258f-b743-536f-ea69-2eca07d4c95b.png)

**Accept**してあげよう！！

ということで今回のDiscordBotを作成するに至りました。
（もう、そんな言い訳出来ない環境にしてやる。）

# 2. 制作物紹介
制作したDiscordBotの主な機能はこちらです。

- コンテスト通知機能
- 精進通知機能
- 今日の一問機能
- バーチャルコンテスト機能

順番に紹介していきます！

## 2.1. コンテスト通知機能
コンテストの開催をお知らせしてくれます。現在はABCのみの対応です。

<img width="400" alt="スクリーンショット 2024-01-28 174147.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1377150/65ee82a5-8c8a-bccf-e395-bc823c554f14.png">


コンテスト開催のお知らせにリアクションを付けると、開催直前にDMでリマインドしてくれる機能付き！もう忘れる心配はないね♪

<img width="400" alt="スクリーンショット 2024-01-28 174217.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1377150/8f58b1d8-8680-8bbf-d133-26197c0201a6.png">


## 2.2. 精進通知機能
サーバーのメンバーが一週間でどれだけ精進したかお知らせしてくれます。
Difficultyごとの解いた問題数を教えてくれるのが気が利くポイントです。
競争心が煽られてモチベーション爆上がり！！

<img width="400" alt="スクリーンショット 2024-01-28 174322.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1377150/ad0499ff-768a-aa90-0c74-6ff9ce4b5cf0.png">


## 2.3. 今日の一問機能
毎日指定したDifficultyの問題を送信してくれます。
「やる気の起こらない日でも、今日の一問だけは解く！」
と決めておくことで、継続力が付きます。

<img width="400" alt="スクリーンショット 2024-01-28 174425.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1377150/40ae76c0-77ed-8272-e81a-6436e2dc0bd8.png">


<img width="400" alt="スクリーンショット 2024-01-28 174502.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1377150/3acfb260-4058-958f-f266-cbe488900b82.png">

## 2.4. バーチャルコンテスト機能
問題の難易度や、制限時間を指定してバーチャルコンテストを開催できます。
AtCoderProblemsのVirtualContest機能を、Discordサーバーで使いやすくしたイメージです！


まず、コンテストを作成します。

<img width="400" alt="スクリーンショット 2024-01-28 175028.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1377150/14330084-afe1-8c0c-c835-18ca5e1799ce.png">

時間になると、問題が送信されます。

<img width="400" alt="スクリーンショット 2024-01-28 175104.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1377150/262576b9-9228-e6c4-3c1c-42dcfbff3c7a.png">

テキストチャンネルで、リアルタイムに順位表が確認できます！（すごい！！！）

![スクリーンショット 2024-01-28 175159.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1377150/c471207f-c524-5824-28db-aa70b93118f0.png)


# 3. 技術紹介＆制作物詳細
技術構成は次のようになっています。

- bot
  - JavaScript
  - Node.js
  - Discord.js
- API
  - TypeScript
  - Node.js
  - express
  - MySQL
- Deploy先
  - Raspberry Pi4

Dockerコンテナをそれぞれ作って、それぞれで通信するようにしました。
Dockerをしっかり使ったのは初めてだったのですが、共同開発で環境を簡単に共有できるのが本当に便利だった、、、
ここからは、それぞれの部分の詳細を解説していこうと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1377150/024a2232-719a-dbd6-ebb5-a0147f664294.png)

## 3.1. Bot
Bot側の役割はバックエンドが作ってくれたAPIを使っていい感じにBotを作ることです（適当）。

説明が適当すぎるのでもう少し詳しく説明します。
主にやることは次の通りです。
- コマンドの作成
- 定期イベントの実行

### 3.1.1. コマンドの作成
Botを快適に使えるようにコマンドを沢山作ります。
作成したコマンドは次の通り
- register_user
- unregister_user
- register_shojin
- unregister_shojin
- send_shojin
- send_daily_problem
- contest_results
- make_virtual_contest

ザっと解説していきます。

#### register_user & unregister_user
DiscordIDとAtCoderIDの紐づけ、紐づけ解除を行います。
引数にはAtCoderIDを渡します。
![スクリーンショット 2024-01-28 212742.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1377150/a0c129dc-70fa-7b7e-d810-402578b618ec.png)
![スクリーンショット 2024-01-28 212822.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1377150/4b80581d-1323-133b-add8-1bf4da979096.png)
![スクリーンショット 2024-01-28 213020.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1377150/c2a8eb10-74b2-2a2a-2909-2b44f5b76264.png)


#### register_shojin $ unregister_shojin
精進登録を行います。DiscordIDとAtCoderIDの紐づけが出来ていないと実行できません。
![スクリーンショット 2024-01-28 213133.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1377150/12f1ba63-2056-4061-221e-1f2ebc555263.png)


#### send_shojin & send_daily_problem & contest_results
本来定期実行するものをコマンドで好きな時間に実行できるシリーズです。
それぞれ、一週間の精進記録、今日の一問、コンテストの結果を送信します。
（画像は2.2,2.3を参照してください。）

#### make_virtual_contest
バーチャルコンテストを作成します。
コマンドに渡す必要のある値の数が12です、、、。本当に12です。
あまりにも最悪すぎるUIで最高のAPIを作ってくれたバックに申し訳ない（また後で改善します）。
ただ、開催時刻とか、コンテスト名とか、難易度とかちゃんと調節できるところはGOODだと思います！
（バーチャルコンテストの画像は2.4を参照してください。）
![スクリーンショット 2024-01-28 212639.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1377150/f336af98-6468-8323-c2e0-244fab2e9972.png)

### 3.1.2. 定期イベントの実行
定期イベントの実行です。
今日の一問の送信、その日に開催されるコンテストがあるか確認、コンテストがあるなら、通知＆直前DM、精進通知の送信。
そんなに大変そうではないですが、意外と苦戦したところでもあります。

## 3.2. バックエンド
バックエンドです。主な仕事は次の通り。

- 提出の所得
- コンテスト情報の所得
- データをDBへ格納
- APIの作成

### 3.2.1. 提出の所得
提出の所得です。AtCoderへの提出データをすべて所得します。
ユーザー数がとても多いので必然的にデータベースへの負荷は膨大です、、、
AtCoderProblemsのSubmissionAPIを使わせていただいています。

### 3.2.2. コンテスト情報の所得
開催予定のコンテスト情報を所得します。
これはAPIが存在しないため、自分たちでスクレイピングを行いました。

### 3.2.3. データをDBへ格納
さまざまなデータをDBへ格納しておきます、用意したテーブルは次の通りです。

- users
- submissions
- problems
- servers
- contests
- virtual_contests

それぞれ解説していきます。

#### users
ユーザー情報を格納します。DiscordIDとAtCoderIDを紐づけます。

#### submissions
提出データをすべて格納していきます。
AtCoderProblemsのSubmissionAPIを利用させていただいており、15分おきに新たな提出データを所得することで漏れの無いようにしています。
データ所得は一定数ごとに間隔を置いて行っているので、アクセス過多にはなっていないはずです。

#### problems
過去の問題データをすべて所得しています。
今日の一問を用意したり、バーチャルコンテストを開催するのに大切なテーブルです。

#### servers
Botが参加しているDiscordサーバーのデータを格納しています。
サーバーIDや、精進登録しているユーザーIDなどが記録されています。

#### contests
開催されたコンテストデータが格納されています。
スクレイピングしてきた開催予定のコンテストデータも所得次第ここに格納されます。

#### virtual_contests
開催されたバーチャルコンテストの情報をすべて格納しています。
まだ未完成ではありますが、後述するWeb版において威力を発揮してくれます。


### 3.2.4. APIの作成
バックエンドの肝、APIです。
使いやすいAPIを沢山作っていただきました:sob:
本当に感謝しかない:pray:

沢山ありすぎて、ひとつずつ紹介していてはキリがないので画像で迫力だけ伝えておきます。
![スクリーンショット 2024-01-28 220027.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1377150/bd08acfc-7c51-00e4-22d4-6b1d1d406305.png)

 ***

私はBot担当でバックエンドの詳しい把握までは出来ていないので、ざっくりとした説明になってしまいました。ここに書ききれないくらい沢山の苦労があったはず、、、。今回の開発で一番貢献してくれたのは間違いなくバックエンド担当の彼です。（制作物がバックエンドの塊のようなものなので）
本当にありがとう。

# 4. 今後の展望
さて、せっかく開発したDiscordBotなのでちゃんと使わなければもったいないです。

先ほどの技術紹介の章ではDeploy先をRaspberry Pi 4としていましたが、今は停止しています。
ハッカソン後の懇親会で伺った話なのですが、どうやらラズパイだとサーバー用途としては安定性に欠けるとのことです。（数日に一回落ちるとかなんとか）

そのため、レンタルサーバーに切り替えよう！！！となりましたが、、、

な、なんと！
Azureのバーチャルマシンで十分に動かそうとしたところ、月39ドル＋αがかかると判明しました、、、学生にはさすがに痛すぎる🥲
現在は無料クレジットを使ってAzureで動かしていますが、限界が来る日も近いです。
そこで、もう自宅サーバーを立ててしまおうということになりました。
早速、サーバー用のミニPCを購入。

https://x.com/inukaki_i/status/1751092895984300525?s=20

記事を執筆している日に丁度お家に届いたところです。
これから、環境を整えて自宅で動かせるように頑張ろうと思います。

現在はC0deサーバーのみで稼働していますが、安定運用できるようになったら広く公開したいと考えています。楽しみにお待ちください。

***

また、バーチャルコンテスト機能に特化したWebサイトも公開予定です。
Webからのバーチャルコンテストの作成や、過去のバーチャルコンテストの観覧を可能にする予定です。
Web版はざっくり考えていたのですが、開発メンバーにお願いしたらめちゃくちゃいい感じに仕上げてくれました！感謝！（共同開発最高↑↑）
![2024-01-17_142728.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1377150/63eb96e7-e570-7058-be7a-f789f39fa7ab.png)

![2024-01-17_142811.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1377150/59243243-abd7-8558-c5e9-8c447982d890.png)

![2024-01-17_143805.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1377150/678dfafe-fbf5-43ff-2a92-802e1a623937.png)


# 5. さいごに

私自身ハッカソン参加は三回目なのですが、今回のハッカソンは競争相手のほとんどが知り合い、という状態でとても燃えたハッカソンになりました。制作物も自分たちが本当に欲しいと思っていたものを作ることが出来大満足です。今後も継続開発を頑張りたいと思います（嘘じゃないよ）。


協賛していただいたPixivさん、ありがとうございました（お寿司美味しかったです）。

そして、今回のハッカソンの開催に向けて尽力してくださった部長さんには感謝してもしきれません。本当に良い思い出になりました。ありがとうございました。


今回の制作物のGitHubリンクを添付しておきます。
良ければご覧ください。（汚いコード注意！主にBot！！！）

Bot：https://github.com/inukaki/AtCoderBot_DiscordBot
API：https://github.com/inukaki/AtCoderBot_API