الكلية الجامعية للعلوم التطبيقيةبرمجة 1
English
المحاضرة 9 · 100 دقيقة

حلقات while

كيف يكرّر البرنامج عملًا دون أن نكرّر كتابته؟

في نهاية هذه المحاضرة ستكون قادرًا على

  1. تكتب حلقة while بأجزائها الثلاثة: التهيئة والشرط والتحديث
  2. تتتبّع تكرارات الحلقة في جدول وباستخدام المتتبّع
  3. تستخدم العدّاد والمجموع التراكمي لحساب المجاميع والمعدلات
  4. تكتشف الحلقة اللانهائية وخطأ الفرق بواحد وتصلحهما
  5. تقرأ مدخلات حتى قيمة حارسة، وتتحقق من صحة المدخلات باستخدام do-while
  6. تحلّ مسائل أرقام العدد، ولعبة التخمين، والمضروب بالحلقات
محتويات المحاضرة
  1. طباعة الأعداد من 1 إلى 100 يدويًا تعني كتابة 100 سطر
  2. لكل حلقة while ثلاثة أجزاء: التهيئة والشرط والتحديث
  3. جدول التتبّع يسجّل ما يحدث في كل دورة
  4. المتتبّع يريك الحلقة وهي تدور سطرًا بعد سطر
  5. العدّاد يزيد بواحد، والمجموع التراكمي يضيف قيمة جديدة
  6. المعدل هو المجموع التراكمي مقسومًا على العدّاد، بعد التحويل إلى double
  7. الحلقة التي لا يصبح شرطها false لا تنتهي، وزر «إيقاف» ينهيها
  8. خطأ الفرق بواحد: الحلقة تزيد دورة أو تنقص دورة
  9. القيمة الحارسة تخبر الحلقة بأن المدخلات انتهت
  10. do-while تنفّذ الجسم مرة أولًا، ثم تفحص الشرط
  11. do-while تناسب التحقق من المدخلات: اسأل، ثم أعد السؤال إذا كانت الإجابة خاطئة
  12. % 10 تعطي آخر رقم، و/ 10 تحذفه
  13. الفكرة نفسها تعكس العدد وتعدّ أرقامه
  14. لعبة التخمين تجمع الحلقة والشرط والعدّاد
  15. المضروب يبدأ من 1، لأن الضرب في 0 يمحو كل شيء
  16. أسئلة المراجعة
الجزء الأول: تشريح الحلقة وتتبّعها

طباعة الأعداد من 1 إلى 100 يدويًا تعني كتابة 100 سطر

ما نعرفه حتى الآن ينفّذ كل سطر مرة واحدة على الأكثر. فإذا أردنا طباعة الأعداد من 1 إلى 100 احتجنا إلى 100 أمر println متشابه، وأي تعديل صغير يعني تعديل 100 سطر. الحلقة تحلّ هذه المشكلة: نكتب العمل مرة واحدة، ونقول متى يتوقف.

خمسة أسطر بدل مئة

شغّل البرنامج ولاحظ الناتج، ثم غيّر 100 إلى 20 وشغّله مجددًا.

public class OneToHundred {
    public static void main(String[] args) {
        int number = 1;
        while (number <= 100) {
            System.out.println(number);
            number++;
        }
    }
}
الناتج
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

لكل حلقة while ثلاثة أجزاء: التهيئة والشرط والتحديث

التهيئة

تعطي متغير الحلقة قيمته الأولى قبل أن تبدأ الحلقة، وتُنفَّذ مرة واحدة.

int count = 1;
الشرط

يُفحص قبل كل دورة: إذا كان true نُفّذ الجسم، وإذا كان false انتهت الحلقة.

while (count <= 3)
التحديث

يغيّر متغير الحلقة داخل الجسم، فيقترب الشرط من أن يصبح false.

count++;

الأجزاء الثلاثة في برنامج واحد

توقّع الناتج قبل التشغيل. ثم غيّر التحديث إلى count += 2، واشرح لزميلك سبب تغيّر الناتج.

public class CountToThree {
    public static void main(String[] args) {
        int count = 1;                     // initialise
        while (count <= 3) {               // test
            System.out.println(count);
            count++;                       // update
        }
        System.out.println("Done");
    }
}
الناتج
1
2
3
Done

