ビンゴマシンをリファクタ

# 流石に放っておけなかった

Twitterで流れてきた[ビンゴマシンのコード](http://qiita.com/Yuta_Fujiwara/items/076b6ea61f456d9649e9)を見たけれども、流石に見過ごせなかった。
見た目(UI)の出来は良かったので、中身をしっかりダイエットしてみました。

## HTMLの修正

```html:index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>BINGO MACHINE</title>
  <link href="css/style.css" rel="stylesheet" type="text/css">
</head>
<body>
  <div>
    <div class="panel" id="panel1">︎</div>
    <div class="panel" id="panel10">︎</div>
  </div>
  <div class="btn inactive" id="btn0">STOP</div>
  </div>
  <div id="spinButton">SPIN</div>

  <div id="result">
  </div>
</br></br>
    <div class="copy">By ＠Fujiwara_Yuta, Thanks to @Ishi </div>
</div>
<audio id="audio_drum" src="audio/drumroll.wav"></audio>
<audio id="audio_cymbal" src="audio/cymbal.wav"></audio>

<script type="text/javascript" src="jquery/jquery.min.js"></script>
<script type="text/javascript" src="jquery/jquery-ui.min.js"></script>
<script type="text/javascript" src="js/Bingo.js"></script>
</body>
</html>
```

## 簡単な修正点

- 数字の出力はJavaScriptに任せる

例えば、数字が99のビンゴ（そんなのあるか知らないけれど）でビンゴやろうってなった時にこのHTMLを修正するのは多大な労力が掛かる。こういう可変部分に関してはJSに任せちゃう方が絶対楽だし、間違いが無い。


## JavaScriptの修正

```js:Bingo.js
(function(){
  'use strict';

    //ビンゴの数字の数 5×5 = 75
    var Bingo = ['01', '02', '03', '04', '05', '06', '07', '08', '09', '10',
                   '11','12', '13', '14', '15', '16', '17', '18', '19', '20',
                   '21','22', '23', '24', '25', '26', '27', '28', '29', '30',
                   '31','32', '33', '34', '35', '36', '37', '38', '39', '40',
                   '41','42', '43', '44', '45', '46', '47', '48', '49', '50',
                   '51','52', '53', '54', '55', '56', '57', '58', '59', '60',
                   '61','62', '63', '64', '65', '66', '67', '68', '69', '70',
                   '71','72', '73', '74', '75'];

    var timer = null;
    var isPlaying = false;

    //乱数によってセレクトされた数字
    var bingoNum = 0;

    //bingoNumでセレクトされた数字をBingo配列から削除する変数
    var delBingoNum = 0;

    var panel1 = document.getElementById('panel1');
    var panel10 = document.getElementById('panel10');

    var btn0 = document.getElementById('btn0');

    var spinButton = document.getElementById('spinButton');

    var soundManager = SoundManager();


    // ビンゴの結果エリアのレンダリング
    var renderBingo = function(){
        var fragment= document.createDocumentFragment();
        var divWrapper;
        Bingo.forEach(function(elem, index){
            if( index % 15 === 0 ){
                divWrapper = fragment.appendChild(document.createElement("div"));
            }
            var numDiv = divWrapper.appendChild(document.createElement("div"));
            numDiv.className = "bingo";
            numDiv.innerHTML = elem;
        });
        var result = document.getElementById("result");
        result.appendChild(fragment);
    };
    renderBingo();



    //『SPIN』ボタン押下
    spinButton.addEventListener('click', function() {
        if (isPlaying) return;

        soundManager.playDrum();

        isPlaying = true;
        spinButton.className = 'inactive';
        btn0.className = 'btn';

        timer = setInterval(function(){
            //『SPIN』ボタン押下後の処理
            // ランダム表示
            var num = Math.floor(Math.random() * Bingo.length);
            bingoNum = num;
            panel1.innerHTML = Bingo[num].substr(0,1);
            panel10.innerHTML = Bingo[num].substr(1,2);
        } , 25 );

    });

    btn0.addEventListener('click', function() {
        stopSlot(0, this);
    });

    //『STOP』ボタン押下後の処理
    function stopSlot(n, btn) {
        if (!isPlaying) return;
        btn.className = 'btn inactive';

        soundManager.stopDrum();
        soundManager.playCymbal();

        clearInterval(timer);

        delBingoNum = Bingo.indexOf(bingoNum);
        Bingo.splice(delBingoNum,1);

        var bingoDiv = document.querySelectorAll(".bingo");

        // change color
        var tBingo = Number(Bingo[bingoNum]);
        bingoDiv[tBingo-1].innerHTML = Bingo[bingoNum];
        bingoDiv[tBingo-1].className = 'bingo unmatched';

        // init
        isPlaying = false;
        timer = null;
        spinButton.className = '';
    }

    function SoundManager(){
        var drum = document.getElementById('audio_drum');
        var cymbal = document.getElementById('audio_cymbal');
        return {
          playDrum    : playDrum,
          stopDrum    : stopDrum,
          playCymbal  : playCymbal
        }

        function playDrum(){
          if(drum == null){
            return;
          }
          drum.currentTime = 0;
          drum.play();
        }

        function stopDrum(){
          if(drum == null){
            return;
          }
          drum.pause();
        }

        function playCymbal(){
          if(cymbal == null){
            return;
          }
          cymbal.currentTime = 0;
          cymbal.play();
        }
    }

})();
```


## 簡単な修正点

- elseifのお化けを<del>2行に</del>3行に
- timerを1個に
- 使ってない関数削除

elseifのお化け関数は<del>2行に</del>3行ににまで圧縮出来る。
折角クラス名を振っているのだから、querySelectorAll使えば、ピュアな関数で処理出来るので、お得。
もちろん、普通にjQueryからアクセスしても良い。
timerもなぜか二つ使っていたが、これは1個で処理出来る。
setTimeoutを使う形式も悪くはないのだが、今回のように同じ処理をループさせる場合は、setIntervalの方が何かと分かりやすい。
setIntervalオススメ。
あと、PrintBingoとかresultsとかcountとか良く分からない変数はごっそり削った


# 今後の展望

このリファクタでも直してない箇所が数か所あるので、腕に覚えのある方は是非リファクタというマサカリを投げてください。
僕にとっても勉強になるからです。
ぱっと見ただけでも、panel1とpanel10とか何だよとか、bingoNumをグローバル変数にするなよとか色々ツッコミどころがあると思いますので、是非良いリファクタをお願いします。

# 編集履歴
バグってたのをちょっと修正