Upload files to ''

This commit is contained in:
Coder 2019-09-30 08:58:41 +00:00
parent 17a9a4dd53
commit c568338e83
8 changed files with 858 additions and 0 deletions

BIN
CSCI251-A1- Spring 2019.pdf Normal file

Binary file not shown.

24
Readme.txt Normal file
View File

@ -0,0 +1,24 @@
// License: AGPLv3 or later. https://www.gnu.org/licenses/licenses.html
Compile on UOW Banshee server using either of the following command in terminal/shell:
$ make
OR
$ CC -std=c++11 -o ABC driver.cpp abc.cpp general_functions.cpp
As per test on my machine using folowwing code, there is no memory leak:
$ valgrind --tool=memcheck ./ABC Students.txt Subjects.txt Teachers.txt Results.txt
However, there is leak when running bcheck on banshee. This could be because of bug in compiler CC.
Documentation:
Commenting explaning functions use and rational are in header files. Comments explaning implementation of functions are in cpp files.
Exit codes error list:
(Read standard error output to find the exact reason of errors.)
1 - Error related to arguments recived
2 - Error while reading file
3 - Error while processing subjects file lines string into subject structs
4 - Error while processing teachers file lines string into teacher structs
5 - Subject code in student's subject list or teacher's subject list is out of range (more than number of subjects)
6 - Error while writting results to output-file

541
abc.cpp Normal file
View File