الشرط يُفحص قبل الدورة الأولى أيضًا. ماذا يطبع البرنامج؟

public class NeverRuns {
    public static void main(String[] args) {
        int count = 10;
        while (count < 5) {
            System.out.println(count);
            count++;
        }
        System.out.println("Done");
    }
}
أظهر الناتج
الناتج
Done

لماذا؟ الشرط 10 < 5 قيمته false من البداية، فلا يُنفَّذ الجسم ولا مرة، وينتقل البرنامج مباشرة إلى ما بعد الحلقة.

الشرط قيمته true أو false

أردنا طباعة 0 و1 و2، لكن المترجم يرفض الشرط. أصلحه.

public class TestType {
    public static void main(String[] args) {
        int count = 0;
        while (count = 3) {
            System.out.println(count);
            count++;
        }
    }
}
رسالة المترجمincompatible types: int cannot be converted to boolean
أظهر التصحيح
public class TestType {
    public static void main(String[] args) {
        int count = 0;
        while (count < 3) {
            System.out.println(count);
            count++;
        }
    }
}
الناتج
0
1
2

لماذا؟ العلامة = إسناد، فقيمة count = 3 هي العدد 3 وليست true أو false، والحلقة تحتاج إلى شرط منطقي مثل count < 3.

جدول التتبّع يسجّل ما يحدث في كل دورة

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

الدورةcount عند الفحصcount <= 3يطبعcount بعد التحديث
11true12
22true23
33true34
تنتهي4falseلا شيءلا يتغير

املأ جدول التتبّع. ماذا يطبع البرنامج؟

public class TraceByThree {
    public static void main(String[] args) {
        int i = 2;
        while (i < 12) {
            System.out.println(i);
            i += 3;
        }
        System.out.println("End: " + i);
    }
}
أظهر الناتج
الناتج
2
5
8
11
End: 14

لماذا؟ تزيد i بمقدار 3 في كل دورة: 2 ثم 5 ثم 8 ثم 11. وبعد طباعة 11 تصبح 14، فيصبح الشرط false وتطبع السطر الأخير.

المتتبّع يريك الحلقة وهي تدور سطرًا بعد سطر

  1. اضغط «تتبّع سطرًا سطرًا»يتوقف البرنامج عند أول سطر ويظلّله. السطر المظلل لم يُنفَّذ بعد.
  2. اضغط «السطر التالي» أو F8قبل كل ضغطة، قل بصوت عالٍ أي سطر سيُنفَّذ بعده.
  3. راقب الصندوقيظهر الصندوق count ثم تتغير قيمته عند سطر التحديث.
  4. راقب القفزةبعد آخر سطر في الجسم يرجع التظليل إلى سطر while، وهنا تحدث الحلقة حقًا.

تتبّع العدّ التنازلي

تتبّع البرنامج حتى نهايته، وعدّ المرات التي يتوقف فيها التظليل عند سطر while. ثم غيّر 3 إلى 5 وتوقّع العدد الجديد قبل أن تتتبّعه.

public class Countdown {
    public static void main(String[] args) {
        int count = 3;
        while (count > 0) {
            System.out.println(count);
            count--;
        }
        System.out.println("Go!");
    }
}
الناتج
3
2
1
Go!

جدول على الورق، ثم المتتبّع

املأ جدولًا لـ total وsteps على الورق أولًا، ثم تتبّع البرنامج وقارن كل صف بما تراه في الصناديق. أين يختلف جدولك عن المتتبّع؟

public class Doubling {
    public static void main(String[] args) {
        int total = 1;
        int steps = 0;
        while (total < 50) {
            total = total * 2;
            steps++;
        }
        System.out.println("total = " + total);
        System.out.println("steps = " + steps);
    }
}
الناتج
total = 64
steps = 6

حلقة تنفّذ جسمها 5 مرات ثم تنتهي بصورة طبيعية. كم مرة فُحص شرطها؟

الجزء الثاني: العدّادات والأخطاء الشائعة

العدّاد يزيد بواحد، والمجموع التراكمي يضيف قيمة جديدة

number4int
sum6int

هذه الصناديق تصف البرنامج أدناه لحظة بدء الدورة الرابعة: جمعنا 1 و2 و3 فصار المجموع 6. يبدأ المجموع من 0، لأن إضافة 0 لا تغيّر شيئًا، ويتراكم داخل الحلقة بالأمر sum += number.

