Menu
CoddyTech
flag Ar iconالعربيةdown icon

المكررات المخصصة

جزء من قسم البرمجة كائنية التوجّه في رحلة 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 عبر الإنترنت