社内交流会向けに、なるべく部署が異なる社員が同じグループになるようにシャッフルするツールを、Google Apps Scriptとclaspで作ってみた

うちの会社では社員交流会を毎月やっています！

いわゆる任意参加のオンライン飲み会というやつです。

30人くらいが参加しまして、4・5人のグループに分ける必要があります。

今までは完全ランダムにシャッフルしてたんですが、それだと同じ部署の人ばかりのグループもできちゃったりします。

「普段あまり話さない別の部署の人とおしゃべりしたい！」という意見がちょくちょく増えてきたので、グループ分けツールを作ることにしました！

できたのがこちらです！

![20220522_member_grouping_tool.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/914711c5-450e-b6c8-58fe-722884de4c65.gif)

社員をシャッフルしてグループ分けするだけのツールです。

これが完成するまでに辿った道のりを書いていこうと思います。



# やりたいこと

まずは、何ができたら嬉しいのか？という `要件` を整理するため、ざっくりとした図を描きました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/8c899141-45aa-c3b2-d2ab-d2b92409f269.png)

- 社員の所属部署がわかる名簿はあらかじめ用意します。
- `Shuffle` ボタンを用意して、クリックした時にグループ分けツールを実行するようにします。
- グループ分けの結果をどこかに出力します。
- なるべく部署がかぶらないようにグループ分けします。



# 動作環境はGoogle Apps Scriptに決定！

やりたいことを実現するのに、どんなツールを使うのがよいのかを、次に考えました。

社員名簿は表形式のデータですので、Googleスプレッドシートを使うことにしました。
これならプログラマーじゃない人でも入力ができるので、良さそうだと思いました。

そして、グループ分けツールの動作環境にはGoogle Apps Scriptを採用しました。Googleスプレッドシートと連携しやすいからです。

図にするとこんな風になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/b5315a2c-d507-05e2-f307-c81184e493c6.png)



# 開発環境はclaspに決定

Google Apps Scriptのアプリを開発する環境として、claspを採用しました。

これは、以下の理由があります。

- ソースコードをGitでバージョン管理できる。
- TypeScriptが利用できるので、型安全に開発ができる。
- Google Apps Scriptのブラウザ内エディターではなく、自分の好きなエディターで開発できる。（VS Code等）

さきほどの図にclaspを追加するとこうなります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/277d77ba-54fa-2590-00cd-33c1e5461ffa.png)

以上で開発環境は整いました！


# 社員のグループ分けアルゴリズム

次に、グループ分けのアルゴリズムを説明します！

ソースコードを載せると、かなりの量になってしまうため、今回は図のみで解説します。

もっと高速な方法や、効率の良い方法はいくらでもあるとは思いますが、今回はその辺を気にせず、なるべくわかりやすいアルゴリズムになるように心がけました。


## 人数が多い順に部署を並べ替える。

たとえば、以下のように3つの部署が名簿に載っているとします。

- さばんな部署が2名
- へいげん部署が4名
- ゆきやま部署が3名

この部署を、人数が多い順に並べ替えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/dc04494b-a931-a231-a808-1d968b3a3642.png)

1. へいげん部署
1. ゆきやま部署
1. さばんな部署

という順番になりました。


# 人数の少ないグループに参加してもらう。

今度は、社員をグループ分けしていきましょう！

以下のように、左に部署の箱、右にグループの箱がある状況を想像してください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/dc3f9267-2559-975b-2be1-0881799ddcde.png)

まず、人数の一番多い `へいげん部署` に注目します。

所属している4名をシャッフルしてから、 `人数が一番少ないグループ` に参加してもらいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/02babd62-c939-aa3a-c756-b090f3c374ea.png)

最初はどのグループも0名で差がありません。こういう時は `先頭` のAグループに決めます。
ということで、1人目の `アラビアオリックス` さんはAグループに決まりました。

Aグループの人数が1名になったので、現時点で `人数が一番少ないグループ` はBグループかCグループのどちらかになります。
そういう時は `先頭に近い方` のBグループにします。
ということで、2人目の `ニホンツキノワグマ` さんにはBグループに参加してもらいます。

そうすると、 `人数が一番少ないグループ` はCグループになるので、3人目の `オーロックス` さんにはCグループに加わってもらいます。

これで、全グループに一人ずつ割り当てられたことになり、どこも人数が同じになりました。
こうなると一巡しまして、4人目の `ライオン` さんは `先頭` のAグループに決まります。



これで `へいげん部署` は全員グループが決まりました！
次は `ゆきやま部署` に注目します。

所属している3名をシャッフルしてから、 `人数が一番少ないグループ` に参加してもらいます。
さきほどと同じ要領で、どんどんグループを決めていきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/40f1a9d9-3e47-5345-3f97-8038cc464728.png)

これで `ゆきやま部署` も全員グループが決まりました！
最後に `さばんな部署` にも同じ処理をしてグループ分けは完了です！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221845/1436d674-d193-37c9-6b78-a3140146237c.png)

このアルゴリズムを使うと、 **同じ部署の人をバラけさせつつ、グループ間の人数差を必ず1名以内に抑えられます。**

たとえば、Aグループは4名もいるのに、Cグループは2名しかいない、ということは絶対に起きません。
（Aグループは4名だけど、Cグループは3名ということは起こり得ます。）

アルゴリズムの解説は以上です。


# さいごに

本記事作成にあたり以下の記事を参考にさせていただきました。ありがとうございました。

- [TypeScript で記述した Google Apps Script を clasp と GitHub Actions を使ってデプロイする](https://dev.classmethod.jp/articles/typescript-clasp-github-actions/)
- [GASをclasp（CLIツール）+ TypeScriptでローカルで開発する](https://panda-program.com/posts/clasp-typescript)