JavaRush /مدونة جافا /Random-AR /لعبة جافا للمبتدئين
timurnav
مستوى

لعبة جافا للمبتدئين

نشرت في المجموعة
مرحبا أصدقاء وزملاء المستقبل! لعبة جافا للمبتدئين - 1لقد أجريت مؤخرًا اختبارًا للمشاركة في مشروع حقيقي، ونجحت في اجتيازه، لكن حدث أنه بسبب ظروف شخصية لم أتمكن من المشاركة في البرنامج نفسه. بعد هذه المشاكل المثيرة للاهتمام مثل اختبار RP، أصبحت مشاكل الدورة المعتادة هواية أقل جاذبية، خاصة وأنني قد قمت بحل معظمها بالفعل. لذلك، حتى لا تضيع موهبتي في مواصلة التعلم، قررت إنشاء لعبة ويب متعددة اللاعبين. روابط لألعاب أخرى:
  1. استمرار هذه المادة
  2. 2048
بدت لعبة Tic Tac Toe وكأنها أبسط لعبة بالنسبة لي، لذلك قررت تقسيم المهمة إلى عدد من المهام الفرعية:
  1. تطبيق وحدة التحكم لاختبار منطق اللعبة
  2. متعددة اللاعبين
  3. إرفاق قاعدة بيانات اللاعب بتطبيق وحدة التحكم
  4. إنشاء تصميم الواجهة الأمامية وكتابة قوالب الصفحات وواجهة اللعبة
  5. ضع كل شيء معا
هناك احتمال أن يتم توبيخي لمثل هذا التسلسل، وعلى الأرجح يتم بناء جميع المشاريع الجادة في تسلسل مختلف تمامًا، وسأجيب على الفور، وأكتب منشورًا حول هذا "للمبتدئين" حتى يتمكن الجميع (بما فيهم أنا) يمكن أن أتعلم هذا :) حسنًا، لنبدأ في كتابة تطبيق وحدة التحكم! سأتبع نفس خطوات تحديات المستوى 20 الكبيرة. ماذا يوجد في لعبة تيك تاك تو؟!
  1. مجال
  2. لاعبان يتناوبان، أحدهما يضع عرضية، والآخر صفرًا. انه سهل.