اجمع الأعداد من 1 إلى 10

تتبّع البرنامج وراقب sum في كل دورة. ثم انقل int sum = 0; إلى داخل الحلقة وتوقّع ما سيحدث: سيرفض المترجم آخر سطر، لأن sum لم يعد معروفًا خارج الحلقة.

public class RunningSum {
    public static void main(String[] args) {
        int number = 1;
        int sum = 0;
        while (number <= 10) {
            sum += number;
            number++;
        }
        System.out.println("Sum = " + sum);
    }
}
الناتج
Sum = 55

عدّاد لا يزيد في كل دورة: ماذا يطبع البرنامج؟

public class CountEvens {
    public static void main(String[] args) {
        int number = 1;
        int evens = 0;
        while (number <= 9) {
            if (number % 2 == 0) {
                evens++;
            }
            number++;
        }
        System.out.println(evens);
    }
}
أظهر الناتج
الناتج
4

لماذا؟ تدور الحلقة 9 مرات، لكن evens يزيد فقط عند 2 و4 و6 و8. أما number++ فخارج if ليتغير في كل دورة.

مجموع الأعداد حتى n

اقرأ عددًا صحيحًا n، ثم اطبع مجموع الأعداد من 1 إلى n. لا تطبع نصًا آخر. وإذا كان n يساوي 0 فالناتج 0.

import java.util.Scanner;

public class SumToN {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        // Add the numbers from 1 to n, then print the sum

    }
}
stdin
5
الناتج المتوقع
15
تلميح 1

تحتاج إلى متغيرين قبل الحلقة: عدّاد يبدأ من 1 ومجموع يبدأ من 0.

تلميح 2

شرط الحلقة counter <= n، فلا يدخل الجسم إذا كان n يساوي 0.

الحل
import java.util.Scanner;

public class SumToN {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        int counter = 1;
        int sum = 0;
        while (counter <= n) {
            sum += counter;
            counter++;
        }
        System.out.println(sum);
    }
}

المعدل هو المجموع التراكمي مقسومًا على العدّاد، بعد التحويل إلى double

معدل ثلاث علامات

هذا المختبر يقرأ مدخلات ثابتة هي 80 و90 و75. تتبّع البرنامج وراقب sum وcount معًا. ثم غيّر count < 3 إلى count < 2 وتوقّع المعدل الجديد.

import java.util.Scanner;

public class AverageThree {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int count = 0;
        int sum = 0;
        while (count < 3) {
            int grade = input.nextInt();
            sum += grade;
            count++;
        }
        double average = (double) sum / count;
        System.out.println("Sum: " + sum);
        System.out.println("Average: " + average);
    }
}
الناتج
Sum: 245
Average: 81.66666666666667

تذكّر قسمة الأعداد الصحيحة. ماذا يطبع كل سطر؟

public class AverageCast {
    public static void main(String[] args) {
        int sum = 7;
        int count = 2;
        double wrong = sum / count;
        double right = (double) sum / count;
        System.out.println(wrong);
        System.out.println(right);
    }
}
أظهر الناتج
الناتج
3.0
3.5

لماذا؟ في sum / count كلا الطرفين int، فتُحذف الكسور أولًا ثم تُخزَّن 3 على شكل 3.0. أما التحويل (double) فيتم قبل القسمة، فتبقى الكسور.

الحلقة التي لا يصبح شرطها false لا تنتهي، وزر «إيقاف» ينهيها

إذا نسيت سطر التحديث بقيت قيمة count كما هي، وبقي الشرط true إلى الأبد. هذه حلقة لا نهائية، وهي تحدث لكل مبرمج. لا تخف منها: في هذا الموقع يظهر زر «إيقاف» أثناء تشغيل البرنامج، فتنتهي الحلقة وتبقى الصفحة تعمل.

int count = 1;
while (count <= 5) {
    System.out.println(count);
}
حلقة لا نهائية: أين التحديث؟

اكتب حلقة لا نهائية عن قصد

هذا البرنامج ينتهي الآن. اكتب الجزء أعلاه داخل main بدل أسطرها الحالية، ثم اضغط «تشغيل»، وراقب الأعداد تتدفق، ثم اضغط «إيقاف». وبعدها اضغط «استعادة الأصل» لتعود إلى البرنامج الأصلي.

