إعلان
دورة تطوير التطبيقات باستخدام لغة JavaScript في هذه الدورة ستتعلم لغة جافا سكريبت, استخدام مكتبة React.js, بناء API الموقع بواسطة Node.js, تطوير تطبيق جوال باستخدام React Native, و في نهاية الدورة ستتعلم تطوير تطبيق محادثة شبيه بتطبيق WhatsApp. تعلم الآن
دورة تطوير واجهات المستخدم في هذه الدورة ستتعلم لغة HTML و لغة CSS و لغة JavaScript. من ناحية التطبيق العملي ستتعلم طريقة بناء واجهة متجر إلكتروني مكون من ست صفحات, تحويل خمسة تصاميم PSD إلى صفحات ويب, بناء واجهة مستخدم تشبه موقع يوتيوب, بناء لوحة تحكم إحترافية. تعلم الآن
تطوير تطبيقات باستخدام لغة بايثون في هذه الدورة ستتعلم أساسيات البرمجة بلغة بايثون وصولاً إلى التعامل مع أشهر أطر العمل (Flask و Django) و ستتعلم كيف تبني متجر إلكتروني يمكن للمستخدمين البيع و الشراء من خلاله. تعلم الآن
دورة تطوير تطبيقات الويب باستخدام لغة PHP في هذه الدورة ستتعلم لغة PHP من الصفر, استخدام إطار العمل Laravel بشرح مفصّل و عملي, كيفية تطوير شبكة اجتماعية تشبه Instagram, بناء API لتطبيق جوال وفق أسلوب RESTful, تطوير موقع إعلانات مبوبة, تطوير نظام إدارة محتوى CMS كامل. تعلم الآن
دورة تطوير تطبيقات الويب باستخدام لغة Ruby في هذه الدورة ستتعلم البرمجة بلغة Ruby إنطلاقاً من أبسط المفاهيم وحتى بناء تطبيق حقيقي, إستخدام إطار العمل Ruby on Rails بشرح مفصّل و عملي, بناء تطبيق حقيقي عبارة عن شبكة اجتماعية تشبه تويتر, تطوير مجتمع الكتروني يشبه حسوب I/O. تعلم الآن
دورة علوم الحاسوب هذه الدورة معدة لتكون مدخل لعلوم الحاسوب و لغات البرمجة حيث ستتعرف فيها على أنظمة التشغيل و ستتعمق في نظام لينكس و في كيفية التعامل معه من خلال موجه الأوامر, بالإضافة إلى قواعد البيانات و أساسيات الشبكات و الخوادم و مبادئ الحماية والأمان في الويب. تعلم الآن

    JavaFX طريقة إنشاء لعبة Tic Tac Toe

    في هذا الدرس ستتعلم طريقة إنشاء لعبة ( Tic Tac Toe ) إحترافية باستخدام إطار الـ JavaFX.

    javafx tic tac toe source code تحميل كود لعبة tic tac toe في جافا



    مميزات اللعبة

    • يمكن لعب هذه اللعبة مع صديق أو ضد الكمبيوتر نفسه.
    • يمكن تعديل تصميمها بكل سهولة من داخل اللعبة.


    بناء اللعبة

    • ملفات الجافا وضعناها مباشرةً في المشروع.
    • الصور وضعناها بداخل مجلد إسمه images.


    خيارات التحميل

    ⇓ تحميل اللعبة ⇓ تحميل المشروع كاملاً ⇓ تحميل مجلد الصور فقط



    كود اللعبة

    StartPane.java
    import javafx.scene.control.Alert;
    import javafx.scene.control.Alert.AlertType;
    import javafx.scene.control.Button;
    import javafx.scene.layout.Pane;
    
    // يمثل الحاوية التي سنظهرها عند تشغيل البرنامج StartPane الكلاس 
    public class StartPane extends Pane {
    
    	// هنا قمنا بإنشاء جميع الأشياء التي سنضعها في الحاوية
        Button singlePlayer = new Button("Single Player");
        Button multiPlayer = new Button("Multi Player");
        Button settings = new Button("Settings");
        Button about = new Button("About");
        Button exit = new Button("Exit");
    
    	// about لأننا سنستخدمه لعرض نافذة منبثقة عندما يقوم المستخدم بالنقر على الزر Alert هنا قمنا بإنشاء كائن من الكلاس
        Alert alert = new Alert(AlertType.INFORMATION);
    
    	// هذا كونستركور الكلاس
        public StartPane() {
    
    		// StartPane هنا قمنا بتحديد حجم كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
            singlePlayer.setPrefSize(240, 40);
            multiPlayer.setPrefSize(240, 40);
            settings.setPrefSize(240, 40);
            about.setPrefSize(240, 40);
            exit.setPrefSize(240, 40);
    
    		// StartPane هنا قمنا بتحديد موقع كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
            singlePlayer.setTranslateX(80);
            singlePlayer.setTranslateY(110);
            multiPlayer.setTranslateX(80);
            multiPlayer.setTranslateY(170);
            settings.setTranslateX(80);
            settings.setTranslateY(230);
            about.setTranslateX(80);
            about.setTranslateY(290);
            exit.setTranslateX(80);
            exit.setTranslateY(350);
    
    		// StartPane هنا قمنا بإضافة كل شيء قمنا بإنشائه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
            getChildren().add(singlePlayer);
            getChildren().add(multiPlayer);
            getChildren().add(settings);
            getChildren().add(about);
            getChildren().add(exit);
    
    		// singlePlayer هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
    		// مكان الحاوية الحالية singlePlayerPane لعرض الحاوية التي يمثلها الكائن viewPane() سيتم إستدعاء الدالة الثابتة
            singlePlayer.setOnAction((Action) -> {
                AppManager.viewPane(AppManager.singlePlayerPane);
            });
    
    		// multiPlayer هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
    		// مكان الحاوية الحالية multiPlayerPane لعرض الحاوية التي يمثلها الكائن viewPane() سيتم إستدعاء الدالة الثابتة
            multiPlayer.setOnAction((Action) -> {
                AppManager.viewPane(AppManager.multiPlayerPane);
            });
    
    		// settings هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
    		// مكان الحاوية الحالية settings لعرض الحاوية التي يمثلها الكائن viewPane() سيتم إستدعاء الدالة الثابتة
            settings.setOnAction((Action) -> {
                AppManager.viewPane(AppManager.settingsPane);
            });
    
    		// about هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
            // alert سيتم تجهيز نص يمثل معلومات عامة عن اللعبة و الذي سنعرضه بداخل النافذة المنبثقة التي يمثلها الكائن
            about.setOnAction((Action) -> {
                String str
                        = "Prepared by Mhamad Harmush\n\n"
                        + "If you have any comments, ideas.. just let me know\n\n"
                        + "Email:   mhamad.harmush@gmail.com\n"
                        + "Twitter & Facebook:   @MhamadHarmush\n\n"
                        + "Note\n"
                        + "I used JDK 1.8 to compile the source code.\n\n"
                        + "© Copyright 2019 harmash.com - All Rights Reserved";
    
                alert.setTitle("About Tic Tac Toe");
                alert.setHeaderText("About Tic Tac Toe");
                alert.setContentText(str);
                alert.showAndWait();
            });
    
    		// exit هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
            exit.setOnAction((Action) -> {
                System.exit(0);
            });
        }
    
    }
    		

    SettingsPane.java
    import javafx.beans.value.ObservableValue;
    import javafx.scene.control.Button;
    import javafx.scene.control.ComboBox;
    import javafx.scene.control.Label;
    import javafx.scene.layout.Pane;
    import javafx.scene.text.Font;
    import javafx.scene.text.FontWeight;
    
    // ( Settings ) يمثل الحاوية التي سنظهرها عند النقر على زر ضبط اللعبة SettingsPane الكلاس 
    public class SettingsPane extends Pane {
    
    	// هنا قمنا بإنشاء جميع الأشياء التي سنضعها في الحاوية
        Label labelForBoards = new Label("Game Board");
        Label labelForFontSizes = new Label("Font Size");
        ComboBox boardsComboBox = new ComboBox();
        ComboBox fontSizesComboBox = new ComboBox();
        Button reset = new Button("Reset Default Settings");
        Button back = new Button("Back");
    
    	// هذا كونستركور الكلاس
        public SettingsPane() {
    
    		// fontSizesComboBox و boardsComboBox هنا قمنا بوضع الخيارات التي يمكن للمستخدم اختيارها في الكائنين
            boardsComboBox.getItems().addAll("Board 1", "Board 2", "Board 3", "Board 4");
            fontSizesComboBox.getItems().addAll("Small", "Medium", "Large");
    
    		// SettingsPane هنا قمنا بتحديد حجم كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
            labelForBoards.setPrefSize(100, 30);
            boardsComboBox.setPrefSize(120, 30);
            labelForFontSizes.setPrefSize(100, 30);
            fontSizesComboBox.setPrefSize(120, 30);
            reset.setPrefSize(240, 40);
            back.setPrefSize(240, 40);
    
    		// SettingsPane هنا قمنا بتحديد موقع كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
            labelForBoards.setTranslateX(80);
            labelForBoards.setTranslateY(130);
            boardsComboBox.setTranslateX(200);
            boardsComboBox.setTranslateY(130);
            labelForFontSizes.setTranslateX(80);
            labelForFontSizes.setTranslateY(190);
            fontSizesComboBox.setTranslateX(200);
            fontSizesComboBox.setTranslateY(190);
            reset.setTranslateX(80);
            reset.setTranslateY(250);
            back.setTranslateX(80);
            back.setTranslateY(310);
     
    		// SettingsPane هنا قمنا بإضافة كل شيء قمنا بإنشائه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس       
            getChildren().add(labelForBoards);
            getChildren().add(boardsComboBox);
            getChildren().add(labelForFontSizes);
            getChildren().add(fontSizesComboBox);
            getChildren().add(reset);
            getChildren().add(back);
            
    		// boardsComboBox هنا قمنا بتحديد ما سيحدث عندما يقوم المستخدم بتغيير القيمة الظاهرة في الكائن
            // AppManager الموضوع في الكلاس preferredBoard بناءاً على القيمة التي يختارها سيتم تمرير إسم الصورة للمتغير الثابت
            boardsComboBox.getSelectionModel().selectedIndexProperty().addListener(
                (ObservableValue<? extends Number> ov, Number oldVal, Number newVal) -> {
                    switch((int)newVal) {
                        case 0:
                            AppManager.preferredBoard = "board_1.png";
                            break;
                            
                        case 1:
                            AppManager.preferredBoard = "board_2.png";
                            break;
                            
                        case 2:
                            AppManager.preferredBoard = "board_3.png";
                            break;
                            
                        case 3:
                            AppManager.preferredBoard = "board_4.png";
                            break;
                    }
            });
     
    		// fontSizesComboBox هنا قمنا بتحديد ما سيحدث عندما يقوم المستخدم بتغيير القيمة الظاهرة في الكائن
            // AppManager الموضوع في الكلاس preferredFont بناءاً على القيمة التي يختارها سيتم تمرير حجم الخط للكائن الثابت
    		// لتغيير حجم خط كل الأزرار, النصوص و مربعات النصوص الموضوعة في اللعبة setFont() كما أنه سيتم استدعاء الدالة
    		fontSizesComboBox.getSelectionModel().selectedIndexProperty().addListener(
                (ObservableValue<? extends Number> ov, Number oldVal, Number newVal) -> {
                    
                String selectedFont = fontSizesComboBox.getSelectionModel().getSelectedItem().toString();
                int fontSize = 0;
    
                switch(selectedFont) {
                    case "Small":
                        fontSize = 15;
                        break;
                    
                    case "Medium":
                        fontSize = 16;
                        break;
                        
                    case "Large":
                        fontSize = 17;
                        break;
                }
                
                AppManager.preferredFont = Font.font("Arial", FontWeight.BOLD, fontSize);
                AppManager.setFont();
    
            });
            
    		// reset هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
    		// لإرجاع القيم الإفتراضية التي كانت موضوعة في الحاوية AppManager الموجودة في الكلاس setDefaultSettings() سيتم استدعاء الدالة
            reset.setOnAction((Action) -> {
    			AppManager.setDefaultSettings();
                boardsComboBox.getSelectionModel().selectFirst();
                fontSizesComboBox.getSelectionModel().select(1);
            });
            
    		// back هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
    		// مكان الحاوية الحالية startPane لعرض الحاوية التي يمثلها الكائن viewPane() سيتم إستدعاء الدالة الثابتة
            back.setOnAction((Action) -> {
                AppManager.viewPane(AppManager.startPane);
            });
            
        }
    
    }
    		

    SinglePlayerPane.java
    import javafx.scene.control.Button;
    import javafx.scene.control.Label;
    import javafx.scene.control.TextField;
    import javafx.scene.image.Image;
    import javafx.scene.layout.Pane;
    
    // ( Single Player ) يمثل الحاوية التي سنظهرها عند النقر على زر اللعب ضد الكمبيوتر SinglePlayerPane الكلاس 
    public class SinglePlayerPane extends Pane {
        
    	// هنا قمنا بإنشاء جميع الأشياء التي سنضعها في الحاوية
        Label playerNameLabel = new Label("Player Name");
        TextField playerName = new TextField("player");
        Button start = new Button("Start");
        Button back = new Button("Back");
        
    	// هذا كونستركور الكلاس
    	public SinglePlayerPane() {
    
    		// SinglePlayerPane هنا قمنا بتحديد حجم كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
            playerNameLabel.setPrefSize(100, 30);
            playerName.setPrefSize(130, 30);
            start.setPrefSize(240, 40);
            back.setPrefSize(240, 40);
    
    		// SinglePlayerPane هنا قمنا بتحديد موقع كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
            playerNameLabel.setTranslateX(80);
            playerNameLabel.setTranslateY(170);
            playerName.setTranslateX(190);
            playerName.setTranslateY(170);
            start.setTranslateX(80);
            start.setTranslateY(220);
            back.setTranslateX(80);
            back.setTranslateY(280);
    
    		// SinglePlayerPane هنا قمنا بإضافة كل شيء قمنا بإنشائه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس   
            getChildren().add(playerNameLabel);
            getChildren().add(playerName);
            getChildren().add(start);
            getChildren().add(back);
            
    		// start هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
    		// مع وضع القيمة 0 كنتيجة أولية له و للكمبيوتر gamePane سيتم تمرير الإسم الذي يدخله المستخدم, كإسم اللاعب الذي سيظهر في الحاوية
    		// gamePane بعدها سيتم وضع صورة الخلفية التي اختارها المستخدم أو الصورة المختارة إفتراضياً كخلفية للعبة في الحاوية
    		// مكان الحاوية الحالية gamePane لعرض الحاوية التي يمثلها الكائن viewPane() في الأخير سيتم إستدعاء الدالة الثابتة
            start.setOnAction((Action) -> {
                AppManager.gamePane.firstPlayerName.setText(playerName.getText());
                AppManager.gamePane.secondPlayerName.setText("Computer");
                AppManager.gamePane.firstPlayerScore.setText("0");
                AppManager.gamePane.secondPlayerScore.setText("0");
    
    			// للإشارة إلى أنه سيتم اللعب ضد الكمبيوتر AppManager الموضوع في الكلاس challengeComputer للمتغير الثابت true مررنا القيمة
                AppManager.challengeComputer = true;
                
                AppManager.gamePane.boardBackground
                        .setImage(new Image(getClass().getResourceAsStream("/images/"+AppManager.preferredBoard)));
                
                AppManager.viewPane(AppManager.gamePane);
            });
    
    		// back هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
    		// مكان الحاوية الحالية startPane لعرض الحاوية التي يمثلها الكائن viewPane() سيتم إستدعاء الدالة الثابتة        
            back.setOnAction((Action) -> {
                AppManager.viewPane(AppManager.startPane);
            });
        }
        
    }
    		

    MultiPlayerPane.java
    import javafx.scene.control.Button;
    import javafx.scene.control.Label;
    import javafx.scene.control.TextField;
    import javafx.scene.image.Image;
    import javafx.scene.layout.Pane;
    
    // ( Multi Player ) يمثل الحاوية التي سنظهرها عند النقر على زر اللعبة بين شخصين موجودين على نفس الجهاز MultiPlayerPane الكلاس 
    public class MultiPlayerPane extends Pane {
    
    	// هنا قمنا بإنشاء جميع الأشياء التي سنضعها في الحاوية
        Label playerXLabel = new Label("Player X");
        Label playerOLabel = new Label("Player O");
        TextField firstPlayerName = new TextField("player 1");
        TextField secondPlayerName = new TextField("player 2");
        Button start = new Button("Start");
        Button back = new Button("Back");
    
    	// هذا كونستركور الكلاس
        public MultiPlayerPane() {
    
    		// MultiPlayerPane هنا قمنا بتحديد حجم كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
            playerXLabel.setPrefSize(70, 30);
            firstPlayerName.setPrefSize(160, 30);
            playerOLabel.setPrefSize(70, 30);
            secondPlayerName.setPrefSize(160, 30);
            start.setPrefSize(240, 40);
            back.setPrefSize(240, 40);
    
    		// MultiPlayerPane هنا قمنا بتحديد موقع كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
            playerXLabel.setTranslateX(80);
            playerXLabel.setTranslateY(130);
            firstPlayerName.setTranslateX(160);
            firstPlayerName.setTranslateY(130);
            playerOLabel.setTranslateX(80);
            playerOLabel.setTranslateY(190);
            secondPlayerName.setTranslateX(160);
            secondPlayerName.setTranslateY(190);
            start.setTranslateX(80);
            start.setTranslateY(250);
            back.setTranslateX(80);
            back.setTranslateY(310);
            
    		// MultiPlayerPane هنا قمنا بإضافة كل شيء قمنا بإنشائه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس   
            getChildren().add(playerXLabel);
            getChildren().add(playerOLabel);
            getChildren().add(firstPlayerName);
            getChildren().add(secondPlayerName);
            getChildren().add(start);
            getChildren().add(back);
    
    		// start هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
    		// مع وضع القيمة 0 كنتيجة أولية لكلا اللاعبين gamePane سيتم تمرير أسماء اللاعبين اللذين سيدخلوهما للحاوية
    		// gamePane بعدها سيتم وضع صورة الخلفية التي اختاروها أو الصورة المختارة إفتراضياً كخلفية للعبة في الحاوية
    		// مكان الحاوية الحالية gamePane لعرض الحاوية التي يمثلها الكائن viewPane() في الأخير سيتم إستدعاء الدالة الثابتة
            start.setOnAction((Action) -> {
                AppManager.gamePane.firstPlayerName.setText(firstPlayerName.getText());
                AppManager.gamePane.secondPlayerName.setText(secondPlayerName.getText());
                AppManager.gamePane.firstPlayerScore.setText("0");
                AppManager.gamePane.secondPlayerScore.setText("0");
    
    			// للإشارة إلى أنه لن يتم اللعب ضد الكمبيوتر AppManager الموضوع في الكلاس challengeComputer للمتغير الثابت false مررنا القيمة
                AppManager.challengeComputer = false;
                
                AppManager.gamePane.boardBackground
                        .setImage(new Image(getClass().getResourceAsStream("/images/"+AppManager.preferredBoard)));
                
                AppManager.viewPane(AppManager.gamePane);
            });
            
    		// back هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
    		// مكان الحاوية الحالية startPane لعرض الحاوية التي يمثلها الكائن viewPane() سيتم إستدعاء الدالة الثابتة        
            back.setOnAction((Action) -> {
                AppManager.viewPane(AppManager.startPane);
            });
        }
        
    }
    		

    AppManager.java
    import javafx.scene.layout.Pane;
    import javafx.scene.text.Font;
    
    // static قمنا بإنشائه لتمرير القيم المشتركة بين حاويات اللعبة بسهولة لهذا قمنا بتعريف كل شيء فيه كـ AppManager الكلاس
    public class AppManager {
        
    	// هنا قمنا بإنشاء كائن من كل كلاس يمثل حاوية قمنا بتجهيزه سابقاً
        static StartPane startPane = new StartPane();
        static SinglePlayerPane singlePlayerPane = new SinglePlayerPane();
        static MultiPlayerPane multiPlayerPane = new MultiPlayerPane();
        static SettingsPane settingsPane = new SettingsPane();
        static GamePane gamePane = new GamePane();
        
    	// SettingsPane سنخزن فيه إسم صورة خلفية اللعبة التي يستطيع المستخدم تغييرها من الحاوية preferredBoard المتغير
        static String preferredBoard;
    
    	// SettingsPane سنخزن فيه حجم خط كل زر, نص و مربع نص أضفناه في اللعبة و الذي يستطيع المستخدم تغييره من الحاوية preferredFont الكائن
        static Font preferredFont;
        
    	// للإشارة إلى أنه سيتم اللعب ضد الكمبيوتر SinglePlayerPane الموضوع في الحاوية start عند النقر على الزر true سنخزن فيه القيمة challengeComputer المتغير
        static boolean challengeComputer;
        
    	// pane الدالة التالية نستخدمها لإخفاء أي نافذة معروضة حالياً في النافذة و عرض الحاوية التي نمررها لها فقط مكان الباراميتر
        public static void viewPane(Pane pane)
        {
            startPane.setVisible(false);
            singlePlayerPane.setVisible(false);
            multiPlayerPane.setVisible(false);
            settingsPane.setVisible(false);
            gamePane.setVisible(false);
            
            pane.setVisible(true);
        }
        
    	// settingsPane الدالة التالية نستخدمها لوضع الخيارات الإفتراضية التي يمكن تغييرها في الحاوية
        public static void setDefaultSettings()
        {
    		// fontSizesComboBox و ثاني خيار في الكائن boardsComboBox هنا قلنا أنه سيتم إختيار أول خيار في الكائن
            settingsPane.boardsComboBox.getSelectionModel().selectFirst();
            settingsPane.fontSizesComboBox.getSelectionModel().select(1);
    		
    		// preferredFont لتغيير حجم خط كل زر, نص و مربع نص موضوع في اللعبة نسبةً لقيمة الكائن setFont() هنا قمنا باستدعاء الدالة
            setFont();
        }
    
    	// preferredFont الدالة التالية نستخدمها لتحديد حجم خط كل زر, نص و مربع نص موضوع في اللعبة نسبةً لقيمة الكائن
        public static void setFont()
        {
            startPane.singlePlayer.setFont(preferredFont);
            startPane.multiPlayer.setFont(preferredFont);
            startPane.settings.setFont(preferredFont);
            startPane.about.setFont(preferredFont);
            startPane.exit.setFont(preferredFont);
            
            singlePlayerPane.playerNameLabel.setFont(preferredFont);
            singlePlayerPane.playerName.setFont(preferredFont);
            singlePlayerPane.start.setFont(preferredFont);
            singlePlayerPane.back.setFont(preferredFont);
            
            multiPlayerPane.playerXLabel.setFont(preferredFont);
            multiPlayerPane.playerOLabel.setFont(preferredFont);
            multiPlayerPane.firstPlayerName.setFont(preferredFont);
            multiPlayerPane.secondPlayerName.setFont(preferredFont);
            multiPlayerPane.start.setFont(preferredFont);
            multiPlayerPane.back.setFont(preferredFont);
            
            gamePane.firstPlayerName.setFont(preferredFont);
            gamePane.secondPlayerName.setFont(preferredFont);
            gamePane.firstPlayerScore.setFont(preferredFont);
            gamePane.secondPlayerScore.setFont(preferredFont);
            gamePane.currentPlayerSymbol.setFont(preferredFont);
            gamePane.restart.setFont(preferredFont);
            gamePane.back.setFont(preferredFont);
            
            
            settingsPane.labelForBoards.setFont(preferredFont);
            settingsPane.labelForFontSizes.setFont(preferredFont);
            settingsPane.reset.setFont(preferredFont);
            settingsPane.back.setFont(preferredFont);
    		
    		// لتحديد لهما setStyle() لا يملكان دالة خاصة لتحديد حجم الخط, لذلك قمنا باستخدام الدالة fontSizesComboBox و boardsComboBox الكائنين
            settingsPane.boardsComboBox.setStyle(
                "-fx-font-family:" + preferredFont.getName() + ";"
               +"-fx-font-size: " + preferredFont.getSize() +"px;"
               +"-fx-font-weight: bold;"
            );
            settingsPane.fontSizesComboBox.setStyle(
                "-fx-font-family:" + preferredFont.getName() + ";"
               +"-fx-font-size: " + preferredFont.getSize() +"px;"
               +"-fx-font-weight: bold;"
            );
        }
        
    }
    		

    GamePane.java
    import java.util.Random;
    import javafx.event.ActionEvent;
    import javafx.event.EventHandler;
    import javafx.geometry.Insets;
    import javafx.geometry.Pos;
    import javafx.scene.control.Button;
    import javafx.scene.control.Label;
    import javafx.scene.image.ImageView;
    import javafx.scene.layout.GridPane;
    import javafx.scene.layout.Pane;
    import javafx.scene.paint.Color;
    import javafx.scene.text.Font;
    import javafx.scene.text.FontWeight;
    
    // ( Multi Player ) و ( Single Player ) يمثل حاوية اللعب التي سنظهرها عند النقر على زر بدء اللعبة الموجود في كل من الحاويتين GamePane الكلاس 
    public class GamePane extends Pane {
    
        // هنا قمنا بإنشاء جميع الأشياء التي سنضعها في الحاوية
        Label firstPlayerName = new Label();
        Label secondPlayerName = new Label();
        Label firstPlayerScore = new Label("0");
        Label secondPlayerScore = new Label("0");
        Label currentPlayerSymbol = new Label();
        GridPane boardPane = new GridPane();
        Button[] boardButtons = new Button[3*3];
        Button back = new Button("Back");
        Button newGame = new Button("New Game");
        ImageView boardBackground = new ImageView();
    
        // سنستخدم هذا المتغير أيضاً لتحديد ما إذا كان سيتم إيقاف اللعبة بسبب فوز أحد اللاعبين
        boolean isGameEnds;
        
        // سنستخدم هذا المتغير لتحديد دور من في اللعب
        boolean isFirstPlayerTurn = true;
        
        // سنستخدم هذا المتغير لحساب عدد النقرات و بالتالي لتحديد ما إذا كان سيتم إيقاف اللعبة أم لا
        int XOCounter = 0;
        
        // randomNumber لتوليد أرقام عشوائية عند اللعب ضد الكمبيوتر. و سنخزن الرقم في المتغير random سنستخدم الكائن
        Random random = new Random();
        int randomNumber;
        
        // O و X يمثلان الألوان الإفتراضية التي سنضعها للرموز Color هنا قمنا بإنشاء كائنين من الكلاس
        Color xForeground = Color.BLUE;
        Color oForeground = Color.RED;
    
        
        // boardPane لأننا سنستخدمه لتحديد ما سيحدث عند النقر على أي زر موضوع في الحاوية EventHandler هنا قمنا بإنشاء كائن من الإنترفيس
        // e و تمرير الكائن الذي يمثل الزر الذي تم النقر عليه مكان الباراميتر actionPerformed() بشكل عام, سيتم استدعاء الدالة
        EventHandler<ActionEvent> eventHandler = (ActionEvent e) -> {
            actionPerformed(e);
        };
    
        
        // سنستخدم هذه الدالة لتلوين خلفية المربعات التي بسببها فاز اللاعب باللون الأصفر
        private void colorBackgroundWinnerButtons(Button b1, Button b2, Button b3)
        {
            b1.setStyle("-fx-background-color: yellow;");
            b2.setStyle("-fx-background-color: yellow;");
            b3.setStyle("-fx-background-color: yellow;");
        }
        
        
        // O و X سنستخدم هذه الدالة لإنشاء الأزرار التي يمكن النقر عليها لإظهار الرموز
        // أيضاَ boardPane و سنضيفها في الحاوية boardButtons كما أننا سنخزن هذه الأزرار في المصفوفة
        private void createGameBoard() {
            
            int row = 0;
            int column = 0;
            
            for (int i = 0; i < boardButtons.length; i++) {
    
                boardButtons[i] = new Button();
    
                boardButtons[i].setPrefSize(90, 90);
                boardButtons[i].setFocusTraversable(false);
    
                GridPane.setMargin(boardButtons[i], new Insets(5));
                boardButtons[i].setFont(Font.font("Arial", FontWeight.BOLD, 40));
    
                boardPane.add(boardButtons[i], column, row);
    
                boardButtons[i].addEventHandler(ActionEvent.ACTION, e -> {
                    actionPerformed(e);
                });
                    
                column++;
                if(column == 3)
                {
                    row++;
                    column = 0;
                }
            }
            
        }
    
        // سنستخدم هذه الدالة في كل مرة يلعب فيها اللاعبون للتأكد ما إذا كان هناك فائز أم لا
        // لتلوين خلفية خلفية المربعات التي كانت سبب فوز الاعب colorBackgroundWinnerButtons و في حال كان يوجد فائز سيتم مناداة الدالة
        // لإيقاف اللعبة. و سيتم إضافة واحد في نتيجة اللاعب الفائز true إلى isGameEnds كما أننا سنقوم بتغيير قيمة المتغير
        private void checkIfGameEnds() {
                
            String t00 = boardButtons[0].getText();
            String t01 = boardButtons[1].getText();
            String t02 = boardButtons[2].getText();
            String t10 = boardButtons[3].getText();
            String t11 = boardButtons[4].getText();
            String t12 = boardButtons[5].getText();
            String t20=  boardButtons[6].getText();
            String t21 = boardButtons[7].getText();
            String t22 = boardButtons[8].getText();
      
            if (t00.equals(t01) && t00.equals(t02) && !t00.equals("")) {
                isGameEnds = true;
                colorBackgroundWinnerButtons(boardButtons[0], boardButtons[1], boardButtons[2]);
            }
     
            if (t10.equals(t11) && t10.equals(t12) && !t10.equals("")) {
                isGameEnds = true;
                colorBackgroundWinnerButtons(boardButtons[3], boardButtons[4], boardButtons[5]);
            }
     
            if (t20.equals(t21) && t20.equals(t22) && !t20.equals("")) {
                isGameEnds = true;
                colorBackgroundWinnerButtons(boardButtons[6], boardButtons[7], boardButtons[8]);
            }
     
            if (t00.equals(t10) && t00.equals(t20) && !t00.equals("")) {
                isGameEnds = true;
                colorBackgroundWinnerButtons(boardButtons[0], boardButtons[3], boardButtons[6]);
            }
     
            if (t01.equals(t11) && t01.equals(t21) && !t01.equals("")) {
                isGameEnds = true;
                colorBackgroundWinnerButtons(boardButtons[1], boardButtons[4], boardButtons[7]);
            }
     
            if (t02.equals(t12) && t02.equals(t22) && !t02.equals("")) {
                isGameEnds = true;
                colorBackgroundWinnerButtons(boardButtons[2], boardButtons[5], boardButtons[8]);
            }
     
            if (t00.equals(t11) && t00.equals(t22) && !t00.equals("")) {
                isGameEnds = true;
                colorBackgroundWinnerButtons(boardButtons[0], boardButtons[4], boardButtons[8]);
            }
     
            if (t02.equals(t11) && t02.equals(t20) && !t02.equals("")) {
                isGameEnds = true;
                colorBackgroundWinnerButtons(boardButtons[2], boardButtons[4], boardButtons[6]);
            }
            
            if( XOCounter >= 9)
            {
                isGameEnds = true;
                isFirstPlayerTurn = true;
                XOCounter = 0;
            }
            
            if(isGameEnds == true)
            {
                if(isFirstPlayerTurn)
                    firstPlayerScore.setText(Integer.valueOf(firstPlayerScore.getText()) + 1 + "");
        
                else
                    secondPlayerScore.setText(Integer.valueOf(secondPlayerScore.getText()) + 1 + "");
    
                XOCounter = 0;
                newGame.requestFocus();
            }
            
        }
        
        // موضوع  في الحاوية و لإزالة أي O و X نستخدم هذه الدالة في كل مرة عند بدء اللعب من جديد لإزالة أي رمز
        // و لتحديد دور اللاعب الذي سيبدأ colorBackgroundWinnerButtons() ألوان موضوعة بسبب الدالة 
        private void startNewGame() {
    
            isGameEnds = false;
            setCurrentPlayerSymbol();
    
            for (Button boardButton : boardButtons) {
                boardButton.setText("");
                boardButton.setStyle("-fx-background-color: none; -fx-cursor: hand;");
            }
    
        }
    
    
        // مما يجعلنا نعرف دور من الآن في اللعب currentPlayerSymbol كنص للكائن O أو X نستخدم هذه الدالة في كل مرة لإظهار الرمز
        private void setCurrentPlayerSymbol() {
            
            if (isFirstPlayerTurn == true) {
                currentPlayerSymbol.setText("X");
                currentPlayerSymbol.setTextFill(xForeground);
            } else {
                currentPlayerSymbol.setText("O");
                currentPlayerSymbol.setTextFill(oForeground);
            }
            
        }
    
        
        // boardPane في هذه الدالة قمنا بتحديد ما سيحدث عندما يقوم اللاعبون بالنقر على أي زر موضوع في الحاوية
        private void actionPerformed(ActionEvent e)
        {
            // clickedButton سيتم تخزين الزر الذي تم النقر عليه بشكل مؤقت في الكائن
            Button clickedButton = (Button) e.getSource();
            
            // سيحدث التالي O أو X إذا لم تكن اللعبة قد انتهت و كان المستخدم قد قام بالنقر على زر لا يوجد عليه رمز
            if( isGameEnds == false && clickedButton.getText().equals("") )
            {
                // إذا كان يوجد لاعبين يلعبان ضد بعضهما سيتم وضع رمز اللاعب الحالي على الزر الذي تم النقر عليه
                if(AppManager.challengeComputer == false)
                {
                    if(isFirstPlayerTurn) {
                        clickedButton.setTextFill(xForeground);
                        clickedButton.setText("X");
                    }
                    else {
                        clickedButton.setTextFill(oForeground);
                        clickedButton.setText("O");
                    }
                    
                    // بعدها سيتم التأكد ما إن فاز أم لا و سيتم تبديل الأدوار إن لم يكن قد فاز
                    checkIfGameEnds();
                    setCurrentPlayerSymbol();
                    isFirstPlayerTurn = !isFirstPlayerTurn;
                    setCurrentPlayerSymbol();
                }
        
                // إذا كان اللاعب يلعب ضد الكمبيوتر
                if (AppManager.challengeComputer == true)
                {
                    // على الزر الذي نقر عليه و من ثم التأكد ما إن فاز أم لا X سيتم وضع الرمز
                    XOCounter++;
                    isFirstPlayerTurn = true;
                    clickedButton.setTextFill(xForeground);
                    clickedButton.setText("X");
                    checkIfGameEnds();
                    
                    // إذا لم يكن المستخدم قد فاز, أي إذا لم يتم إيقاف اللعبة, سيحد التالي
                    if(isGameEnds == false)
                    {
                        // O هنا قمنا بجعل جميع الأزرار غير قابلة للنقر, لأننا نريد جعل الكمبيوتر الآن يقوم بالنقر و وضع الرمز
                        for (Button boardButton : boardButtons) {
                            boardButton.removeEventHandler(ActionEvent.ACTION, eventHandler);
                        }
                        
                        // في مكان عشوائي و من ثم تأكدنا ما إن كان قد فاز أم لا O هنا جعلنا الكمبيوتر يضع الرمز
                        XOCounter++;
                        isFirstPlayerTurn = false;
                        for (;;) {
                            randomNumber = random.nextInt(9);
                            if (boardButtons[randomNumber].getText().equals(""))
                            {
                                boardButtons[randomNumber].setTextFill(oForeground);
                                boardButtons[randomNumber].setText("O");
                                break;
                            }
                        }
                        checkIfGameEnds();
                        
                        // X هنا قمنا بجعل جميع الأزرار قابلة للنقر من جديد, لأننا نريد جعل المستخدم قادر على النقر و وضع الرمز
                        for (Button boardButton : boardButtons) {
                            boardButton.addEventHandler(ActionEvent.ACTION, eventHandler);
                        }
                    }
                }
        
            } 
        }
        
        // هذا كونستركور الكلاس
        public GamePane() {
            
            // GamePane هنا قمنا بتحديد حجم كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
            firstPlayerName.setPrefSize(150, 30);
            secondPlayerName.setPrefSize(150, 30);
            firstPlayerScore.setPrefSize(150, 30);
            secondPlayerScore.setPrefSize(150, 30);
            currentPlayerSymbol.setPrefSize(150, 30);
            boardPane.setPrefSize(300, 300);
            newGame.setPrefSize(140, 30);
    
            // GamePane هنا قمنا بتحديد موقع كل شيء سنضيفه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس
            firstPlayerName.setTranslateY(10);
            secondPlayerName.setTranslateX(250);
            secondPlayerName.setTranslateY(10);
            firstPlayerScore.setTranslateY(40);
            secondPlayerScore.setTranslateX(250);
            secondPlayerScore.setTranslateY(40);
            currentPlayerSymbol.setTranslateX(120);
            currentPlayerSymbol.setTranslateY(25);
            boardBackground.setFitWidth(300);
            boardBackground.setFitHeight(300);
            boardBackground.setTranslateX(45);
            boardBackground.setTranslateY(105);
            boardPane.setTranslateX(45);
            boardPane.setTranslateY(105);
            back.setPrefSize(140, 30);
            back.setTranslateX(20);
            back.setTranslateY(455);
            newGame.setTranslateX(230);
            newGame.setTranslateY(455);
            
            // هنا قمنا بجعل نصوص أسماء اللاعبين, و نتيجتهم تظهر في وسط المكان المخصص لظهورهم
            firstPlayerName.setAlignment(Pos.CENTER);
            secondPlayerName.setAlignment(Pos.CENTER);
            firstPlayerScore.setAlignment(Pos.CENTER);
            secondPlayerScore.setAlignment(Pos.CENTER);
            currentPlayerSymbol.setAlignment(Pos.CENTER);
    
            // boardPane و التي سيتم عرضها في الحاوية boardButtons حتى تنشئ الأزرار التي سيتم وضعها في المصفوفة createGameBoard() هنا قمنا باستدعاء الدالة
            createGameBoard();
            
            // GamePane هنا قمنا بإضافة كل شيء قمنا بإنشائه في الحاوية التي يمثلها الكائن الذي ننشئه من الكلاس   
            getChildren().add(firstPlayerName);
            getChildren().add(secondPlayerName);
            getChildren().add(firstPlayerScore);
            getChildren().add(secondPlayerScore);
            getChildren().add(currentPlayerSymbol);
            getChildren().add(boardPane);
            getChildren().add(boardBackground);
            getChildren().add(back);
            getChildren().add(newGame);
    
            // لبدء لعبة جديدة startNewGame() هنا قمنا باستدعاء الدالة
            startNewGame();
            
            // back هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
            // لعرض الحاوية التي كانت معروضة قبل عرض الحاوية الحالية viewPane() سيتم إستدعاء الدالة الثابتة   
            back.setOnAction((Action) -> {
    
                startNewGame();
                
                if (AppManager.challengeComputer)
                    AppManager.viewPane(AppManager.singlePlayerPane);
                
                else
                    AppManager.viewPane(AppManager.multiPlayerPane);
                
            });
    
            // newGame هنا قمنا بتحديد ما سيحدث عند النقر على الزر الذي يمثله الكائن
            // لبدء اللعبة من جديد startNewGame() سيتم استدعاء الدالة
            newGame.setOnAction((Action) -> {
                startNewGame();
            });
    
        }
    
    }
    		

    Main.java
    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.layout.Pane;
    import javafx.stage.Stage;
    
    public class Main extends Application {
        
        @Override
        public void start(Stage stage) {
            
    		// لتحديد خصائص الخط الإفتراضي الذي سيتم وضعه لكل setDefaultSettings() هنا قمنا باستدعاء الدالة الثابتة
    		// زر, نص و مربع نص تم وضعه في اللعبة. بالإضافة إلى الصورة التي سيتم وضعها كخلفية في حاوية اللعب
            AppManager.setDefaultSettings();
            
    		// لكل الحاويات التي سنضعها في اللعبة Root Node و الذي سنضعه كـ Pane هنا قمنا بإنشاء كائن من الكلاس
            Pane root = new Pane();
            
    		// حتى نكون قادرين على عرضها في النافذة root في الكائن AppManager هنا قمنا بإضافة جميع الحاويات التي أنشأناها في الكلاس
            root.getChildren().add(AppManager.startPane);
            root.getChildren().add(AppManager.singlePlayerPane);
            root.getChildren().add(AppManager.multiPlayerPane);
            root.getChildren().add(AppManager.settingsPane);
            root.getChildren().add(AppManager.gamePane);
            
    		// لها لأننا نريد عرض هذه الحاوية في النافذة عند تشغيل اللعبة startPane و تمرير الحاوية AppManager من الكلاس viewPane() هنا قمنا باستدعاء الدالة الثابتة
            AppManager.viewPane(AppManager.startPane);
    
            // فيها و تحديد حجمها Node كأول root هنا قمنا بإنشاء محتوى النافذة مع تعيين الكائن
            Scene scene = new Scene(root, 380, 500);
            
    		// هنا قمنا بإنشاء و إظهار نافذة اللعبة مع جعل حجمها غير قابل للتكبير أو التصغي
            stage.setTitle("Tic Tac Toe");
            stage.setScene(scene);
            stage.setResizable(false);
            stage.show();
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    
    }
    		

    هذه الصور جميعها من اللعبة.

    javafx tic tac toe source code تحميل كود لعبة tic tac toe في جافا
    إعلان

    Eqla3Tech.com

    شروحات مكتوبة حول لغات البرمجة و تقنية المعلومات باللغة العربية مقدمة من إقلاع تك.

    لغة جافا لغة ++C قواعد البيانات نظام ويندوز نظام لينكس الشبكات تقنية المعلومات الأمن السيبراني

    الدورات

    أدوات مساعدة

    الأقسام

    دورات
    مقالات أسئلة مشاريع كتب