@ -0,0 +1,541 @@
// License: AGPLv3 or later. https://www.gnu.org/licenses/licenses.html
#include <fstream>
#include <iostream>
#include <sstream>
# include "general_functions.h"
# include "abc.h"
using namespace std;
const int MAX_ATTEMPTS_ALLOWED = 3;
input_files_name perform_checks_on_args(
int argc, char *argv[])
{
if (argc != 5)
{
cerr << "Expected 5 arguments, received " << argc
<< " argument(s). Please provide exactly 5 arguments and "
"in correct order i.e.:\n"
"1. Program name/path (received automatically)\n"
"2. Students File such as Students.txt\n"
"3. Subjects File such as Subjects.txt\n"
"4. Teachers File such as Teachers.txt\n"
"5. Output-file such as Results.txt\n"
"\n"
"Run program similar to this:\n"
"$ ./ABC Students.txt Subjects.txt Teachers.txt "
"Results.txt\n";
exit(1);
}
else
{
input_files_name args;
args.students = argv[1];
args.subjects = argv[2];
args.teachers = argv[3];
args.results = argv[4];
return args;
}
}
input_files_textlines read_input_files(
input_files_name file_names)
{
input_files_textlines files_textlines;
files_textlines.students = get_textfile_lines(
file_names.students);
files_textlines.subjects = get_textfile_lines(
file_names.subjects);
files_textlines.teachers = get_textfile_lines(
file_names.teachers);
print_three_newlines();
return files_textlines;
}
vector<student> generate_students_struct(
vector<string> students_lines)
{
cout << "Processing students file text:" << endl;
vector<student> students;
int line_number = 0;
for (auto student_line:students_lines)
{
line_number++;
// Ignoring empty line. Giving no warning/error for it either.
if (student_line.size() == 0)
continue;
try
{
student a_student;
string ability_string;
string consistency_string;
string subject_sring;
istringstream line(student_line);
getline(line, a_student.name, ',');
getline(line, a_student.code, ',');
getline(line, ability_string, ',');
a_student.ability = stoi(ability_string);
getline(line, consistency_string, ',');
a_student.consistency = stoi(consistency_string);
getline(line, a_student.program, ':');
while(getline(line, subject_sring, ','))
{
int subject_code = stoi(subject_sring);
if (subject_code > 0)
a_student.subjects.push_back(subject_code);
else
throw "Anything that you can";
}
if (a_student.name.size() == 0
or a_student.code.size() != 6
or is_string_some_positive_number(
a_student.code) == false
or a_student.ability < 0
or a_student.ability > 100
or a_student.consistency < 0
or a_student.consistency > 15
or a_student.program.size() == 0
or a_student.subjects.size() == 0)
{
throw "All the things that you can";
}
students.push_back(a_student);
cout << "Student Name: " << a_student.name << '\n'
<< "Code: " << a_student.code << '\n'
<< "Ability: " << a_student.ability << '\n'
<< "Consistency: " << a_student.consistency << '\n'
<< "Program Name: " << a_student.program << '\n'
<< "Subjects code: ";
for (auto subject_code: a_student.subjects)
{
cout << subject_code << " ";
}
cout << '\n' << endl;
}
catch(...)
{
cerr << "Non-Fatal Error Occured while processing student"
<< " file lines into student structs. However as per "
<< "specifiction, skipping proccesing anymore "
<< "students.\n"
<< "Line number: " << line_number << " is not in "
<< "proper format.\n"
<< "Actual Line:\n"
<< student_line << "\n"
<< "Expected line format:\n"
<< "Name,Student code,Ability,Consistency,Program "
<< "name:Subject list\n"
<< "Where,\n"
<< "1. Name is an non-empty string.\n"
<< "2. Student code is 6 *digit* string.\n"
<< "3. Ability is an integer in range 0 to 100.\n"
<< "4. Consistency is an integer in range 0 to 15.\n"
<< "5. Program name is an non-empty string.\n"
<< "6. Subject list is the list of comma-seprated "
<< "positive integers representing subject codes.\n";
break;
}
}
print_three_newlines();
return students;
}
vector<subject> generate_subjects_struct(
vector<string> subjects_lines)
{
cout << "Processing subjects file text:" << endl;
vector<subject> subjects;
int line_number = 0;
for (auto subject_line: subjects_lines)
{
line_number++;
// Ignoring empty line. Giving no warning/error for it either.
if (subject_line.size() == 0)
continue;
try
{
subject a_subject;
string difficulty_string;
string variability_string;
istringstream line(subject_line);
getline(line, a_subject.name, ',');
getline(line, difficulty_string, ',');
a_subject.difficulty = stoi(difficulty_string);
getline(line, variability_string);
a_subject.variability = stoi(variability_string);
if (a_subject.name.size() == 0
or a_subject.difficulty < -15
or a_subject.difficulty > 15
or a_subject.variability < -3
or a_subject.variability > 3)
{
throw "Buzzwords";
}
subjects.push_back(a_subject);
cout << "Subject Name: " << a_subject.name << '\n'
<< "Difficulty: " << a_subject.difficulty << '\n'
<< "Variability: " << a_subject.variability << '\n'
<< endl;
}
catch (...)
{
cerr << "Fatal error occured while processing subjects "
<< "file lines into subject structs. Line: "
<< line_number << " is not in proper format.\n"
<< "Actual line:\n"
<< subject_line << "\n"
<< "Expected line format: \n"
<< "Name,Difficulty,Variability\n"
<< "Where,\n"
<< "1. Name is a non-empty string.\n"
<< "2. Diffuculty is interger in range -15 to 15.\n"
<< "3. Variability is integer in range -3 to 3.\n";
exit(3);
}
}
print_three_newlines();
return subjects;
}
vector<teacher> generate_teachers_struct(
vector<string> teachers_lines)
{
cout << "Processing teachers file text:" << endl;
vector<teacher> teachers;
int line_number = 0;
for (auto teacher_line: teachers_lines)
{
line_number++;
// Ignoring empty line. Giving no warning/error for it either.
if (teacher_line.size() == 0)
continue;
try
{
teacher a_teacher;
istringstream line(teacher_line);
string toughness_string;
string variability_string;
string subject_string;
getline(line, a_teacher.name, ',');
getline(line, toughness_string, ',');
a_teacher.toughness = stoi(toughness_string);
getline(line, variability_string, ':');
a_teacher.variability = stoi(variability_string);
while(getline(line, subject_string, ','))
{
int subject_code = stoi(subject_string);
if (subject_code > 0)
a_teacher.subjects.push_back(subject_code);
else
throw "Cheesy praises at teacher";
}
if (a_teacher.name.size() == 0
or a_teacher.toughness < -15
or a_teacher.toughness > 15
or a_teacher.variability < -3
or a_teacher.variability > 3
or a_teacher.subjects.size() == 0)
{
throw "some swag";
}
cout << "Teacher Name: " << a_teacher.name << '\n'
<< "Toughness: " << a_teacher.toughness << '\n'
<< "Variability: " << a_teacher.variability << '\n'
<< endl;
teachers.push_back(a_teacher);
}
catch (...)
{
cerr << "Fatal error occured while processing teachers "
<< "file lines into teacher structs. Line: "
<< line_number << " is not in proper format.\n"
<< "Actual line:\n"
<< teacher_line << "\n"
<< "Expected line format: \n"
<< "Name,Toughness,Variability:Subjects List\n"
<< "Where,\n"
<< "1. Name is a non-empty string.\n"
<< "2. Toughness is interger in range -15 to 15.\n"
<< "3. Variability is integer in range -3 to 3.\n"
<< "4. Subects list is comma-seprated list of positive"
<< "integers representing subjects codes.\n";
exit(4);
}
}
print_three_newlines();
return teachers;
}
void add_teachers_vector_index_number_to_subjects_struct(
vector<teacher> &teachers,
vector<subject> &subjects)
{
for (int i=0; i < teachers.size(); i++)
{
for (auto subject_code: teachers[i].subjects)
{
if (subject_code <= subjects.size())
{
/* -1 and +1 since indexes starts from 0.
*/
subjects[subject_code-1].teachers.push_back(i+1);
}
else
{
cerr << "Fatal error. Subject code " << subject_code
<< " of teacher: " << i+1 << " i.e. "
<< teachers[i].name << " is more than total "
<< "number of subjects i.e. " << subjects.size()
<< '\n';
exit(5);
}
}
}
}
void process_students_and_generate_results(
vector<student> &students,
vector<subject> &subjects,
vector<teacher> &teachers)
{
cout << "Processing students results:" << endl;
int student_number = 0;
for (auto &a_student: students)
{
student_number++;
int attempts = 0;
cout << "Processing student " << student_number << " i.e. "
<< a_student.name << ":" << endl;
for (int i=0; i < a_student.subjects.size(); i++)
{
attempts++;
result a_result;
a_result.subject_code = a_student.subjects[i];
if (a_result.subject_code > subjects.size())
{
cerr << "Fatal error. Subject code "
<< a_result.subject_code << " of student: "
<< student_number << " i.e. " << a_student.name
<< " is more than total number of subjects i.e. "
<< subjects.size() << '\n';
exit(5);
}
// -1 since index starts at 0
auto &a_subject = subjects[a_result.subject_code-1];
a_result.subject_name = a_subject.name;
a_result.teacher_code = pick_teacher_randomly(
a_subject.teachers);
// -1 since index starts at 0
auto &a_teacher = teachers[a_result.teacher_code-1];
a_result.teacher_name = a_teacher.name;
int attempts_based_marks_modifier = (attempts-1)*5;
a_result.mean = (
a_student.ability
- a_subject.difficulty
- a_teacher.toughness
+ attempts_based_marks_modifier);
a_result.standard_deviation = (
a_student.consistency
- a_subject.variability
- a_teacher.variability);
a_result.standard_deviation = absolute_number(
a_result.standard_deviation);
int minimum_possible_marks = (
a_result.mean - a_result.standard_deviation);
minimum_possible_marks = bigger_number(
minimum_possible_marks, 0);
minimum_possible_marks = smaller_number(
minimum_possible_marks, 100);
int maximum_possible_marks = (
a_result.mean + a_result.standard_deviation);
maximum_possible_marks = smaller_number(
maximum_possible_marks, 100);
maximum_possible_marks = bigger_number(
maximum_possible_marks, 0);
int marks = random_int(
minimum_possible_marks,
maximum_possible_marks);
a_result.marks = marks;
a_result.grade = return_grade_for_float((float)marks);
a_student.results.push_back(a_result);
cout << a_result.subject_name << " ("
<< a_result.subject_code << ") by "
<< a_result.teacher_name << " ("
<< a_result.teacher_code << ") Attempt: "
<< attempts << " Mean: "
<< a_result.mean << " Standard Deviation: "
<< a_result.standard_deviation << " Maximum: "
<< maximum_possible_marks << " Minimum: "
<< minimum_possible_marks << " Marks: "
<< a_result.marks << " Grade: " << a_result.grade
<< endl;
// Supplementary provided.
if (marks >= 45 and marks < 50)
{
int supplementary_marks_modifier = 5;
a_result.mean += supplementary_marks_modifier;
marks = random_int(
minimum_possible_marks,
maximum_possible_marks)
+ supplementary_marks_modifier;
a_result.marks = marks;
if (marks >= 50)
{
a_result.grade = "SP";
}
else
a_result.grade = "F";
a_student.results.push_back(a_result);
cout << "Supplementary Marks: " << a_result.marks
<< " Grade: " << a_result.grade << endl;
}
// Fail.
if (a_result.grade == "F")
{
/* Max attempts allowed reached. Excluded from college.
* No more subjects are taught.
*/
if (attempts >= MAX_ATTEMPTS_ALLOWED)
{
a_student.overall_marks += marks;
cout << endl; //cosmetic hotfix
a_student.overall_grade_or_status = "F";
a_student.subjects_studied += 1;
break;
}
// Repeat same subject
else
{
i--;
}
}
// Study next subject with attempt reset to 0.
else
{
a_student.overall_marks += marks;
attempts = 0;
a_student.subjects_studied += 1;
}
// line between every subject attempt
cout << endl;
}
a_student.percentage = ((float)
((a_student.overall_marks*100)/\
a_student.subjects_studied)/100.0);
if (a_student.overall_grade_or_status == "?")
{
a_student.overall_grade_or_status =\
return_grade_for_float(a_student.percentage);
}
cout << "Overall Percentage: " << a_student.percentage
<< " Overall Grade: " << a_student.overall_grade_or_status
<< '\n' << endl;
}
}
void write_results_to_output_file(
vector<student> &students, std::string results_file_name)
{
ofstream results_file(results_file_name);
if (!results_file.good())
{
cerr << "Fatal Error: Could not write results to output-file:"
<< results_file_name << "\n"
<< "Possibly do not have write acces to directory\n";
exit(6);
}
for (auto a_student: students)
{
results_file << a_student.code << "-" << a_student.name << ","\
<< a_student.program << "-" << a_student.percentage << "-"\
<< a_student.overall_grade_or_status << ":";
for (auto a_result:a_student.results)
{
results_file << a_result.subject_code << "-"\
<< a_result.subject_name << ","\
<< a_result.teacher_code << "-"\
<< a_result.teacher_name << ","\
<< a_result.mean << "+-"\
<< a_result.standard_deviation << "=>"\
<< a_result.marks << "-" << a_result.grade << ";";
}
results_file << "\n";
}
results_file.close();
}
int pick_teacher_randomly(vector<int> teachers_codes)
{
int selected_teacher_index = random_int(
0, (teachers_codes.size()-1));
return teachers_codes[selected_teacher_index];
}
string return_grade_for_float(float percentage)
{
if (percentage >= 85.0)
return "HD";
else if (percentage >= 75.0)
return "D";
else if (percentage >= 65.0)
return "C";
else if (percentage >= 50.0)
return "P";
else
return "F";
}