public class LoopPlayground {
    public static void main(String[] args) {
        int count = 1;
        while (count <= 5) {
            System.out.println(count);
            count++;
        }
    }
}
الناتج
1
2
3
4
5

سطر لن يصل إليه البرنامج أبدًا

المترجم يكتشف أحيانًا الحلقة اللانهائية بنفسه. أصلح البرنامج ليطبع Hi ثلاث مرات ثم Done.

public class Unreachable {
    public static void main(String[] args) {
        while (true) {
            System.out.println("Hi");
        }
        System.out.println("Done");
    }
}
رسالة المترجمunreachable statement
أظهر التصحيح
public class Unreachable {
    public static void main(String[] args) {
        int count = 0;
        while (count < 3) {
            System.out.println("Hi");
            count++;
        }
        System.out.println("Done");
    }
}
الناتج
Hi
Hi
Hi
Done

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

خطأ الفرق بواحد: الحلقة تزيد دورة أو تنقص دورة

هذا أشهر أخطاء الحلقات: يعمل البرنامج ولا يشتكي المترجم، لكن عدد الدورات يخطئ بواحد. والسبب غالبًا < بدل <=، أو قيمة بداية خاطئة.

البدايةالشرطالقيم داخل الجسمعدد الدورات
i = 1i <= 51 2 3 4 55
i = 1i < 51 2 3 44
i = 0i < 50 1 2 3 45
i = 0i <= 50 1 2 3 4 56

البرنامج يعمل لكنه مخطئ

المطلوب مجموع الأعداد من 1 إلى 5، وهو 15، لكن البرنامج يطبع 10. تتبّعه، واعرف الدورة الناقصة، ثم أصلح الشرط وتأكد أن الناتج صار 15.

public class OffByOne {
    public static void main(String[] args) {
        int i = 1;
        int sum = 0;
        while (i < 5) {
            sum += i;
            i++;
        }
        System.out.println(sum);
    }
}
الناتج
10

كم مرة يُنفَّذ جسم هذه الحلقة؟

int i = 0;
while (i <= 10) {
    i += 2;
}
int i = 1;
while (i <= 5);
{
    i++;
}
خطأ آخر: الفاصلة المنقوطة بعد الشرط تصنع حلقة صامتة لا نهائية. اكتب هذا الجزء داخل main في المختبر أعلاه بدل أسطرها الحالية، وستجد أن البرنامج لا يطبع شيئًا، وأن «إيقاف» هو طريق الخروج.
الجزء الثالث: المدخلات ومسائل الأرقام

القيمة الحارسة تخبر الحلقة بأن المدخلات انتهت

قد لا نعرف مسبقًا كم عددًا سيدخل المستخدم. الحل: نتفق على قيمة خاصة لا يمكن أن تكون بيانات حقيقية، مثل -1، تعني «انتهيت». هذه هي القيمة الحارسة (sentinel).

اكتب بنفسك

شغّل البرنامج وأدخل بعض الأعداد، ثم أدخل -1. جرّب إدخال -1 أولًا: ماذا يطبع؟

import java.util.Scanner;

public class SentinelSum {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int sum = 0;
        System.out.print("Number (-1 to stop): ");
        int number = input.nextInt();
        while (number != -1) {
            sum += number;
            System.out.print("Number (-1 to stop): ");
            number = input.nextInt();
        }
        System.out.println("Sum: " + sum);
    }
}

المدخلات هنا 4 ثم 10 ثم 6 ثم -1. هل تدخل -1 في المجموع أو في العدّ؟

import java.util.Scanner;

public class SentinelCount {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int sum = 0;
        int count = 0;
        int number = input.nextInt();
        while (number != -1) {
            sum += number;
            count++;
            number = input.nextInt();
        }
        System.out.println(count + " numbers, sum " + sum);
    }
}
أظهر الناتج
الناتج
3 numbers, sum 20

لماذا؟ عندما تُقرأ -1 يُفحص الشرط مباشرة فتنتهي الحلقة قبل أن تصل القيمة إلى sum أو count. لهذا كانت القراءة آخر سطر في الجسم.

معدل حتى القيمة الحارسة

