Menu
CoddyTech

回顾:学生记录系统

本课属于 Coddy GDScript 学习旅程的“面向对象编程”单元。第 30 课,共 65 课。

challenge icon

挑战

中等

用两个类构建一个小型学生记录系统。

Student 在 student.gd 中保存其私有数据:

  • _init(id, new_name) 将 ID 存储在私有变量中,并通过 student_name setter 设置姓名。
  • student_id 是只读的,会返回 ID。
  • student_name 有一个 setter:如果姓名少于 2 个字符,就会被拒绝(旧姓名保持不变),并且 last_error 会变为 Name must be at least 2 characters。有效姓名会清空 last_error。
  • add_grade(course, grade) 会将课程成绩存储在私有字典中(同一门课程的新成绩会替换旧成绩),并返回 true。低于 0 或高于 100 的成绩不会被存储,并会返回 false。
  • average 是只读的计算属性:返回成绩的平均值,类型为 float;没有成绩时返回 0.0。
  • course_count() 返回有成绩的课程数量。

StudentRegistry 在 student_registry.gd 中将学生存储在私有字典中,并以 ID 作为键:

  • add_student(student) 在 ID 已被占用时返回 false,且不做任何更改;否则存储该学生并返回 true。
  • remove_student(id) 返回是否移除了学生。
  • get_student(id) 返回该学生,若没有则返回 null。
  • top_student() 返回平均成绩最高的学生(平均成绩并列时返回先添加的学生);注册表为空时返回 null。
  • get_ids() 按学生添加的顺序返回 ID。

提供的代码会读取命令数量,然后逐行运行一条命令:add ID NAME、grade ID COURSE GRADE、rename ID NAME、remove ID、show ID、tamper ID(尝试覆盖 student_id 和 average,它们必须保持不变)、top 和 list。对于以下输入:

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
list

输出为:

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.00

请将代码写入 student.gd 和 student_registry.gd。main.gd 包含提供的输入/输出代码,不能编辑。

亲手试试

extends Node

func _ready():
	# 提供的输入输出代码:保持原样
	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":
			# 尝试覆盖只读属性
			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])

面向对象编程中的所有课

自己练习: GDScript 在线编译器