120
abc.h Normal file
View File

@ -0,0 +1,120 @@
// License: AGPLv3 or later. https://www.gnu.org/licenses/licenses.html
/* Functions which are written specifically for A Big College (ABC)
*/
#ifndef _ABC_H_
#define _ABC_H_
#include <vector>
struct input_files_name
{
std::string students;
std::string subjects;
std::string teachers;
std::string results; // output-file
};
struct input_files_textlines
{
std::vector<std::string> students;
std::vector<std::string> subjects;
std::vector<std::string> teachers;
};
struct teacher
{
/* teacher's index no.+1 is treated as teacher code which is used
* internally in subject's struct as teachers who can teach those
* subjects
*/
// int code;
std::string name;
int toughness;
int variability;
std::vector<int> subjects;
};
struct result
{
int subject_code;
/* Even though redundant, it makes function statements a lot more
* readable.
*/
std::string subject_name;
int teacher_code;
// Same as previous comment
std::string teacher_name;
int mean;
int standard_deviation;
int marks;
std::string grade;
};
struct student
{
std::string name;
std::string code;
int ability;
int consistency;
std::string program;
// Only the last attempt of every subject is added to overall_marks
int overall_marks = 0;
/* Following calculation is used to obtain percentage upto two decimal
* points precision only:
* ((float)((overall_marks*100)/subjects_studied)/100.0)
*/
float percentage;
/* If fail, F will be added at exclusion time. Else, will be
* calculated based on percentage.
*/
std::string overall_grade_or_status = "?";
std::vector<int> subjects;
// used for calculating overall percentage
int subjects_studied = 0;
std::vector<result> results;
};
struct subject
{
// subject's index no.+1 is treated as subject code
// int code;
std::string name;
int difficulty;
int variability;
std::vector<int> teachers;
};
input_files_name perform_checks_on_args(
int argc, char *argv[]);
input_files_textlines read_input_files(
input_files_name file_names);
std::vector<student> generate_students_struct(
std::vector<std::string> students);
std::vector<subject> generate_subjects_struct(
std::vector<std::string> subjects);
std::vector<teacher> generate_teachers_struct(
std::vector<std::string> teachers);
void add_teachers_vector_index_number_to_subjects_struct(
std::vector<teacher> &teachers,
std::vector<subject> &subjects);
void process_students_and_generate_results(
std::vector<student> &students,
std::vector<subject> &subjects,
std::vector<teacher> &teachers);
void write_results_to_output_file(
std::vector<student> &students, std::string results_file_name);
int pick_teacher_randomly(std::vector<int> teachers_codes);
std::string return_grade_for_float(float percentage);
#endif