اقرأ أعدادًا صحيحة حتى -1 دون طباعة رسائل طلب إدخال. اطبع Count: ثم عددها، وفي السطر التالي Average: ثم معدلها من النوع double. وإذا كان أول مدخل -1 فاطبع No numbers فقط.

import java.util.Scanner;

public class SentinelAverage {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        // Read until -1, keeping a sum and a count

    }
}
stdin
80
90
70
-1
الناتج المتوقع
Count: 3
Average: 80.0
تلميح 1

ابدأ من نمط البرنامج SentinelCount أعلاه.

تلميح 2

بعد الحلقة استخدم if (count == 0) حتى لا تقسم على صفر.

الحل
import java.util.Scanner;

public class SentinelAverage {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int sum = 0;
        int count = 0;
        int number = input.nextInt();
        while (number != -1) {
            sum += number;
            count++;
            number = input.nextInt();
        }
        if (count == 0) {
            System.out.println("No numbers");
        } else {
            double average = (double) sum / count;
            System.out.println("Count: " + count);
            System.out.println("Average: " + average);
        }
    }
}

do-while تنفّذ الجسم مرة أولًا، ثم تفحص الشرط

while: تفحص ثم تنفّذ

قد لا يُنفَّذ الجسم أبدًا.

while (test) {
    body;
}
do-while: تنفّذ ثم تفحص

يُنفَّذ الجسم مرة واحدة على الأقل. ولاحظ الفاصلة المنقوطة في النهاية.

do {
    body;
} while (test);

الشرط نفسه والبداية نفسها. ماذا يطبع البرنامج؟

public class WhileVsDo {
    public static void main(String[] args) {
        int a = 10;
        while (a < 5) {
            System.out.println("while " + a);
            a++;
        }
        int b = 10;
        do {
            System.out.println("do " + b);
            b++;
        } while (b < 5);
    }
}
أظهر الناتج
الناتج
do 10

لماذا؟ الشرط false في الحالتين. لكن while تفحص أولًا فلا تطبع شيئًا، وdo-while تنفّذ الجسم مرة ثم تفحص فتتوقف.

تتبّع الفرق

تتبّع البرنامج ولاحظ أن التظليل يدخل الجسم مباشرة، وأن سطر while يأتي في الأسفل. ثم غيّر البداية إلى n = 100 وتوقّع الناتج.

public class DoWhileTrace {
    public static void main(String[] args) {
        int n = 1;
        do {
            System.out.println(n);
            n = n * 3;
        } while (n < 20);
    }
}
الناتج
1
3
9

متغير لا يراه الشرط

صرّحنا عن n داخل الجسم، وسطر while يقع خارج القوسين. أصلح البرنامج ليطبع 3 ثم 2 ثم 1.

public class DoScope {
    public static void main(String[] args) {
        do {
            int n = 3;
            System.out.println(n);
            n--;
        } while (n > 0);
    }
}
رسالة المترجمcannot find symbol
أظهر التصحيح
public class DoScope {
    public static void main(String[] args) {
        int n = 3;
        do {
            System.out.println(n);
            n--;
        } while (n > 0);
    }
}
الناتج
3
2
1

لماذا؟ المتغير المصرَّح عنه داخل { } لا يوجد خارجهما، وسطر while في do-while يقع خارجهما. ونقل التصريح قبل do يصلح أيضًا خطأً ثانيًا: لو بقي داخل الجسم لعادت n إلى 3 في كل دورة.

do-while تناسب التحقق من المدخلات: اسأل، ثم أعد السؤال إذا كانت الإجابة خاطئة

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

حاول أن تخدع البرنامج

شغّل البرنامج وأدخل 150، ثم -3، ثم علامة صحيحة. جرّب الحدّين 0 و100 أيضًا. ثم بدّل || بـ && وتوقّع النتيجة: إن صار البرنامج يقبل كل شيء، فلماذا؟

import java.util.Scanner;

public class ValidateGrade {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int grade;
        do {
            System.out.print("Grade (0-100): ");
            grade = input.nextInt();
        } while (grade < 0 || grade > 100);
        System.out.println("Accepted: " + grade);
    }
}

نريد إعادة السؤال حتى يُدخل المستخدم عددًا موجبًا. ما الشرط الصحيح في while؟

تقييم من 1 إلى 5