نجعل الحقل حقلاً قياسيًا 3x3. كيف يمكن تخزين مثل هذا الحقل؟ الخيار الأول هو مصفوفة ثنائية الأبعاد. ما العناصر التي يجب أن تحتويها هذه المصفوفة؟ الجواب هو أننا بحاجة إلى التفكير فيما سنفعله بهذه العناصر، وهو العرض والمقارنة للعثور على الفائز. إذا كنا نعرضها على الشاشة فقط، فسيكون من المنطقي الاحتفاظ بها كسلسلة، ثم ستبدو المصفوفة نفسها وعرضها على الشاشة في حلقة كما يلي:
String[][] strings = {{"O", "O", "_"},
                    {"_", "X", "O"},
                    {"X", "X", "X"},
for (String [] ss : strings){
    for (String s : ss) System.out.print(s + " ");
    System.out.println(); //для перевода строки
}
ستعرض الشاشة:
O O _
_ X O
X X X
ولكن بالإضافة إلى العرض، لدينا أيضًا مقارنة للقيم، وهنا الخيارات ممكنة بالفعل. يمكنك مقارنة السلاسل، ويمكنك إنشاء فئة تعداد خاصة ( enum)، لكنني أفضل مقارنة الأرقام واستبدالها بـ "X" و"O" فقط عند عرضها على الشاشة. فليكن، على سبيل المثال، 1 - "X"، 2 - "O"، 0 - "_". إذًا، كيف يمكنك التحقق من الحقل بحثًا عن تطابق ثلاثي X أو O؟
تقوم الخوارزمية الأولى بفحص الحقل بأكمله
int[][] canvas = {{00, 01, 02},
                 {10, 11, 12},
                 {20, 21, 22}}
المجموعات الفائزة:
00-01-02, 10-11-12, 20-21-22, 00-10-20, 01-11-21, 02-12-22, 00-11-22, 20-11-02 — всего 8.
يتم التحقق من خلال مقارنة الأرقام، ولكن اتضح أنك بحاجة إلى التحقق من الحقل بأكمله، وجميع المجموعات الثمانية، في كل مرة. بالطبع، هذا ليس كثيرًا، هذا ليس بحثًا عن أرقام أرمسترونج في النطاق من 0 إلى 1 مليار، ولا يوجد سوى عدد قليل من الحسابات هنا، لكنك لا تزال تريد شيئًا أكثر مثالية من التحقق من الحقل بأكمله. الفكرة الثانية التي طرأت على ذهني هي التحقق فقط من الخلية التي تم وضع علامة عليها في الحركة السابقة، حتى نتمكن من تحديد الفائز، لأننا سنعرف من قام بهذه الخطوة. وبالتالي، بدلاً من جميع المجموعات الثمانية، نحصل على 2 أو 3 أو 4 مجموعات فقط، اعتمادًا على الخلية، انظر الصورة: لعبة جافا للمبتدئين - 2الآن نحن بحاجة إلى معرفة كيفية تحديد المجموعة التي يجب إطلاقها؟ هذا هو المكان الذي أدركت فيه أن استخدام مصفوفة ثنائية الأبعاد ليس أمرًا مريحًا للغاية. قررت النظر في خيارات أخرى. في البداية خطرت لي فكرة أن الحقل يمكن أن يبقى في رقم مكون من تسعة أرقام، مثلا نفس الحقل الذي عرضناه على الشاشة يمكن كتابته هكذا: 220012111، سأشرح بأصابعي ما هو هو... الكود هو نفسه، 1 - "X"، 2 - "O"، 0 - " "، مما يعني 220012111 = "OO__XOXXX"، أو إذا قمت بعد كل رقم ثالث بإدخال فاصل أسطر وإضافة مسافات لـ وضوح:
О О _
_ Х О
Х Х Х
هنا مرة أخرى، مناسب للتخزين، تم اختراع جهاز للعرض، ولكنه غير مناسب للمقارنة! الحل وجد عندما قمت بترقيم الخلايا من 1 إلى 9 ففكرت، لأنه في البرمجة يبدأ العد التنازلي من 0 وترقيمه كما في الصورة، لعبة جافا للمبتدئين - 3ألم تلاحظوا أي خصوصيات؟ إذا نظرت إلى الصورة أعلاه، فسيصبح من الواضح أن الحلول التي تحتوي على مجموعتين لها رقم تسلسلي فردي، و4 مجموعات لها رقم تسلسلي 4، و3 مجموعات لها الباقي. لذلك توصلت إلى استنتاج مفاده أنك بحاجة إلى الحفاظ على ساحة اللعب في مجموعة منتظمة من الأرقام: التكرار البسيط بين الأرقام، والقدرة على المقارنة وفقًا للخوارزمية التي تم اختيارها، والإخراج البسيط على الشاشة. أما بالنسبة لخوارزمية المقارنة نفسها. دعنا نذهب بالترتيب: في جميع الخيارات هناك فحص للصف والعمود، نتحقق منهم فقط. إذا لم ينتج البحث، فإننا نتحقق من رقم الخلية بحثًا عن زوجي/فردي، وإذا كان فرديًا، فإننا نعود إلى اللعبة، فلا فائدة من التحقق أكثر، إذا كان زوجيًا، فإننا نتحقق مما إذا كانت هذه الخلية تقع على القطر الأيسر، أرقام هذا القطر عند القسمة على 4 يكون الباقي 0. إذا كان كاذبًا، فإننا نتحقق من التطابقات، إذا لم يتم العثور على تطابقات، فإننا نتحقق من الرقم 4، إذا لم يكن الأمر كذلك، نعود إلى اللعبة، إذا نعم، نذهب أبعد من خلال الكود ونعيد نتيجة التحقق من القطر الأخير. ربما، بالنسبة لشخص غير مستعد، من الصعب فهم هذا بعد قراءة مجموعة الأحرف أعلاه، ولكن قد يقول شخص ما أن هناك الكثير من الحروف في الكود نفسه، والتي يمكن أن تكون أبسط، وسأكون سعيدًا بمناقشة هذا الأمر. لقد قمنا بفرز المجال، والآن نحتاج إلى التعامل مع مستخدمين يتناوبان ولكل منهما علامة خاصة به، X أو O. في المرحلة الأولى، ليس لدينا أي وظيفة متعددة المستخدمين، لذا فإن أسهل طريقة هي استخدام الرموز واحدة تلو الأخرى. يقوم X دائمًا بالحركة الأولى، ويقوم O دائمًا بالخطوة الثانية، ثم يقوم X مرة أخرى، وهكذا. يجب التحقق منه ( صواب/خطأ )، وإذا كان صحيحًا - فإن اللاعب الحالي هو X، وإذا كان خطأ - ثم O وفي بداية كل حركة، فإن flag=!flag يبقى تلقي إشارة بطريقة أو بأخرى من اللاعبين حول ما الخلية التي يختارونها. سنحتاج هنا إلى قيام BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); اللاعبين الذين لا يُنسى بإدخال أرقام الخلايا في وحدة التحكم، والضغط على Enter سيؤدي إلى التحرك. ستقوم الخلية المقابلة للرقم المُدخل بتغيير قيمتها من 0 إلى 1 أو 2، اعتمادًا على الحالة الحالية لمربع الاختيار، والتي تمت مناقشتها في الفقرة أعلاه. هذا هو المكان المهم للتحقق من صحة الإدخال حتى لا يتمكن أي شخص من تغيير X إلى O عندما تكون الخلية ممتلئة بالفعل :) ما الذي يمكن للاعب إدخاله في وحدة التحكم؟
  1. خط فارغ
  2. الحروف، علامات الترقيم، الأقواس... في كلمة واحدة، غير الأرقام
  3. أرقام غير صحيحة - سالبة أو خارج حجم الصفيف، خلايا مشغولة.
