Skip to main content Skip to local navigation

Automated Student Evaluations in C (part 2)

Automated Student Evaluations in C (part 2)

Here's a simple VPL exercise that can grade a simple student-submitted function. The idea is that there are two bash scripts, one for rough work and one for graded evaluation and these scripts will compile the C program, consisting of a main function that calls the student function, passing two integers to it and having the student's function return an integer value as a result.

The bash scripts are based on the fantastic work of Smith College professor emeritus, Dr. Dominique Thiébaut. He wrote about his VPL work here and while his original tutorials are now removed from the College website (a shame), most can be found on Archive.org. In this case, the basic C example is found here.

I won't go through all the setup for VPL. You can find those on my YouTube page and in other blog posts.

Here are the files required for this exercise:

  1. The run script (for student practice): vpl_run.sh
  2. The evaluate script (for grading): vpl_evaluate.sh
  3. The main function (for accessing the student submission): main.c
  4. The student function: studentTemplate.c
  5. The header file for the student template: studentTemplate.h

Important settings within VPL include:

  1. Declaring the name of the VPL server (see your system admin)
  2. Setting the maximum grade value (both in Moodle / eClass and in the evaluate script, vpl_evaluate.sh)
  3. Ensuring that the "files to keep" in VPL include the main.c and studentTemplate.h files

When your student runs VPL to see if there function is working they should see a screen like this:

program running in VPL saying that it was successful.
A student will see this screen when they have a successfully implemented function.

And when the student chooses to evaluate their function they should end up seeing a predicted score that will then be transmitted to their grade book on eClass / Moodle:

After a successful evaluation using the checkbox icon, a proposed grade should show up and comments should be provided to the student. Both the grade and comments will be transmitted to the student's grade book on eClass.

You can also test out these scripts and C files from any computer already equipped with gcc (like a Linux or macOS) and a terminal, like this:

You can test out these scripts from a regular Unix terminal.

Note that you need to execute the vpl_run.sh script prior to running the vpl_execution.sh script that it produces. The compiling and evaluation happens within that secondary script, vpl_execution.sh. Likewise if you want to see how the evaluation works (including the funny-formatted comments), execute vpl_evaluate.sh and then vpl_execution.sh. Ensure that you have modified permissions on the shell scripts first, though.

Here is the first script, vpl_run.sh:

#!/bin/bash
#
# vpl_run.sh script 
# Here, a student function is called by a main function.
# The output of the student function is tested against an expected output string.
# 
# James Andrew Smith; drsmith@yorku.ca July 2021 (updated August 2023)
# Based on example by D. Thiebaut at Smith College
# http://www.science.smith.edu/dftwiki/index.php/Tutorial:_Moodle_VPL_--_Testing_a_C_Program
# now at
# https://web.archive.org/web/20190208191644/http://www.science.smith.edu/dftwiki/index.php/Tutorial:_Moodle_VPL_--_Testing_a_C_Program
# -----------------------------------------------------------------


cat > vpl_execution <<EEOOFF
#!/bin/bash

# Variables (don't add whitespace)
studentProgram=studentTemplate
teacherProgram=main
compiledProgram=alltogether
maxGrade=1
minGrade=0
consolationGrade=0
 
# --- program tested (no extension) ---
gcc -Wall \${teacherProgram}.c \${studentProgram}.c -o \${compiledProgram}  



# --- create test input files ---
cat > solution.txt <<EOF
The student answer is 5 and the teacher answer is 5.
EOF


#grade= \${minGrade}
grade=\$( expr \$minGrade )

for i in 1 ; do
   echo "TEST \$i"

   # ==============================================
   # TEST i
   # ==============================================
   #--- run program, capture output, display to student ---

   ./\${compiledProgram}  &> user.out
   cp user.out user.out.org

   #--- remove non numbers and non minus---
   #cat user.out | sed 's/[^0-9\ -]*//g' > dummy.out
   #mv dummy.out user.out
 
   #--- remove multiple spaces --- 
   cat user.out | sed 's/  */ /g' > dummy.out
   mv dummy.out user.out

   #--- remove blank lines ---
   cat user.out | sed '/^\s*$/d' > dummy.out
   mv dummy.out user.out

   #--- compute difference --- 
   diff -y -w --ignore-all-space user.out solution.txt > diff.out
   #echo "----- diff.out ------"
   #cat diff.out
   #echo "---------------------"
   diff -y -w --ignore-all-space user.out solution.txt > diff.out

   
   #--- reject if different ---
   if ((\$? > 0)); then
      echo "Your program is incorrect."


      echo "---------------"
      echo "The result of the testing program, with the student function included:"
      echo "---------------"
      echo ""
      cat user.out
      echo ""
      echo ""
      echo ""
      echo "---------------"
      echo "The desired output is : "
      echo "---------------"
      echo ""
      cat solution.txt
      echo ""
   
      grade=\$( expr \$minGrade )
   
      #--- consolation grade ("thanks for coming out")---   
      #grade=\$( expr \$consolationGrade )

      # --------------------- REWARD IF CORRECT OUTPUT -----------------
   else
      #--- good output ---
      echo "Congrats, your function is correct."
      echo "... now hit the evaluate button to register a grade."
      echo " -----------------"
      echo ""
      cat user.out.org
      echo ""
      echo ""
      grade=\$( expr \$maxGrade )
   fi
done

echo "***********************"
echo "No grade has been saved."
echo "Use the evaluation button for grading."
echo "***********************"

EEOOFF

 
chmod +x vpl_execution

Here is the vpl_evaluate.sh script:

#!/bin/bash
#
# vpl_evaluate.sh script 
# Here, a student function is called by a main function.
# The output of the student function is tested against an expected output string.
# 
# James Andrew Smith; drsmith@yorku.ca July 2021 (updated August 2023)
# Based on example by D. Thiebaut at Smith College
# http://www.science.smith.edu/dftwiki/index.php/Tutorial:_Moodle_VPL_--_Testing_a_C_Program
# now at
# https://web.archive.org/web/20190208191644/http://www.science.smith.edu/dftwiki/index.php/Tutorial:_Moodle_VPL_--_Testing_a_C_Program
# -----------------------------------------------------------------


cat > vpl_execution <<EEOOFF
#!/bin/bash

# Variables (don't add whitespace)
studentProgram=studentTemplate
teacherProgram=main
compiledProgram=alltogether
maxGrade=1
minGrade=0
consolationGrade=0
 
# --- program tested (no extension) ---
gcc -Wall \${teacherProgram}.c \${studentProgram}.c -o \${compiledProgram}  



# --- create test input files ---
cat > solution.txt <<EOF
The student answer is 5 and the teacher answer is 5.
EOF


#grade= \${minGrade}
grade=\$( expr \$minGrade )

for i in 1 ; do
   echo "Comment :=>>-TEST \$i"

   # ==============================================
   # TEST i
   # ==============================================
   #--- run program, capture output, display to student ---

   ./\${compiledProgram}  &> user.out
   cp user.out user.out.org

   #--- remove non numbers and non minus---
   #cat user.out | sed 's/[^0-9\ -]*//g' > dummy.out
   #mv dummy.out user.out
 
   #--- remove multiple spaces --- 
   cat user.out | sed 's/  */ /g' > dummy.out
   mv dummy.out user.out

   #--- remove blank lines ---
   cat user.out | sed '/^\s*$/d' > dummy.out
   mv dummy.out user.out

   #--- compute difference --- 
   diff -y -w --ignore-all-space user.out solution.txt > diff.out
   #echo "----- diff.out ------"
   #cat diff.out
   #echo "---------------------"
   diff -y -w --ignore-all-space user.out solution.txt > diff.out

   
   #--- reject if different ---
   if ((\$? > 0)); then
      echo "Comment :=>>- Your program is incorrect."


      echo "Comment :=>> ---------------"
      echo "Comment :=>>- The result of the testing program, with the student function included:"
      echo "Comment :=>> ---------------"
      echo "<|--"
      cat user.out
      echo ""
      echo "--|>"
      echo ""
      echo "Comment :=>> ---------------"
      echo "Comment :=>>- The desired output is : "
      echo "Comment :=>> ---------------"
      echo "<|--"
      cat solution.txt
      echo "--|>"
   
      grade=\$( expr \$minGrade )
   
      #--- consolation grade ("thanks for coming out")---   
      #grade=\$( expr \$consolationGrade )

      # --------------------- REWARD IF CORRECT OUTPUT -----------------
   else
      #--- good output ---
      echo "Comment :=>>- Congrats, your function is correct."
      echo "Comment :=>> -----------------"
      echo "<|--"
      cat user.out.org
      echo ""
      echo "--|>"
      grade=\$( expr \$maxGrade )
   fi
done

echo "Grade :=>> \$grade"

EEOOFF

 
chmod +x vpl_execution

Here is the main.c file:

// main.c
// this will call the student function.  
// the printed string here gets evaluated by the bash script to see if it's correct.

#include <stdlib.h>
#include <stdio.h>
#include "studentTemplate.h"

int main(void)
{
	int studentAnswer = 0;
	int inputA = 2;
	int inputB = 3;
	int referenceAnswer = inputA + inputB;
	
	studentAnswer = studentMethod(inputA, inputB);
	
	printf("The student answer is %d and the teacher answer is %d.", studentAnswer, referenceAnswer);
	return -1; 
}

Next up is the really simple header file for the student function, studentTemplate.h, which is referenced by main.c:

// studentTemplate.h
int studentMethod(int, int);

And, finally, here is the template file, which you save under "requested files" because VPL will request the student to fill in the template. Here, I've just commented out the real answer. For your students you could leave a lot less information in it. Here's studentTemplate.c:

// the requested studentTemplate.c file.
#include <stdlib.h>
#include <stdio.h>

int studentMethod(int a, int b)
{
	return a-b;  	// wrong answer	
//	return a+b; 	// right answer
}

James Andrew Smith is a Professional Engineer and Associate Professor in the Electrical Engineering and Computer Science Department of York University's Lassonde School, with degrees in Electrical and Mechanical Engineering from the University of Alberta and McGill University.  Previously a program director in biomedical engineering, his research background spans robotics, locomotion, human birth and engineering education. While on sabbatical in 2018-19 with his wife and kids he lived in Strasbourg, France and he taught at the INSA Strasbourg and Hochschule Karlsruhe and wrote about his personal and professional perspectives.  James is a proponent of using social media to advocate for justice, equity, diversity and inclusion as well as evidence-based applications of research in the public sphere. You can find him on Twitter. Originally from Québec City, he now lives in Toronto, Canada.