اطبع Rating (1-5): باستخدام print واقرأ عددًا، وكرّر ذلك حتى يكون العدد بين 1 و5. ثم اطبع Thanks, you chose متبوعًا بالعدد. انتبه: ما تكتبه لا يظهر في ناتج الاختبار، لذلك تتجاور رسائل الطلب.

import java.util.Scanner;

public class ValidRating {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int rating;
        // Ask with a do-while loop until the rating is valid
        rating = 0;
        System.out.println("Thanks, you chose " + rating);
    }
}
stdin
9
0
4
الناتج المتوقع
Rating (1-5): Rating (1-5): Rating (1-5): Thanks, you chose 4
تلميح 1

احذف السطر rating = 0; واكتب مكانه الحلقة.

تلميح 2

الشرط يصف الرفض: rating < 1 || rating > 5.

الحل
import java.util.Scanner;

public class ValidRating {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int rating;
        do {
            System.out.print("Rating (1-5): ");
            rating = input.nextInt();
        } while (rating < 1 || rating > 5);
        System.out.println("Thanks, you chose " + rating);
    }
}

% 10 تعطي آخر رقم، و/ 10 تحذفه

هذان العاملان يفكّكان أي عدد: نأخذ آخر رقم، ثم نحذفه، ونكرر حتى يصير العدد 0. هذا جدول التتبّع للعدد 472:

الدورةn عند الفحصn % 10sum بعد الإضافةn بعد n / 10
14722247
247794
344130
تنتهي0لا يُحسب130

مجموع الأرقام

تتبّع البرنامج وقارن كل دورة بالجدول أعلاه. ثم غيّر العدد إلى 9075 واكتب جدوله قبل التشغيل.

public class SumOfDigits {
    public static void main(String[] args) {
        int n = 472;
        int sum = 0;
        while (n > 0) {
            int digit = n % 10;
            sum += digit;
            n = n / 10;
        }
        System.out.println(sum);
    }
}
الناتج
13

كم مرة يظهر الرقم 7 في العدد؟

public class CountSevens {
    public static void main(String[] args) {
        int n = 7170;
        int sevens = 0;
        while (n > 0) {
            if (n % 10 == 7) {
                sevens++;
            }
            n = n / 10;
        }
        System.out.println(sevens);
    }
}
أظهر الناتج
الناتج
2

لماذا؟ تقرأ الحلقة الأرقام من اليمين: 0 ثم 7 ثم 1 ثم 7، فيزيد العدّاد مرتين.

الفكرة نفسها تعكس العدد وتعدّ أرقامه

اعكس العدد

الأمر reversed = reversed * 10 + digit يزيح الأرقام إلى اليسار ويضع الرقم الجديد في خانة الآحاد. تتبّع البرنامج وراقب الصندوق reversed: 3 ثم 32 ثم 321. ثم جرّب 120 وفسّر الناتج.

public class ReverseNumber {
    public static void main(String[] args) {
        int n = 123;
        int reversed = 0;
        while (n > 0) {
            int digit = n % 10;
            reversed = reversed * 10 + digit;
            n = n / 10;
        }
        System.out.println(reversed);
    }
}
الناتج
321

عدّ الأرقام

اقرأ عددًا صحيحًا غير سالب، ثم اطبع عدد أرقامه. لا تطبع نصًا آخر. انتبه إلى أن العدد 0 له رقم واحد.

import java.util.Scanner;

public class CountDigits {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        // Count the digits of n, then print the count

    }
}
stdin
4096
الناتج المتوقع
4
تلميح 1

في كل دورة احذف رقمًا بالأمر n = n / 10، وزد العدّاد.

تلميح 2

استخدم do-while مع الشرط n > 0 لتنجح حالة الصفر.

الحل
import java.util.Scanner;

public class CountDigits {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        int count = 0;
        do {
            count++;
            n = n / 10;
        } while (n > 0);
        System.out.println(count);
    }
}

لعبة التخمين تجمع الحلقة والشرط والعدّاد

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

العب

شغّل البرنامج وخمّن العدد، فهو بين 1 و100. ثم غيّر السر والعب مع زميلك: ما أقل عدد من المحاولات يضمن الفوز إذا بدأت دائمًا من المنتصف؟

import java.util.Scanner;