الطريقة القياسية للحصول على رقم من سلسلة هي الطريقة الثابتة parseInt لفئة Integer، Integer.parseInt("2");وهي تطرح استثناءً NumberFormatExceptionإذا لم تتمكن من الحصول على رقم من سلسلة معينة، يمكننا توفير الحماية من النقطتين الأوليين عن طريق اعتراض هذا الاستثناء. بالنسبة للنقطة الثالثة، سأقوم بإنشاء طريقة أخرى للتحقق من القيمة المدخلة، ولكن سيكون من الأصح نقل طلب السلسلة إلى طريقة منفصلة سيتم من خلالها إجراء التحقق من الصحة، وسوف يُرجع رقمًا فقط. للتلخيص، قمنا بإنشاء حقل، وصنعنا طريقة لعرضه، وصنعنا طريقة للتحقق من "ما إذا كان هذا اللاعب قد فاز بساعة؟"، والتحقق من صحة الأرقام المدخلة. لم يتبق سوى القليل جدًا للقيام به، والتحقق من التعادل - وهي طريقة منفصلة تعمل عبر المصفوفة وتبحث عن 0، وتعرض نتائج اللعبة. هذا كل شيء، الكود جاهز، اللعبة كانت صغيرة، فئة واحدة فقط، لذلك يمكن للنسخ الصعب، دون فهم، فقط نسخ كل شيء في مشروعهم وتشغيله بمفردهم، لقد كنت هكذا بنفسي، لكن الآن أحاول ألا أفعل ذلك ولا أوصي به لأي شخص :) حظًا سعيدًا للجميع في تعلم JAVA! ملاحظة: بقية النقاط - تعدد اللاعبين وقاعدة البيانات سيأتيان لاحقًا، لقد بدأت بالفعل في دراسة المادة :)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class GameField {

    static int [] canvas = {0,0,0,
                            0,0,0,
                            0,0,0};

    //012, 345, 678, 036, 147, 258, 048, 246
    public static void main(String[] args){

        boolean b;
        boolean isCurrentX = false;
        do {
            isCurrentX = !isCurrentX;
            drawCanvas();
            System.out.println("mark " + (isCurrentX ? "X" : "O"));
            int n = getNumber();
            canvas[n] = isCurrentX ? 1 : 2;
            b = !isGameOver(n);
            if (isDraw()){
                System.out.println("Draw");
                return;
            }
        } while (b);
        drawCanvas();
        System.out.println();

        System.out.println("The winner is " + (isCurrentX ? "X" : "O") + "!");
    }

    static int getNumber(){
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        while (true){
            try {
                int n = Integer.parseInt(reader.readLine());
                if (n >= 0 && n < canvas.length && canvas[n]==0){
                    return n;
                }
                System.out.println("Choose free cell and enter its number");
            } catch (NumberFormatException e) {
                System.out.println("Please enter the number");
            } catch (IOException e) {
            }
        }
    }

    static boolean isGameOver(int n){
        // 0 1 2
        // 3 4 5
        // 6 7 8
        //поиск совпадений по горизонтали
        int row = n-n%3; //номер строки - проверяем только её
        if (canvas[row]==canvas[row+1] &&
                canvas[row]==canvas[row+2]) return true;
        //поиск совпадений по вертикали
        int column = n%3; //номер столбца - проверяем только его
        if (canvas[column]==canvas[column+3])
            if (canvas[column]==canvas[column+6]) return true;
        //мы здесь, значит, первый поиск не положительного результата
        //если meaning n находится на одной из граней - возвращаем false
        if (n%2!=0) return false;
        //проверяем принадлежит ли к левой диагонали meaning
        if (n%4==0){
            //проверяем есть ли совпадения на левой диагонали
            if (canvas[0] == canvas[4] &&
                    canvas[0] == canvas[8]) return true;
            if (n!=4) return false;
        }
        return canvas[2] == canvas[4] &&
                canvas[2] == canvas[6];
    }

    static void drawCanvas(){
        System.out.println("     |     |     ");
        for (int i = 0; i < canvas.length; i++) {
            if (i!=0){
                if (i%3==0) {
                    System.out.println();
                    System.out.println("_____|_____|_____");
                    System.out.println("     |     |     ");
                }
                else
                    System.out.print("|");
            }

            if (canvas[i]==0) System.out.print("  " + i + "  ");
            if (canvas[i]==1) System.out.print("  X  ");
            if (canvas[i]==2) System.out.print("  O  ");
        }
        System.out.println();
        System.out.println("     |     |     ");
    }

    public static boolean isDraw() {
        for (int n : canvas) if (n==0) return false;
        return true;
    }
}
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION