quiz/quiz.sh

180 lines
5.1 KiB
Bash
Executable File

#!/usr/bin/env bash
add_question() {
question="|"
until [[ ${#question} -eq 0 ]]; do
read -p "Enter the question. (leave blank to end): " question
if [[ ${#question} -eq 0 ]]; then
continue
fi
while [[ $question == *"|"* ]]; do
echo "Question cannot contain '|'. Please try again."
read -p "Enter the question (without '|' character): " question
done
question="${question^}"
answers=()
read -p "Enter the answer (or press Enter to proceed to correct answer): " answer
while [[ -n $answer ]]; do
answers+=("$answer")
if [[ "${answer^^}" =~ ^(T(R(U(E)?)?)?|F(A(L(S(E)?)?)?)?)$ ]]; then
break
fi
read -p "Next answer? (press Enter to proceed): " answer
done
if [[ ${#answers[@]} -gt 1 ]]; then
choices=()
for ((i=1; i<=${#answers[@]}; i++)); do
letter=$(printf "%s" $((i)) | tr '1-9' 'A-J')
choices+=("${letter}: ${answers[$((i-1))]}")
done
choicesStr="${choices[0]}"
for ((i=1; i<${#choices[@]}; i++)); do
choicesStr+="|${choices[$i]}"
done
echo "Enter the correct choice:"
read -p "${choicesStr//|/$'\n'}: " correct
correct="${correct^}"
while [[ ! $correct =~ ^[A-${letter}]$ ]]; do
echo "Invalid choice. Please try again."
read -p "Enter the correct choice (${choicesStr}): " correct
done
correctChoice="${correct:0:1}"
elif [[ ${#answers[@]} -eq 1 ]]; then
choice=${answers[0]}
if [[ "${choice^^}" =~ ^[T][R][U][E]?$ ]]; then
correctChoice="T"
elif [[ "$choice" =~ ^[F][A][L][S][E]?$ ]]; then
correctChoice="F"
else
echo "Invalid choice. Assuming 'T' (True) as the correct answer."
correctChoice="T"
fi
else
echo "No answers provided. Skipping the question."
return
fi
question="${question}|${correctChoice:0:1}|${choicesStr}"
question="${question%|}"
echo "${question}" >> "$0"
echo "Question added successfully!"
done
exit 0
}
shuffle_choices() {
if [[ ${#answers[@]} -lt 2 ]]; then
return
fi
local letter=({A..Z})
local length="${#answers[@]}"
local newAnswer
local shuffledChoices
mapfile -t shuffledChoices < <(shuf -e "${answers[@]#*: }")
for i in "${!answers[@]}" ; do
if [[ "${answers[$i]:0:1}" == "${answer}" ]]; then
newAnswer="${answers[$i]}"
fi
done
for i in "${!shuffledChoices[@]}" ; do
shuffledChoices[$i]="${letter[$i]}: ${shuffledChoices[$i]}"
if [[ "${shuffledChoices[$i]#*:}" == "${newAnswer#*:}" ]]; then
answer="${letter[$i]}"
fi
done
answers=("${shuffledChoices[@]}")
}
if [[ $# -gt 1 ]]; then
echo "Only 1 argument supported, -a or --question."
exit 0
fi
if [[ $# -eq 1 ]]; then
if [[ "${1}" == "-a" ]] || [[ "${1}" == "--add-question" ]]; then
add_question
else
echo "Only 1 argument supported, -a or --question."
exit 0
fi
fi
startPosition="$(grep -n '^exit 0$' "${0}")"
startPosition="${startPosition%%:*}"
((startPosition++))
mapfile -t data < <(tail -n +${startPosition} "$0" | grep -v "^#" | grep -v "^$" | shuf)
right=0
wrong=0
echo "Total questions: ${#data[@]}"
if [[ ${#data[@]} -eq 0 ]]; then
echo "To add questions use the -a or --add-questions flag."
fi
for i in "${data[@]}" ; do
question="${i%%|*}"
i="${i#*|}"
answer="${i%%|*}"
answer="${answer^}"
i="${i#*|}"
unset answers
while [[ ${#i} -gt 1 ]]; do
answers+=("${i%%|*}")
i="${i#*|}"
if [[ "${i%%|*}" == "${i}" ]]; then
answers+=("${i}")
break
fi
done
shuffle_choices
echo
echo "${question}"
for i in "${answers[@]}" ; do
echo "${i}"
done
read -r choice
choice="${choice:0:1}"
choice="${choice^}"
if [[ "${choice}" == "${answer}" ]]; then
echo "Correct!"
((right++))
else
echo -n "Wrong, the answer is: "
for i in "${answers[@]}" ; do
if [[ "${answer}" == "${i:0:1}" ]]; then
echo "$i"
fi
done
((wrong++))
fi
if [[ "${answer}" == "F" ]] || [[ "${answer}" == "T" ]]; then
answer="${answer/F/False}"
answer="${answer/T/True}"
echo "${answer}"
fi
read -rp "Press enter to continue"
done
# Results
echo
echo "Out of ${#data[@]} questions, you got ${right} correct."
if [[ ${#wrong} -gt 0 ]]; then
echo "You missed ${wrong} questions."
fi
if command -v bc &> /dev/null ; then
grade=$(echo "scale=2; $right * 100 / ${#data[@]}" | bc)
echo "On a 100 based grading scale, this gives you a score of $grade."
fi
exit 0