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

المشروع النهائي والمراجعة

اجمع كل ما تعلمته في برنامج حقيقي، ثم اختبر نفسك

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

  1. تقسّم برنامجًا إلى عدة ملفات داخل حزمة واحدة
  2. تبني مدير درجات بقائمة وحلقة ومصفوفات ودوال، مرحلة بعد مرحلة
  3. تنقل مشروعك من مختبر Java إلى NetBeans عبر ملف ZIP
  4. تتجنب الفخاخ الكلاسيكية التي مرت في كل محاضرة
  5. تحل امتحانًا عمليًا تجريبيًا في وقت محدد
محتويات المحاضرة
  1. ستبني برنامجًا يدير درجات صف كامل، بكل ما تعلمته
  2. كل ملف له مهمة واحدة، وتجمعها حزمة grades
  3. يحفظ مختبر Java مشروعك، ويسلّمك إياه ZIP لتفتحه في NetBeans
  4. المرحلة 1: Stats تحسب المعدل وأعلى درجة وأدناها
  5. المرحلة 2: Report يطبع جدولًا بأعمدة مستقيمة
  6. المرحلة 3: حلقة do-while وswitch يصنعان القائمة
  7. المرحلة 5: تجمّعت القطع في برنامج كامل
  8. الطباعة والمتغيرات والمدخلات: محاضرات 1 إلى 6
  9. الشروط والقرارات: محاضرتا 7 و8
  10. الحلقات: محاضرتا 9 و10
  11. الدوال: محاضرتا 11 و12
  12. المصفوفات والنصوص: محاضرات 13 إلى 15
  13. الامتحان: 120 دقيقة وستة أسئلة تتصاعد صعوبتها
  14. السؤالان 3 و4: المصفوفات والدوال، ثم النصوص
  15. السؤالان 5 و6: مصفوفة ثنائية، ثم برنامج يجمع كل شيء
  16. أسئلة المراجعة الأخيرة، وإلى اللقاء في برمجة 2
الجزء الأول: مشروع مدير الدرجات

ستبني برنامجًا يدير درجات صف كامل، بكل ما تعلمته

الفكرةأين تظهر في المشروع
Scanner وnextLineقراءة الأسماء والدرجات
do-while وswitchالقائمة التي تتكرر حتى الخروج
while للتحقق من المدخلاترفض الدرجة خارج المدى من 0 إلى 100
المصفوفات و2DString[] للأسماء وint[][] للدرجات
الدوال والمعاملاتكل مهمة في دالة، وكل مجموعة دوال في صنف
printf وequalsIgnoreCaseجدول منسق وبحث بالاسم

كل ملف له مهمة واحدة، وتجمعها حزمة grades

الملفمهمتهدواله
grades/GradeBook.javamain والقائمة والقراءة من المستخدمmain, addStudent, readMark, findStudent
grades/Stats.javaالحساب فقط، دون طباعةaverage, max, min
grades/Report.javaالطباعة المنسقة فقطprintTable, printSummary
  • أول سطر في كل ملف هو package grades;، والملف داخل مجلد بالاسم نفسه.
  • الأصناف هنا تجمع دوالًا ثابتة static فقط، ولا ننشئ منها كائنات.
  • داخل الحزمة نفسها لا حاجة إلى import: نكتب Stats.average(row) مباشرة.

البداية: ملفان يعملان معًا

انتقل بين الملفين من أعلى المحرر. اضغط «تتبّع سطرًا سطرًا» وادخل إلى Stats.average لترى كيف ينتقل التنفيذ إلى ملف آخر ثم يعود. غيّر الدرجات وتوقّع النتيجة.

grades/GradeBook.java
package grades;

public class GradeBook {
    public static void main(String[] args) {
        int[] marks = {70, 85, 90};
        System.out.printf("Average: %.2f%n", Stats.average(marks));
        System.out.println("Best: " + Stats.max(marks));
        System.out.println("Lowest: " + Stats.min(marks));
    }
}
grades/Stats.java
package grades;

public class Stats {
    public static double average(int[] values) {
        int sum = 0;
        for (int value : values) {
            sum += value;
        }
        return (double) sum / values.length;
    }

    public static int max(int[] values) {
        int best = values[0];
        for (int value : values) {
            if (value > best) {
                best = value;
            }
        }
        return best;
    }

    public static int min(int[] values) {
        int worst = values[0];
        for (int value : values) {
            if (value < worst) {
                worst = value;
            }
        }
        return worst;
    }
}
الناتج
Average: 81.67
Best: 90
Lowest: 70

لماذا لا يطبع الصنف Stats شيئًا، بل يرجع القيم فقط؟

يحفظ مختبر Java مشروعك، ويسلّمك إياه ZIP لتفتحه في NetBeans

المختبر أعلى الموقع يتسع لمشروع كامل بعدة ملفات وحزم، ولا يحتاج إلى تثبيت.

  1. افتح «مختبر Java» من أعلى الموقعمن القائمة «+ مشروع جديد…» اختر «برنامج فارغ»، ثم اضغط «إعادة التسمية» وسمّه Grades.
  2. أضف الملفات بزر + فوق المحرراكتب الاسم مع المجلد: grades/GradeBook.java، ثم grades/Stats.java وgrades/Report.java. يضيف المختبر سطر package بنفسه. احذف Main.java بزر ×.
  3. اكتب الكود، أو انسخه من المختبرات في هذه الصفحةيُحفظ كل شيء في هذا المتصفح تلقائيًا. اضغط Ctrl+Enter للتشغيل.
  4. اضغط «تنزيل ZIP»ثم فك الضغط في مجلد جديد، مثل GradesSource. يجب أن تجد في داخله المجلد grades.
  5. افتحه في NetBeans 8.2اختر File ثم New Project ثم Java ثم Java Project with Existing Sources. سمّ المشروع، وعند Source Package Folders اضغط Add Folder واختر GradesSource، وليس grades.
  6. شغّله بالمفتاح F6إذا سألك NetBeans عن الصنف الرئيسي، فاختر grades.GradeBook.

المرحلة 1: Stats تحسب المعدل وأعلى درجة وأدناها

المرحلة 1: أكمل Stats

الدالة main جاهزة: تقرأ عدد الدرجات ثم الدرجات. أكمل الدوال الثلاث في Stats دون أن تطبع منها شيئًا.

import java.util.Scanner;

class Stats {
    static double average(int[] values) {
        return 0; // Replace this
    }

    static int max(int[] values) {
        return 0; // Replace this
    }

    static int min(int[] values) {
        return 0; // Replace this
    }
}

