Menu
CoddyTech

איטרטורים מותאמים אישית

חלק מהיחידה תכנות מונחה עצמים במסלול ה-GDScript של Coddy. שיעור 33 מתוך 65.

Python מאפשרת למחלקה להתנהג כמו רשימה באמצעות שיטות קסם כגון __len__, __getitem__, __contains__ ו-__iter__. ל-Godot יש שיטות וירטואליות רק לאחת מהמשימות האלה: לולאת for. שלוש שיטות מאפשרות ל-for item in my_object: לפעול:

  • _iter_init(iter) פועלת פעם אחת, לפני הסיבוב הראשון. היא קובעת את מיקום ההתחלה ומחזירה true אם יש איבר ראשון.
  • _iter_get(position) מחזירה את האיבר במיקום הנוכחי, ומשתנה הלולאה מקבל את הערך הזה.
  • _iter_next(iter) פועלת לפני כל סיבוב נוסף. היא עוברת למיקום הבא ומחזירה false כשלא נותרו איברים, ובכך מסיימת את הלולאה.
# team.gd
class_name Team
extends RefCounted

var _members: Array[String] = []

func add(member: String) -> void:
	_members.append(member)

func _iter_init(iter: Array) -> bool:
	iter[0] = 0
	return iter[0] < _members.size()

func _iter_next(iter: Array) -> bool:
	iter[0] += 1
	return iter[0] < _members.size()

func _iter_get(position):
	return _members[position]

iter הוא מערך עם תא אחד ש-Godot יוצר עבור כל לולאה. iter[0] מכיל את המיקום של אותה לולאה, ו-Godot מעביר את הערך שלו אל _iter_get(). עכשיו Team פועל בלולאת for:

var team := Team.new()
team.add("Ada")
team.add("Bo")
for member in team:
	print(member) # Ada, ואז Bo

שמור את המיקום בתוך iter[0], ולא במשתנה חבר כגון _position. לכל לולאה יש iter משלה, ולכן שתי לולאות שעוברות על אותה קבוצה, אפילו כשאחת מקוננת בתוך השנייה, אינן מפריעות זו לזו. עם משתנה חבר, הלולאה הפנימית הייתה מזיזה את המיקום של הלולאה החיצונית.

לפעולות האחרות של רשימה אין מתודה וירטואלית: len(team) ו־team[0] הן שגיאות. כתבו מתודות רגילות בשמות כמו אלה של Array, כגון size(), get_at(index) ו־has(member). אל תבדקו חברות באמצעות in: "Ada" in team בודק אם ל־Team יש מאפיין או מתודה בשם Ada, ולכן התוצאה היא false.

challenge icon

אתגר

קל

כתבו את המחלקה Bookshelf בקובץ bookshelf.gd. היא שומרת את הכותרים ב־_titles ומחזיקה לכל היותר _capacity ספרים:

  • add(title) מוסיפה את הכותר ומחזירה true, או מחזירה false בלי להוסיף אותו כאשר המדף מלא או שהכותר כבר נמצא בו.
  • size() מחזירה את מספר הספרים, ו־has(title) מחזירה אם הכותר נמצא במדף.
  • get_at(index) מחזירה את הכותר שנמצא באינדקס הזה, או מחרוזת ריקה כשהאינדקס מחוץ לטווח המדף.
  • _iter_init(), _iter_next() ו־_iter_get() מאפשרות ללולאת for לעבור על הכותרים לפי סדר הוספתם.

הקוד שסופק קורא את הקיבולת, את מספר הכותרים וכותר אחד בכל שורה, ומדווח על הכותרים שלא הצליח להוסיף. הוא מדפיס את מספר הספרים, מציג אותם באמצעות לולאת for שעוברת על המדף, ואז קורא כותר נוסף ומדפיס אם הוא נמצא במדף ואת הספר האחרון. עבור קיבולת 3, הכותרים Dune, Emma, Dune, Ulysses, Hamlet והחיפוש Emma, הפלט הוא:

Could not add: Dune
Could not add: Hamlet
Books: 3
1. Dune
2. Emma
3. Ulysses
Has Emma: true
Last: Ulysses

כתבו את הקוד שלכם בקובץ bookshelf.gd. הקובץ main.gd מכיל את קוד הקלט/פלט שסופק ואי אפשר לערוך אותו.

נסו בעצמכם

extends Node

func _ready():
	# קוד הקלט/פלט שסופק: יש להשאיר אותו כפי שהוא
	var shelf := Bookshelf.new(int(OS.read_string_from_stdin()))
	var count := int(OS.read_string_from_stdin())
	for i in count:
		var title := OS.read_string_from_stdin()
		if not shelf.add(title):
			print("Could not add: " + title)
	print("Books: %d" % shelf.size())
	var number := 1
	for title in shelf:
		print("%d. %s" % [number, title])
		number += 1
	var query := OS.read_string_from_stdin()
	print("Has %s: %s" % [query, shelf.has(query)])
	print("Last: " + shelf.get_at(shelf.size() - 1))
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר GDScript אונליין