JavaScriptでタイピングゲームを作ろう（ドットインストールから引用）

ドットインストールを参考にしてます。
https://dotinstall.com/
※プレミアム会員のみ閲覧可能

# 完成イメージ
<img width="570" alt="スクリーンショット 2019-04-22 16.51.42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114933/830a42ba-4ba9-2ef1-faa3-4cc74cff0c95.png">
　　　　　　　　　　　　　　　　　　↓
<img width="713" alt="スクリーンショット 2019-04-22 16.52.00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114933/e4b33b01-e829-2269-4a20-3d01c722497d.png">
　　　　　　　　　　　　　　　　　　↓
<img width="451" alt="スクリーンショット 2019-04-22 16.52.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114933/2f697502-aec0-8269-a615-78971e12652a.png">

# 実装したい要件の整理
- 初期画面:
  - UI設定。  
  - 画面をクリックするとタイマー起動＋クイズが出現
- クイズ画面：
  - タイマー稼働。  
  - 正解数、誤答数の表示
  - ランダムにクイズを出題。
  - 正解すると次のクイズがランダム表示
- 結果画面  
  - 正解数等、成績を表示  
  - リプレイの選択肢を表示


```html:ソースコード(body要素のみ表示/CSSは省略)
<p id="target">Click To Start</p>
  <p class="info">
    Letter count: <span id="score">0</span>,
    Miss count: <span id="miss">0</span>
    Timer left: <span id="timer">0</span>
  </p>

<script type="text/javascript">
  'use strict';

{
  // 初期値の設定
  const words = [
    "apple",
    "sky",
    "blue",
    "middle",
    "set"
  ];

  // Math.floor() → 引数の結果の小数点以下を切り捨てる
  // Math.random()関数は、0以上、1未満の範囲で浮動小数点の擬似乱数を返す。
  let word;
  let loc;
  let score;
  let miss;
  // 3000ミリ秒と設定
  const timeLimit = 3 * 1000;
  // ゲーム開始時刻を保持
  let startTime;
  // ゲームが始まっているかどうか変数で
  let isPlaying = false;

  // 各要素の取得
  const target = document.getElementById('target');
  const scoreLabel = document.getElementById('score');
  const missLabel = document.getElementById('miss');
  const timerLabel = document.getElementById('timer');

  function updateTarget(){
    let placeholder = '';
    for (let i = 0; i < loc; i++) {
      placeholder += '_';
    }
    target.textContent = placeholder + word.substring(loc);
  }

  function showResult(){
    // 条件演算子を使用
    const accuracy = score + miss === 0 ? 0 : score / (score+miss) * 100;
    // テンプレートリテラルで、結果を表示させる
    alert(`${score} letters, ${miss} misses, ${accuracy.toFixed(2)}% accuracy!`)
  }

  function updateTimer(){
    // ゲーム開始時刻 + 制限時間 - 現在の時刻
    const timeLeft = startTime + timeLimit - Date.now();
    // 小数点以下を2桁まで表示
    timerLabel.textContent = (timeLeft / 1000).toFixed(2);

    // setTimeout関数を定義。10ミリ秒毎に、updateTimer関数を呼ぶ。
    const timeoutId = setTimeout(() => {
      updateTimer();
    }, 10);

    // 解除したいタイマのID。 IDはsetTimeout()の返値によって取得できる。
    if (timeLeft < 0) {
      isPlaying = false;
      clearTimeout(timeoutId);
      // alert処理を100ミリ秒後に遅らせる。
      setTimeout(() => {
         showResult();
      },100);

      timerLabel.textContent = "0.00";
      target.textContent = "Click to Replay" 
    }
  }

  window.addEventListener('click', () => {
    if(isPlaying === true){
      return;
    }
    isPlaying = true;

    loc = 0;
    score = 0;
    miss = 0;
    scoreLabel.textContent = score;
    missLabel.textContent = miss;
    word = words[Math.floor(Math.random() * words.length)];


    updateTarget();
    // 基準日から経過ミリ秒を計算
    startTime = Date.now();
    updateTimer();
  });

  // キーボードから入力された値を取得
  window.addEventListener('keyup', e => {
    if(isPlaying !== true){
      return;
    }
    if (e.key === word[loc]) {
      loc++;
      // locの数がwordの文字数を超えたタイミングで
      if(loc === word.length){
        word= words[Math.floor(Math.random() * words.length)];
        loc = 0;
      }
      score++;
      scoreLabel.textContent = score;
      // updateTarget関数を呼び出す
      updateTarget();
    } else {
      miss++;
      missLabel.textContent = miss;
    }
  });
}
</script>

```