public class StageStats {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        int[] marks = new int[n];
        for (int i = 0; i < n; i++) {
            marks[i] = input.nextInt();
        }
        System.out.printf("Average: %.2f%n", Stats.average(marks));
        System.out.println("Max: " + Stats.max(marks));
        System.out.println("Min: " + Stats.min(marks));
    }
}
stdin
3
70 85 90
الناتج المتوقع
Average: 81.67
Max: 90
Min: 70
تلميح 1

قسمة sum / values.length بين عددين صحيحين تحذف الكسر. استخدم (double) sum.

تلميح 2

ابدأ max وmin بالقيمة values[0]، وليس 0: لماذا تفشل min إذا بدأت بصفر؟

الحل
import java.util.Scanner;

class Stats {
    static double average(int[] values) {
        int sum = 0;
        for (int value : values) {
            sum += value;
        }
        return (double) sum / values.length;
    }

    static int max(int[] values) {
        int best = values[0];
        for (int value : values) {
            if (value > best) {
                best = value;
            }
        }
        return best;
    }

    static int min(int[] values) {
        int worst = values[0];
        for (int value : values) {
            if (value < worst) {
                worst = value;
            }
        }
        return worst;
    }
}

public class StageStats {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        int[] marks = new int[n];
        for (int i = 0; i < n; i++) {
            marks[i] = input.nextInt();
        }
        System.out.printf("Average: %.2f%n", Stats.average(marks));
        System.out.println("Max: " + Stats.max(marks));
        System.out.println("Min: " + Stats.min(marks));
    }
}

المرحلة 2: Report يطبع جدولًا بأعمدة مستقيمة

الدرجات في مصفوفة ثنائية: كل صف طالب، وكل عمود امتحان. وmarks[i] هو صف كامل من نوع int[]، فنمرره مباشرة إلى Stats.average.

ثلاثة ملفات وجدول

افتح Report.java وغيّر %-12s إلى %12s: ماذا يحدث لعمود الأسماء؟ ثم أضف طالبًا ثالثًا في GradeBook.java.

grades/GradeBook.java
package grades;

public class GradeBook {
    public static void main(String[] args) {
        String[] names = {"Sara Ali", "Omar"};
        int[][] marks = {
            {80, 90, 100},
            {55, 60, 70}
        };
        Report.printTable(names, marks, 2);
        Report.printSummary(marks, 2);
    }
}
grades/Stats.java
package grades;

public class Stats {
    public static double average(int[] values) {
        int sum = 0;
        for (int value : values) {
            sum += value;
        }
        return (double) sum / values.length;
    }

    public static int max(int[] values) {
        int best = values[0];
        for (int value : values) {
            if (value > best) {
                best = value;
            }
        }
        return best;
    }

    public static int min(int[] values) {
        int worst = values[0];
        for (int value : values) {
            if (value < worst) {
                worst = value;
            }
        }
        return worst;
    }
}
grades/Report.java
package grades;

public class Report {
    public static void printTable(String[] names, int[][] marks, int count) {
        if (count == 0) {
            System.out.println("No students yet.");
            return;
        }
        System.out.printf("%-12s%5s%5s%5s%8s%6s%6s%n", "Name", "M1", "M2", "M3", "Avg", "Best", "Low");
        for (int i = 0; i < count; i++) {
            int[] row = marks[i];
            System.out.printf("%-12s%5d%5d%5d%8.2f%6d%6d%n", names[i], row[0], row[1], row[2],
                    Stats.average(row), Stats.max(row), Stats.min(row));
        }
    }

    public static void printSummary(int[][] marks, int count) {
        if (count == 0) {
            System.out.println("No students yet.");
            return;
        }
        double total = 0;
        for (int i = 0; i < count; i++) {
            total += Stats.average(marks[i]);
        }
        System.out.printf("Students: %d%n", count);
        System.out.printf("Class average: %.2f%n", total / count);
    }
}
الناتج
Name           M1   M2   M3     Avg  Best   Low
Sara Ali       80   90  100   90.00   100    80
Omar           55   60   70   61.67    70    55
Students: 2
Class average: 75.83

المرحلة 2: أكمل Report

تقرأ main عدد الطلاب، ثم لكل طالب اسمًا من كلمة واحدة وثلاث درجات. أكمل printRow لتطبع سطرًا بالتنسيق %-10s%5d%5d%5d%8.2f%n وآخره المعدل، وprintPassed لتطبع Passed: مع عدد الطلاب الذين معدلهم 60 فأكثر.

import java.util.Scanner;

class Report {
    static void printRow(String name, int[] row) {
        // printf with %-10s%5d%5d%5d%8.2f%n
    }

    static void printPassed(int[][] marks) {
        // Count the rows whose average is 60 or more
    }
}

public class StageReport {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        int[][] marks = new int[n][3];
        for (int i = 0; i < n; i++) {
            String name = input.next();
            for (int k = 0; k < 3; k++) {
                marks[i][k] = input.nextInt();
            }
            Report.printRow(name, marks[i]);
        }
        Report.printPassed(marks);
    }
}
stdin
2
Sara 80 90 100
Omar 55 60 70
الناتج المتوقع
Sara         80   90  100   90.00
Omar         55   60   70   61.67
Passed: 2
تلميح 1

المعدل (row[0] + row[1] + row[2]) / 3.0، والقسمة على 3.0 تمنع حذف الكسر.

تلميح 2

marks[i] صف كامل، فالحلقة في printPassed تكفيها marks.length.

الحل
import java.util.Scanner;

class Report {
    static double average(int[] row) {
        return (row[0] + row[1] + row[2]) / 3.0;
    }

    static void printRow(String name, int[] row) {
        System.out.printf("%-10s%5d%5d%5d%8.2f%n", name, row[0], row[1], row[2], average(row));
    }

    static void printPassed(int[][] marks) {
        int passed = 0;
        for (int i = 0; i < marks.length; i++) {
            if (average(marks[i]) >= 60) {
                passed++;
            }
        }
        System.out.println("Passed: " + passed);
    }
}

public class StageReport {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        int[][] marks = new int[n][3];
        for (int i = 0; i < n; i++) {
            String name = input.next();
            for (int k = 0; k < 3; k++) {
                marks[i][k] = input.nextInt();
            }
            Report.printRow(name, marks[i]);
        }
        Report.printPassed(marks);
    }
}

المرحلة 3: حلقة do-while وswitch يصنعان القائمة

العدّاد count

حجم المصفوفة ثابت، لكن عدد الطلاب يكبر. نضيف عند الموقع count ثم نزيده، ولا نمر إلا على i < count.

names[count] = name;
count++;
فخ nextInt

يترك nextInt نهاية السطر خلفه. إذا لم تتجاوزها، فستقرأ nextLine التالية اسمًا فارغًا.

choice = input.nextInt();
input.nextLine();

المرحلة 3: القائمة