public class GuessGame {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int secret = 42;
        int guess;
        do {
            System.out.print("Your guess: ");
            guess = input.nextInt();
            if (guess < secret) {
                System.out.println("Too low");
            } else if (guess > secret) {
                System.out.println("Too high");
            }
        } while (guess != secret);
        System.out.println("Correct!");
    }
}

عدّ المحاولات

السر هو 7. اقرأ تخمينات دون طباعة رسائل طلب إدخال: اطبع Too low أو Too high بعد كل تخمين خاطئ. وعند الإصابة اطبع Correct! Attempts: متبوعًا بعدد المحاولات.

import java.util.Scanner;

public class GuessAttempts {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int secret = 7;
        // Keep reading guesses, and count them

    }
}
stdin
3
9
7
الناتج المتوقع
Too low
Too high
Correct! Attempts: 3
تلميح 1

زد عدّاد المحاولات في كل دورة، سواء كان التخمين صحيحًا أم خاطئًا.

تلميح 2

اطبع رسالة الفوز بعد الحلقة، لا داخلها.

الحل
import java.util.Scanner;

public class GuessAttempts {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int secret = 7;
        int attempts = 0;
        int guess;
        do {
            guess = input.nextInt();
            attempts++;
            if (guess < secret) {
                System.out.println("Too low");
            } else if (guess > secret) {
                System.out.println("Too high");
            }
        } while (guess != secret);
        System.out.println("Correct! Attempts: " + attempts);
    }
}

المضروب يبدأ من 1، لأن الضرب في 0 يمحو كل شيء

المضروب 5! يعني 5 × 4 × 3 × 2 × 1 = 120، و0! يساوي 1 بالتعريف. والنمط نفسه نمط المجموع التراكمي، مع الضرب بدل الجمع والبدء من 1 بدل 0.

بدأنا الناتج من 0 كما في المجموع. ماذا يطبع البرنامج؟

public class ZeroStart {
    public static void main(String[] args) {
        int n = 4;
        int result = 0;
        while (n > 0) {
            result = result * n;
            n--;
        }
        System.out.println(result);
    }
}
أظهر الناتج
الناتج
0

لماذا؟ أي عدد مضروب في 0 يساوي 0، فتبقى result صفرًا في كل دورة. ابدأ حاصل الضرب من 1، وابدأ المجموع من 0.

الصندوق يمتلئ مرة أخرى

شغّل البرنامج: الناتج غير صحيح، فـ 13! أكبر من أقصى قيمة في int. غيّر نوع result إلى long، وشغّله مجددًا وقارن.

public class FactorialOverflow {
    public static void main(String[] args) {
        int n = 13;
        int result = 1;
        while (n > 0) {
            result = result * n;
            n--;
        }
        System.out.println(result);
    }
}
الناتج
1932053504

احسب المضروب

اقرأ عددًا صحيحًا n بين 0 و20، ثم اطبع مضروبه. استخدم النوع long. لا تطبع نصًا آخر.

import java.util.Scanner;

public class FactorialN {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        // Multiply the result by n, n - 1, ... 1

    }
}
stdin
5
الناتج المتوقع
120
تلميح 1

ابدأ بالأمر long result = 1;.

تلميح 2

الحلقة while (n > 0) لا تدخل عند 0، فتبقى النتيجة 1 كما نريد.

الحل
import java.util.Scanner;

public class FactorialN {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        long result = 1;
        while (n > 0) {
            result = result * n;
            n--;
        }
        System.out.println(result);
    }
}

أسئلة المراجعة

ماذا يحدث إذا نسيت جزء التحديث في حلقة while؟

متى تفضّل do-while على while؟

لماذا نختار -1 قيمة حارسة في قائمة علامات؟

تتبّع على الورق، ثم تأكد بالمتتبّع. ماذا يطبع البرنامج؟

public class ReviewTrace {
    public static void main(String[] args) {
        int x = 20;
        int steps = 0;
        while (x > 1) {
            x = x / 2;
            steps++;
        }
        System.out.println(x + " " + steps);
    }
}
أظهر الناتج
الناتج
1 4

لماذا؟ تمر x بالقيم 20 ثم 10 ثم 5 ثم 2 ثم 1، مع حذف الكسر في 5 / 2. وهذه أربع دورات، وعند 1 يصبح الشرط false.