Assignment-1/abc.cpp

542 lines
16 KiB
C++
Raw Normal View History

2019-09-30 10:58:41 +02:00
// 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";
}