CodeCamp Webマスターコース JavaScript 提出課題 ルーレット

#制作環境
Windows 10
Visual Studio Code

#はじめに
この記事はプログラミングをはじめたばかりの素人が、メモするのに利用しています。
内容には誤りがあるかもしれません。

当方は2月から2ヶ月間CodeCampのWebマスターコースを受講しました。
CodeCampは、意向により模範解答などを見ることができません。
※理由は、コードの記述に正解がないからだそうです。

他の人のコードを見る事も参考になると思いますので、つたないコード記述ではありますが、合格をもらったコードを掲載します。

良くも悪くも参考になればと思います。

#課題の内容
jQueryでWeb上で動くルーレットを作成する。

####合格ライン
・指定要件が全て満たされていること
・エラーがなく、分かりやすいソースコードになっていること

####要件

|範囲|No.|内容|
|:---|:---:|:---|
|全体|1|ルーレットの目を16個作成する|
|スタート|2|スタートボタンを押すとルーレットが回転する|
|スタート|3|ルーレットの回転にランダム要素を組み込む|
|スタート|4|回転中はスタートボタンを押せなくする＊disabled属性を利用＊disabled属性を利用がわからない場合はフラグ管理でも良い|
|ストップ|5|ルーレットが回っているときに、ストップボタンを押すとルーレットが止まる|
|ストップ|6|一度ストップボタンで停止した目は次回以降は停止しない|
|ストップ|7|ストップボタンを16回、押すことの繰り返して、全ての目に停止する|
|リセット|8|16回停止後はスタートボタンが押せなくなる(リセットボタンで押せるようになる)＊disabled属性を利用＊disabled属性を利用がわからない場合はフラグ管理でも良い|
|リセット|9|過去に停止した目が何か、ユーザに分かるようにする（目に色がつくなど）|
|リセット|10|リセットボタンを押すと初期表示の状態に戻る（もしルーレットが回っている場合はルーレットの回転が止まり、初期表示の状態になる）|
|ソースコード|11|比較演算子は、「===」や「!==」を利用すること|

要件を満たしていれば、見た目(デザイン)等は自由。

ファイル名はroulette.html。

#掲載している記述について
要件ではルーレットの目は16個なので、マス目も16個固定ですが、個人的な要件としてマス目の数の変更が簡単に行えるようにしてます。

#当方のやり方
一番多いかなと思うやり方だと、出た目と既に出た目を比較するやり方だと思いますが、当方面倒くさがり屋(笑)なので、比較するやり方はとっていません。
個人的にこの内容であれば、比較は不要だと思います。

出る目の候補は1～16と決まっている(それ以外の数字は出ない)ので、出る目の候補から既に出た目を削除してしまえば、比較しなくても同じ目が二度と出る事は無くなります。

イメージ

|出る目の候補|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|
|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

抽選で例えば9の目が出たら、

|出る目の候補|1|2|3|4|5|6|7|8|10|11|12|13|14|15|16|
|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|

候補から9を削除する。
削除されているから二度と抽選で選ばれない。

これをコードで置き換えると、
出る目の候補を配列に全て格納し、格納した配列の中からランダムに値(目)を取り出す。
取り出した値(目)は配列から削除する。
次にランダムに値(目)を取り出す時には、削除された中からの抽出になるので、既に出た値(目)は削除されているので、絶対に選ばれない。

というやり方にしてます。

#記述
以下、当方が作成した記述です。