اكتب حلقة تقرأ رقم خيار في سطر، حتى يكون 0. الخيار 1: اقرأ اسمًا في السطر التالي (قد يحوي مسافات)، احفظه واطبع Added مع الاسم. الخيار 2: اطبع كل اسم في سطر بالشكل 1. Sara، أو No students إذا لم يوجد أحد. الخيار 0: اطبع Goodbye. أي رقم آخر: Unknown. احفظ حتى 30 اسمًا. لا تطبع أي نص يطلب الإدخال.

import java.util.Scanner;

public class StageMenu {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        // A String array, a count, then a do-while loop with a switch inside

    }
}
stdin
1
Sara Ali
1
Omar
2
0
الناتج المتوقع
Added Sara Ali
Added Omar
1. Sara Ali
2. Omar
Goodbye
تلميح 1

ألم تنسَ break في كل case؟ بدونها ينفذ البرنامج الحالة التالية أيضًا.

تلميح 2

بعد nextInt استدعِ nextLine لتجاوز نهاية السطر، حتى في الخيارات التي لا تقرأ اسمًا.

الحل
import java.util.Scanner;

public class StageMenu {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        String[] names = new String[30];
        int count = 0;
        int choice;
        do {
            choice = input.nextInt();
            input.nextLine();
            switch (choice) {
                case 1:
                    names[count] = input.nextLine();
                    System.out.println("Added " + names[count]);
                    count++;
                    break;
                case 2:
                    if (count == 0) {
                        System.out.println("No students");
                    }
                    for (int i = 0; i < count; i++) {
                        System.out.println((i + 1) + ". " + names[i]);
                    }
                    break;
                case 0:
                    System.out.println("Goodbye");
                    break;
                default:
                    System.out.println("Unknown");
            }
        } while (choice != 0);
    }
}

المرحلة 4: البحث بالاسم

السطر الأول عدد الطلاب، ثم لكل طالب سطر اسمه وسطر درجته، ثم سطر الاسم المطلوب. اكتب دالة find ترجع موقع الطالب أو -1، مع إهمال حالة الأحرف والمسافات الزائدة. اطبع Sara Ali: 80، أو Not found.

import java.util.Scanner;

public class StageFind {
    static int find(String[] names, String target) {
        // Return the position of target, or -1
        return -1;
    }

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        // Read the students, read the target, call find, print

    }
}
stdin
2
Sara Ali
80
Omar
75
sara ali
الناتج المتوقع
Sara Ali: 80
تلميح 1

قارن بالدالة equalsIgnoreCase، وليس بالعامل ==.

تلميح 2

Integer.parseInt(input.nextLine().trim()) تقرأ العدد من سطر كامل، فتتجنب فخ nextInt.

الحل
import java.util.Scanner;

public class StageFind {
    static int find(String[] names, String target) {
        for (int i = 0; i < names.length; i++) {
            if (names[i].equalsIgnoreCase(target.trim())) {
                return i;
            }
        }
        return -1;
    }

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = Integer.parseInt(input.nextLine().trim());
        String[] names = new String[n];
        int[] marks = new int[n];
        for (int i = 0; i < n; i++) {
            names[i] = input.nextLine();
            marks[i] = Integer.parseInt(input.nextLine().trim());
        }
        int at = find(names, input.nextLine());
        if (at == -1) {
            System.out.println("Not found");
        } else {
            System.out.println(names[at] + ": " + marks[at]);
        }
    }
}

المرحلة 5: تجمّعت القطع في برنامج كامل

مدير الدرجات: جرّبه بنفسك

الملف الذي فيه main أولًا. أضف طالبين، واطلب الجدول، وجرّب إدخال الدرجة 150. ثم انسخ الملفات الثلاثة إلى مشروعك في مختبر Java ونزّلها ZIP وافتحها في NetBeans.

grades/GradeBook.java
package grades;

import java.util.Scanner;

public class GradeBook {
    static final int MAX_STUDENTS = 30;
    static final int EXAMS = 3;

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        String[] names = new String[MAX_STUDENTS];
        int[][] marks = new int[MAX_STUDENTS][EXAMS];
        int count = 0;
        int choice;
        do {
            System.out.println("1 Add  2 Table  3 Summary  4 Find  0 Exit");
            System.out.print("Choice: ");
            choice = input.nextInt();
            input.nextLine(); // nextInt leaves the end of the line behind
            switch (choice) {
                case 1:
                    count = addStudent(input, names, marks, count);
                    break;
                case 2:
                    Report.printTable(names, marks, count);
                    break;
                case 3:
                    Report.printSummary(marks, count);
                    break;
                case 4:
                    findStudent(input, names, marks, count);
                    break;
                case 0:
                    System.out.println("Goodbye.");
                    break;
                default:
                    System.out.println("Unknown choice.");
            }
        } while (choice != 0);
    }

    static int addStudent(Scanner input, String[] names, int[][] marks, int count) {
        if (count == MAX_STUDENTS) {
            System.out.println("The class is full.");
            return count;
        }
        System.out.print("Name: ");
        names[count] = input.nextLine().trim();
        for (int exam = 0; exam < EXAMS; exam++) {
            marks[count][exam] = readMark(input, exam + 1);
        }
        input.nextLine();
        System.out.println("Added " + names[count] + ".");
        return count + 1;
    }

    static int readMark(Scanner input, int number) {
        System.out.print("Mark " + number + ": ");
        int mark = input.nextInt();
        while (mark < 0 || mark > 100) {
            System.out.print("Enter 0 to 100: ");
            mark = input.nextInt();
        }
        return mark;
    }

    static void findStudent(Scanner input, String[] names, int[][] marks, int count) {
        System.out.print("Name to find: ");
        String target = input.nextLine().trim();
        for (int i = 0; i < count; i++) {
            if (names[i].equalsIgnoreCase(target)) {
                System.out.printf("%s: average %.2f%n", names[i], Stats.average(marks[i]));
                return;
            }
        }
        System.out.println("Not found.");
    }
}
grades/Stats.java
package grades;

public class Stats {
    public static double average(int[] values) {
        int sum = 0;
        for (int value : values) {
            sum += value;
        }
        return (double) sum / values.length;
    }

    public static int max(int[] values) {
        int best = values[0];
        for (int value : values) {
            if (value > best) {
                best = value;
            }
        }
        return best;
    }

    public static int min(int[] values) {
        int worst = values[0];
        for (int value : values) {
            if (value < worst) {
                worst = value;
            }
        }
        return worst;
    }
}
grades/Report.java
package grades;

