Javascriptでタイピングアプリを作成してみた

# 現段階のタイピングアプリ
現在のタイピングアプリは以下のようになっています。
[![Image from Gyazo](https://i.gyazo.com/1084c360e5c598223e3d0ee618f17b12.gif)](https://gyazo.com/1084c360e5c598223e3d0ee618f17b12)

# コードは？
このアプリのコードは以下のようになっています。
```javascript
function ready(){
  document.getElementById("btn").addEventListener('click',() =>{
    let readyTime = 3;
    document.getElementById("btn").style.visibility = "hidden";
    document.getElementById("start").innerHTML = "";
    let readyTimer = setInterval(function(){
      document.getElementById("timer").innerHTML=readyTime;
      readyTime--;
      if(readyTime < 0){
        clearInterval(readyTimer);
        gameStart();
      };
    },1000);
  });
};

function gameStart(){
  let timeLimit = 90;
  typing();
  let timeRead = timeLimit;
  let gameTimer = setInterval(function(){
    document.getElementById("timer").innerHTML = "残り時間：" + timeRead;
    timeRead--;
    if (timeRead < 0){
      finish();
      clearInterval(gameTimer);
    };
  },1000);
};

function finish(){
  document.getElementById("timer").innerHTML="ここに時間が表示されます"
  document.getElementById("japanese").innerHTML = "";
  document.getElementById("start").innerHTML = "";
  document.getElementById("btn").style.visibility = "visible";
  window.alert("終了!")
};

function typing(){
  const Q = [["ishinouenimo3nenn","石の上にも3年"],
              ["aaiebakoiu","ああ言えばこう言う"],
              ["berurinnokabe","ベルリンの壁"],
              ["uousaou","右往左往"],
              ["keizokuhatikaranari","継続は力なり"],
              ["saisyusyokusaki","再就職先"],
              ["taihusekkintyu","台風接近中"],
              ["puroguraminguwobenkyoutyu","プラグラミングを勉強中"],
              ["namamuginamagomenamatamago","生麦生米生卵"],
              ["ikkyuunyukon","一球入魂"],
              ["sushi","寿司"],
              ["tekkukyanpu","テックキャンプ"],
              ["onigiri","おにぎり"],
              ["gya-!","ぎゃー!"],
              ["ko-hi-bureiku","コーヒーブレイク"],
              ["yujuhudan","優柔不断"],
              ["nihonnkokukenpou",,"日本国憲法"],
              ["amazonsyoppingu","アマゾンショッピング"],
              ["merukari","メルカリ"],
              ["rakuten","楽天"],
              ["yu-tyu-ba-","ユーチューバー"],
              ["tanjoubiomedetou!","誕生日おめでとう!"],
              ["oninoinumanisentaku","鬼の居ぬ間に洗濯"],
              ["shinrigakuwosenkosuru","心理学を専攻する"],
              ["hayaokihasanmonnotoku","早起きは三文の徳"],
              ["arubaitobosyutyu","アルバイト募集中"],
              ["kansaikokusaikukou","関西国際空港"],
              ["nantekotta","なんてこった"],
              ["koukiatsu","高気圧"],
              ["saidaikouyakusu","最大公約数"],
              ["ra-men","ラーメン"],
              ["tenkiyoho","天気予報"],
              ["shiori","詩織"],
              ["wareomou,yueniwareari","我思う、ゆえに我あり"],
              ["syonnenyo,taishiwoidake","少年よ、大志を抱け"],
              ["saikokeieisekininsya","最高経営責任者"],
              ["saiyuki","西遊記"],
              ["suisankanatoriumusuiyoeki","水酸化ナトリウム水溶液"],
              ["mikakuninhikobuttai","未確認飛行物体"],
              ["usotsukihadorobonohajimaridesu","嘘つきは泥棒の始まりです"],
              ["nihonnosyutohatokyo","日本の首都は東京"],
              ["apurike-syonera-desu","アプリケーションエラーです"],
              ["modameda,kosansiyo","もうダメだ,降参しよう"],
              ["shitarayondemosinbunshi","下から読んでも新聞紙"],
              ["uekarayondemoshinbunshi","上から読んでも新聞紙"],
              ["saikokyunoomotenashi","最高級のおもてなし"],
              ["kannukokusaieigasai","カンヌ国際映画祭"],
              ["syogaibutsukyoso","障害物競争"],
              ["kyosesyuryo","強制終了"],
              ["kasejinsyurai","火星人襲来"],
              ["rodokijunho","労働基準法"],
              ["kanzennensyo","完全燃焼"],
              ["yukyukyuka","有給休暇"],
              ["hikarifaiba-","光ファイバー"],
              ["sekenkotai","政権交代"],
              ["soranooja","空の王者"],
              ["dosokai","同窓会"],
              ["taionke","体温計"],
              ["shinhakken","新発見"],
              ["shinritesuto","心理テスト"],
              ["mitinimayou","道に迷う"],
              ["buyuden","武勇伝"],
              ["kamakurabakuhu","鎌倉幕府"],
              ["zannensyo","残念賞"],
              ["gohantabeta?","ご飯食べた？"],
              ["tengokutojigoku","天国と地獄"]
            ];

  // 配列にある要素のうち一つを取り出す
  let Q_No = Math.floor(Math.random()* Q.length);
  let Q_i = 0;//解答初期値・現在単語はどこまであっているのか
  let Q_l = Q[Q_No][0].length;//取得した文字の長さ
  document.getElementById("japanese").innerHTML = Q[Q_No][1].substring(Q_i,Q_l);
  document.getElementById("start").innerHTML = Q[Q_No][0].substring(Q_i,Q_l);

  window.addEventListener("keydown",(event) =>{
    const KeyCode = event.key;
      if (Q_l == Q_l - Q_i){
        document.getElementById("japanese").innerHTML = Q[Q_No][1].substring(Q_i,Q_l);
        document.getElementById("start").innerHTML = Q[Q_No][0].substring(Q_i,Q_l);
      };
      if (Q[Q_No][0].charAt(Q_i) == KeyCode){ 
        Q_i++;
        document.getElementById("start").innerHTML = Q[Q_No][0].substring(Q_i,Q_l);
        if (Q_l - Q_i === 0){ //全問正解したら

          new Audio('ok.mp3').play();

          Q_No = Math.floor(Math.random() * Q.length);
          Q_i = 0;
          Q_l = Q[Q_No][0].length
          document.getElementById("japanese").innerHTML = Q[Q_No][1].substring(Q_i,Q_l)
          document.getElementById("start").innerHTML = Q[Q_No][0].substring(Q_i,Q_l);
        }else{
          new Audio('good.mp3').play();
        }
      };
    });
};

window.addEventListener('load',ready)
```

# タイピングの処理の流れ
大雑把な流れとしては以下のようになります。

まずはローマ字と日本語の文字列が出力される。
　　　　　　　　　　↓
ローマ字の最初の文字とキーボードで押した文字が同じ場合はその文字が消される
　　　　　　　　　　↓
全てのローマ字の入力を終えると、新しい文字列が出力される

キーボードで何か入力した時に、そのキーボードの文字とローマ字の最初の文字が同じ場合、Q_iの値は+１されローマ字に出力される文字は１番目の値から最後の値までを出力するようにしています。
これにより、ローマ字と同じ文字を入力するたびに、ローマ字の文字列が少なくなり、最後にはなくなります。

そして、全ての文字を入力できた時に現在設定している配列の中からランダムに選択されて次の問題に進むようになっています。

# 問題の配列を二次元配列にした理由
配列を二次元配列にしたのは、二つの理由があります。
一つ目の理由は別々にしてしまうと、ローマ字と日本語の順番がわかりにくくなることを防ぐため。
二つ目の理由は問題を新しく追加したい時にローマ字と日本語でセットで入力する必要があるので、わかりやすいためです。

# 最後に
最後まで見ていただきありがとうございます。
何か間違いや不明点があればコメントをいただけると幸いです。