```HTML:roulette.html
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8" />
    <title>ルーレット</title>
    <link rel="stylesheet" href="roulette.css" />
    <script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
    <script>
        var interval_id; // 繰り返しの定義
        var n; // 1行に入る数字のカウント
        var i = 1; // マスに入る数字
        var go = 4; // 行の折り返し位置 ここを変更するだけでマス目等増減可
        var nums = []; // 出る値の格納場所
        var ran_num; // ランダムに出てきた値
        var idx; // 値削除用のキー

        // ボタン操作の監視及びマスの作成
        $(function() {
            // 各ボタンの監視
            $('.start').click(pre_start);
            $('.stop').click(stop_r);
            $('.reset').click(reset_r);

            // trの作成 ※goの値で作成数自動変更
            for (n = 1; n <= go; n++) {
                // cellの要素を取得しtableタグの後ろにtrを追加
                $('#matrix').append("<tr id='target'>");
                // trタグのid名を変数を使用して変更
                $('#target').attr('id', 'tr' + n);

                // 各行の折り返し位置
                var j = n * go;

                // マスの数字作成 ※goの値で自動追加
                while (i <= j) {
                    $('#' + 'tr' + n).append("<td id='target_td' class='case1'>" + i + '</td>');
                    $('#target_td').attr('id', 'td' + i);
                    i++;
                }
            }
            // 1~16の出る値全てをtdから取得し配列numsに格納 ※goの値で範囲自動変更
            $('tr').each(function() {
                $('td', this).each(function() {
                    nums.push($(this).text());
                });
            });
        });

        // 繰り返し時間の設定
        function pre_start() {
            $('.start').prop('disabled', true); // スタートボタン使用不可に変更
            $('.stop').prop('disabled', false); // ストップボタン使用可に変更
            clearInterval(interval_id); // 二重クリック防止
            // タイマーセット
            interval_id = setInterval(start_r, 50);
            // td背景色の変更
            $('#' + 'td' + ran_num).addClass('case4');
        }

        // スタートボタンの動作
        function start_r() {
            // td背景色の変更
            $('#' + 'td' + ran_num).removeClass('case2');
            $('#' + 'td' + ran_num).addClass('case1');

            // 配列内からランダムに値を抽出
            ran_num = nums[Math.floor(Math.random() * nums.length)];

            // td背景色の変更
            $('#' + 'td' + ran_num).addClass('case2');
        }

        // ストップボタンの動作
        function stop_r() {
            clearInterval(interval_id); // タイマーを止める
            $('.stop').prop('disabled', true); // ストップボタン使用不可に変更
            $('.start').prop('disabled', false); // スタートボタン使用可に変更
            // 止まったマスの背景色を変更
            $('#' + 'td' + ran_num).addClass('case3');
            // 同じ値が出ないように出た値をnumsから削除
            idx = $.inArray(ran_num, nums);
            nums.splice(idx, 1);

            // 全値が出た時の動作
            if (nums.length < 1) {
                $('.start').prop('disabled', true); // スタートボタン使用不可に変更
            }
        }

        // リセットボタンの動作
        function reset_r() {
            clearInterval(interval_id); // タイマーを止める
            $('.start').prop('disabled', false); // スタートボタン使用可に変更
            nums = []; // 値の初期化
            ran_num = 0; // 値の初期化
            // 背景色を初期化
            $('td').removeClass('case1 case2 case3 case4');
            $('td').addClass('case1');
            // 出る値全てを配列に再格納
            $('tr').each(function() {
                $('td', this).each(function() {
                    nums.push($(this).text());
                });
            });
        }
    </script>
</head>

<body>
    <div id="roulette">
        <table id="matrix"></table>
        <div class="buttons">
            <button class="start">スタート</button>
            <button class="stop">ストップ</button>
            <button class="reset">リセット</button>
        </div>
    </div>
</body>

</html>
```

以下、css

```CSS:roulette.css
body {
    width: 400px
}

.buttons {
    text-align: center;
    margin-top: 15px;
}

.start, .stop, .reset {
    display: inline-block;
    padding: 0.5em 1em;
    text-decoration: none;
    border-radius: 4px;
    box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.29);
}

.start:active {
    transform: translateY(4px);
    box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.2);
    border-bottom: none;
}

.start {
    color: #ffffff;
    background-image: linear-gradient(45deg, #FFC107 0%, #ff8b5f 100%);
    border-bottom: solid 3px #c58668
}

.stop {
    color: #ffffff;
    background-image: linear-gradient(45deg, #ff4208 0%, #c16548 100%);
    border-bottom: solid 3px #c17168
}

.stop:active {
    transform: translateY(4px);
    box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.2);
    border-bottom: none;
}

.reset {
    color: #ffffff;
    background-image: linear-gradient(45deg, #23ff0b 0%, #7fbc4a 100%);
    border-bottom: solid 3px #76bf6a
}

.reset:active {
    transform: translateY(4px);
    box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.2);
    border-bottom: none;
}

table {
    margin: 0 auto;
}

table {
    border: solid 10px #1b1464;
    font-size: 24px;
    border-collapse: collapse;
    border-spacing: 0;
}

tr, td {
    border: solid 2px #2e3192;
}

td {
    width: 50px;
    height: 50px;
    text-align: center;
    line-height: 50px;
}

.case1 {
    background-color: #ffffff;
}

.case2 {
    background-color: #F4CDB3;
}

.case3 {
    background-color: #FBB03B;
}

.case4 {
    background-color: #FFEED7;
    color: #B3B3B3;
}
```