public class Report {
    public static void printTable(String[] names, int[][] marks, int count) {
        if (count == 0) {
            System.out.println("No students yet.");
            return;
        }
        System.out.printf("%-12s%5s%5s%5s%8s%6s%6s%n", "Name", "M1", "M2", "M3", "Avg", "Best", "Low");
        for (int i = 0; i < count; i++) {
            int[] row = marks[i];
            System.out.printf("%-12s%5d%5d%5d%8.2f%6d%6d%n", names[i], row[0], row[1], row[2],
                    Stats.average(row), Stats.max(row), Stats.min(row));
        }
    }

    public static void printSummary(int[][] marks, int count) {
        if (count == 0) {
            System.out.println("No students yet.");
            return;
        }
        double total = 0;
        for (int i = 0; i < count; i++) {
            total += Stats.average(marks[i]);
        }
        System.out.printf("Students: %d%n", count);
        System.out.printf("Class average: %.2f%n", total / count);
    }
}

جلسة كاملة بمدخلات جاهزة

هذه النسخة تقرأ مدخلات جاهزة، فلا تظهر مكتوبة في الناتج، ولذلك تتلاصق النصوص التي تطلب الإدخال. اضغط «تتبّع سطرًا سطرًا» وراقب count وnames.

grades/GradeBook.java
package grades;

import java.util.Scanner;

public class GradeBook {
    static final int MAX_STUDENTS = 30;
    static final int EXAMS = 3;

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        String[] names = new String[MAX_STUDENTS];
        int[][] marks = new int[MAX_STUDENTS][EXAMS];
        int count = 0;
        int choice;
        do {
            System.out.println("1 Add  2 Table  3 Summary  4 Find  0 Exit");
            System.out.print("Choice: ");
            choice = input.nextInt();
            input.nextLine(); // nextInt leaves the end of the line behind
            switch (choice) {
                case 1:
                    count = addStudent(input, names, marks, count);
                    break;
                case 2:
                    Report.printTable(names, marks, count);
                    break;
                case 3:
                    Report.printSummary(marks, count);
                    break;
                case 4:
                    findStudent(input, names, marks, count);
                    break;
                case 0:
                    System.out.println("Goodbye.");
                    break;
                default:
                    System.out.println("Unknown choice.");
            }
        } while (choice != 0);
    }

    static int addStudent(Scanner input, String[] names, int[][] marks, int count) {
        if (count == MAX_STUDENTS) {
            System.out.println("The class is full.");
            return count;
        }
        System.out.print("Name: ");
        names[count] = input.nextLine().trim();
        for (int exam = 0; exam < EXAMS; exam++) {
            marks[count][exam] = readMark(input, exam + 1);
        }
        input.nextLine();
        System.out.println("Added " + names[count] + ".");
        return count + 1;
    }

    static int readMark(Scanner input, int number) {
        System.out.print("Mark " + number + ": ");
        int mark = input.nextInt();
        while (mark < 0 || mark > 100) {
            System.out.print("Enter 0 to 100: ");
            mark = input.nextInt();
        }
        return mark;
    }

    static void findStudent(Scanner input, String[] names, int[][] marks, int count) {
        System.out.print("Name to find: ");
        String target = input.nextLine().trim();
        for (int i = 0; i < count; i++) {
            if (names[i].equalsIgnoreCase(target)) {
                System.out.printf("%s: average %.2f%n", names[i], Stats.average(marks[i]));
                return;
            }
        }
        System.out.println("Not found.");
    }
}
grades/Stats.java
package grades;

public class Stats {
    public static double average(int[] values) {
        int sum = 0;
        for (int value : values) {
            sum += value;
        }
        return (double) sum / values.length;
    }

    public static int max(int[] values) {
        int best = values[0];
        for (int value : values) {
            if (value > best) {
                best = value;
            }
        }
        return best;
    }

    public static int min(int[] values) {
        int worst = values[0];
        for (int value : values) {
            if (value < worst) {
                worst = value;
            }
        }
        return worst;
    }
}
grades/Report.java
package grades;

public class Report {
    public static void printTable(String[] names, int[][] marks, int count) {
        if (count == 0) {
            System.out.println("No students yet.");
            return;
        }
        System.out.printf("%-12s%5s%5s%5s%8s%6s%6s%n", "Name", "M1", "M2", "M3", "Avg", "Best", "Low");
        for (int i = 0; i < count; i++) {
            int[] row = marks[i];
            System.out.printf("%-12s%5d%5d%5d%8.2f%6d%6d%n", names[i], row[0], row[1], row[2],
                    Stats.average(row), Stats.max(row), Stats.min(row));
        }
    }

    public static void printSummary(int[][] marks, int count) {
        if (count == 0) {
            System.out.println("No students yet.");
            return;
        }
        double total = 0;
        for (int i = 0; i < count; i++) {
            total += Stats.average(marks[i]);
        }
        System.out.printf("Students: %d%n", count);
        System.out.printf("Class average: %.2f%n", total / count);
    }
}
الناتج
1 Add  2 Table  3 Summary  4 Find  0 Exit
Choice: No students yet.
1 Add  2 Table  3 Summary  4 Find  0 Exit
Choice: Name: Mark 1: Mark 2: Mark 3: Added Sara Ali.
1 Add  2 Table  3 Summary  4 Find  0 Exit
Choice: Name: Mark 1: Enter 0 to 100: Mark 2: Mark 3: Added Omar.
1 Add  2 Table  3 Summary  4 Find  0 Exit
Choice: Name           M1   M2   M3     Avg  Best   Low
Sara Ali       80   90  100   90.00   100    80
Omar           55   60   70   61.67    70    55
1 Add  2 Table  3 Summary  4 Find  0 Exit
Choice: Students: 2
Class average: 75.83
1 Add  2 Table  3 Summary  4 Find  0 Exit
Choice: Name to find: Sara Ali: average 90.00
1 Add  2 Table  3 Summary  4 Find  0 Exit
Choice: Name to find: Not found.
1 Add  2 Table  3 Summary  4 Find  0 Exit
Choice: Unknown choice.
1 Add  2 Table  3 Summary  4 Find  0 Exit
Choice: Goodbye.
  1. سهل: أضف خيارًا يحذف آخر طالب بإنقاص count.
  2. متوسط: أضف إلى Stats دالة letter(double average) ترجع A إلى F، واعرضها عمودًا في الجدول.
  3. أصعب: رتّب الجدول حسب المعدل بالترتيب الفقاعي. تذكّر: يجب أن تبدّل الاسم والصف معًا.
الجزء الثاني: مراجعة المساق وفخاخه

الطباعة والمتغيرات والمدخلات: محاضرات 1 إلى 6

المحاضرة 1: الصنف العام اسمه Hello. ما اسم الملف الذي يجب أن يحفظ فيه؟

المحاضرة 2: ماذا يفعل المترجم بسطر يبدأ بـ //؟

المحاضرتان 1 و2: print وprintln و\n. ماذا يطبع؟

