24. January 2011 · Comments Off on Quiz a user from a question pool in a txt, tab seperated, spreadsheet. · Categories: Linux Scripts · Tags: , ,
#!/bin/bash
## Created by: deaves
# Quiz a user from a question pool in a txt, tab seperated, spreadsheet.
#
# The following is how to format the rows in the input file:
#   ColumnA [Integer]: True Answer (D=0,E=1,F=2,...)
#   ColumnB [String]:  Answer Number
#   ColumnC [String]:  Question
#   ColumnD+[String]:  Answer
#
# FYI: If you have problems try using Open Office to create the spreadsheet,
# MS Office does not properly suround cells with quotes so it gives eval problems.
#
## Requires: dialog (Optional: TTS synthesizer)
 
## Comment out speakCMD var if no text/speach synth.
#speakCMD="flite -s duration_stretch=0.8"
#speakCMD="xclip -i -selection clipboard"
 
### Begin Functions ###
function diaSTRING () {
  ### Retrun no variables; just create a dialog string.
  printf "dialog --stdout --backtitle \"${cTALLY}/${qTALLY}:\t${backTITLE}\" \\
   --title \"${qArray[1]}\" --menu \'${qArray[2]}\' 0 0 0 "
 
  # Count the total answer elements in the array.
  ansNUM=$(expr ${#qArray[@]} - 3)
  count=0    # The answer number the user sees.
  acount=2   # The true answer element in the array.
 
  # Generate the possible answers.
  while [ "${count}" -lt ${ansNUM} ] && [ -n "${qArray[${acount}]}" ]
  do
    let acount++
    printf "${count} \'${qArray[${acount}]}\' "
    let count++
  done
 
  unset count acount ansNUM   # Unset variables.
}
 
 
function diaRESULT () {
  ### Display the test results...
 
  # Display number of questions answered correctly when finished.
  if [ -z "${dANS}" -a -z "${REVIEW}" ]; then
    dialog --backtitle "${backTITLE}" --title "${quizFILE}" \
     --msgbox "You answered:\n ${cTALLY} questions out of ${qTALLY} correct" 0 0
 
  # Display correct answer if the wrong answer was selected.
  else
    dialog --backtitle "${backTITLE}" --title "${qArray[1]}" \
     --msgbox "Q: $(echo "${qArray[2]}")\n\nA: $(echo "${qArray[`expr ${qArray[0]} + 3`]}")" 0 0
  fi
}
 
 
function pick_Question () {
  ### Select question and build qArray...
  if [ -z ${QUESTION} ]; then
    QUESTION=$[ ( ${RANDOM} % ${QUESTIONS} ) + 1 ]
 
    # Do not ask the same question twice...
    [ -z ${lastQUESTION} ] && { lastQUESTION=0; }
    while [ ${QUESTION} = ${lastQUESTION} ]; do
      QUESTION=$[ ( ${RANDOM} % ${QUESTIONS} ) + 1 ]
    done
 
    lastQUESTION=${QUESTION}  # Remember the previous question.
  fi
 
  # Use eval to load the entire row into qArray...
  eval qArray=( `sed -n ${QUESTION}'p' "${quizFILE}" | 's/%/%%/g'` )
 
  # Unset the current randomly chosen question.
  [ -z ${REVIEW} ] && { unset QUESTION; }
}
 
 
function review_Questions () {
  ### Review each question in the entire pool.
  declare -i QUESTION=1
 
  while [ "${QUESTION}" != `expr ${QUESTIONS} + 1` ]; do
    pick_Question        # Load question into qArray.
    dANS="${qArray[0]}"  # Set the correct answer.
    speakTEXT &          # Read Q&A to the user.
    diaRESULT            # Display Q&A to the user.
 
    unset dANS qArray    # Unset variables.
    let QUESTION++       # Next question.
  done
}
 
 
function speakTEXT () {
  ### Use a text to speach synth to read the question & answer.
  ## If this function is unwanted leave the speakCMD variable blank.
 
  # Ask the question...
  if [ -n "${speakCMD}" ] && [ -z "${dANS}" ]; then
    echo "${qArray[2]}" | ${speakCMD}
 
  # Review the question & answer...
  elif [ -n "${speakCMD}" ] && [ -n "${REVIEW}" ]; then
    echo "Question, ${qArray[1]} . ${qArray[2]}" | ${speakCMD}
    echo "The Answer is, $(echo ${qArray[`expr ${qArray[0]} + 3`]})" | ${speakCMD}
 
  # Give the answer...
  elif [ -n "${speakCMD}" ]; then
    echo "The correct answer was: $(echo ${qArray[`expr ${qArray[0]} + 3`]})" | ${speakCMD}
  fi
}
 
 
function usage () {
  ### Display the script arguments.
  printf "Usage: $0 -f <file .txt> [-rs]\n\n"
  printf "Required...\n"
  printf "\t-f: Specify the file containing the question pool. (required)\n\n"
  printf "Optional...\n"
  printf "\t-r: Review all the questions in the pool.\n"
  printf "\t-s: Disable sound (if the speakCMD is defined).\n\n"
}
 
 
### Get passed arguments. ###
while getopts ":f:rs" ARG; do
  case "${ARG}" in
    f) quizFILE="${OPTARG}";;
    r) REVIEW="Y";;
    s) unset speakCMD;;
  esac
done
 
### Display command usage and exit ###
[ -z "${quizFILE}" ] && { usage && exit 1; }
 
### Variables that should not be changed ###
backTITLE="Dave's cute quiz script."
QUESTIONS=`wc -l "${quizFILE}" | awk '{print $1}'`
qTALLY=0   # Total questions asked...
cTALLY=0   # Total questions correct...
 
 
### Review all questions and exit script ###
[ "${REVIEW}" = "Y" ] && { review_Questions; exit 0; }
 
### Main Loop ###
while true; do
  pick_Question                               # Pick a Question.
  speakTEXT &                                 # Read the question.
  dANS=`bash -c "$(diaSTRING)"`               # Ask question and store response as "dANS".
 
  [ -z "${dANS}" ] && { diaRESULT && break; } # Break out of the loop if user selects cancel.
  let qTALLY++                                # Tally the total number of questions asked.
 
  if [ ${dANS} == "${qArray[0]}" ]; then      ### Response is correct ###
    let cTALLY++                              # Tally the questions answered correct.
 
  else                                        ### Response is wrong ###
    speakTEXT &                               # Speak the correct answer.
    diaRESULT                                 # Show the correct answer.
  fi
 
  unset dANS qArray                           # Unset loop variables at end of pass.
done
 
### Finish ###</file>