davideaves.com

Live in a world of your own, but always welcome visitors.

View on GitHub
24 January 2011

Quiz a user from a question pool in a txt, tab seperated, spreadsheet.

by deaves

#!/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 ###
tags: csv - linux - quiz