質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.79%

Javascript選択肢クイズ クイズと選択肢 整合性

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 1,004

Asylum35aO2

score 17

JSを駆使してクイズサイトを作っています。
選択肢と問題をランダムに出題したいと思っているのですが、以下のコードでは2つうまくいきません。
1つ目は、問題と解答がバラバラになってしまいます。考えてみたら、問題と質問が別々にシャッフルされた後にそれぞれ配置されてるのが理由かな、と思うのですが、どのように訂正できるでしょうか?
2つ目は、質問が被らないようにしたい(全て用意していた質問が終わったら、return或いはalertで「終わりました」と出したい)のですが、それもアドバイスをいただければと思います。

Javascriptのコード

'use strict';

 const question = document.getElementById('question');
 const btn = document.getElementById('btn');
 const choices = document.getElementById('choices');
 const result = document.getElementById('result');
 const timer = document.getElementById('timer');
 const scoreLabel = document.querySelector('#result > p');
 const test = document.getElementById('test');
 let scoreShow = document.getElementById('scoreShow');
 let isAnswered = false;
 let countdown = false;
 let seconds = 200;
 let timerId;
 let isPlaying;
 let intervalid;
 const interval = 100;

 const quizSet = [
   {q: 'Aは何?', c:['A', 'B', 'C', 'D']},
   {q: '1は何?', c:['1', '2', '3', '4']},
   {q: 'あは何?', c:['あ', 'い', 'う', 'え']}
 ];
 let currentNum = 0;
 let score = 3;
 let id;

//初期化処理
 function init(){
   alert('これはライフポイント制のクイズです。3ポイントから始まり、0ポイントになったら失格です。頑張ってください。');
   isPlaying = false;
   btn.classList.add('startgreen');
   btn.classList.remove('disabled');
   btn.textContent = 'Quiz Start';
 }

 init();

 //答えがあっているかを確認する関数
  function checkAnswer(li) {
    if (li.textContent === quizSet[currentNum].c[0]){
      li.classList.add('correct');
    } else {
      li.classList.add('wrong');
      score--;
    }
    btn.classList.remove('disabled');
    scoreShow.textContent = score;
    if(score === 0){
      alert('Game Over');
      clearTimeout(timerId);
    }
  }

  const shuffledChoices = shuffle([...quizSet[currentNum].c]);

  //問題や選択肢をシャッフルしてもらう
  function shuffle(arr){
    let i = arr.length - 1;
    for(i = arr.length -1; i > 0; i--){
      const j = Math.floor(Math.random() * (i + 1));
      [arr[j], arr[i]] = [arr[i], arr[j]];
    }
    return arr;
  }

 //タイプライター的に問題を出題してもらうところ
 function typing(str = ""){
     let tmp = question.innerHTML;
     let writed = buf.length;
     let write = "";
     if(writed < str.length){
         write = str.charAt(writed);
     }
     question.innerHTML = tmp + write;
 }

 var timerArray = new Array();

  //クイズをセットする全般関数
  function setQuiz(){
   isAnswered = false;

   while (timerArray.length > 0) {
     clearInterval(timerArray.shift());
   }

    let temporary = shuffle(quizSet);
    let str = temporary[currentNum].q;
    question.innerHTML = "";
    let typeid = setInterval(function(){
      typing(str);
    }, 150); 
    timerArray.push(typeid);


   while(choices.firstChild){
     choices.removeChild(choices.firstChild);
   }

   shuffledChoices.forEach(choice => {
     const li = document.createElement('li');
     li.textContent = choice;
     li.addEventListener('click', () => {
       if(!isPlaying){
         return;
       }
       if(isAnswered){
         return;
       }
       checkAnswer(li);
       isAnswered = true;
     });
     choices.appendChild(li);
   });

   if(currentNum === quizSet.length -1) {
     btn.textContent = 'Check Result!';
   }
 }

 //カウントダウンを始めるところ
 function cDownStart(){
   countdown = true;
   timer.innerHTML = seconds;
   timerId = setTimeout(cDown, 1000);
 }
 //カウントダウンを続ける処理
 function cDown(){
   seconds--;
   timer.innerHTML = seconds;
   if(seconds <= 0){
     clearTimeout();
     countdown = false;
     alert(`時間切れです。あなたのスコアは${score}点です。`);//日本語だけ
   } else {
     timerId = setTimeout(cDown, 1000);
   }
 }

 //次へのボタンを押したら次に行く処理
 btn.addEventListener('click', () => {
   if(!isPlaying){
     cDownStart();
     setQuiz();
     btn.textContent = 'Next';
     btn.classList.remove('startgreen');
     btn.classList.add('disabled');
     isPlaying = true;
     return;
   }
   if(btn.classList.contains('disabled')) {
     return;
   }
   btn.classList.add('disabled');
   if(currentNum === quizSet.length -1){
     scoreLabel.textContent = `あなたのスコアは${score}点です。`;
     result.classList.add('show');
   } else {
     currentNum++;
     setQuiz();
   }
 });

HTMLのコード

<!DOCTYPE html>
<html lang="ja">
<head>
 <meta charset="utf-8">
 <title>Quiz</title>
 <link rel="stylesheet" href="css/styles2_rev.css">
</head>
<body>
  <div class="container">
    <p id="timer" class="margin"></p>
    <p id="scoreShow" class="margin"></p>
    <br>
    <p id="question"></p>
    <ul id="choices">
    </ul>
    <div id="btn" class="disabled">Next</div>
    <dev id="test"></dev>

    <section id="result">
      <p></p>
      <a href="">REPLAY?</a>
    </select>
  </div>

<script src="js/main_rev.js"></script>
</body>
</html>

CSのコード

body {
  background: #efdec1;
  font-size: 14px;
  font-family: Verdana, sans-serif;
}

.container {
  width: 400px;
  margin: 8px auto;
  background: #fff;
  border-radius: 4px;
  padding: 16px;
  position: relative;
}

#question {
  margin-bottom: 16px;
  font-weight: bold;
}

#choices {
  list-style: none;
  padding: 0;
  margin-bottom: 16px;
}

#choices > li {
  border: 1px solid #ccc;
  border-radius: 4px;
  padding: 10px;
  margin-bottom: 10px;
  cursor: pointer;
}

#choices > li:hover{
  background: #f8f8f8;
}

#btn {
  background: #3498db;
  padding: 10px;
  border-radius: 4px;
  cursor: pointer;
  color: #fff;
  text-align: center;
  box-shadow: 0 4px 0 #2880b9;
}

#btn.disabled {
  background: #ccc;
  box-shadow: 0 4px 0 #bbb;
  opacity: 0.7;
}

#choices > li.correct {
  background: #d4edda;
  border-color: #c3e6cb;
  color: #155724;
  font-weight: bold;
}

#choices > li.correct::after {
  content: "....Correct!";
}

#choices > li.wrong {
  background: #f8d8da;
  border-color: #f5c6cb;
  color: #721c24;
  font-weight: bold;
}

#choices > li.wrong::after {
  content: "....Wrong!";
}

#result {
  position: absolute;
  width: 300px;
  background: #fff;
  padding: 30px;
  box-shadow: 0 0 2px rgba(0, 0, 0, 0.5);
  top: -500px;
  left: 0;
  right: 0;
  margin: 0 auto;
  border-radius: 3px;
  text-align: center;
  transition: 0.4s ease-out;
}

#result > p {
  font-size: 14px;
}

#result > a {
  background: #3498db;
  padding: 10px;
  border-radius: 4px;
  cursor: pointer;
  color: #fff;
  text-align: center;
  box-shadow: 0 4px 0 #2880b9;
  display: block;
  text-decoration: none;
}

#result.show {
  top: 50px;
}

#btn.startgreen{
  background: lightgreen;
  box-shadow: 0 4px 0 green;
}

#scoreShow {
  float: right;
  color: purple;
}

.margin {
  margin-bottom: 10px;
}

#timer.danger {
  color: red;
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • mather

    2019/04/20 00:32

    そもそも問題文が表示されないなどのバグがあるみたいですが…。

    キャンセル

  • Asylum35aO2

    2019/04/20 07:47

    なるほど、そこも訂正しないといけないみたいですね。ご指摘ありがとうございます

    キャンセル

回答 1

checkベストアンサー

+1

1つ目は、問題と解答がバラバラになってしまいます。

問題をシャッフルしてから、shuffledChoicesを取り出せばいいかと思います。

2つ目は、質問が被らないようにしたい

setQuiz()が呼ばれるたびにシャッフルせずに、一度だけシャッフルすればいいかと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/04/22 02:34

    アドバイスいただきましてありがとうございました。助かりました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.79%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る