Skip to content

Instantly share code, notes, and snippets.

@megabert
Last active October 20, 2020 11:46
Show Gist options
  • Save megabert/a26138563b87fa8659e3f70a01d4364b to your computer and use it in GitHub Desktop.
Save megabert/a26138563b87fa8659e3f70a01d4364b to your computer and use it in GitHub Desktop.
math task generator
#!/bin/bash
answer_pattern="<ans>"
answer_text="____"
columns_per_row=3
export answer_pattern answer_text columns_per_row tasks
dbg() {
echo "$*" >&2
}
replace_shell() {
local row="$1" varname varvalue cmd res
if [[ "$row" =~ \{[^{}]+=[^{}]+\} ]] ; then
# replace a line with a variable definition if { ... = ... } is found
[[ $row =~ \{([^=]+)=([^}]+)\} ]]
varname="${BASH_REMATCH[1]}"
# evaluate var definition twice, so a command to generate the value will be executed
eval varvalue="${BASH_REMATCH[2]}"
# replace $varname and remove variable definition
sed -r <<<"$row" \
-e "s/\\\$$varname/$varvalue/g" \
-e "s/\{[^{}]+\}//g"
else
# else replace shell code in template { ... } as long as there are still unresolved { ... } blocks
while [[ $row =~ \{([^{}]+)\} ]] ;do
[[ $row =~ \{([^{}]+)\} ]]
cmd="${BASH_REMATCH[1]}"
res="$($cmd)"
row="$(sed -r -e "s/\{[^{}]+\}/$res/" <<<"$row")"
done
echo "$row"
fi
}
task_output() {
local idx task lines
# get total number of rows to be printed
lines=$(( ($taskcount + $columns_per_row - 1) / $columns_per_row ))
# generate randomized index for output
idx=($(shuf -e $( seq 1 ${#tasks[@]} )))
for((line=1,i=0;line<=lines;line++));do
for((col=1;col<=columns_per_row;col++));do
((i++))
task="${tasks[${idx[$i]}]}"
# change output field size here if necessary
[ -n "${idx[$i]}" ] && \
printf "%2d) %-20s" "$(( $line + (($col - 1) * $lines) ))" "$task"
done
echo -e "\n"
done
}
main() {
local line content result count tasks template=$1
# read the template and render the requested number of the single tasks
while read line ; do
[[ $line =~ ^# ]] && continue
content="${line%%|*}"
count="${line##*|}"
for((i=1;i<=count;i++)) ; do
result="$(replace_shell "$content")"
tasks[++taskcount]="${result//$answer_pattern/$answer_text}"
done
done <$template
task_output
}
# PROGRAM STARTS HERE
main ${1:-magnus.tmpl}
#
# example template file: magnus.tmpl
#
# question | times
#-------------------------------+-----------------
{rnd1=$(shuf -i 1-9 -n 1)}$rnd1 + $rnd1 = <ans>|7
{shuf -i 10-20 -n 1} - 1 = <ans>|3
{shuf -i 10-20 -n 1} + 1 = <ans>|5
{shuf -i 1-9 -n 1} + <ans> = 10|5
{shuf -i 1-99 -n 1} - 10 = <ans>|5
10 - <ans> = {shuf -i 1-9 -n 1}|5
10 x {shuf -i 1-10 -n 1} = <ans>|5
{shuf -i 11-99 -n 1} + {shuf -n 1 -e 10 20 30 40 50 60 70 80 90} = <ans>|5
Is {shuf -i 1-9 -n 1} O / E <ans>|5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment