المسارات
/
Elixir
Elixir
/
التمارين
/
سيارة التحكم عن بُعد
سيارة التحكم عن بُعد

سيارة التحكم عن بُعد

تمرين تعلّمي

مقدمة

البُنى

البنى امتداد مبني فوق الخرائط، وهي توفر فحوصات وقت الترجمة وقيمًا افتراضية. تُسمّى البنية على اسم الوحدة التي عُرّفت فيها. لتعريف بنية، استخدم التركيب defstruct. غالبًا ما يأتي هذا التركيب مباشرةً بعد تعريف الوحدة. يقبل defstruct إما قائمة من الذرات (لقيم افتراضية nil) أو قائمة كلمات مفتاحية (لقيم افتراضية محددة). يجب أن تأتي الحقول بدون قيم افتراضية قبل الحقول ذات القيم الافتراضية.

defmodule Plane do
  defstruct [:engine, wings: 2]
end

plane = %Plane{}
# => %Plane{engine: nil, wings: 2}

الوصول إلى الحقول وتحديثها

بما أن البُنى مبنية على الخرائط، يمكننا استخدام معظم دوال الخرائط للحصول على القيم والتعامل معها. لا تُنفَّذ Access Behaviour للبنى. يوصى باستخدام عامل الوصول الساكن . للوصول إلى حقول البنية بدلًا من ذلك.

  • جلب/استرجاع قيم الحقول:

    plane = %Plane{}
    plane.engine
    # => nil
    Map.fetch(plane, :wings)
    # => {:ok, 2}
    
  • تحديث قيم الحقول

    plane = %Plane{}
    %{plane | wings: 4}
    # => %Plane{engine: nil, wings: 4}
    

مطابقة الأنماط

يمكن استخدام البُنى في مطابقة الأنماط مع اسم البنية أو بدونه.

plane = %Plane{}
%Plane{wings: wings} = plane
%{wings: wings} = plane

بتضمين اسم البنية في النمط، يمكنك التأكد من أن كلا الجانبين الأيسر والأيمن بنيتان من النوع نفسه.

defmodule Helicopter do
  defstruct [:engine, rotors: 1]
end

%Plane{} = %Helicopter{}
# => (MatchError) no match of right hand side value: %Helicopter{engine: nil, rotors: 1}

فرض تهيئة قيم الحقول

يمكننا استخدام سمة الوحدة @enforce_keys مع قائمة مفاتيح الحقول لضمان تهيئة القيم عند إنشاء البنية. إذا لم يُدرج مفتاح، فستكون قيمته nil كما في المثال أعلاه. إذا لم تتم تهيئة مفتاح مفروض، فسيُرفَع خطأ.

defmodule User do
  @enforce_keys [:username]
  defstruct [:username]
end

%User{}
# => (ArgumentError) the following keys must also be given when building struct User: [:username]

التعليمات

في هذا التمرين ستلعب بسيارة يتم التحكم فيها عن بُعد، وقد ادّخرت أخيرًا ما يكفي من المال لشرائها.

تبدأ السيارات ببطارية ممتلئة بالكامل (100%). في كل مرة تقود السيارة باستخدام جهاز التحكم عن بُعد، تقطع 20 مترًا وتستهلك واحدًا بالمئة من البطارية. ولا يُعرف لقب السيارة إلا عند إنشائها.

تحتوي السيارة التي يتم التحكم فيها عن بُعد على شاشة LED أنيقة تعرض معلومتين:

  • المسافة الإجمالية التي قطعتها، معروضة على النحو التالي: "<METERS> meters".
  • شحن البطارية المتبقي، معروض على النحو التالي: "Battery at <PERCENTAGE>%".

إذا كانت البطارية عند 0%، فلن تتمكن من قيادة السيارة بعد الآن، وستعرض شاشة البطارية "Battery empty".

1. إنشاء سيارة جديدة تمامًا يتم التحكم فيها عن بُعد

نفّذ الدالة RemoteControlCar.new/0 بحيث تُرجع struct سيارة جديدة تمامًا يتم التحكم فيها عن بُعد:

RemoteControlCar.new()
# => %RemoteControlCar{
#      battery_percentage: 100,
#      distance_driven_in_meters: 0,
#      nickname: "none"
#    }

اللقب مطلوب في struct، فتأكد من تهيئة قيمة له في الدالة new، وليس في struct.

2. إنشاء سيارة جديدة تمامًا يتم التحكم فيها عن بُعد مع لقب

نفّذ الدالة RemoteControlCar.new/1 بحيث تُرجع struct سيارة جديدة تمامًا يتم التحكم فيها عن بُعد مع لقب مُحدَّد:

RemoteControlCar.new("Blue")
# => %RemoteControlCar{
#      battery_percentage: 100,
#      distance_driven_in_meters: 0,
#      nickname: "Blue"
#    }

3. عرض المسافة

نفّذ الدالة RemoteControlCar.display_distance/1 لإرجاع المسافة كما تُعرض على شاشة LED:

car = RemoteControlCar.new()
RemoteControlCar.display_distance(car)
# => "0 meters"

تأكد من أن الدالة لا تقبل سوى struct من نوع RemoteControlCar كوسيط.

4. عرض نسبة شحن البطارية

نفّذ الدالة RemoteControlCar.display_battery/1 لإرجاع نسبة شحن البطارية كما تُعرض على شاشة LED:

car = RemoteControlCar.new()
RemoteControlCar.display_battery(car)
# => "Battery at 100%"

تأكد من أن الدالة لا تقبل سوى struct من نوع RemoteControlCar كوسيط. وإذا كانت البطارية عند 0%، فستعرض شاشة البطارية "Battery empty".

5. القيادة تغيّر البطارية والمسافة المقطوعة

نفّذ الدالة RemoteControlCar.drive/1 التي:

  • تزيد عدد الأمتار المقطوعة بمقدار 20
  • تستهلك 1% من البطارية
RemoteControlCar.new("Red")
|> RemoteControlCar.drive()

# => %RemoteControlCar{
#      battery_percentage: 99,
#      distance_driven_in_meters: 20,
#      nickname: "Red"
#    }

تأكد من أن الدالة لا تقبل سوى struct من نوع RemoteControlCar كوسيط.

6. مراعاة القيادة ببطارية فارغة

حدّث الدالة RemoteControlCar.drive/1 بحيث لا تزيد المسافة المقطوعة ولا تنقص نسبة شحن البطارية عندما تكون البطارية فارغة (عند 0%):

%RemoteControlCar{
  battery_percentage: 0,
  distance_driven_in_meters: 1980,
  nickname: "Red"
}
|> RemoteControlCar.drive()

# => %RemoteControlCar{
#      battery_percentage: 0,
#      distance_driven_in_meters: 1980,
#      nickname: "Red"
#    }
تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة
Elixir Exercism

مستعد لبدء سيارة التحكم عن بُعد؟

سجّل في Exercism لتتعلّم وتتقن Elixir عبر 58 مفهومًا168 تمرينًا، وإرشاد بشري حقيقي، وكل ذلك مجانًا.