Menu
CoddyTech

E-learning Platform

Part of the Object Oriented Programming section of Coddy's GDScript journey. Lesson 62 of 65.

challenge icon

Challenge

Hard

Build 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 the Array[String] student_emails and completed_emails.
  • The constructor takes the title and the capacity, which defaults to 30.
  • A signal course_full(title: String), emitted by add_student() when it takes the last free seat.
  • add_student(email) -> bool: returns false when the course is full or the email is already a student; otherwise adds the email and returns true.
  • remove_student(email) -> bool: removes a current student, false if the email is not one.
  • mark_completed(email) -> bool: moves a current student to completed_emails, false if the email is not a current student.
  • assign_instructor(instructor) -> bool: stores the instructor's name, or returns false when the course already has one.
  • _to_string() returns TITLE: N/CAPACITY students, M completed, instructor: NAME, with none when 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: false when the course is already in enrolled or completed, or when course.add_student() refuses; otherwise adds the title and returns true.
  • unenroll(course: Course) -> bool: only for an enrolled course; removes the student from the course and the title from enrolled.
  • complete_course(course: Course) -> bool: only for an enrolled course; calls course.mark_completed() and moves the title from enrolled to completed.
  • _to_string() returns Student , the text of Person, 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: calls course.assign_instructor() with its name; on success adds the title and returns true.
  • _to_string() returns Instructor , the text of Person, , EXPERTISE: and the titles joined with , , or no 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
report

the 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 101

Your 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

Practice on your own: Online GDScript compiler