拡張性のあるクイズアプリ⑩

選択肢をシャッフルできるようにしました。

App.js

import { StatusBar } from "expo-status-bar";
import { StyleSheet, Text, View, Button } from "react-native";
import { useEffect, useState } from "react";
import { dataSetArray } from "./setData/dataSet";

export default function App() {
  const [problemText, setProblemText] = useState("");
  const [correctAnswerText, setCorrectAnswerText] = useState("");
  const [correctAnswerAlp, setCorrectAnswerAlp] = useState("");
  const [explanationText, setExplanationText] = useState("");

  const [totalAnswerNumber, setTotalAnswerNumber] = useState(0);
  const [correctAnswerNumber, setCorrectAnswerNumber] = useState(0);

  const [selectionArraySet, setSelectionArraySet] = useState();
  const [selectionSetText, setSelectionSetText] = useState("");

  const [judgementText, setJudgementText] = useState("");

  const [explanationSentence, setExplanationSentence] = useState("");
  const [finishSentence, setFinishSentence] = useState("");

  const createProblemHandler = () => {
    const randomNumber = Math.floor(Math.random() * 1);
    setProblemText(dataSetArray[randomNumber].problem);
    setCorrectAnswerText(dataSetArray[randomNumber].correctAnswer);
    setExplanationText(dataSetArray[randomNumber].explanation);
    setSelectionArraySet(dataSetArray[randomNumber].selectionArray);
    const selectionArrSet = [...selectionArraySet];
    //シャッフル
    const shuffleArray = (arr) => {
      for (let i = arr.length - 1; i > 0; i--) {
        let j = Math.floor(Math.random() * (i + 1));
        let tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
      }
      return arr;
    };
    shuffleArray(selectionArrSet);

    setSelectionSetText(
      `a.${selectionArrSet[0]}\r\nb.${selectionArrSet[1]}\r\nc.${selectionArrSet[2]}\r\nd.${selectionArrSet[3]}`
    );

    const getCorrectAlp = () => {
      const linearSearch = (array, target) => {
        //見つかったらその時点で終了
        for (let i = 0; i < array.length; i++) {
          if (array[i] == target) {
            return i;
          }
        }
        return -1;
      };

      switch (linearSearch(selectionArrSet, correctAnswerText)) {
        case -1:
          console.log("ありませんでした");
        case 0:
          return "a";
        case 1:
          return "b";
        case 2:
          return "c";
        case 3:
          return "d";
      }
    };
    setCorrectAnswerAlp(getCorrectAlp());

    setExplanationSentence("");
    setJudgementText("");
    setFinishSentence("");
  };

  const pressHandler = (buttonTitle) => {
    setTotalAnswerNumber((prevState) => prevState + 1);

    if (buttonTitle == correctAnswerAlp) {
      setJudgementText("Correct");
      setExplanationSentence("");
      setCorrectAnswerNumber((prevState) => prevState + 1);
    } else {
      setJudgementText("InCorrect");
      setExplanationSentence(explanationText);
    }
  };

  const pressHandler_a = () => {
    pressHandler("a");
  };

  const pressHandler_b = () => {
    pressHandler("b");
  };

  const pressHandler_c = () => {
    pressHandler("c");
  };

  const pressHandler_d = () => {
    pressHandler("d");
  };

  const finishHandler = () => {
    setFinishSentence(
      `解いた問題数は${totalAnswerNumber}です。\r\n 正解した問題数は${correctAnswerNumber}です。`
    );
  };

  //1回だけ
  useEffect(() => {
    createProblemHandler();
  }, );

  return (
    <View style={styles.container}>
      <View style={styles.upperButtonContainer}>
        <Button title="次の問題へ" onPress={createProblemHandler}></Button>
        <Button title="終了" onPress={finishHandler}></Button>
      </View>
      <Text style={{ marginTop: 20, marginBottom: 30, fontSize: 20 }}>
        {problemText}
      </Text>
      <Text style={{ fontSize: 20 }}>{selectionSetText}</Text>
      <View style={styles.lowerButtonContainer}>
        <Button title="a" onPress={pressHandler_a}></Button>
        <Button title="b" onPress={pressHandler_b}></Button>
        <Button title="c" onPress={pressHandler_c}></Button>
        <Button title="d" onPress={pressHandler_d}></Button>
      </View>
      <Text style={{ fontSize: 20, marginTop: 30 }}>{judgementText}</Text>
      <Text style={{ fontSize: 20 }}>{explanationSentence}</Text>
      <Text style={{ fontSize: 20 }}>{finishSentence}</Text>
      <StatusBar style="auto" />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#fff",
    alignItems: "center",
    justifyContent: "center",
  },
  upperButtonContainer: {
    flexDirection: "row",
    justifyContent: "space-around",
    width: "80%",
  },
  lowerButtonContainer: {
    flexDirection: "row",
    justifyContent: "space-around",
    width: "80%",
  },
});

setData/dataSet.js

export const dataSetArray = [
  {
    id: 1,
    problem: "コンパイラによる最適化の主な目的はどれか。",
    correctAnswer: "プログラムの実行時間を短縮する",
    selectionArray: [
      "プログラムの実行時間を短縮する",
      "プログラムのデバッグを容易にする",
      "プログラムの保守性を改善する",
      "目的プログラムを生成する時間を短縮する",
    ],
    explanation:
      "コンパイラは、高水準言語で書かれたソースプログラムを機械語コンパイル(翻訳)し、プログラムを生成するソフトウェアです。コンパイルの手順は、1.字句解析、2.構文解析、3.意味解析、4.最適化、5.コード生成の順で行われる。このうち、4の最適化では、処理時間や使用するメモリ量が少なくなるようにプログラムを再編成します。",
  },
];

 

注意点としては下記。

getCorrectAnswerAlp を作らず、switch文のところで、各自、setCorrectAnswerAlpを設定してしまうと、レンダリングが複数回されてしまい、変なことになってしまいます。

なお、AlpはAlphabetを略してます。

 

そのあと、データセットのデータを複数にすると、問題文と選択肢が食い違うバグあり。

useEffectのところを下記へ書き換えると、Console Warning出ながらも実行は可能

  useEffect(() => {
    createProblemHandler();
  }, [problemText, selectionSetText]);

原因はおいおい考えることとする。