33
driver.cpp Normal file
View File

@ -0,0 +1,33 @@
// License: AGPLv3 or later. https://www.gnu.org/licenses/licenses.html
#include <iostream>
#include <vector>
#include "abc.h"
using namespace std;
int main(int argc, char *argv[])
{
input_files_name args = perform_checks_on_args(argc, argv);
input_files_textlines input_files_by_line = read_input_files(
args);
vector<student> students = generate_students_struct(
input_files_by_line.students);
vector<subject> subjects = generate_subjects_struct(
input_files_by_line.subjects);
vector<teacher> teachers = generate_teachers_struct(
input_files_by_line.teachers);
add_teachers_vector_index_number_to_subjects_struct(teachers, subjects);
process_students_and_generate_results(
students, subjects, teachers);
write_results_to_output_file(students, args.results);
return 0;
}

65
general_functions.cpp Normal file
View File

@ -0,0 +1,65 @@
// License: AGPLv3 or later. https://www.gnu.org/licenses/licenses.html
#include <fstream>
#include <iostream>
#include <random>
# include "general_functions.h"
using namespace std;
vector<string> get_textfile_lines(std::string filename)
{
ifstream file(filename);
vector<string> file_lines;
if (! file.good())
{
cerr << "Failed to open/read file: " << filename\
<< ". Non-exhaustive list of possible reasons:\n"\
<< "1. File does not exist.\n"\
<< "2. Unable to read file due to:\n"\
<< "2.1 Don't have read access to file\n"\
<< "2.2 File is opened elsewhere and some program have a "\
<< "lock on file.\n";
exit(2);
}
cout << "Reading file: " << filename << endl;
while (file.good())
{
string line;
getline(file, line);
file_lines.push_back(line);
}
file.close();
return file_lines;
}
int random_int(int lower_bound, int upper_bound)
{
static std::random_device seed;
static std::mt19937 random_number_generator(seed());
std::uniform_int_distribution<std::mt19937::result_type> range(
lower_bound, upper_bound);
return range(random_number_generator);
}
bool is_string_some_positive_number(std::string a_string)
{
for (int i=0; i < a_string.size(); i++)
{
string character(1, a_string[i]);
try
{
stoi(character);
}
catch(...)
{
return false;
}
}
return true;
}

64
general_functions.h Normal file
View File

@ -0,0 +1,64 @@
// License: AGPLv3 or later. https://www.gnu.org/licenses/licenses.html
/* General functions which can be used in any program
*/
#ifndef _GENERAL_FUNCTIONS_H_
#define _GENERAL_FUNCTIONS_H_
#include <vector>
std::vector<std::string> get_textfile_lines(std::string filename);
int random_int(int lower_bound, int upper_bound);
bool is_string_some_positive_number(std::string a_string);
/* Its a good practice to prototype all functions including which are
* defined in header file itself such as inline functions before defining
* any function. This way, even if we use one function in another
* function, we do not have to worry about function undefined error
* possibilities.
*/
inline int absolute_number(int number);
inline int smaller_number(int a, int b);
inline int bigger_number(int a, int b);
/* this function is used between different parts of program's standard
* output for better sepration of dissimilar outputs
*/
inline void print_three_newlines();
inline int absolute_number(int number)
{
if (number < 0)
return -(number);
else
return number;
}
inline int smaller_number(int a, int b)
{
if (a > b)
return b;
else
return a;
}
inline int bigger_number(int a, int b)
{
if (a < b)
return b;
else
return a;
}
inline void print_three_newlines()
{
std::cout << "\n" << std::endl;
}
#endif

11
makefile Normal file
View File

@ -0,0 +1,11 @@
ABC: driver.o abc.o general_functions.o
CC -std=c++11 -o ABC driver.o abc.o general_functions.o && rm *.o
driver.o: driver.cpp abc.h
CC -std=c++11 -c driver.cpp
abc.o: abc.cpp general_functions.h
CC -std=c++11 -c abc.cpp
general_functions.o: general_functions.cpp
CC -std=c++11 -c general_functions.cpp