Last active
May 7, 2026 10:05
-
-
Save ShardulJunagade/e8bfe861dd663fa34c843d32bd9d8ef3 to your computer and use it in GitHub Desktop.
CPI and P/F Calculator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Description: This program calculates the Cumulative Performance Index (CPI) of a student based on their grades and credits. | |
| # Author: Shardul Junagade | |
| # Date: 24-12-2024 | |
| class Course: | |
| def __init__(self, name, course_code, grade, credit, pass_fail=False): | |
| if grade < 0 or credit < 0: | |
| raise ValueError("Grade and credits must be non-negative.") | |
| self.name = name | |
| self.course_code = course_code | |
| self.grade = grade | |
| self.credit = credit | |
| self.pass_fail = pass_fail # New attribute | |
| def weighted_score(self): | |
| return 0 if self.pass_fail else self.grade * self.credit | |
| class Semester: | |
| def __init__(self, semester_number): | |
| self.semester_number = semester_number | |
| self.courses = [] | |
| def add_course(self, course): | |
| self.courses.append(course) | |
| def calculate_spi(self): | |
| total_weighted_score = sum(course.weighted_score() for course in self.courses if not course.pass_fail) | |
| total_credits = sum(course.credit for course in self.courses if not course.pass_fail) | |
| return round(total_weighted_score / total_credits, 2) if total_credits > 0 else 0 | |
| def total_score(self): | |
| return sum(course.weighted_score() for course in self.courses if not course.pass_fail) | |
| def total_credits(self): | |
| return sum(course.credit for course in self.courses if not course.pass_fail) | |
| class Student: | |
| def __init__(self, name): | |
| self.name = name | |
| self.semesters = [] | |
| self.total_score = 0 | |
| self.total_credits = 0 | |
| self.cpi = 0 | |
| def add_semester(self, semester): | |
| self.semesters.append(semester) | |
| self.total_score += semester.total_score() | |
| self.total_credits += semester.total_credits() | |
| def calculate_cpi(self): | |
| self.total_score = sum(sem.total_score() for sem in self.semesters) | |
| self.total_credits = sum(sem.total_credits() for sem in self.semesters) | |
| self.cpi = round(self.total_score / self.total_credits, 2) if self.total_credits > 0 else 0 | |
| return self.cpi | |
| def get_spi_history(self): | |
| return {sem.semester_number: sem.calculate_spi() for sem in self.semesters} | |
| def convert_to_pass_fail(self, course_code, show_message=True): | |
| for sem in self.semesters: | |
| for course in sem.courses: | |
| if course.course_code == course_code: | |
| course.pass_fail = True | |
| if show_message: | |
| print(f"Converted {course.name} ({course.course_code}) to pass/fail.") | |
| self.calculate_cpi() | |
| return | |
| if show_message: | |
| print(f"Course with code {course_code} not found.") | |
| def convert_to_grade(self, course_code): | |
| for sem in self.semesters: | |
| for course in sem.courses: | |
| if course.course_code == course_code: | |
| course.pass_fail = False | |
| print(f"Converted {course.name} ({course.course_code}) to graded.") | |
| self.calculate_cpi() | |
| return | |
| print(f"Course with code {course_code} not found.") | |
| def print_student_summary(student): | |
| print(f"\n{'='*40}") | |
| print(f"Student Name: {student.name}") | |
| # print(f"{'='*40}") | |
| # print(f"Total Credits Completed: {student.total_credits}") | |
| print(f"{'='*40}") | |
| print(f"{'Semester':<10} {'Credits':<10} {'SPI':<10}") | |
| print(f"{'-'*40}") | |
| for sem in student.semesters: | |
| print(f"{sem.semester_number:<10} {sem.total_credits():<10} {sem.calculate_spi():<10.2f}") | |
| print(f"{'-'*40}") | |
| cpi = student.calculate_cpi() | |
| # show the CPI with 2 decimal places and total number of credits | |
| print(f"{'Total':<10} {student.total_credits:<10} CPI: {cpi:<10.2f}") | |
| print(f"{'='*40}") | |
| # List current pass/fail courses and their credits | |
| pf_courses = [] | |
| for sem in student.semesters: | |
| for course in sem.courses: | |
| if course.pass_fail: | |
| pf_courses.append((course.name, course.course_code, course.credit, sem.semester_number)) | |
| if pf_courses: | |
| print("Current Pass/Fail Courses:") | |
| print(f"{'Semester':<10} {'Course Name':<40} {'Code':<12} {'Credits':<7}") | |
| print(f"{'-'*75}") | |
| for name, code, credit, semnum in pf_courses: | |
| print(f"{semnum:<10} {name:<40} {code:<12} {credit:<7}") | |
| print(f"{'-'*75}") | |
| print(f"Credits in Pass/Fail Courses: {sum(credit for _, _, credit, _ in pf_courses)}") | |
| print(f"Total Credits including Pass/Fail: {student.total_credits + sum(credit for _, _, credit, _ in pf_courses)}") | |
| if cpi >= 9: | |
| print("Good Job!\n") | |
| else: | |
| print("Keep Improving!\n") | |
| def suggest_courses_to_maximize_cpi(student): | |
| print("\nSuggesting courses to convert to pass/fail to maximize CPI...") | |
| original_cpi = student.calculate_cpi() | |
| best_cpi = original_cpi | |
| best_combination = [] | |
| # Collect all courses that are not already pass/fail | |
| all_courses = [ | |
| (course, sem) | |
| for sem in student.semesters | |
| for course in sem.courses | |
| if not course.pass_fail | |
| ] | |
| # Check the effect of converting each course individually | |
| for course, sem in all_courses: | |
| # Temporarily mark the course as pass/fail | |
| course.pass_fail = True | |
| student.calculate_cpi() # Recalculate CPI | |
| # Check if this improves the CPI | |
| if student.cpi > best_cpi: | |
| best_cpi = student.cpi | |
| best_combination = [(course.name, course.course_code)] | |
| # Revert the course to its original state | |
| course.pass_fail = False | |
| # Check the effect of converting pairs of courses | |
| for i in range(len(all_courses)): | |
| for j in range(i + 1, len(all_courses)): | |
| course1, sem1 = all_courses[i] | |
| course2, sem2 = all_courses[j] | |
| # Temporarily mark both courses as pass/fail | |
| course1.pass_fail = True | |
| course2.pass_fail = True | |
| student.calculate_cpi() # Recalculate CPI | |
| # Check if this combination improves the CPI | |
| if student.cpi > best_cpi: | |
| best_cpi = student.cpi | |
| best_combination = [ | |
| (course1.name, course1.course_code), | |
| (course2.name, course2.course_code), | |
| ] | |
| # Revert the courses to their original state | |
| course1.pass_fail = False | |
| course2.pass_fail = False | |
| # Print and return the best result | |
| print(f"Original CPI: {original_cpi:.2f}") | |
| print("Suggested courses to convert to pass/fail to maximize CPI:") | |
| for course in best_combination: | |
| print(f" Course: {course[0]} (Code: {course[1]})") | |
| print(f"Improved CPI: {best_cpi:.2f}") | |
| return best_combination, best_cpi | |
| # Example Usage | |
| student = Student("Shardul Junagade") | |
| # Semester 1 | |
| sem1 = Semester(1) | |
| sem1.add_course(Course("Foundation Programme", "FP 100", 10, 4)) | |
| sem1.add_course(Course("Engineering Graphics", "ES 101", 10, 3)) | |
| sem1.add_course(Course("Computing", "ES 112", 10, 3)) | |
| sem1.add_course(Course("The World of Engineering", "ES 117", 10, 2)) | |
| sem1.add_course(Course("Materials for the Future", "ES 118", 10, 3)) | |
| sem1.add_course(Course("Introduction to Writing I", "HS 191", 10, 2)) | |
| sem1.add_course(Course("Calculus of Single Variable and Linear Algebra", "MA 103", 10, 4)) | |
| sem1.add_course(Course("World Civilizations and Cultures", "HS 201", 9, 4)) | |
| student.add_semester(sem1) | |
| student.convert_to_pass_fail("FP 100", show_message=False) | |
| # Semester 2 | |
| sem2 = Semester(2) | |
| sem2.add_course(Course("Ordinary Differential Equations", "MA 104", 10, 2)) | |
| sem2.add_course(Course("Data-Centric Computing", "ES 113", 9, 3)) | |
| sem2.add_course(Course("Probability, Statistics, and Data Visualization", "ES 114", 8, 3)) | |
| sem2.add_course(Course("Design, Innovation, and Prototyping", "ES 115", 8, 5)) | |
| sem2.add_course(Course("Principles and Applications of Electrical Engineering", "ES 116", 9, 5)) | |
| sem2.add_course(Course("Undergraduate Science Laboratory", "BS 192", 9, 3)) | |
| sem2.add_course(Course("Introduction to Writing II", "HS 192", 9, 2)) | |
| sem2.add_course(Course("General Education I", "GE 101", 10, 2)) | |
| student.add_semester(sem2) | |
| student.convert_to_pass_fail("GE 101", show_message=False) | |
| # Semester 3 | |
| sem3 = Semester(3) | |
| sem3.add_course(Course("Machine Learning", "ES 335", 10, 4)) | |
| sem3.add_course(Course("Data Structures and Algorithms I", "ES 242(N)", 10, 4)) | |
| sem3.add_course(Course("Biology for Engineers", "ES 243", 8, 4)) | |
| sem3.add_course(Course("Introduction to Philosophy", "HS 221", 9, 4)) | |
| sem3.add_course(Course("Calculus of Several Variables", "MA 205", 9, 2)) | |
| sem3.add_course(Course("Discrete Mathematics", "ES 214", 9, 4)) | |
| sem3.add_course(Course("Introduction to Partial Differential Equations", "MA 204", 9, 2)) | |
| sem3.add_course(Course("General Education II", "GE 102", 10, 2)) | |
| student.add_semester(sem3) | |
| student.convert_to_pass_fail("GE 102", show_message=False) | |
| # Semester 4 | |
| sem4 = Semester(4) | |
| sem4.add_course(Course("Theory of Computing", "CS 201", 8, 4)) | |
| sem4.add_course(Course("Digital Systems", "ES 204", 8, 4)) | |
| sem4.add_course(Course("Numerical Methods", "MA 203", 10, 2)) | |
| sem4.add_course(Course("Data Structures and Algorithms II", "ES 301", 8, 4)) | |
| sem4.add_course(Course("Introduction to Data Science", "ES 328", 7, 4)) | |
| sem4.add_course(Course("Project Course", "CS 299", 9, 4)) | |
| # sem4.add_course(Course("Online ML Course - Coursera", "Online ML", 10, 5)) | |
| student.add_semester(sem4) | |
| # student.convert_to_pass_fail("Online ML", show_message=False) | |
| # Semester 5 | |
| sem5 = Semester(5) | |
| sem5.add_course(Course("Operating Systems", "CS 330", 10, 4)) | |
| sem5.add_course(Course("Computer Networks", "CS 331", 6, 4)) | |
| sem5.add_course(Course("Computer Vision", "EE 666", 8, 4)) | |
| sem5.add_course(Course("Deep Learning", "ES 667", 8, 4)) | |
| sem5.add_course(Course("STT CSE", "CS 202", 10, 4)) | |
| sem5.add_course(Course("Foundations of AI", "CS 329", 8, 4)) | |
| sem5.add_course(Course("Economics", "HS 151", 7, 4)) | |
| student.add_semester(sem5) | |
| # Semester 6 | |
| sem6 = Semester(6) | |
| sem6.add_course(Course("Computer Organization and Architecture", "ES 215", 6, 4)) | |
| sem6.add_course(Course("Compilers", "CS 327", 10, 5)) | |
| sem6.add_course(Course("Databases", "CS 433", 9, 4)) | |
| sem6.add_course(Course("Biodiversity Conservation and Sustainable Development", "EH 608", 7, 4)) | |
| sem6.add_course(Course("Ocean and Global Change", "EH 612", 9, 4)) | |
| sem6.add_course(Course("History of Computing and its Applications to Domains", "ES 670", 7, 2)) | |
| student.add_semester(sem6) | |
| # Semester 7 | |
| # sem7 = Semester(7) | |
| # sem7.add_course(Course("Modelling of Earth Systems", "EH 605", int(input("Modelling of Earth Systems: ")), 4)) | |
| # sem7.add_course(Course("Natural Language Processing", "CS 613", int(input("Natural Language Processing: ")), 4)) | |
| # Convert some courses to pass/fail | |
| # student.convert_to_pass_fail("CS 331") | |
| # student.convert_to_pass_fail("ES 215") | |
| # Print the student summary | |
| print_student_summary(student) | |
| # Suggest courses to convert to pass/fail to maximize CPI | |
| suggest_courses_to_maximize_cpi(student) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment