IPPONグランプリ主催できるようにしてみた！

## はじめに

こんにちは！[MYJLab Advent Calendar 2023](https://qiita.com/advent-calendar/2023/myjlab)の22日目です。遅れてすみませんでした涙

今日の担当は今年も3年生だった @mahirooooon です！去年のゼミで私が制作した、IPPONグランプリを主催できるシステムについて書こうと思います。皆さんもIPPONグランプリやったことあると思うんですが、全部手動でやろうとするとかなり大変ですよね...？？？ぜひ今後の参考にしてください！

## IPPONグランプリとは
この説明が必要かわからないですが、かの有名な大喜利番組のことです。私は去年までアナウンス研究会という部活に所属していて、その活動の発表会で、大喜利が得意な部員を集めてIPPONグランプリを定期的に開催していました。回答者は5人、審査員は観覧車から募集した5人、審査員全員が面白いと投票した回答がIPPONとなり、1ポイント入ります。お題は3問。全て終了した時点でもっともポイントを稼いだ人が優勝です。

## 実装
環境はNode.jsとSocket.IOを使用しました。Socket.IOは、Node.js サーバーとクライアントの間のリアルタイム通信を提供するライブラリです。通信ゲームやチャットアプリに使われることが多いです。私はUdemyでチャットアプリ開発の動画を見ながら、必要なところを変えてこのシステムを制作していたような気がします。

### 審査画面
```js:
const socket = io("http://localhost:5000");


socket.on("connect", ()=>{
    console.log("接続しました")
});

var point = 0;

const dom = {
    form : document.getElementById("form"),
    input : document.getElementById("input"),
    nowpoint : document.getElementById("nowpoint"),
}

dom.form.addEventListener("submit", touhyo);

function touhyo(e){
    e.preventDefault();
    point ++;
    socket.emit("point", point);
    dom.input.value = "投票しました";
    dom.input.disabled = true;
}
socket.on("point", function(pt){
    if(pt==0){
        dom.input.value = "面白い！";
        dom.input.disabled = false;
    }
    point = pt;
    dom.nowpoint.textContent = point;
})
```
![スクリーンショット 2023-12-24 20.00.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982094/6dbcff1b-c6c7-71de-ea99-9b34e4456a81.png)
真ん中の面白いボタンを押すとポイントが加算されます。

### プロジェクター表示画面
```js:
const dom = {
    video : document.getElementById("video"),
    canvas : document.getElementById("canvas"),
}
navigator.mediaDevices.getUserMedia({
    video: true,
    audio: false,
}).then(stream => {
    dom.video.srcObject = stream;
    dom.video.play()
}).catch(e => {
    console.log(e)
})

const socket = io("http://localhost:5000");

socket.on("connect", ()=>{
    console.log("管理者として接続しました");
});

socket.on("point", function(pt){
    get(pt);
    console.log(pt);
});

function get(points){
if (points>=1) {
        var ctx = dom.canvas.getContext("2d");
        ctx.fillStyle = "#FFFF33";
        ctx.fillRect(0, 0, 800, 600);
        ctx.clearRect(60, 65, 680, 470);
        ctx.strokeStyle = "#CCCC00"
        ctx.strokeRect(60, 65, 680, 470);
    }
    if (points>=2) {
        var ctx = dom.canvas.getContext("2d");
        ctx.fillStyle = "#FFFF33";
        ctx.fillRect(60, 65, 680, 470);
        ctx.clearRect(120, 130, 560, 340);
        ctx.strokeStyle = "#CCCC00"
        ctx.strokeRect(120, 130, 560, 340);
    }
    if (points>=3) {
        var ctx = dom.canvas.getContext("2d");
        ctx.fillStyle = "#FFFF33";
        ctx.fillRect(120, 130, 560, 340);
        ctx.clearRect(180, 195, 440, 210);
        ctx.strokeStyle = "#CCCC00"
        ctx.strokeRect(180, 195, 440, 210);
    }
    if (points>=4) {
        var ctx = dom.canvas.getContext("2d");
        ctx.fillStyle = "#FFFF33";
        ctx.fillRect(180, 195, 440, 210);
        ctx.clearRect(240, 260, 320, 80);
        ctx.strokeStyle = "#CCCC00"
        ctx.strokeRect(240, 260, 320, 80);
    }
    if (points>=5) {
        var ctx = dom.canvas.getContext("2d");
        ctx.fillStyle = "#FFFF33";
        ctx.fillRect(240, 260, 320, 80);
        ctx.font = '150pt IMPACT';
        ctx.fillStyle = "#000000";
        ctx.fillText('IPPON', 175, 350);
    }
    if(points==0){
        var ctx = dom.canvas.getContext("2d"); 
        ctx.clearRect(0, 0, 800, 600);
    }
}
```
socketを接続し、審査員のポイントに応じて画面を変化させます。ポイントが増えるごとに画面の枠が埋まります。5ポイントでIPPON！！！

### 管理画面
```js:
const video = document.getElementById("video")
navigator.mediaDevices.getUserMedia({
    video: true,
    audio: false,
}).then(stream => {
    video.srcObject = stream;
    video.play()
}).catch(e => {
    console.log(e)
})

const socket = io("http://localhost:5000");

socket.on("connect", ()=>{
    console.log("管理者として接続しました")
});

const dom = {
    form : document.getElementById("form"),
    reset : document.getElementById("reset"),
    test : document.getElementById("test"),
}
const kiroku = document.getElementById("kiroku");

dom.form.addEventListener("submit", pointreset);

function pointreset(e){
    e.preventDefault();
    point = 0;
    socket.emit("reset", point);
}
socket.on("point", function(pt){
    let item = document.createElement("li");
    item.textContent = pt;
    kiroku.appendChild(item);
})
```
こちらのタイミングでポイントをリセットできるように管理画面があるのが非常に便利です。

## おわり
このシステムは、引退前に完成できなかったため、まだ実際に使えていません！2,3月あたりに使えるチャンスが来そうなので、実際に使うことを楽しみにしています。大喜利に自信がある人はぜひ声かけてください！