public class PrintReview {
    public static void main(String[] args) {
        System.out.print("A");
        System.out.println("B");
        System.out.print("C\nD");
    }
}
أظهر الناتج
الناتج
AB
C
D

لماذا؟ print لا ينزل إلى سطر جديد، وprintln ينزل بعد الطباعة، و\n داخل النص ينزل في مكانه.

المحاضرة 3: + مع النصوص والأرقام. ماذا يطبع؟

public class ConcatReview {
    public static void main(String[] args) {
        int a = 2;
        int b = 3;
        System.out.println("Sum: " + a + b);
        System.out.println(a + b + " is the sum");
    }
}
أظهر الناتج
الناتج
Sum: 23
5 is the sum

لماذا؟ تُقرأ + من اليسار. بعد أول نص يصبح كل شيء دمجًا، أما قبله فالعددان يُجمعان. والأقواس هي الحل: "Sum: " + (a + b).

المحاضرة 3: x++ يستخدم القيمة ثم يزيدها. ماذا يطبع؟

public class IncrementReview {
    public static void main(String[] args) {
        int x = 5;
        int y = x++;
        System.out.println(x + " " + y);
    }
}
أظهر الناتج
الناتج
6 5

لماذا؟ تأخذ y القيمة القديمة 5، ثم تصبح x مساوية 6.

المحاضرة 4: ماذا يحدث عند تنفيذ System.out.printf("%d%n", 3.5);؟

المحاضرة 5: المدخلات هي 19 ثم Sara، كل منهما في سطر. ماذا يطبع؟

import java.util.Scanner;

public class NextLineTrap {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int age = input.nextInt();
        String name = input.nextLine();
        System.out.println(age);
        System.out.println("[" + name + "]");
    }
}
أظهر الناتج
الناتج
19
[]

لماذا؟ تقرأ nextInt الرقم وتترك نهاية السطر. ثم تقرأ nextLine ما بقي من السطر، وهو لا شيء. الحل: input.nextLine(); إضافية بعد nextInt.

علاج فخ nextLine

السطر الإضافي يتجاوز نهاية السطر الأول. احذفه وشغّل البرنامج لترى الاسم الفارغ يعود.

import java.util.Scanner;

public class NextLineFix {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int age = input.nextInt();
        input.nextLine();
        String name = input.nextLine();
        System.out.println(age);
        System.out.println("[" + name + "]");
    }
}
الناتج
19
[Sara]

المحاضرة 6: قسمة الأعداد الصحيحة. ماذا تطبع الأسطر الأربعة؟

public class DivisionReview {
    public static void main(String[] args) {
        System.out.println(7 / 2);
        System.out.println(7 / 2.0);
        System.out.println((double) 7 / 2);
        System.out.println((double) (7 / 2));
    }
}
أظهر الناتج
الناتج
3
3.5
3.5
3.0

لماذا؟ عددان صحيحان يعطيان ناتجًا صحيحًا. في السطر الأخير حدثت القسمة أولًا فضاع الكسر، ثم جاء التحويل متأخرًا. لذلك ضع (double) على أحد طرفي القسمة.

المحاضرة 6: ما قيمة 2 + 3 * 4 % 5؟

الشروط والقرارات: محاضرتا 7 و8

= أم ==؟

المحاضرة 7: أصلح الشرط ليطبع five.

public class AssignOrEqual {
    public static void main(String[] args) {
        int x = 5;
        if (x = 5) {
            System.out.println("five");
        }
    }
}
رسالة المترجمincompatible types: int cannot be converted to boolean
أظهر التصحيح
public class AssignOrEqual {
    public static void main(String[] args) {
        int x = 5;
        if (x == 5) {
            System.out.println("five");
        }
    }
}
الناتج
five

لماذا؟ x = 5 إسناد ناتجه العدد 5، والشرط يحتاج إلى boolean. لذلك تتحدث الرسالة عن الأنواع ولا تذكر السبب الحقيقي: العلامة الناقصة.

المحاضرة 7: المستخدم يكتب java. ماذا يطبع؟

import java.util.Scanner;

public class StringEquals {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        String word = input.next();
        System.out.println(word == "java");
        System.out.println(word.equals("java"));
    }
}
أظهر الناتج
الناتج
false
true

لماذا؟ == تسأل عن المكان في الذاكرة، وما يُقرأ من المستخدم نص جديد في مكان جديد. قارن النصوص دائمًا بالدالة equals.

المحاضرة 8: ترتيب الشروط. الدرجة 95. ماذا يطبع؟

public class GradeOrder {
    public static void main(String[] args) {
        int mark = 95;
        if (mark >= 60) {
            System.out.println("D");
        } else if (mark >= 80) {
            System.out.println("B");
        } else if (mark >= 90) {
            System.out.println("A");
        }
    }
}
أظهر الناتج
الناتج
D

لماذا؟ في سلسلة else if ينفذ أول فرع يتحقق شرطه فقط، ولا تُفحص البقية. ابدأ من الدرجة الأعلى.

المحاضرة 8: نسينا break. ماذا يطبع؟

public class MissingBreak {
    public static void main(String[] args) {
        int day = 2;
        switch (day) {
            case 1:
                System.out.println("Sunday");
            case 2:
                System.out.println("Monday");
            case 3:
                System.out.println("Tuesday");
                break;
            default:
                System.out.println("Other");
        }
    }
}
أظهر الناتج
الناتج
Monday
Tuesday

لماذا؟ يبدأ التنفيذ عند case 2، ويستمر إلى الحالة التالية حتى يصل إلى break. ولا يصل إلى default لأن break أوقفه.

فاصلة منقوطة صغيرة. ماذا يطبع؟

public class IfSemicolon {
    public static void main(String[] args) {
        int x = 3;
        if (x > 10);
        {
            System.out.println("big");
        }
        System.out.println("done");
    }
}
أظهر الناتج
الناتج
big
done

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

ما قيمة result بعد String result = (7 % 2 == 0) ? "even" : "odd";؟

الحلقات: محاضرتا 9 و10

خطأ الزيادة بواحد. كم مرة تدور الحلقة؟

public class OffByOne {
    public static void main(String[] args) {
        int count = 0;
        for (int i = 1; i <= 5; i++) {
            count++;
        }
        for (int i = 0; i <= 5; i++) {
            count++;
        }
        System.out.println(count);
    }
}
أظهر الناتج
الناتج
11

لماذا؟ الأولى من 1 إلى 5 خمس مرات، والثانية من 0 إلى 5 ست مرات. تذكر: i < n من 0 تدور n مرة بالضبط.

المحاضرة 9: الشرط خاطئ من البداية. ماذا يطبع؟

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

لماذا؟ while تفحص الشرط أولًا فلا تدخل. وdo-while تنفذ مرة ثم تفحص، ولهذا تناسب القوائم والتحقق من المدخلات.

