E-learning Platform
Part of the Object Oriented Programming section of Coddy's GDScript journey. Lesson 62 of 65.
Challenge
HardBuild the classes of an e-learning platform: courses, students and instructors. Students and instructors are both people, so they share a parent class.
The objects must not point at each other: a course stores the emails of its students and the name of its instructor, and students and instructors store course titles. A method that needs a course receives it as an argument.
Person in person.gd: the constructor takes person_name and email and stores them. _to_string() returns NAME (EMAIL).
Course in course.gd:
- Properties:
title,max_capacity,instructor_name(starts as""), and theArray[String]student_emailsandcompleted_emails. - The constructor takes the title and the capacity, which defaults to
30. - A signal
course_full(title: String), emitted byadd_student()when it takes the last free seat. add_student(email) -> bool: returnsfalsewhen the course is full or the email is already a student; otherwise adds the email and returnstrue.remove_student(email) -> bool: removes a current student,falseif the email is not one.mark_completed(email) -> bool: moves a current student tocompleted_emails,falseif the email is not a current student.assign_instructor(instructor) -> bool: stores the instructor's name, or returnsfalsewhen the course already has one._to_string()returnsTITLE: N/CAPACITY students, M completed, instructor: NAME, withnonewhen there is no instructor.
Student in student.gd extends Person and keeps its constructor. It has two Array[String] of titles, enrolled and completed:
enroll(course: Course) -> bool:falsewhen the course is already inenrolledorcompleted, or whencourse.add_student()refuses; otherwise adds the title and returnstrue.unenroll(course: Course) -> bool: only for an enrolled course; removes the student from the course and the title fromenrolled.complete_course(course: Course) -> bool: only for an enrolled course; callscourse.mark_completed()and moves the title fromenrolledtocompleted._to_string()returnsStudent, the text ofPerson, then: N enrolled, M completed.
Instructor in instructor.gd extends Person. Its constructor takes person_name, email and expertise, and it keeps an Array[String] course_titles:
assign_to_course(course: Course) -> bool: callscourse.assign_instructor()with its name; on success adds the title and returnstrue._to_string()returnsInstructor, the text ofPerson,, EXPERTISE:and the titles joined with,, orno courses.
The supplied code reads commands with fields separated by | and connects to course_full to print Course full: TITLE. For this input:
course Python 101|2
course Data Science
student Ana|ana@mail.com
student Ben|ben@mail.com
instructor Grace Hopper|grace@mail.com|Compilers
enroll ana@mail.com|Python 101
enroll ben@mail.com|Python 101
enroll ben@mail.com|Data Science
assign grace@mail.com|Python 101
reportthe output is:
Enroll Ana in Python 101: true
Course full: Python 101
Enroll Ben in Python 101: true
Enroll Ben in Data Science: true
Assign Grace Hopper to Python 101: true
Python 101: 2/2 students, 0 completed, instructor: Grace Hopper
Data Science: 1/30 students, 0 completed, instructor: none
Student Ana (ana@mail.com): 1 enrolled, 0 completed
Student Ben (ben@mail.com): 2 enrolled, 0 completed
Instructor Grace Hopper (grace@mail.com), Compilers: Python 101Your code goes in person.gd, course.gd, student.gd and instructor.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 courses := {}
var people := {}
var line := OS.read_string_from_stdin()
while line != "":
var parts := line.split(" ", true, 1)
var f: PackedStringArray = parts[1].split("|") if parts.size() > 1 else PackedStringArray()
match parts[0]:
"course":
var course: Course
if f.size() > 1:
course = Course.new(f[0], int(f[1]))
else:
course = Course.new(f[0])
course.course_full.connect(func(title): print("Course full: ", title))
courses[f[0]] = course
"student":
people[f[1]] = Student.new(f[0], f[1])
"instructor":
people[f[1]] = Instructor.new(f[0], f[1], f[2])
"enroll":
var ok: bool = people[f[0]].enroll(courses[f[1]])
print("Enroll ", people[f[0]].person_name, " in ", f[1], ": ", ok)
"unenroll":
var ok: bool = people[f[0]].unenroll(courses[f[1]])
print("Unenroll ", people[f[0]].person_name, " from ", f[1], ": ", ok)
"complete":
var ok: bool = people[f[0]].complete_course(courses[f[1]])
print(people[f[0]].person_name, " completes ", f[1], ": ", ok)
"assign":
var ok: bool = people[f[0]].assign_to_course(courses[f[1]])
print("Assign ", people[f[0]].person_name, " to ", f[1], ": ", ok)
"report":
for title in courses:
print(courses[title])
for email in people:
print(people[email])
line = OS.read_string_from_stdin()
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