// License: AGPLv3 or later. https://www.gnu.org/licenses/licenses.html #include #include #include # 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 generate_students_struct( vector students_lines) { cout << "Processing students file text:" << endl; vector 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 generate_subjects_struct( vector subjects_lines) { cout << "Processing subjects file text:" << endl; vector 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 generate_teachers_struct( vector teachers_lines) { cout << "Processing teachers file text:" << endl; vector 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 &teachers, vector &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 &students, vector &subjects, vector &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 &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 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"; }