المحاضرة 10: continue وbreak معًا. ماذا يطبع؟

public class BreakContinue {
    public static void main(String[] args) {
        for (int i = 1; i <= 6; i++) {
            if (i == 2) {
                continue;
            }
            if (i == 5) {
                break;
            }
            System.out.print(i + " ");
        }
        System.out.println();
    }
}
أظهر الناتج
الناتج
1 3 4

لماذا؟ continue تتخطى بقية هذه الدورة، وbreak تنهي الحلقة كلها قبل طباعة 5.

المحاضرة 10: حلقتان متداخلتان. ماذا يطبع؟

public class NestedReview {
    public static void main(String[] args) {
        for (int row = 1; row <= 3; row++) {
            for (int col = 1; col <= row; col++) {
                System.out.print("*");
            }
            System.out.println();
        }
    }
}
أظهر الناتج
الناتج
*
**
***

لماذا؟ تكتمل الحلقة الداخلية في كل دورة من الخارجية، ويتوقف طولها على row.

أين انتهى المتغير i؟

نريد طباعة قيمة i بعد الحلقة. أصلح البرنامج ليطبع 3.

public class LoopScope {
    public static void main(String[] args) {
        for (int i = 0; i < 3; i++) {
            System.out.println("Hi");
        }
        System.out.println(i);
    }
}
رسالة المترجمcannot find symbol
أظهر التصحيح
public class LoopScope {
    public static void main(String[] args) {
        int i;
        for (i = 0; i < 3; i++) {
            System.out.println("Hi");
        }
        System.out.println(i);
    }
}
الناتج
Hi
Hi
Hi
3

لماذا؟ المتغير المعرّف في رأس for يعيش داخل الحلقة فقط. صرّح عنه قبلها إذا احتجته بعدها.

ماذا ينقص هذه الحلقة؟

int n = 3;
while (n > 0) {
    System.out.println(n);
}

الدوال: محاضرتا 11 و12

التمرير بالقيمة. ماذا يطبع؟ تتبّعه أيضًا بزر «تتبّع سطرًا سطرًا».

public class PassByValue {
    static void change(int x, int[] a) {
        x = 99;
        a[0] = 99;
    }

    public static void main(String[] args) {
        int n = 1;
        int[] list = {1, 2};
        change(n, list);
        System.out.println(n);
        System.out.println(list[0]);
    }
}
أظهر الناتج
الناتج
1
99

لماذا؟ يأخذ المعامل نسخة من القيمة دائمًا. نسخة n عدد، فلا يتأثر الأصل. ونسخة list عنوان المصفوفة نفسها، فيظهر التغيير في الأصل.

دالة تبديل. هل تبدّل القيمتين؟

public class SwapMethod {
    static void swap(int a, int b) {
        int temp = a;
        a = b;
        b = temp;
    }

    public static void main(String[] args) {
        int a = 1;
        int b = 2;
        swap(a, b);
        System.out.println(a + " " + b);
    }
}
أظهر الناتج
الناتج
1 2

لماذا؟ التبديل حدث في نسختين داخل الدالة، ثم اختفتا عند انتهائها. تشابه الأسماء لا يربط المتغيرين.

كل طريق يحتاج إلى return

أصلح الدالة لترجع القيمة الأكبر. لاحظ أن الرسالة تشير إلى آخر الدالة، لا إلى مكان محدد داخلها.

public class MaxOfTwo {
    static int max(int a, int b) {
        if (a > b) {
            return a;
        }
    }

    public static void main(String[] args) {
        System.out.println(max(3, 8));
    }
}
رسالة المترجمmissing return statement
أظهر التصحيح
public class MaxOfTwo {
    static int max(int a, int b) {
        if (a > b) {
            return a;
        }
        return b;
    }

    public static void main(String[] args) {
        System.out.println(max(3, 8));
    }
}
الناتج
8

لماذا؟ إذا لم يتحقق الشرط فلن تجد الدالة ما ترجعه. يطلب المترجم return في كل طريق ممكن عبر الدالة.

المحاضرة 12: أي دالة يستدعيها show(5.0) إذا وُجدت show(int) وshow(double)؟

المحاضرة 12: الاستدعاء الذاتي. ماذا يطبع؟

public class RecursionReview {
    static int sum(int n) {
        if (n == 0) {
            return 0;
        }
        return n + sum(n - 1);
    }

    public static void main(String[] args) {
        System.out.println(sum(4));
    }
}
أظهر الناتج
الناتج
10

لماذا؟ 4 + 3 + 2 + 1 + 0 = 10. وشرط التوقف n == 0 هو ما يمنع الاستدعاء من الاستمرار إلى الأبد.

المصفوفات والنصوص: محاضرات 13 إلى 15

حدود المصفوفة

شغّله وأنت تعلم أنه سيتوقف: تظهر 3 أرقام، ثم ArrayIndexOutOfBoundsException: 3. غيّر الشرط إلى i < marks.length.

public class ArrayBounds {
    public static void main(String[] args) {
        int[] marks = {70, 85, 92};
        for (int i = 0; i <= marks.length; i++) {
            System.out.println(marks[i]);
        }
    }
}
الناتج
70
85
92

المحاضرة 13: نسخنا المصفوفة، أم لا؟ ماذا يطبع؟

public class ArrayAlias {
    public static void main(String[] args) {
        int[] a = {1, 2, 3};
        int[] b = a;
        b[0] = 9;
        System.out.println(a[0]);
        int[] c = new int[2];
        System.out.println(c[1]);
    }
}
أظهر الناتج
الناتج
9
0

لماذا؟ b = a لا تنشئ مصفوفة، بل اسمًا ثانيًا للمصفوفة نفسها. وعناصر int[] الجديدة تبدأ بالقيمة 0.

المحاضرة 14: Arrays والمصفوفة الثنائية. ماذا يطبع؟

import java.util.Arrays;

public class ArraysReview {
    public static void main(String[] args) {
        int[] nums = {3, 1, 2};
        Arrays.sort(nums);
        System.out.println(Arrays.toString(nums));
        int[][] grid = {{1, 2, 3}, {4, 5, 6}};
        System.out.println(grid.length);
        System.out.println(grid[0].length);
        System.out.println(grid[1][2]);
    }
}
أظهر الناتج
الناتج
[1, 2, 3]
2
3
6

لماذا؟ grid.length عدد الصفوف، وgrid[0].length عدد أعمدة الصف الأول. والمواقع تبدأ من 0، فالموقع [1][2] هو آخر عنصر. وsort تغيّر المصفوفة نفسها، خلافًا لدوال النصوص.

ماذا يطبع System.out.println(marks); إذا كانت marks مصفوفة int[]؟

