المسارات
/
Swift
Swift
/
التمارين
/
خبير خلط المشروبات
خبير خلط المشروبات

خبير خلط المشروبات

تمرين تعلّمي

مقدمة

جملة switch

تتيح لك جملة switch مقارنة قيمة بعدة قيم محتملة قد تطابقها. وهي تتيح لك كتابة كود أكثر إيجازًا من استخدام عدة عبارات else-if. تبدأ جملة switch بالكلمة المفتاحية switch متبوعة بالقيمة المراد مقارنتها. ثم يمكنك تعريف الحالات باستخدام الكلمة المفتاحية case متبوعة بالقيمة التي ستُقارن بها. وتُستخدم الكلمة المفتاحية default لتعريف الحالة الافتراضية عندما لا تطابق أي من الحالات. ومثل عبارات else-if، لا تنفّذ جمل switch إلا كتلة الكود المرتبطة بأول حالة مطابقة.

switch value {
case 1:
    print("One")
case 2:
    print("Two")
default:
    print("Other")
}

تأمّل المثال التالي:

if str == "apple" {
    print("Let's bake an apple crumble")
} else if str == "lemon" {
    print("Let's bake a lemon meringue pie!")
} else if str == "peach" {
    print("Let's bake a peach pie!")
} else {
    print("Let's buy ice cream.")
}

يمكن بدلًا من ذلك كتابته هكذا:

switch str {
case "apple":
    print("Let's bake an apple crumble")
case "lemon":
    print("Let's bake a lemon meringue pie!")
case "peach":
    print("Let's bake a peach pie!")
default:
    print("Let's buy ice cream.")
}

حلقات while

حلقة while عبارة تحكّم في مسار التنفيذ تتيح تنفيذ الكود ما دام شرط معيّن صحيحًا. يوفّر Swift نوعين من حلقات while: حلقة while وحلقة repeat-while. يُقيَّم شرط حلقة while قبل تنفيذ جسم الحلقة؛ فإذا كان الشرط خطأ، فلن يُنفَّذ جسم الحلقة إطلاقًا. تكون بنية حلقات while في Swift على النحو التالي:

while <#condition#> {
  <#code#>
}

هنا ستستمر الحلقة في التنفيذ ما دام count أكبر من 0، وستطبع بذلك العددين 2 و1 ثم "Liftoff!".

var count = 2
while count > 0 {
  print("\(count)…")
  count -= 1
}
print("Liftoff!")

// prints:
// 2…
// 1…
// Liftoff!

حلقة repeat-while تشبه حلقة while، لكن الشرط يُقيَّم بعد تنفيذ جسم الحلقة. وهذا يعني أن جسم الحلقة سيُنفَّذ مرة واحدة على الأقل دائمًا، حتى لو كان الشرط خطأ. تكون بنية حلقات repeat-while في Swift على النحو التالي:

repeat {
  <#code#>
} while <#condition#>

هنا ستُنفَّذ الحلقة مرة واحدة فقط، لأن الشرط خطأ. ولأنها حلقة repeat-while، سيُنفَّذ جسم الحلقة مرة واحدة قبل تقييم الشرط.

var count = 2
repeat {
  print("\(count)…")
} while count < 0
print("Liftoff!")

نقل التحكّم

يمتلك Swift مجموعة من العبارات التي يمكن استخدامها لتغيير مسار التحكّم الطبيعي للحلقات. تُعرف هذه بعبارات نقل التحكّم. لقد رأيت return من قبل؛ وسيعرّفك هذا المفهوم بعبارات أخرى، منها continue وbreak والتسميات. لن نتناول fallthrough في هذا المفهوم، لكن يمكنك القراءة عنه في كتاب Swift.

continue

أحيانًا يلزم الانتقال مبكرًا إلى التكرار التالي في الحلقة، دون إكمال بقية العبارات في التكرار الحالي من الحلقة. يمكن استخدام الكلمة المفتاحية continue لهذا الغرض. عند تنفيذ continue، تنتقل الحلقة إلى الفحص التالي لمعرفة ما إذا كان يمكن تشغيل التكرار التالي من الحلقة، أي while في حلقات while وrepeat-while، أو التحقق من وجود عنصر آخر في المتتالية في حلقات for-in.

count = 1
while count < 6 {
  count += 1
  if count == 4 { continue }
  print(count)
}

// prints:
// 2
// 3
// 5

break

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

for fruit in ["banana", "grapes", "apple", "strawberry", "kiwi", "lemon"] {
  if !fruit.count.isMultiple(of: 2) { break }
  print(fruit)
}

// prints:
// banana
// grapes

التسميات

عندما تكون الحلقات متداخلة، قد تحتاج أحيانًا إلى استخدام break أو continue للخروج من الحلقات الخارجية التي تحتوي الحلقة التي استُخدم فيها break أو continue، أو لإعادة تشغيلها. في حالات كهذه، يمكن استخدام التسميات لتحديد الحلقة المطلوب الخروج منها أو إعادة تشغيلها. يمكن تسمية الحلقة بوضع اسم متبوع بنقطتين قبل while أو repeat أو for التي تبدأ الحلقة.

لترى أثر استخدام التسميات بهذه الطريقة، تأمّل الحلقة التالية.

outerLoop: for fruit in ["banana", "grapes", "apple", "strawberry", "kiwi", "lemon"] {
  print("\n--- \(fruit) ---")
  for letter in fruit {
    guard letter != "n" else { break outerLoop }
    print(letter)
  }
}

// prints:
// --- banana ---
// b
// a

التعليمات

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

1. تحديد المدة التي يستغرقها تحضير طلب

