Recap - Student Records System
Part of the Object Oriented Programming section of Coddy's GDScript journey. Lesson 30 of 65.
Challenge
MediumBuild a small student records system from two classes.
Student in student.gd keeps its data private:
_init(id, new_name)stores the ID in a private variable and assigns the name through thestudent_namesetter.student_idis read-only and returns the ID.student_namehas a setter: a name shorter than2characters is rejected (the old name stays) andlast_errorbecomesName must be at least 2 characters. A valid name clearslast_error.add_grade(course, grade)stores the grade for the course in a private Dictionary (a new grade for the same course replaces the old one) and returnstrue. A grade below0or above100is not stored and returnsfalse.averageis a read-only computed property: the average of the grades as afloat, or0.0without grades.course_count()returns the number of courses with a grade.
StudentRegistry in student_registry.gd keeps the students in a private Dictionary, with the ID as key:
add_student(student)returnsfalseand changes nothing when the ID is taken, otherwise stores the student and returnstrue.remove_student(id)returns whether a student was removed.get_student(id)returns the student, ornull.top_student()returns the student with the highest average (the one added first on a tie), ornullwhen the registry is empty.get_ids()returns the IDs in the order the students were added.
The supplied code reads the number of commands, then runs one command per line: add ID NAME, grade ID COURSE GRADE, rename ID NAME, remove ID, show ID, tamper ID (tries to overwrite student_id and average, which must not change), top and list. For this input:
10
add 1001 Alice Smith
add 1002 Bob
grade 1001 Math 90
grade 1001 Art 85
grade 1002 Math 95
grade 1002 Art 120
rename 1002 B
show 1002
top
listit prints:
Added Alice Smith (1001)
Added Bob (1002)
Alice Smith: Math = 90
Alice Smith: Art = 85
Bob: Math = 95
Invalid grade: 120
Rejected: Name must be at least 2 characters
ID: 1002, Name: Bob, Courses: 1, Average: 95.00
Top: Bob (95.00)
ID: 1001, Name: Alice Smith, Courses: 2, Average: 87.50
ID: 1002, Name: Bob, Courses: 1, Average: 95.00Your code goes in student.gd and student_registry.gd. main.gd holds the supplied input/output code and cannot be edited.
Try it yourself
extends Node
func _ready():
# Supplied input/output code: keep it as it is
var registry := StudentRegistry.new()
var count := int(OS.read_string_from_stdin())
for i in count:
var parts := OS.read_string_from_stdin().split(" ", true, 2)
var command := parts[0]
if command == "top":
var best := registry.top_student()
if best == null:
print("Top: none")
else:
print("Top: %s (%.2f)" % [best.student_name, best.average])
continue
if command == "list":
for listed_id in registry.get_ids():
print_student(registry.get_student(listed_id))
continue
var id := int(parts[1])
if command == "add":
var student := Student.new(id, parts[2])
if student.last_error != "":
print("Rejected: " + student.last_error)
elif registry.add_student(student):
print("Added %s (%d)" % [student.student_name, id])
else:
print("Duplicate ID: %d" % id)
continue
if command == "remove":
print(("Removed %d" if registry.remove_student(id) else "No student %d") % id)
continue
var student := registry.get_student(id)
if student == null:
print("No student %d" % id)
elif command == "grade":
var grade_parts := parts[2].split(" ")
if student.add_grade(grade_parts[0], int(grade_parts[1])):
print("%s: %s = %s" % [student.student_name, grade_parts[0], grade_parts[1]])
else:
print("Invalid grade: " + grade_parts[1])
elif command == "rename":
student.student_name = parts[2]
if student.last_error != "":
print("Rejected: " + student.last_error)
else:
print("Renamed to " + student.student_name)
elif command == "tamper":
# Tries to overwrite the read-only properties
student.student_id = 0
student.average = 100.0
print_student(student)
else:
print_student(student)
func print_student(student: Student) -> void:
print("ID: %d, Name: %s, Courses: %d, Average: %.2f" % [student.student_id, student.student_name, student.course_count(), student.average])
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesIntroduction to OOPClasses vs ObjectsThe self KeywordMethodsPropertiesConstructor (_init)Recap - Simple Calculator4Polymorphism
Method Overriding RevisitedDuck TypingAbstract Classes and MethodsInterface DesignRecap - Shape Calculator2Class Properties
Instance vs Static VariablesStatic FunctionsProperty SettersProperty GettersPrivate by ConventionRecap - Bank Account Manager5Encapsulation
Public and Private MembersValidation with SettersInformation HidingRead-Only PropertiesRecap - Student Records System8Advanced OOP Concepts
Composition vs InheritanceInner ClassesNodes as ComponentsRefCounted vs NodeEnums in Classes11Project: Library Management
Project OverviewBook and User Classes3Inheritance
Basic InheritanceThe super KeywordMethod OverridingInheritance ChainsType Checks with isRecap - Employee Hierarchy6Special Methods
Virtual Methods IntroductionThe _to_string MethodCustom IteratorsRecap - Custom List9Design Patterns Part 1
Intro to Design PatternsSingleton PatternFactory PatternObserver PatternStrategy PatternPractice on your own: Online GDScript compiler