المحاضرة 15: ما الذي تغيّر فعلًا؟ ماذا يطبع؟

public class StringReview {
    public static void main(String[] args) {
        String s = " Gaza ";
        s.trim();
        System.out.println(s.length());
        s = s.trim().toUpperCase();
        System.out.println(s + s.length());
        System.out.println(s.substring(1, 3));
    }
}
أظهر الناتج
الناتج
6
GAZA4
AZ

لماذا؟ s.trim(); وحدها تهمل الناتج، فالطول ما زال 6. وبعد الحفظ يصبح الطول 4. وsubstring(1, 3) تأخذ الموقعين 1 و2 فقط.

الجزء الثالث: امتحان عملي تجريبي

الامتحان: 120 دقيقة وستة أسئلة تتصاعد صعوبتها

  • شغّل مؤقتًا. الوقت المقترح مكتوب في عنوان كل سؤال، ومجموعه 120 دقيقة.
  • لا تفتح التلميحات أو الحل حتى ينتهي الوقت، فلن تجدها في امتحان حقيقي.
  • لا تطبع أي نص يطلب الإدخال، واطبع الناتج كما هو مطلوب تمامًا. زر «تحقّق من الحل» يشغّل عدة اختبارات، منها حالات حدية.
  • إذا علقت في سؤال أكثر من وقته، فانتقل إلى التالي. الدرجات الجزئية موجودة.

السؤال 1 (10 دقائق): أجرة الموقف

اقرأ عدد الساعات عددًا صحيحًا. الساعتان الأوليان بسعر 2.50 للساعة، وكل ساعة بعدهما بسعر 1.50، والحد الأقصى للأجرة 15.00. اطبع Fee: مع الأجرة بمنزلتين. وإذا كان عدد الساعات صفرًا أو سالبًا فاطبع Invalid.

import java.util.Scanner;

public class Parking {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        // Read the hours, work out the fee, print it

    }
}
stdin
1
الناتج المتوقع
Fee: 2.50
تلميح 1

Math.min(fee, 15.0) تطبق الحد الأقصى.

الحل
import java.util.Scanner;

public class Parking {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int hours = input.nextInt();
        if (hours <= 0) {
            System.out.println("Invalid");
        } else {
            double fee;
            if (hours <= 2) {
                fee = hours * 2.5;
            } else {
                fee = 5 + (hours - 2) * 1.5;
            }
            System.out.printf("Fee: %.2f%n", Math.min(fee, 15.0));
        }
    }
}

السؤال 2 (15 دقيقة): الأرقام

اقرأ عددًا صحيحًا غير سالب. اطبع في ثلاثة أسطر: Digits: مع عدد أرقامه، وSum: مع مجموعها، وReversed: مع العدد معكوسًا بوصفه عددًا، فمعكوس 1200 هو 21. لا تستخدم النصوص، بل % و/.

import java.util.Scanner;

public class Digits {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        // Take digits off the end with % 10 and / 10

    }
}
stdin
1234
الناتج المتوقع
Digits: 4
Sum: 10
Reversed: 4321
تلميح 1

الحالة 0 تحتاج انتباهًا: حلقة while (n > 0) لا تدور، لكن للعدد 0 رقم واحد. فكّر في do-while.

الحل
import java.util.Scanner;

public class Digits {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        int digits = 0;
        int sum = 0;
        int reversed = 0;
        do {
            int last = n % 10;
            digits++;
            sum += last;
            reversed = reversed * 10 + last;
            n = n / 10;
        } while (n > 0);
        System.out.println("Digits: " + digits);
        System.out.println("Sum: " + sum);
        System.out.println("Reversed: " + reversed);
    }
}

السؤالان 3 و4: المصفوفات والدوال، ثم النصوص

السؤال 3 (20 دقيقة): تحليل مصفوفة

اقرأ n (واحد أو أكثر)، ثم n عددًا صحيحًا قد تكون سالبة. اكتب دالة لكل مطلوب، واطبع: Max: 9 at 2 أكبر قيمة وموقع أول ظهور لها، وAbove average: مع عدد القيم الأكبر تمامًا من المعدل الحقيقي، وReversed: مع القيم معكوسة تفصلها مسافة.

import java.util.Scanner;

public class ArrayStats {
    // Write your methods here: indexOfMax, countAboveAverage, printReversed

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        int[] values = new int[n];
        // Read the values, then call your methods

    }
}
stdin
5
4 8 15 16 23
الناتج المتوقع
Max: 23 at 4
Above average: 3
Reversed: 23 16 15 8 4
تلميح 1

ابدأ بأول عنصر لا بصفر، فكل القيم قد تكون سالبة.

تلميح 2

المعدل double. قسمة الأعداد الصحيحة تعطي جوابًا خاطئًا في الاختبار الأخير.

الحل
import java.util.Scanner;

public class ArrayStats {
    static int indexOfMax(int[] values) {
        int best = 0;
        for (int i = 1; i < values.length; i++) {
            if (values[i] > values[best]) {
                best = i;
            }
        }
        return best;
    }

    static int countAboveAverage(int[] values) {
        int sum = 0;
        for (int value : values) {
            sum += value;
        }
        double average = (double) sum / values.length;
        int count = 0;
        for (int value : values) {
            if (value > average) {
                count++;
            }
        }
        return count;
    }

    static void printReversed(int[] values) {
        System.out.print("Reversed:");
        for (int i = values.length - 1; i >= 0; i--) {
            System.out.print(" " + values[i]);
        }
        System.out.println();
    }

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        int[] values = new int[n];
        for (int i = 0; i < n; i++) {
            values[i] = input.nextInt();
        }
        int at = indexOfMax(values);
        System.out.println("Max: " + values[at] + " at " + at);
        System.out.println("Above average: " + countAboveAverage(values));
        printReversed(values);
    }
}

السؤال 4 (20 دقيقة): تنسيق العناوين

اقرأ سطرًا قد يحوي مسافات زائدة. اطبع كلماته في سطر واحد بينها مسافة واحدة، وكل كلمة تبدأ بحرف كبير وبقيتها صغيرة. ثم اطبع Words: مع عددها، ثم Longest: مع أطول كلمة بعد تنسيقها، والأولى عند التساوي. وإذا كان السطر فارغًا فاطبع Words: 0 فقط.

import java.util.Scanner;

public class TitleCase {
    // Write a method that formats one word

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        String line = input.nextLine();
        // Clean the line, split it, build the result

    }
}
stdin
hello world
الناتج المتوقع
Hello World
Words: 2
Longest: Hello
تلميح 1

Character.toUpperCase(w.charAt(0)) + w.substring(1).toLowerCase() تنسق كلمة واحدة، وتعمل حتى لو كانت من حرف واحد.

تلميح 2

StringBuilder مناسب لبناء السطر. لا تضف مسافة قبل الكلمة الأولى.

الحل
import java.util.Scanner;

public class TitleCase {
    static String format(String word) {
        return Character.toUpperCase(word.charAt(0)) + word.substring(1).toLowerCase();
    }

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        String line = input.nextLine().trim();
        if (line.length() == 0) {
            System.out.println("Words: 0");
            return;
        }
        String[] words = line.split("\\s+");
        StringBuilder out = new StringBuilder();
        String longest = "";
        for (int i = 0; i < words.length; i++) {
            String word = format(words[i]);
            if (i > 0) {
                out.append(" ");
            }
            out.append(word);
            if (word.length() > longest.length()) {
                longest = word;
            }
        }
        System.out.println(out);
        System.out.println("Words: " + words.length);
        System.out.println("Longest: " + longest);
    }
}

السؤالان 5 و6: مصفوفة ثنائية، ثم برنامج يجمع كل شيء

السؤال 5 (25 دقيقة): مجاميع الجدول

اقرأ عدد الصفوف r وعدد الأعمدة c (واحد أو أكثر)، ثم قيم الجدول صفًا بعد صف. اطبع Row 0: مع مجموع كل صف، ثم Column 0: مع مجموع كل عمود، ثم Best row: مع موقع الصف ذي المجموع الأكبر، والأول عند التساوي. اكتب دالة rowSum ودالة columnSum.

import java.util.Scanner;

public class TableTotals {
    // Write rowSum and columnSum here

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int r = input.nextInt();
        int c = input.nextInt();
        int[][] table = new int[r][c];
        // Read the table, then print the totals

    }
}
stdin
2 3
1 2 3
4 5 6
الناتج المتوقع
Row 0: 6
Row 1: 15
Column 0: 5
Column 1: 7
Column 2: 9
Best row: 1
تلميح 1

في columnSum يتغير الصف ويثبت العمود: table[i][col]، وتدور الحلقة حتى table.length.

تلميح 2

الجدول ليس مربعًا دائمًا: لا تخلط بين r وc. وقد تكون كل المجاميع سالبة، فابدأ بالصف 0 لا بالقيمة 0.

الحل
import java.util.Scanner;

public class TableTotals {
    static int rowSum(int[][] table, int row) {
        int sum = 0;
        for (int k = 0; k < table[row].length; k++) {
            sum += table[row][k];
        }
        return sum;
    }

    static int columnSum(int[][] table, int col) {
        int sum = 0;
        for (int i = 0; i < table.length; i++) {
            sum += table[i][col];
        }
        return sum;
    }

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int r = input.nextInt();
        int c = input.nextInt();
        int[][] table = new int[r][c];
        for (int i = 0; i < r; i++) {
            for (int k = 0; k < c; k++) {
                table[i][k] = input.nextInt();
            }
        }
        int best = 0;
        for (int i = 0; i < r; i++) {
            System.out.println("Row " + i + ": " + rowSum(table, i));
            if (rowSum(table, i) > rowSum(table, best)) {
                best = i;
            }
        }
        for (int k = 0; k < c; k++) {
            System.out.println("Column " + k + ": " + columnSum(table, k));
        }
        System.out.println("Best row: " + best);
    }
}

السؤال 6 (30 دقيقة): تقرير من ملف درجات

السطر الأول n، ثم n سطرًا بالشكل name,m1,m2,m3، وقد توجد مسافات حول الفواصل. يكون السطر سليمًا إذا كان فيه أربع قطع، وكانت كل درجة أرقامًا فقط وقيمتها من 0 إلى 100. لكل سطر سليم اطبع Sara: 90.00 A، والحرف: A من 90، وB من 80، وC من 70، وD من 60، وإلا F. ولكل سطر غير سليم اطبع Line 2: invalid برقم السطر من 1. وفي النهاية اطبع Valid: 2 of 3، ثم Top: Sara 90.00 للمعدل الأعلى والأول عند التساوي، أو Top: none.

import java.util.Scanner;

public class MarksReport {
    // Suggested methods: isMark(String text), letter(double average)

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = Integer.parseInt(input.nextLine().trim());
        // Read n lines and process each one

    }
}
stdin
3
Sara,80,90,100
Omar,70,70,71
Huda,50,55,60
الناتج المتوقع
Sara: 90.00 A
Omar: 70.33 C
Huda: 55.00 F
Valid: 3 of 3
Top: Sara 90.00
تلميح 1

اكتب isMark تفحص أن النص غير فارغ، وكل محارفه Character.isDigit، ثم حوّله وافحص المدى. الدرجة 0 يمكن أن تكون الأعلى، فلا تجعل top يبدأ من 0 مع >.

تلميح 2

قد تكون الدرجة الأولى فارغة بين فاصلتين، فلا تحوّل قبل الفحص، وإلا ظهر NumberFormatException.

الحل
import java.util.Scanner;

public class MarksReport {
    static boolean isMark(String text) {
        if (text.length() == 0 || text.length() > 3) {
            return false;
        }
        for (int i = 0; i < text.length(); i++) {
            if (!Character.isDigit(text.charAt(i))) {
                return false;
            }
        }
        return Integer.parseInt(text) <= 100;
    }

    static char letter(double average) {
        if (average >= 90) {
            return 'A';
        } else if (average >= 80) {
            return 'B';
        } else if (average >= 70) {
            return 'C';
        } else if (average >= 60) {
            return 'D';
        }
        return 'F';
    }

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = Integer.parseInt(input.nextLine().trim());
        int valid = 0;
        String topName = "";
        double topAverage = -1;
        for (int line = 1; line <= n; line++) {
            String[] parts = input.nextLine().split(",");
            boolean good = parts.length == 4;
            int total = 0;
            for (int i = 1; good && i < 4; i++) {
                String mark = parts[i].trim();
                if (isMark(mark)) {
                    total += Integer.parseInt(mark);
                } else {
                    good = false;
                }
            }
            if (good) {
                String name = parts[0].trim();
                double average = total / 3.0;
                System.out.printf("%s: %.2f %c%n", name, average, letter(average));
                valid++;
                if (average > topAverage) {
                    topAverage = average;
                    topName = name;
                }
            } else {
                System.out.println("Line " + line + ": invalid");
            }
        }
        System.out.println("Valid: " + valid + " of " + n);
        if (valid == 0) {
            System.out.println("Top: none");
        } else {
            System.out.printf("Top: %s %.2f%n", topName, topAverage);
        }
    }
}

أسئلة المراجعة الأخيرة، وإلى اللقاء في برمجة 2

في مشروعنا نحتفظ بالأسماء في names والدرجات في marks. ما المشكلة عند ترتيب الطلاب؟

ما دور الصنف Stats في مشروعنا؟