تستغرق المشروبات المختلفة أوقاتًا مختلفة في التحضير:

  • يستغرق كل من "beer" و"soda" و"water" ‏0.5 دقيقة.
  • تستغرق "shot" ‏1.0 دقيقة، وتستغرق "mixed drink" ‏1.5 دقيقة،
  • تستغرق "fancy drink" ‏2.5 دقيقة،
  • تستغرق "frozen drink" ‏3.0 دقيقة.

نفّذ الدالة timeToPrepare(drinks:)، التي تأخذ الوسيط drinks الذي يحمل مصفوفة من السلاسل النصية تمثّل المشروبات التي يجب تحضيرها. يجب أن تُرجع الدالة الوقت الإجمالي اللازم لتحضير كل المشروبات في المصفوفة.

timeToPrepare(drinks: ["beer", "frozen drink", "shot"])
// returns 4.5

2. إعادة تعبئة مخزونك من شرائح الليمون

من أول الأشياء التي عليك فعلها عند بدء نوبتك أن تتأكد من امتلاء علبتك الصغيرة بشرائح الليمون استعدادًا للنوبة القادمة. ستحصل على أحجام مختلفة من الليمون تعطي عددًا مختلفًا من الشرائح، فيمكنك الحصول على 6 شرائح من ليمونة "small"، و8 شرائح من ليمونة "medium"، و10 من ليمونة "large".

طالما أنك ما زلت بحاجة إلى مزيد من الشرائح وما زال لديك مزيد من الليمون لتقطيعه، خذ أول ليمونة من المصفوفة، واطرح العدد المناسب من الشرائح من الكمية التي تحتاجها. استمر في ذلك حتى لا تعود بحاجة إلى أي شرائح أخرى أو تنفد الليمونات لديك.

نفّذ الدالة makeWedges(needed:limes:)، التي تأخذ الوسيطين needed الذي يحمل عدد الشرائح التي تحتاج إلى تقطيعها، وlimes الذي يحمل مصفوفة من السلاسل النصية تمثّل أحجام الليمون المتاحة لديك لتقطيعها. يجب أن تُرجع الدالة عدد الليمونات التي قطّعتها.

makeWedges(needed: 25, limes: ["small", "small", "large", "medium", "small"])
// returns 4

3. إنهاء نوبتك

تهانينا! يوم عملك الطويل أوشك على الانتهاء، وستعود قريبًا إلى المنزل للعمل على تطبيقك الجديد. لكن لا يزال أمامك سيل من طلبات المشروبات لتجهيزها قبل أن تسلّم الطلبات إلى النوبة التالية وتغادر.

طالما لا يزال لديك وقت متبقٍ في نوبتك، عليك تجهيز أول طلب في المصفوفة ثم إزالة ذلك الطلب من المصفوفة. يمكنك بعد ذلك طرح مقدار الوقت الذي استغرقه تحضير ذلك الطلب، وفقًا لدالتك timeToPrepare(drinks:)، من الوقت المتبقي في نوبتك.

نفّذ الدالة finishShift(minutesLeft:remainingOrders:) التي تأخذ عدد الدقائق المتبقية في نوبتك (المضمون أن تكون أكبر من 0)، ومصفوفة غير فارغة من طلبات المشروبات. يجب أن تُرجع الدالة مصفوفة الطلبات التي لم تتمكن من تجهيزها قبل نهاية نوبتك.

finishShift(minutesLeft: 5, remainingOrders: [["beer", "frozen drink", "shot"], ["fancy drink", "soda"], ["beer", "beer", "water"], ["mixed drink", "frozen drink"]])
// returns [["beer", "beer", "water"], ["mixed drink", "frozen drink"]]

4. تتبّع طلبات معينة

للتأكد من بقاء البيرة والصودا طازجتين، عليك تتبّع طلباتهما مع أوقات تقديم تلك الطلبات.

نفّذ الدالة orderTracker(orders: [(drink: String, time: String)]) -> (beer: (first: String, last: String, total: Int)?, soda: (first: String, last: String, total: Int)?) التي، عند إعطائها قائمة من الطلبات والأوقات، تُرجع زوجًا من الصفوف الاختيارية يحتوي على أوقات أول وآخر طلبَي بيرة وصودا، مع العدد الإجمالي لطلبات كل منهما، وnil إذا لم تُقدَّم أي طلبات لتلك المشروبات. ولا تحتاج إلى تتبّع أي مشروبات أخرى.

نفّذ الدالة orderTracker(orders:) التي تأخذ مصفوفة من الصفوف، حيث يحمل كل صف المشروب المطلوب والوقت الذي قُدّم فيه الطلب. يجب أن تُرجع الدالة صفًا يحتوي على أول وآخر وقت طُلبت فيه البيرة، والعدد الإجمالي لطلبات البيرة، وأول وآخر وقت طُلبت فيه الصودا، والعدد الإجمالي لطلبات الصودا. ويجب أن يكون المُرجَع صفًا بالصيغة التالية: (beer: (first: String, last: String, total: Int)?, soda: (first: String, last: String, total: Int)?).

let orders = [
    (drink: "beer", time: "10:01"), (drink: "frozen drink", time: "10:02"),
    (drink: "shot", time: "10:05"), (drink: "fancy drink", time: "10:06"),
    (drink: "soda", time: "10:09"), (drink: "beer", time: "10:15"), (drink: "beer", time: "10:22"),
    (drink: "water", time: "10:26"), (drink: "mixed drink", time: "10:28"),
    (drink: "frozen drink", time: "10:33"),
]

orderTracker(orders: orders)

// returns (beer: (first "10:01", last "10:22", total 3), soda: (first "10:09", last "10:09", total 1))
تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة
Swift Exercism

مستعد لبدء خبير خلط المشروبات؟

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