...
 
Commits (2)
  • Olivier's avatar
    Add license file (GPLv3) · ee0d3536
    Olivier authored
    ee0d3536
  • Olivier's avatar
    Module 2: customize assignments · 45ce96c2
    Olivier authored
    The code in this commit is contributed by Germán Santa Maria.
    
    Add code for module 2: given a list of students, this will generate,
    for each, a set of variables within specified ranges.
    
    Example input and output data is provided.
    
    The output data will be used in Module 3 to create a unique PDF
    assignment for each student.
    45ce96c2
This diff is collapsed.
Script: assign_customizer.py
============================
## Description
This script takes a `tex` file with marked parameters and a list of students matriculation numbers to produce a new `tex` file with custom parameters for each student and a `csv` file with all the output assignments data.
The input files should be placed in the `script_input` folder which is in the same path as the script. The output files will be saved in the `script_output` folder.
## Script input
1. `parameters.tex`: file containing the parameters, with markers on the places where the values should be customized, for example: `XXlengthXX`, `XXdiameterXX`.
1. `canonical.csv`: file with the students data, example:
| name | lastname | email | matrikel|
|---|---|---|---|
|Theodore |Von Kárman |example1@ovgu.de |123456|
|Osborne |Reynolds |example2@st.ovgu.de |123457|
1. `assignment_info.csv` :file with the range for the marked values.
|find_marker |range_min |range_max |round_off_decimals
|---|---|---|---|
|XXpipediameterXX |0.5 |3 |1|
|XXpipelengthXX |100 |350 |0|
|XXmassflowXX |1.5 |4 |1|
## Script output
1. `output_assignments.csv`:file with a summary of all the output data.
1. `parameters_ID_xxxxxxxx`: one `tex` file, with custom parameters, for each student.
# -*- coding: utf-8 -*-
"""
Author: German Santa Maria
Script: Assignment Customizer
Description:
This script takes a tex file with marked parameters and a list of students
matriculation numbers to produce a new tex file with custom parameters for
each student and a csv file with all the output assignments data.
"""
"""-------------------------Hard coded input--------------------------------"""
# Input files paths
parameters_path = 'script_input/parameters.tex'
canoniccl_path = 'script_input/canonical.csv'
assignment_info_path = 'script_input/assignment_info.csv'
# Output files paths
output_csv_path = 'script_output/output_assignments.csv'
output_parameters_path = 'script_output/parameters_ID_'
"""-------------------------------------------------------------------------"""
# Import modules
import csv # For reading cvs files
from hash_function import hash_function # Import hash_function
# Initialize arrays to store data
names = [] # Student name
last_name = [] # Student last name
emails = [] # Student email address
matrikel_num = [] # Student matrikel number
markers = [] # Marker for the number to customize
range_min = [] # Maximum value that the custom number can take
range_max = [] # Minimum value that the custom number can take
decimals = [] # Number of decimals to round off the custom numbers
custom_ID = [] # Custom ID for the student
rand_matrix = [] # These are the random numbers to customize the assignments
custom_values = [] # Matrix with all custom values for each student assingment
# Open and read original parameters tex file
with open(parameters_path,'r') as f:
parameters = f.read()
# Store students data from csv file into variables
with open(canoniccl_path, newline='') as f:
canoniccl_reader = csv.reader(f)
next(canoniccl_reader) # Skip header [name, last name, email, matrikel_num]
canoniccl_data = [row for row in canoniccl_reader]
for row in canoniccl_data:
names.append(row[0])
last_name.append(row[1])
emails.append(row[2])
matrikel_num.append(row[3])
# Store assignment data from csv file into variables
with open(assignment_info_path, newline='') as f:
assignment_info_reader = csv.reader(f)
next(assignment_info_reader) # Skip header [marker, min, max, decimals]
assignment_info_data = [row for row in assignment_info_reader]
for row in assignment_info_data:
markers.append(row[0])
range_min.append(float(row[1]))
range_max.append(float(row[2]))
decimals.append(int(row[3]))
# Generate anonimus ID and six semi-randoms numbers for each student
for number in matrikel_num:
[ID, rand_numbers]=hash_function(number)
custom_ID.append(ID)
rand_matrix.append(rand_numbers)
# Generate custom values for each student from the semi-random numbers
for i in range (0,len(names)):
counter = 0 # Initialize counter for random numbers indexes
temp_array = [] # Initialize temporal array
for j in range (0,len(markers)):
if counter>5: # This is for the case when len(markers)>random numbers
counter=0
temp_array.append(round((rand_matrix[i][counter]*(range_max[j]-
range_min[j])+range_min[j]), decimals[j]))
counter = counter+1
custom_values.append(temp_array)
# Store the custom assignment data fo all the students in a csv file
with open (output_csv_path,'w',newline='') as f:
writer = csv.writer(f)
writer.writerow(['name','lastname','email','matrikel','custom_ID']+markers)
for i in range(0,len(names)):
writer.writerow([names[i],last_name[i],emails[i],matrikel_num[i],
custom_ID[i]]+custom_values[i])
# Generate modified tex files with custom parameters for each student
for i in range (0,len(names)): # For each student
temp_param=parameters
for j in range (0, len(markers)): # Replace each marker by a custom value
temp_param=temp_param.replace(markers[j],str(custom_values[i][j]))
with open ((output_parameters_path+custom_ID[i]+'.tex'),'w') as f:
for line in temp_param:
f.write(line)
# End of script
# -*- coding: utf-8 -*-
"""
Author: German Santa Maria
Script: Hash Function
Description:
This script takes a matriculation number (for example:123456)
and uses a cryptographic hash function and that generates an eight-digit
anonymous ID to identify the assignments submitted by the students.
Based on the matriculation number, the script also generates an array
with six random numbers that take values from 0 to 1.
"""
def hash_function(matrikel_num):
import hashlib
salt = "insert_your_salt_here" # Salt for the hash function
hash_input = salt + str(matrikel_num) # Input for hash function
hf = hashlib.md5(hash_input.encode('utf-8')).hexdigest() # Digest hash
hf = str(int(hf,16)) # Convert from hexadecimal to integer string
custom_ID = hf[1:9] # Custom ID for student
rand_n = [hf[9:12],hf[12:15],hf[15:18],hf[18:21],hf[21:24],hf[24:27]]
rand_n = list(map(int, rand_n)) # Random numbers from list to number
for i in range(len(rand_n)): # Turn random numbers into values from 0 to 1
rand_n[i] = rand_n[i]*0.001
return [custom_ID, rand_n]
# End of script
find_marker,range_min,range_max,round_off_decimals
XXpipediameterXX,0.5,3,1
XXpipelengthXX,100,350,0
XXmassflowXX,1.5,4,1
XXdensityXX,980,1300,0
name,lastname,email,matrikel
Osborne,Von Kármán,example1@ovgu.de,123456
Theodore,Reynolds,example2@ovgu.de,123457
student1,one,one@st.ovgu.de,100001
student2,two,two@st.ovgu.de,100002
student3,three,three@st.ovgu.de,100003
student4,four,four@st.ovgu.de,100004
student5,five,five@st.ovgu.de,100005
student6,six,six@st.ovgu.de,100006
student7,seven,seven@st.ovgu.de,100007
student8,eight,eight@st.ovgu.de,100008
\newcommand{\pipediameter}{XXpipediameterXX}
\newcommand{\pipelength}{XXpipelengthXX}
\newcommand{\massflow}{XXmassflowXX}
\newcommand{\density}{XXdensityXX}
name,lastname,email,matrikel,custom_ID,XXpipediameterXX,XXpipelengthXX,XXmassflowXX,XXdensityXX
Osborne,Von Kármán,example1@ovgu.de,123456,28107819,1.2,102.0,2.0,1097.0
Theodore,Reynolds,example2@ovgu.de,123457,17688816,1.9,349.0,3.6,990.0
student1,one,one@st.ovgu.de,100001,32203334,1.7,270.0,2.4,1044.0
student2,two,two@st.ovgu.de,100002,90886833,1.1,308.0,3.0,1010.0
student3,three,three@st.ovgu.de,100003,89131963,2.6,133.0,2.8,1267.0
student4,four,four@st.ovgu.de,100004,25214889,1.9,172.0,2.9,1272.0
student5,five,five@st.ovgu.de,100005,31675588,1.2,180.0,1.7,1060.0
student6,six,six@st.ovgu.de,100006,26783579,2.8,346.0,1.9,1219.0
student7,seven,seven@st.ovgu.de,100007,91213660,2.9,141.0,3.6,1144.0
student8,eight,eight@st.ovgu.de,100008,33105406,1.3,105.0,2.5,1218.0
\newcommand{\pipediameter}{1.9}
\newcommand{\pipelength}{349.0}
\newcommand{\massflow}{3.6}
\newcommand{\density}{990.0}
\newcommand{\pipediameter}{1.9}
\newcommand{\pipelength}{172.0}
\newcommand{\massflow}{2.9}
\newcommand{\density}{1272.0}
\newcommand{\pipediameter}{2.8}
\newcommand{\pipelength}{346.0}
\newcommand{\massflow}{1.9}
\newcommand{\density}{1219.0}
\newcommand{\pipediameter}{1.2}
\newcommand{\pipelength}{102.0}
\newcommand{\massflow}{2.0}
\newcommand{\density}{1097.0}
\newcommand{\pipediameter}{1.2}
\newcommand{\pipelength}{180.0}
\newcommand{\massflow}{1.7}
\newcommand{\density}{1060.0}
\newcommand{\pipediameter}{1.7}
\newcommand{\pipelength}{270.0}
\newcommand{\massflow}{2.4}
\newcommand{\density}{1044.0}
\newcommand{\pipediameter}{1.3}
\newcommand{\pipelength}{105.0}
\newcommand{\massflow}{2.5}
\newcommand{\density}{1218.0}
\newcommand{\pipediameter}{2.6}
\newcommand{\pipelength}{133.0}
\newcommand{\massflow}{2.8}
\newcommand{\density}{1267.0}
\newcommand{\pipediameter}{1.1}
\newcommand{\pipelength}{308.0}
\newcommand{\massflow}{3.0}
\newcommand{\density}{1010.0}
\newcommand{\pipediameter}{2.9}
\newcommand{\pipelength}{141.0}
\newcommand{\massflow}{3.6}
\newcommand{\density}{1144.0}
......@@ -27,9 +27,9 @@ A total of nine modules (six of which being locally-run scripts) are needed to r
(in Moodle or through email)
### [ ] Module 2: Generate custom variables for assignments
### [x] Module 2: Generate custom variables for assignments
(in Python)
[Module 2](M2_customize_assignments) (in Python)
### [ ] Module 3: Generate assignments and solutions
......