班決めを考えるのが嫌すぎて「良い感じに班決め君」作ってみた

#はじめに
コロナ前を想像してみてください。

飲み会で居酒屋にいざ着いたとき、みんながみんな
「どこの卓に行こう」
「先輩に先に席選んでもらわないと」
「新人の子はこの席のほうがいいよね」
とか考えてﾅｯｶﾅｶ席につかない、__壮絶な牽制大会__が始まることありませんか？
僕は__鳥貴族__でよくありました。
安くてしかも旨いので大人数で行きがちなんですよね。

仕事であれば、例えばグループディスカッションをするとなったときに、どんな班分けにするかって地味に悩むと思います。
そこまで深く考えずえいやで決めてしまえばいいとは思うんですが、いざ班分けをする場面になると「この人とこの人は関わりが薄いよなあ」とか「ここ若手一人になっちゃうわ」とかいろいろ考えちゃうんですよね。

色々情報をインプットして、__自動で班分けをしてくれるツールあればなあ__と思い、作ってみちゃいました。
アプリはデプロイして試験利用できるようにあるので是非是非利用してみてくださいね。
コードはGistをご参照ください！
App: https://dazzling-albattani-2c12ef.netlify.app/hangimekun.html
Gist: https://gist.github.com/canonno/e08ba37eff5e736aa50cd08b08b9ec01

~~全然関係ないですけど「班」って響きなんか小学生っぽくて懐かしいですよね~~

#完成デモ
##班の数・メンバーインプット
まず班の数を決めます。
今回は最大6人班の個数のみを設定できるようにしています。
4人班と6人班を組み合わせた場合も考えたんですが、ﾄﾘｯｷｰ過ぎて断念しました。

そのあと参加者の属性をインプットします。
偉い人・先輩・新人の身分3種類と、男女の性別2種類の合計6属性の人数をインプットします。
ここでインプットすると、原則__同じ属性の人がばらけるように席が配置されます__。
例えば新人は同じ班には固まらないとか、女性が同じ班に固まらないとか、というイメージですね。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">良い感じに班決めしてくれるウェブアプリつくりました<br>班の数とメンバーの属性をインプットしGOを押すと、メンバー属性がなるだけばらけるような班分けになります。<br>「偉い男がばらける」「先輩女がばらける」みたいなイメージですね。<a href="https://twitter.com/hashtag/protoout?src=hash&amp;ref_src=twsrc%5Etfw">#protoout</a> <a href="https://twitter.com/hashtag/html?src=hash&amp;ref_src=twsrc%5Etfw">#html</a> <a href="https://twitter.com/hashtag/javascript?src=hash&amp;ref_src=twsrc%5Etfw">#javascript</a> <a href="https://t.co/JQevvDlgjQ">pic.twitter.com/JQevvDlgjQ</a></p>&mdash; canonno (@canonno_blog) <a href="https://twitter.com/canonno_blog/status/1290830863999983616?ref_src=twsrc%5Etfw">August 5, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

##いざ班決め
GOボタンを押すと下の図に班分けが描画されます。
コロナ収束後に飲み会の席決めにも使えるように、机っぽい配置にしてあります。
青色が男性・ピンクが女性になっています。

ロジックの中に乱数を組み込んでいるので、ボタンを押すとまた新しい配置になります。
この配置気に食わんなという場合はボタンを連打して良い感じの配置を探すという八百長も可能になっています。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">班決め君、実行するとこんな感じです。<br>「原則」メンバー属性がばらけるようなロジックになっていますが、ランダム要素を追加しているので、GOを押すたびに班分けが変わります。<a href="https://twitter.com/hashtag/protoout?src=hash&amp;ref_src=twsrc%5Etfw">#protoout</a> <a href="https://twitter.com/hashtag/html?src=hash&amp;ref_src=twsrc%5Etfw">#html</a> <a href="https://twitter.com/hashtag/javascript?src=hash&amp;ref_src=twsrc%5Etfw">#javascript</a> <a href="https://t.co/YTzErghO27">pic.twitter.com/YTzErghO27</a></p>&mdash; canonno (@canonno_blog) <a href="https://twitter.com/canonno_blog/status/1290831309741285376?ref_src=twsrc%5Etfw">August 5, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

もちろん、一度班分けをした後に条件変更しても大丈夫です。
一つの班の人数調整に利用できそうですね。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">班決め君、班分け後に条件を変えてもちゃんと反映されます。<a href="https://twitter.com/hashtag/protoout?src=hash&amp;ref_src=twsrc%5Etfw">#protoout</a> <a href="https://twitter.com/hashtag/html?src=hash&amp;ref_src=twsrc%5Etfw">#html</a> <a href="https://twitter.com/hashtag/javascript?src=hash&amp;ref_src=twsrc%5Etfw">#javascript</a> <a href="https://t.co/I4tLubO9yO">pic.twitter.com/I4tLubO9yO</a></p>&mdash; canonno (@canonno_blog) <a href="https://twitter.com/canonno_blog/status/1290831663971184640?ref_src=twsrc%5Etfw">August 5, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

##応用テク
例えば偉い人男性2人・先輩男性6人女性1人・新人男性2人女性1人で合計12人の時を考えます。
女性が2人しかおらず、女性2人を同じ卓に入れたいとしましょう。
こういう時は女性2人を、__先輩男性6人に足して8人とみなして__実行します。

すると、こんな結果になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666990/6f3b3634-1ea0-f877-a735-4d921d3a1d5d.png)

この結果を受けて__後出しでどこかの班の先輩男性2人を女性2人に置き換える__と、必然的に女性2人を同じ班にすることができます。
ややﾄﾘｯｷｰですが、意外といろんな用途に使えるのかなあとかぼんやり思っていたりします。
「この人たちは固める」みたいな機能をつけたかったんですが、ロジックが地味難しく途中で力尽きました。
いつかｼﾞﾂｹﾞﾝｼﾃｪ


#環境
Visual Studio Code 1.47.1

#手順
##いい感じのヘッダーを付ける
Progateの「HTML&CSS学習コース　初級編」というオンライン講座をかなり参考にしました。
ベイビーステップで少しずつ少しずつ、手を動かしながら勉強できるのでProgateかなりおすすめです。
オンラインですのでコロナ自粛の間是非是非お試しくださいね。
(Progate: https://prog-8.com/courses)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666990/2a339404-ed84-702e-454c-a17e275cd314.png)
こんなのがｻｸｻｸつくれます

##条件インプット部分作る
まずボタンをポチー押して条件がﾆｮﾛﾝと出る部分については、簡単に見栄えのいいアイテムを追加できるBootstrapのAccordionというコンポを利用しました。
人数を選ぶラジオボタンもBootrstrapのButton Toolbarを利用しています。
型にﾍﾟｺﾍﾟｺいれるだけで見栄え良く仕上がるので是非利用してみてくださいね。

(Accordion: https://getbootstrap.com/docs/4.5/components/collapse/)
(Button Toolbar: https://getbootstrap.com/docs/4.5/components/button-group/)

```html

<!--Bootstrapのアコーディオンを利用-->        
    <div class="accordion" id="accordionExample">
      <div class="input">
        <!--班の数指定カード-->
        <div class="input-float">
          <div class="card" style = "width:18rem;">
            <div class="card-header" id="headingOne">
              <h2 class="mb-0">
                <button class="btn btn-link btn-block text-left collapsed" type="button" data-toggle="collapse" data-target="#collapseOne" aria-expanded="false" aria-controls="collapseOne">
                  <h3 class="section-title">班</h3>
                </button>
              </h2>
            </div>

            <div id="collapseOne" class="collapse" aria-labelledby="headingOne" data-parent="#accordionExample">
              <div class="card-body">
                <!--4人班の数を選ぶボタン-->
                <div class = "condition-items">
                  <p>最大4人班</p>
                  <div class="btn-group btn-group-toggle" data-toggle="buttons">
                    <label class="btn btn-secondary active">
                      <input type="radio" name="yoninseki" id="option0" checked> 0
                    </label>
                    <label class="btn btn-secondary">
                      <input type="radio" name="yoninseki" id="option1" disabled> 1
                    </label>
                    <label class="btn btn-secondary">
                      <input type="radio" name="yoninseki" id="option2" disabled> 2
                    </label>
                    <label class="btn btn-secondary">
                      <input type="radio" name="yoninseki" id="option3" disabled> 3
                    </label>
                    <label class="btn btn-secondary">
                      <input type="radio" name="yoninseki" id="option4" disabled> 4
                    </label>
                  </div>
                </div>
                
                <!--6人班の数を選ぶボタン-->
                <div class = "condition-items">
                  <p>最大6人班</p>
                  <div class="btn-group btn-group-toggle" data-toggle="buttons">
                    <label class="btn btn-secondary active">
                      <input type="radio" name="rokuninseki" id="option0" value=0 disabled> 0
                    </label>
                    <label class="btn btn-secondary">
                      <input type="radio" name="rokuninseki" id="option1" value=1 disabled> 1
                    </label>
                    <label class="btn btn-secondary">
                      <input type="radio" name="rokuninseki" id="option2" value=2 checked> 2
                    </label>
                    <label class="btn btn-secondary">
                      <input type="radio" name="rokuninseki" id="option3" value=3> 3
                    </label> 
                    <label class="btn btn-secondary">
                      <input type="radio" name="rokuninseki" id="option4" value=4> 4
                    </label>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
```
これが
<img width="250" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666990/769dfd17-c4f4-424d-9e22-287f641e62d9.png">
これになりますﾍﾞﾝﾘｨ！

このまま次のAccordionを作ると、下へ下へボタンができていきます。
今回作成したように、右側にボタンを作りたい場合はcss側でfloat:leftを指定してあげましょう。
ただ指定すると今度は下へ作ってくれなくなるので、下へ追加したくなったらclear:leftを追加しましょう。
(参考：https://udemy.benesse.co.jp/development/web/css-float.html)

```css
.input-float{
  padding: 0px 20px 0px 0px;
  float:left;
}

.contents {
  padding: 20px 20px;
  margin-top: 20px;
  clear:left;
}
```


##クリックしたときのロジック
###最初に考えたこと
GOボタンを押すと、getMemberメソッドが走って条件の読み取りと班決めを行ってくれます。
一番シンプルな班決めロジックはこれではないでしょうか。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666990/0ac614d2-1b34-d5cd-342b-d741aa06ba52.png)

条件から「偉男,偉男,先男,先男・・・」のようなメンバーリストを作り、左から「1班、2班、3班、4班、1班、、、」と決める手法です。
これであれば同じ属性の人はばらけそうですよね。
ただ、__全て結果が同じになってしまってつまらないなあ__と思い、この部分に一つランダム要素を仕込んでみました。

###実装したロジック
今回実装したロジックの全体像はこちらです。
大きな変更点は、一度作ったメンバーリストから、__ランダムに（だけどランダム過ぎない程度に）組み替えて新しいメンバーリストを作る__部分です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666990/6c0e9f0e-6fa0-ae89-04b3-a6ef6a730a8a.png)

このちょこっとランダム要素の具体的な処理はこちら。
全部をランダムにしてしまうと、属性で分ける意味がなくなってしまいますよね。
なので敢えて回りくどく、__「先頭の4人からランダムで取り出し」⇒「新しいメンバーリストに追加」の操作を繰り返し__、全体の傾向が崩れすぎない程度にランダムにシャッフルしています。
こうすることで、前半に男性がきて後半に女性がくるという全体の傾向は保持しつつ、シャッフルすることができます（たぶん）。


<img width="600" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666990/6795778e-2dec-30e8-5911-29e613070569.png">

ジャストアイデアで実装した感じなので、実際効果あるのか検証していませんがきっとうまくいっていると信じていますｽﾐﾏｾﾝﾝﾝﾝﾝ

##班分けを描画する
班分けの描画にはp5jsというライブラリを使いました。
絵も描けるしマウスとインテラクティブな実装もできるし、使い勝手がめちゃめちゃ良いライブラリになっています。
是非こちらも使ってみてくださいね。
p5js: https://p5js.org/examples/

画面更新した際にはまずsetup()が実行され、描画スペースの作成と机の描画が行われます。

```js
//画面更新の度に実行、描画範囲の新規作成
      function setup() {
        // Create the canvas
        createCanvas(920, 300);
        background(235);

        // Set colors
        fill(126, 149, 230, 127);
        stroke(0, 0, 0);
        for (i = 0;i<4;i++){
          rect(40+i*210, 70, 180, 70);
        }
      }
```
その後、先ほどのシャッフルしたメンバーリストを受け取り一人ずつ描画していく処理が走ります。

```js
      //テーブルに描画していく
      function maketable(tablelist,numoftable){
        // A rectangle x座標、y座標,横,縦
        // An ellipse
        textSize(24);
        textAlign(CENTER);

        //ひたすら一人ずつ配置(テーブル左上)
        for (i=0;tablelist.length != 0 && i<numoftable ;i++){     
          gender = tablelist[0].substr(1,1);
          //「偉男」の二文字目を取り出し、男女によって色を変える
          if (gender=="男"){
            fill(126, 149, 230, 127);
            console.log("男や");
          }else if (gender=="女"){
            fill(255, 140, 255 , 127);
            console.log("女や");
          }
          
          //「偉男」の一文字目を取り出し描画
          mibun = tablelist[0].substr(0,1);
          ellipse(75+i*210, 40, 40, 40);
          text(mibun, 75+i*210, 50);
          tablelist.shift();
          console.log(tablelist);
        }

        //テーブル右上
        for (i=0;tablelist.length != 0 && i<numoftable ;i++){     
          gender = tablelist[0].substr(1,1);
          if (gender=="男"){
            fill(126, 149, 230, 127);
            console.log("男や");
          }else if (gender=="女"){
            fill(255, 140, 255 , 127);
            console.log("女や");
          }

・・・
・・・
・・・

```


##あとはhtmlに仕込むだけ！
この作業が地味に難しかったんですがなんとかできました！
Bootstrap君ｽｹﾞｪｯｽﾏｼﾞﾃﾞ
コードの全体像はGistに載せたので是非ご覧になってくださいね。
Gist: https://gist.github.com/canonno/e08ba37eff5e736aa50cd08b08b9ec01


#さいごに
これで少しはストレスフリーに班決めができるのではないでしょうか！
~~いや個人それぞれをどこに配置するか結局決める必要あるやんとか言わないで~~
個人的には名前のインプット欄も作って、それを描画できたらいいなあとか思ってたんですが、人数が増えたときに全員分名前入れるの？と思い断念。
良いUI思いついた人いらっしゃいましたらコメントいただけると嬉しいです！

最後までご覧いただきありがとうございました！
Qiita毎週投稿頑張っております、LTGMいただけると励みになります！
何卒宜しくお願い致します！